1 |
|
|
/* |
2 |
|
|
Teem: Tools to process and visualize scientific data and images . |
3 |
|
|
Copyright (C) 2013, 2012, 2011, 2010, 2009 University of Chicago |
4 |
|
|
Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann |
5 |
|
|
Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah |
6 |
|
|
|
7 |
|
|
This library is free software; you can redistribute it and/or |
8 |
|
|
modify it under the terms of the GNU Lesser General Public License |
9 |
|
|
(LGPL) as published by the Free Software Foundation; either |
10 |
|
|
version 2.1 of the License, or (at your option) any later version. |
11 |
|
|
The terms of redistributing and/or modifying this software also |
12 |
|
|
include exceptions to the LGPL that facilitate static linking. |
13 |
|
|
|
14 |
|
|
This library is distributed in the hope that it will be useful, |
15 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 |
|
|
Lesser General Public License for more details. |
18 |
|
|
|
19 |
|
|
You should have received a copy of the GNU Lesser General Public License |
20 |
|
|
along with this library; if not, write to Free Software Foundation, Inc., |
21 |
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 |
|
|
*/ |
23 |
|
|
|
24 |
|
|
#include "teem/nrrd.h" |
25 |
|
|
|
26 |
|
|
#define BKEY "tskip" |
27 |
|
|
|
28 |
|
|
#if defined(WIN32) || defined(_WIN32) |
29 |
|
|
# define COMMIT "c" |
30 |
|
|
#else |
31 |
|
|
# define COMMIT "" |
32 |
|
|
#endif |
33 |
|
|
|
34 |
|
|
/* |
35 |
|
|
** Tests: |
36 |
|
|
** nrrdLoad with positive and negative byte skipping on data read, |
37 |
|
|
** with nrrdEncodingRaw |
38 |
|
|
*/ |
39 |
|
|
|
40 |
|
|
static const char *tskipInfo = "for testing byte skipping in nrrd files"; |
41 |
|
|
|
42 |
|
|
int |
43 |
|
|
main(int argc, const char **argv) { |
44 |
|
|
/* stock variables */ |
45 |
|
12 |
char me[] = BKEY; |
46 |
|
6 |
hestOpt *hopt=NULL; |
47 |
|
|
hestParm *hparm; |
48 |
|
|
airArray *mop; |
49 |
|
|
/* variables specific to this program */ |
50 |
|
6 |
int negskip, progress; |
51 |
|
|
Nrrd *nref, *nin; |
52 |
|
6 |
size_t *size, ii, nn, tick, pad[2]; |
53 |
|
6 |
unsigned int axi, refCRC, gotCRC, sizeNum; |
54 |
|
6 |
char *berr, *outS[2], stmp[AIR_STRLEN_SMALL], doneStr[AIR_STRLEN_SMALL]; |
55 |
|
|
airRandMTState *rng; |
56 |
|
6 |
unsigned int seed, *rdata, printbytes; |
57 |
|
|
unsigned char *dataUC; |
58 |
|
|
double time0, time1; |
59 |
|
|
FILE *fout; |
60 |
|
|
|
61 |
|
|
/* start-up */ |
62 |
|
6 |
mop = airMopNew(); |
63 |
|
6 |
hparm = hestParmNew(); |
64 |
|
6 |
airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways); |
65 |
|
|
/* learn things from hest */ |
66 |
|
6 |
hestOptAdd(&hopt, "seed", "N", airTypeUInt, 1, 1, &seed, "42", |
67 |
|
|
"seed for RNG"); |
68 |
|
6 |
hestOptAdd(&hopt, "s", "sz0", airTypeSize_t, 1, -1, &size, NULL, |
69 |
|
|
"sizes of desired output", &sizeNum); |
70 |
|
6 |
hestOptAdd(&hopt, "p", "pb pa", airTypeSize_t, 2, 2, pad, "0 0", |
71 |
|
|
"bytes of padding before, and after, the data segment " |
72 |
|
|
"in the written data"); |
73 |
|
6 |
hestOptAdd(&hopt, "ns", "bool", airTypeInt, 0, 0, &negskip, NULL, |
74 |
|
|
"skipping should be relative to end of file"); |
75 |
|
6 |
hestOptAdd(&hopt, "pb", "print", airTypeUInt, 1, 1, &printbytes, "0", |
76 |
|
|
"bytes to print at beginning and end of data, to help " |
77 |
|
|
"debug problems"); |
78 |
|
6 |
hestOptAdd(&hopt, "o", "out.data out.nhdr", airTypeString, 2, 2, |
79 |
|
6 |
outS, NULL, "output filenames of data and header"); |
80 |
|
6 |
hestParseOrDie(hopt, argc-1, argv+1, hparm, me, tskipInfo, |
81 |
|
|
AIR_TRUE, AIR_TRUE, AIR_TRUE); |
82 |
|
6 |
airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways); |
83 |
|
6 |
airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); |
84 |
|
|
|
85 |
|
|
/* generate reference nrrd data */ |
86 |
|
6 |
nref = nrrdNew(); |
87 |
|
6 |
airMopAdd(mop, nref, (airMopper)nrrdNuke, airMopAlways); |
88 |
✗✓ |
6 |
if (nrrdMaybeAlloc_nva(nref, nrrdTypeUInt, sizeNum, size)) { |
89 |
|
|
airMopAdd(mop, berr=biffGetDone(NRRD), airFree, airMopAlways); |
90 |
|
|
fprintf(stderr, "%s: error allocating data: %s\n", me, berr); |
91 |
|
|
airMopError(mop); return 1; |
92 |
|
|
} |
93 |
|
6 |
rng = airRandMTStateNew(seed); |
94 |
|
6 |
airMopAdd(mop, rng, (airMopper)airRandMTStateNix, airMopAlways); |
95 |
|
6 |
nn = nrrdElementNumber(nref); |
96 |
|
6 |
rdata = AIR_CAST(unsigned int *, nref->data); |
97 |
|
6 |
fprintf(stderr, "generating data: . . . "); fflush(stderr); |
98 |
|
6 |
time0 = airTime(); |
99 |
|
|
progress = AIR_FALSE; |
100 |
|
6 |
tick = nn/100; |
101 |
✓✓ |
12733284 |
for (ii=0; ii<nn; ii++) { |
102 |
|
6366636 |
rdata[ii] = airUIrandMT_r(rng); |
103 |
✓✓✓✓
|
12733266 |
if (ii && tick && !(ii % tick)) { |
104 |
|
600 |
time1 = airTime(); |
105 |
✗✓ |
600 |
if (time1 - time0 > 1.0) { |
106 |
|
|
/* if it took more than a second to do 1% of the thing, |
107 |
|
|
would be good to generate some progress indication */ |
108 |
|
|
progress = AIR_TRUE; |
109 |
|
|
} |
110 |
✗✓ |
600 |
if (progress) { |
111 |
|
|
fprintf(stderr, "%s", airDoneStr(0, ii, nn, doneStr)); fflush(stderr); |
112 |
|
|
} |
113 |
|
|
} |
114 |
|
|
} |
115 |
✗✓✗✓
|
12 |
if (progress) { |
116 |
|
6 |
fprintf(stderr, "%s\n", airDoneStr(0, ii, nn, doneStr)); fflush(stderr); |
117 |
|
|
} else { |
118 |
|
6 |
fprintf(stderr, "\n"); |
119 |
|
|
} |
120 |
|
6 |
fprintf(stderr, "finding reference (big-endian) CRC: "); fflush(stderr); |
121 |
|
6 |
refCRC = nrrdCRC32(nref, airEndianBig); |
122 |
|
6 |
fprintf(stderr, "%u\n", refCRC); |
123 |
|
|
|
124 |
|
|
/* write data, with padding */ |
125 |
|
6 |
fprintf(stderr, "saving data . . . "); fflush(stderr); |
126 |
✗✓ |
6 |
if (!(fout = fopen(outS[0], "wb" COMMIT))) { |
127 |
|
|
fprintf(stderr, "\n%s: couldn't open %s for writing: %s\n", me, |
128 |
|
|
outS[0], strerror(errno)); |
129 |
|
|
airMopError(mop); return 1; |
130 |
|
|
} |
131 |
|
6 |
airMopAdd(mop, fout, (airMopper)airFclose, airMopAlways); |
132 |
✓✓ |
584 |
for (ii=0; ii<pad[0]; ii++) { |
133 |
✗✓ |
286 |
if (EOF == fputc(1, fout)) { |
134 |
|
|
fprintf(stderr, "\n%s: error doing pre-padding\n", me); |
135 |
|
|
airMopError(mop); return 1; |
136 |
|
|
} |
137 |
|
|
} |
138 |
✗✓ |
6 |
if (nn != fwrite(nref->data, nrrdElementSize(nref), nn, fout)) { |
139 |
|
|
fprintf(stderr, "\n%s: error writing data\n", me); |
140 |
|
|
airMopError(mop); return 1; |
141 |
|
|
} |
142 |
✓✓ |
732 |
for (ii=0; ii<pad[1]; ii++) { |
143 |
✗✓ |
360 |
if (EOF == fputc(2, fout)) { |
144 |
|
|
fprintf(stderr, "\n%s: error doing post-padding\n", me); |
145 |
|
|
airMopError(mop); return 1; |
146 |
|
|
} |
147 |
|
|
} |
148 |
✗✓ |
6 |
if (EOF == fflush(fout)) { |
149 |
|
|
fprintf(stderr, "\n%s: error fflushing data: %s\n", me, |
150 |
|
|
strerror(errno)); |
151 |
|
|
} |
152 |
|
6 |
fprintf(stderr, "\n"); |
153 |
✗✓ |
6 |
if (printbytes) { |
154 |
|
|
size_t bi, rpb, local_nn; |
155 |
|
|
char local_stmp[AIR_STRLEN_SMALL]; |
156 |
|
|
local_nn = nrrdElementSize(nref)*nrrdElementNumber(nref); |
157 |
|
|
rpb = AIR_MIN(printbytes, local_nn); |
158 |
|
|
dataUC = AIR_CAST(unsigned char *, nref->data); |
159 |
|
|
fprintf(stderr, "CORRECT %s bytes at beginning:\n", |
160 |
|
|
airSprintSize_t(local_stmp, rpb)); |
161 |
|
|
for (bi=0; bi<rpb; bi++) { |
162 |
|
|
fprintf(stderr, "%x ", dataUC[bi]); |
163 |
|
|
} |
164 |
|
|
fprintf(stderr, "...\n"); |
165 |
|
|
fprintf(stderr, "CORRECT %s bytes at end:\n", |
166 |
|
|
airSprintSize_t(local_stmp, rpb)); |
167 |
|
|
fprintf(stderr, "..."); |
168 |
|
|
for (bi=local_nn - rpb; bi<local_nn; bi++) { |
169 |
|
|
fprintf(stderr, " %x", dataUC[bi]); |
170 |
|
|
} |
171 |
|
|
fprintf(stderr, "\n"); |
172 |
|
|
} |
173 |
|
6 |
airMopSingleOkay(mop, fout); |
174 |
|
6 |
airMopSingleOkay(mop, nref); nref = NULL; |
175 |
|
|
|
176 |
|
|
/* write header; for now just writing the header directly */ |
177 |
|
6 |
fprintf(stderr, "writing header . . . \n"); |
178 |
✗✓ |
6 |
if (!(fout = fopen(outS[1], "w"))) { |
179 |
|
|
fprintf(stderr, "%s: couldn't open %s for writing: %s\n", me, |
180 |
|
|
outS[1], strerror(errno)); |
181 |
|
|
airMopError(mop); return 1; |
182 |
|
|
} |
183 |
|
6 |
airMopAdd(mop, fout, (airMopper)airFclose, airMopAlways); |
184 |
|
6 |
fprintf(fout, "NRRD0005\n"); |
185 |
|
6 |
fprintf(fout, "type: unsigned int\n"); |
186 |
|
6 |
fprintf(fout, "dimension: %u\n", sizeNum); |
187 |
|
6 |
fprintf(fout, "sizes:"); |
188 |
✓✓ |
48 |
for (axi=0; axi<sizeNum; axi++) { |
189 |
|
18 |
fprintf(fout, " %s", airSprintSize_t(stmp, size[axi])); |
190 |
|
|
} |
191 |
|
6 |
fprintf(fout, "\n"); |
192 |
|
6 |
fprintf(fout, "endian: %s\n", airEnumStr(airEndian, airMyEndian())); |
193 |
|
6 |
fprintf(fout, "encoding: %s\n", airEnumStr(nrrdEncodingType, |
194 |
|
|
nrrdEncodingTypeRaw)); |
195 |
✓✓ |
6 |
if (!negskip) { |
196 |
✓✓ |
3 |
if (pad[0]) { |
197 |
|
2 |
fprintf(fout, "byte skip: %s\n", airSprintSize_t(stmp, pad[0])); |
198 |
|
2 |
} |
199 |
|
|
} else { |
200 |
|
3 |
fprintf(fout, "byte skip: -%s\n", airSprintSize_t(stmp, pad[1]+1)); |
201 |
|
|
} |
202 |
|
6 |
fprintf(fout, "data file: %s\n", outS[0]); |
203 |
|
6 |
airMopSingleOkay(mop, fout); |
204 |
|
|
|
205 |
|
|
/* read it in, make sure it checks out */ |
206 |
|
6 |
fprintf(stderr, "reading data . . . \n"); |
207 |
|
6 |
nin = nrrdNew(); |
208 |
|
6 |
airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways); |
209 |
✗✓ |
6 |
if (nrrdLoad(nin, outS[1], NULL)) { |
210 |
|
|
airMopAdd(mop, berr=biffGetDone(NRRD), airFree, airMopAlways); |
211 |
|
|
fprintf(stderr, "%s: error reading back in: %s\n", me, berr); |
212 |
|
|
airMopError(mop); return 1; |
213 |
|
|
} |
214 |
✗✓ |
6 |
if (printbytes) { |
215 |
|
|
size_t bi, rpb, local_nn; |
216 |
|
|
char local_stmp[AIR_STRLEN_SMALL]; |
217 |
|
|
local_nn = nrrdElementSize(nin)*nrrdElementNumber(nin); |
218 |
|
|
rpb = AIR_MIN(printbytes, local_nn); |
219 |
|
|
dataUC = AIR_CAST(unsigned char *, nin->data); |
220 |
|
|
fprintf(stderr, "FOUND %s bytes at beginning:\n", |
221 |
|
|
airSprintSize_t(local_stmp, rpb)); |
222 |
|
|
for (bi=0; bi<rpb; bi++) { |
223 |
|
|
fprintf(stderr, "%x ", dataUC[bi]); |
224 |
|
|
} |
225 |
|
|
fprintf(stderr, "...\n"); |
226 |
|
|
fprintf(stderr, "FOUND %s bytes at end:\n", |
227 |
|
|
airSprintSize_t(local_stmp, rpb)); |
228 |
|
|
fprintf(stderr, "..."); |
229 |
|
|
for (bi=local_nn - rpb; bi<local_nn; bi++) { |
230 |
|
|
fprintf(stderr, " %x", dataUC[bi]); |
231 |
|
|
} |
232 |
|
|
fprintf(stderr, "\n"); |
233 |
|
|
} |
234 |
|
6 |
fprintf(stderr, "finding new CRC . . . \n"); |
235 |
|
6 |
gotCRC = nrrdCRC32(nin, airEndianBig); |
236 |
✗✓✗✓
|
12 |
if (refCRC != gotCRC) { |
237 |
|
6 |
fprintf(stderr, "%s: got CRC %u but wanted %u\n", me, gotCRC, refCRC); |
238 |
|
|
airMopError(mop); return 1; |
239 |
|
|
} |
240 |
|
6 |
fprintf(stderr, "(all ok)\n"); |
241 |
|
|
|
242 |
|
|
/* HEY: to test gzip reading, we really want to do a system call to |
243 |
|
|
gzip compress the data, and write a new header to point to the |
244 |
|
|
compressed data, and make sure we can read in that just the same */ |
245 |
|
|
|
246 |
|
6 |
airMopOkay(mop); |
247 |
|
6 |
return 0; |
248 |
|
6 |
} |