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 "nrrd.h" |
25 |
|
|
#include "privateNrrd.h" |
26 |
|
|
|
27 |
|
|
/* |
28 |
|
|
** _nrrdReadNrrdParseField() |
29 |
|
|
** |
30 |
|
|
** This is for parsing the stuff BEFORE the colon |
31 |
|
|
*/ |
32 |
|
|
int |
33 |
|
|
_nrrdReadNrrdParseField(NrrdIoState *nio, int useBiff) { |
34 |
|
|
static const char me[]="_nrrdReadNrrdParseField"; |
35 |
|
|
char *next, *buff, *colon, *keysep; |
36 |
|
|
int ret, fld=nrrdField_unknown, noField, badField=AIR_FALSE; |
37 |
|
|
|
38 |
|
506 |
next = nio->line + nio->pos; |
39 |
|
|
|
40 |
|
|
/* determining if the line is a comment is simple */ |
41 |
✓✓ |
253 |
if (NRRD_COMMENT_CHAR == next[0]) { |
42 |
|
37 |
return nrrdField_comment; |
43 |
|
|
} |
44 |
|
|
|
45 |
✗✓ |
216 |
if (!( buff = airStrdup(next) )) { |
46 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: couldn't allocate buffer!", me); |
47 |
|
|
return nrrdField_unknown; |
48 |
|
|
} |
49 |
|
|
|
50 |
|
|
/* #1: "...if you see a colon, then look for an equal sign..." */ |
51 |
|
|
|
52 |
|
|
/* Look for colon: if no colon, or failed to parse as a field, look for |
53 |
|
|
* equal sign, if that failed then error */ |
54 |
|
|
|
55 |
|
|
/* Let the separator be := */ |
56 |
|
|
/* Escape \n */ |
57 |
|
|
|
58 |
|
216 |
colon = strstr(buff, ": "); |
59 |
|
216 |
noField = !colon; |
60 |
✓✓ |
216 |
if (colon) { |
61 |
|
213 |
*colon = '\0'; |
62 |
|
213 |
badField = ( nrrdField_unknown == (fld = airEnumVal(nrrdField, buff)) ); |
63 |
|
213 |
} |
64 |
✓✓ |
216 |
if (noField || badField) { |
65 |
|
3 |
keysep = strstr(buff, ":="); |
66 |
✗✓ |
3 |
if (!keysep) { |
67 |
|
|
if (noField) { |
68 |
|
|
biffMaybeAddf(useBiff, NRRD, |
69 |
|
|
"%s: didn't see \": \" or \":=\" in line", |
70 |
|
|
me); |
71 |
|
|
} else { |
72 |
|
|
biffMaybeAddf(useBiff, NRRD, |
73 |
|
|
"%s: failed to parse \"%s\" as field identifier", |
74 |
|
|
me, buff); |
75 |
|
|
} |
76 |
|
|
free(buff); return nrrdField_unknown; |
77 |
|
|
} |
78 |
|
|
|
79 |
|
3 |
free(buff); |
80 |
|
|
ret = nrrdField_keyvalue; |
81 |
|
3 |
} else { |
82 |
|
|
|
83 |
|
|
/* *colon = '\0'; */ |
84 |
|
|
/* else we successfully parsed a field identifier */ |
85 |
|
213 |
next += strlen(buff) + 2; |
86 |
|
213 |
free(buff); |
87 |
|
|
|
88 |
|
|
/* skip whitespace prior to start of first field descriptor */ |
89 |
|
213 |
next += strspn(next, _nrrdFieldSep); |
90 |
|
213 |
nio->pos = AIR_CAST(int, next - nio->line); |
91 |
|
|
|
92 |
|
|
ret = fld; |
93 |
|
|
} |
94 |
|
216 |
return ret; |
95 |
|
253 |
} |
96 |
|
|
|
97 |
|
|
/* |
98 |
|
|
** NOTE: it is a common but unfortunate property of these parsers that |
99 |
|
|
** they set values in the nrrd first, and then check their validity |
100 |
|
|
** later. The reason for this is mostly the desire to centralize |
101 |
|
|
** validity checking in one place, and right now that's in the |
102 |
|
|
** _nrrdFieldCheck[] array of checkers |
103 |
|
|
*/ |
104 |
|
|
|
105 |
|
|
static int |
106 |
|
|
_nrrdReadNrrdParse_nonfield(FILE *file, Nrrd *nrrd, |
107 |
|
|
NrrdIoState *nio, int useBiff) { |
108 |
|
|
AIR_UNUSED(file); |
109 |
|
|
AIR_UNUSED(nrrd); |
110 |
|
|
AIR_UNUSED(nio); |
111 |
|
|
AIR_UNUSED(useBiff); |
112 |
|
|
/* |
113 |
|
|
char c; |
114 |
|
|
|
115 |
|
|
c= 10; write(2,&c,1); c= 69; write(2,&c,1); c=108; write(2,&c,1); |
116 |
|
|
c= 32; write(2,&c,1); c= 67; write(2,&c,1); c=104; write(2,&c,1); |
117 |
|
|
c=101; write(2,&c,1); c= 32; write(2,&c,1); c= 86; write(2,&c,1); |
118 |
|
|
c=105; write(2,&c,1); c=118; write(2,&c,1); c=101; write(2,&c,1); |
119 |
|
|
c= 33; write(2,&c,1); c= 10; write(2,&c,1); c= 10; write(2,&c,1); |
120 |
|
|
*/ |
121 |
|
|
return 0; |
122 |
|
|
} |
123 |
|
|
|
124 |
|
|
static int |
125 |
|
|
_nrrdReadNrrdParse_comment(FILE *file, Nrrd *nrrd, |
126 |
|
|
NrrdIoState *nio, int useBiff) { |
127 |
|
|
static const char me[]="_nrrdReadNrrdParse_comment"; |
128 |
|
|
char *info; |
129 |
|
|
|
130 |
|
|
AIR_UNUSED(file); |
131 |
|
74 |
info = nio->line + nio->pos; |
132 |
|
|
/* this skips the '#' at nio->line[nio->pos] and any other ' ' and '#' */ |
133 |
✗✓ |
37 |
if (nrrdCommentAdd(nrrd, info)) { |
134 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble adding comment", me); |
135 |
|
|
return 1; |
136 |
|
|
} |
137 |
|
37 |
return 0; |
138 |
|
37 |
} |
139 |
|
|
|
140 |
|
|
static int |
141 |
|
|
_nrrdReadNrrdParse_content(FILE *file, Nrrd *nrrd, |
142 |
|
|
NrrdIoState *nio, int useBiff) { |
143 |
|
|
static const char me[]="_nrrdReadNrrdParse_content"; |
144 |
|
|
char *info; |
145 |
|
|
|
146 |
|
|
AIR_UNUSED(file); |
147 |
|
8 |
info = nio->line + nio->pos; |
148 |
✓✗✗✓
|
8 |
if (strlen(info) && !(nrrd->content = airStrdup(info))) { |
149 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: couldn't strdup() content", me); |
150 |
|
|
return 1; |
151 |
|
|
} |
152 |
|
4 |
return 0; |
153 |
|
4 |
} |
154 |
|
|
|
155 |
|
|
static int |
156 |
|
|
_nrrdReadNrrdParse_number(FILE *file, Nrrd *nrrd, |
157 |
|
|
NrrdIoState *nio, int useBiff) { |
158 |
|
|
/* |
159 |
|
|
static const char me[]="_nrrdReadNrrdParse_number"; |
160 |
|
|
char *info; |
161 |
|
|
|
162 |
|
|
info = nio->line + nio->pos; |
163 |
|
|
if (1 != sscanf(info, NRRD_BIG_INT_PRINTF, &(nrrd->num))) { |
164 |
|
|
biffMaybeAddf(useBiff, NRRD, |
165 |
|
|
"%s: couldn't parse number \"%s\"", me, info); return 1; |
166 |
|
|
} |
167 |
|
|
*/ |
168 |
|
|
|
169 |
|
|
AIR_UNUSED(file); |
170 |
|
|
AIR_UNUSED(nrrd); |
171 |
|
|
AIR_UNUSED(nio); |
172 |
|
|
AIR_UNUSED(useBiff); |
173 |
|
|
/* It was decided to just completely ignore this field. "number" is |
174 |
|
|
** entirely redundant with the (required) sizes field, and there is no |
175 |
|
|
** need to save it to, or learn it from, the header. In fact the "num" |
176 |
|
|
** field was eliminated from the Nrrd struct some time ago, in favor of |
177 |
|
|
** the nrrdElementNumber() function. It may seem odd or unfortunate that |
178 |
|
|
** |
179 |
|
|
** number: Hank Hill sells propane and propane accessories |
180 |
|
|
** |
181 |
|
|
** is a valid field specification, but at least Peggy is proud ... |
182 |
|
|
*/ |
183 |
|
|
|
184 |
|
|
return 0; |
185 |
|
|
} |
186 |
|
|
|
187 |
|
|
static int |
188 |
|
|
_nrrdReadNrrdParse_type(FILE *file, Nrrd *nrrd, |
189 |
|
|
NrrdIoState *nio, int useBiff) { |
190 |
|
|
static const char me[]="_nrrdReadNrrdParse_type"; |
191 |
|
|
char *info; |
192 |
|
|
|
193 |
|
|
AIR_UNUSED(file); |
194 |
|
46 |
info = nio->line + nio->pos; |
195 |
✗✓ |
23 |
if (!(nrrd->type = airEnumVal(nrrdType, info))) { |
196 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: couldn't parse type \"%s\"", me, info); |
197 |
|
|
return 1; |
198 |
|
|
} |
199 |
✗✓ |
23 |
if (_nrrdFieldCheck[nrrdField_type](nrrd, useBiff)) { |
200 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
201 |
|
|
return 1; |
202 |
|
|
} |
203 |
|
23 |
return 0; |
204 |
|
23 |
} |
205 |
|
|
|
206 |
|
|
#define _PARSE_ONE_VAL(FIELD, CONV, TYPE) \ |
207 |
|
|
if (1 != airSingleSscanf(info, CONV, &(FIELD))) { \ |
208 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: couldn't parse " TYPE \ |
209 |
|
|
" from \"%s\"", me, info); \ |
210 |
|
|
return 1; \ |
211 |
|
|
} |
212 |
|
|
|
213 |
|
|
static int |
214 |
|
|
_nrrdReadNrrdParse_block_size(FILE *file, Nrrd *nrrd, |
215 |
|
|
NrrdIoState *nio, int useBiff) { |
216 |
|
|
static const char me[]="_nrrdReadNrrdParse_block_size"; |
217 |
|
|
char *info; |
218 |
|
|
|
219 |
|
|
AIR_UNUSED(file); |
220 |
|
|
info = nio->line + nio->pos; |
221 |
|
|
if (1 != airSingleSscanf(info, "%z", &(nrrd->blockSize))) { |
222 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: couldn't parse size_t" |
223 |
|
|
" from \"%s\"", me, info); |
224 |
|
|
} |
225 |
|
|
/* because blockSize and type fields may appear in any order, |
226 |
|
|
we can't use _nrrdFieldCheck[] */ |
227 |
|
|
return 0; |
228 |
|
|
} |
229 |
|
|
|
230 |
|
|
static int |
231 |
|
|
_nrrdReadNrrdParse_dimension(FILE *file, Nrrd *nrrd, |
232 |
|
|
NrrdIoState *nio, int useBiff) { |
233 |
|
|
static const char me[]="_nrrdReadNrrdParse_dimension"; |
234 |
|
|
char *info; |
235 |
|
|
|
236 |
|
|
AIR_UNUSED(file); |
237 |
|
46 |
info = nio->line + nio->pos; |
238 |
✗✓ |
23 |
_PARSE_ONE_VAL(nrrd->dim, "%u", "unsigned int"); |
239 |
✗✓ |
23 |
if (_nrrdFieldCheck[nrrdField_dimension](nrrd, useBiff)) { |
240 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
241 |
|
|
return 1; |
242 |
|
|
} |
243 |
|
23 |
return 0; |
244 |
|
23 |
} |
245 |
|
|
|
246 |
|
|
/* |
247 |
|
|
** checking nrrd->dim against zero is valid because it is initialized |
248 |
|
|
** to zero, and, _nrrdReadNrrdParse_dimension() won't allow it to be |
249 |
|
|
** set to anything outside the range [1, NRRD_DIM_MAX] |
250 |
|
|
*/ |
251 |
|
|
#define _CHECK_HAVE_DIM \ |
252 |
|
|
if (0 == nrrd->dim) { \ |
253 |
|
|
biffMaybeAddf(useBiff, NRRD, \ |
254 |
|
|
"%s: don't yet have a valid dimension", me); \ |
255 |
|
|
return 1; \ |
256 |
|
|
} |
257 |
|
|
|
258 |
|
|
#define _CHECK_HAVE_SPACE_DIM \ |
259 |
|
|
if (0 == nrrd->spaceDim) { \ |
260 |
|
|
biffMaybeAddf(useBiff, NRRD, \ |
261 |
|
|
"%s: don't yet have a valid space dimension", me); \ |
262 |
|
|
return 1; \ |
263 |
|
|
} |
264 |
|
|
|
265 |
|
|
#define _CHECK_GOT_ALL_VALUES \ |
266 |
|
|
if (nrrd->dim != ret) { \ |
267 |
|
|
biffMaybeAddf(useBiff, NRRD, \ |
268 |
|
|
"%s: parsed %d values, but dimension is %d", \ |
269 |
|
|
me, ret, nrrd->dim); \ |
270 |
|
|
return 1; \ |
271 |
|
|
} |
272 |
|
|
|
273 |
|
|
static int |
274 |
|
|
_nrrdReadNrrdParse_sizes(FILE *file, Nrrd *nrrd, |
275 |
|
|
NrrdIoState *nio, int useBiff) { |
276 |
|
|
static const char me[]="_nrrdReadNrrdParse_sizes"; |
277 |
|
|
unsigned int ret; |
278 |
|
46 |
size_t val[NRRD_DIM_MAX]; |
279 |
|
|
char *info; |
280 |
|
|
|
281 |
|
|
AIR_UNUSED(file); |
282 |
|
23 |
info = nio->line + nio->pos; |
283 |
✗✓ |
23 |
_CHECK_HAVE_DIM; |
284 |
|
23 |
ret = airParseStrZ(val, info, _nrrdFieldSep, nrrd->dim); |
285 |
✗✓ |
23 |
_CHECK_GOT_ALL_VALUES; |
286 |
|
23 |
nrrdAxisInfoSet_nva(nrrd, nrrdAxisInfoSize, val); |
287 |
|
|
/* HEY: this is a very imperfect check of excess info */ |
288 |
✗✓ |
23 |
if (nrrd->dim+1 == airParseStrZ(val, info, _nrrdFieldSep, nrrd->dim+1)) { |
289 |
|
|
biffMaybeAddf(useBiff, NRRD, |
290 |
|
|
"%s: seem to have more than expected %d sizes", |
291 |
|
|
me, nrrd->dim); |
292 |
|
|
return 1; |
293 |
|
|
} |
294 |
✗✓ |
23 |
if (_nrrdFieldCheck[nrrdField_sizes](nrrd, useBiff)) { |
295 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
296 |
|
|
return 1; |
297 |
|
|
} |
298 |
|
23 |
return 0; |
299 |
|
23 |
} |
300 |
|
|
|
301 |
|
|
static int |
302 |
|
|
_nrrdReadNrrdParse_spacings(FILE *file, Nrrd *nrrd, |
303 |
|
|
NrrdIoState *nio, int useBiff) { |
304 |
|
|
static const char me[]="_nrrdReadNrrdParse_spacings"; |
305 |
|
|
unsigned int ret; |
306 |
|
|
double val[NRRD_DIM_MAX]; |
307 |
|
|
char *info; |
308 |
|
|
|
309 |
|
|
AIR_UNUSED(file); |
310 |
|
|
info = nio->line + nio->pos; |
311 |
|
|
_CHECK_HAVE_DIM; |
312 |
|
|
ret = airParseStrD(val, info, _nrrdFieldSep, nrrd->dim); |
313 |
|
|
_CHECK_GOT_ALL_VALUES; |
314 |
|
|
nrrdAxisInfoSet_nva(nrrd, nrrdAxisInfoSpacing, val); |
315 |
|
|
/* HEY: this is a very imperfect check of excess info */ |
316 |
|
|
if (nrrd->dim+1 == airParseStrD(val, info, _nrrdFieldSep, nrrd->dim+1)) { |
317 |
|
|
biffMaybeAddf(useBiff, NRRD, |
318 |
|
|
"%s: seem to have more than expected %d spacings", |
319 |
|
|
me, nrrd->dim); |
320 |
|
|
return 1; |
321 |
|
|
} |
322 |
|
|
if (_nrrdFieldCheck[nrrdField_spacings](nrrd, useBiff)) { |
323 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
324 |
|
|
return 1; |
325 |
|
|
} |
326 |
|
|
return 0; |
327 |
|
|
} |
328 |
|
|
|
329 |
|
|
static int |
330 |
|
|
_nrrdReadNrrdParse_thicknesses(FILE *file, Nrrd *nrrd, |
331 |
|
|
NrrdIoState *nio, int useBiff) { |
332 |
|
|
static const char me[]="_nrrdReadNrrdParse_thicknesses"; |
333 |
|
|
unsigned int ret; |
334 |
|
|
double val[NRRD_DIM_MAX]; |
335 |
|
|
char *info; |
336 |
|
|
|
337 |
|
|
AIR_UNUSED(file); |
338 |
|
|
info = nio->line + nio->pos; |
339 |
|
|
_CHECK_HAVE_DIM; |
340 |
|
|
ret = airParseStrD(val, info, _nrrdFieldSep, nrrd->dim); |
341 |
|
|
_CHECK_GOT_ALL_VALUES; |
342 |
|
|
nrrdAxisInfoSet_nva(nrrd, nrrdAxisInfoThickness, val); |
343 |
|
|
/* HEY: this is a very imperfect check of excess info */ |
344 |
|
|
if (nrrd->dim+1 == airParseStrD(val, info, _nrrdFieldSep, nrrd->dim+1)) { |
345 |
|
|
biffMaybeAddf(useBiff, NRRD, |
346 |
|
|
"%s: seem to have more than expected %d thicknesses", |
347 |
|
|
me, nrrd->dim); |
348 |
|
|
return 1; |
349 |
|
|
} |
350 |
|
|
if (_nrrdFieldCheck[nrrdField_thicknesses](nrrd, useBiff)) { |
351 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
352 |
|
|
return 1; |
353 |
|
|
} |
354 |
|
|
return 0; |
355 |
|
|
} |
356 |
|
|
|
357 |
|
|
static int |
358 |
|
|
_nrrdReadNrrdParse_axis_mins(FILE *file, Nrrd *nrrd, |
359 |
|
|
NrrdIoState *nio, int useBiff) { |
360 |
|
|
static const char me[]="_nrrdReadNrrdParse_axis_mins"; |
361 |
|
|
unsigned int ret; |
362 |
|
8 |
double val[NRRD_DIM_MAX]; |
363 |
|
|
char *info; |
364 |
|
|
|
365 |
|
|
AIR_UNUSED(file); |
366 |
|
4 |
info = nio->line + nio->pos; |
367 |
✗✓ |
4 |
_CHECK_HAVE_DIM; |
368 |
|
4 |
ret = airParseStrD(val, info, _nrrdFieldSep, nrrd->dim); |
369 |
✗✓ |
4 |
_CHECK_GOT_ALL_VALUES; |
370 |
|
4 |
nrrdAxisInfoSet_nva(nrrd, nrrdAxisInfoMin, val); |
371 |
|
|
/* HEY: this is a very imperfect check of excess info */ |
372 |
✗✓ |
4 |
if (nrrd->dim+1 == airParseStrD(val, info, _nrrdFieldSep, nrrd->dim+1)) { |
373 |
|
|
biffMaybeAddf(useBiff, NRRD, |
374 |
|
|
"%s: seem to have more than expected %d axis mins", |
375 |
|
|
me, nrrd->dim); |
376 |
|
|
return 1; |
377 |
|
|
} |
378 |
✗✓ |
4 |
if (_nrrdFieldCheck[nrrdField_axis_mins](nrrd, useBiff)) { |
379 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
380 |
|
|
return 1; |
381 |
|
|
} |
382 |
|
4 |
return 0; |
383 |
|
4 |
} |
384 |
|
|
|
385 |
|
|
static int |
386 |
|
|
_nrrdReadNrrdParse_axis_maxs(FILE *file, Nrrd *nrrd, |
387 |
|
|
NrrdIoState *nio, int useBiff) { |
388 |
|
|
static const char me[]="_nrrdReadNrrdParse_axis_maxs"; |
389 |
|
|
unsigned int ret; |
390 |
|
8 |
double val[NRRD_DIM_MAX]; |
391 |
|
|
char *info; |
392 |
|
|
|
393 |
|
|
AIR_UNUSED(file); |
394 |
|
4 |
info = nio->line + nio->pos; |
395 |
✗✓ |
4 |
_CHECK_HAVE_DIM; |
396 |
|
4 |
ret = airParseStrD(val, info, _nrrdFieldSep, nrrd->dim); |
397 |
✗✓ |
4 |
_CHECK_GOT_ALL_VALUES; |
398 |
|
4 |
nrrdAxisInfoSet_nva(nrrd, nrrdAxisInfoMax, val); |
399 |
|
|
/* HEY: this is a very imperfect check of excess info */ |
400 |
✗✓ |
4 |
if (nrrd->dim+1 == airParseStrD(val, info, _nrrdFieldSep, nrrd->dim+1)) { |
401 |
|
|
biffMaybeAddf(useBiff, NRRD, |
402 |
|
|
"%s: seem to have more than expected %d axis maxs", |
403 |
|
|
me, nrrd->dim); |
404 |
|
|
return 1; |
405 |
|
|
} |
406 |
✗✓ |
4 |
if (_nrrdFieldCheck[nrrdField_axis_maxs](nrrd, useBiff)) { |
407 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
408 |
|
|
return 1; |
409 |
|
|
} |
410 |
|
4 |
return 0; |
411 |
|
4 |
} |
412 |
|
|
|
413 |
|
|
static int |
414 |
|
|
_nrrdSpaceVectorParse(double val[NRRD_SPACE_DIM_MAX], |
415 |
|
|
char **hhP, unsigned int spaceDim, int useBiff) { |
416 |
|
|
static const char me[]="_nrrdSpaceVectorParse"; |
417 |
|
152 |
char *hh, *buff, sep[]=",)"; |
418 |
|
|
airArray *mop; |
419 |
|
|
unsigned int ret, dd; |
420 |
|
|
size_t length; |
421 |
|
|
|
422 |
|
76 |
mop = airMopNew(); |
423 |
|
|
|
424 |
|
76 |
hh = *hhP; |
425 |
|
|
/* skip past space */ |
426 |
|
76 |
length = strspn(hh, _nrrdFieldSep); |
427 |
|
76 |
hh += length; |
428 |
|
|
|
429 |
|
|
/* make sure we have something */ |
430 |
✗✓ |
76 |
if (!*hh) { |
431 |
|
|
biffMaybeAddf(useBiff, NRRD, |
432 |
|
|
"%s: hit end of string before seeing (", me); |
433 |
|
|
airMopError(mop); return 1; |
434 |
|
|
} |
435 |
|
|
/* first, see if we're getting the non-vector */ |
436 |
✓✓ |
76 |
if ( (strstr(hh, _nrrdNoSpaceVector) == hh) ) { |
437 |
✓✗ |
16 |
if (!hh[strlen(_nrrdNoSpaceVector)] |
438 |
✓✗ |
16 |
|| strchr(_nrrdFieldSep, hh[strlen(_nrrdNoSpaceVector)])) { |
439 |
|
|
/* yes, we got the non-vector */ |
440 |
✓✓ |
64 |
for (dd=0; dd<spaceDim; dd++) { |
441 |
|
24 |
val[dd] = AIR_NAN; |
442 |
|
|
} |
443 |
|
8 |
length += strlen(_nrrdNoSpaceVector); |
444 |
|
|
} else { |
445 |
|
|
/* we got something that started out looking like the non-vector */ |
446 |
|
|
biffMaybeAddf(useBiff, NRRD, |
447 |
|
|
"%s: couldn't parse non-vector \"%s\"", me, hh); |
448 |
|
|
airMopError(mop); return 1; |
449 |
|
|
} |
450 |
|
8 |
} else { |
451 |
|
|
/* this isn't a non-vector */ |
452 |
|
|
/* make sure we have an open paren */ |
453 |
✗✓ |
68 |
if ('(' != *hh) { |
454 |
|
|
biffMaybeAddf(useBiff, NRRD, |
455 |
|
|
"%s: first vector in \"%s\" didn't start with '('", |
456 |
|
|
me, hh); |
457 |
|
|
airMopError(mop); return 1; |
458 |
|
|
} |
459 |
|
|
/* copy string (including open paren) for local fiddling */ |
460 |
✗✓ |
68 |
if (!(buff = airStrdup(hh))) { |
461 |
|
|
biffMaybeAddf(useBiff, NRRD, |
462 |
|
|
"%s: couldn't allocate local buffer", me); |
463 |
|
|
airMopError(mop); return 1; |
464 |
|
|
} |
465 |
|
68 |
airMopAdd(mop, buff, airFree, airMopAlways); |
466 |
|
|
/* scan for close paren */ |
467 |
|
68 |
hh = buff+1; |
468 |
✓✗ |
3066 |
while (*hh) { |
469 |
✓✓ |
1533 |
if (')' == *hh) { |
470 |
|
|
break; |
471 |
|
|
} else { |
472 |
|
1465 |
hh++; |
473 |
|
|
} |
474 |
|
|
} |
475 |
✗✓ |
68 |
if (')' != *hh) { |
476 |
|
|
biffMaybeAddf(useBiff, NRRD, |
477 |
|
|
"%s: didn't see ')' at end of first vector in \"%s\"", |
478 |
|
|
me, hh); |
479 |
|
|
airMopError(mop); return 1; |
480 |
|
|
} |
481 |
|
|
/* terminate at end paren */ |
482 |
|
68 |
*(hh+1) = 0; |
483 |
|
68 |
length += strlen(buff); |
484 |
|
|
/* see if we have too many fields */ |
485 |
|
68 |
ret = airStrntok(buff+1, sep); |
486 |
✗✓ |
68 |
if (ret > spaceDim) { |
487 |
|
|
biffMaybeAddf(useBiff, NRRD, |
488 |
|
|
"%s: space dimension is %d, but seem to have %d " |
489 |
|
|
"coefficients", me, spaceDim, ret); |
490 |
|
|
airMopError(mop); return 1; |
491 |
|
|
} |
492 |
|
|
/* try to parse the values */ |
493 |
|
68 |
ret = airParseStrD(val, buff+1, ",", spaceDim); |
494 |
✗✓ |
68 |
if (spaceDim != ret) { |
495 |
|
|
biffMaybeAddf(useBiff, NRRD, |
496 |
|
|
"%s: parsed %d values, but space dimension is %d", |
497 |
|
|
me, ret, spaceDim); |
498 |
|
|
airMopError(mop); return 1; |
499 |
|
|
} |
500 |
|
|
} |
501 |
|
|
/* probably not useful */ |
502 |
✓✓ |
912 |
for (dd=spaceDim; dd<NRRD_SPACE_DIM_MAX; dd++) { |
503 |
|
380 |
val[dd] = AIR_NAN; |
504 |
|
|
} |
505 |
|
|
/* make sure all coefficients exist or not together */ |
506 |
✓✓ |
456 |
for (dd=1; dd<spaceDim; dd++) { |
507 |
✗✓ |
152 |
if (!!AIR_EXISTS(val[0]) ^ !!AIR_EXISTS(val[dd])) { |
508 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: existance of all space vector " |
509 |
|
|
"coefficients must be consistent (val[0] not like " |
510 |
|
|
"val[%d])", me, dd); |
511 |
|
|
airMopError(mop); return 1; |
512 |
|
|
} |
513 |
|
|
} |
514 |
✓✓ |
608 |
for (dd=0; dd<spaceDim; dd++) { |
515 |
✗✓ |
228 |
if (airIsInf_d(val[dd])) { |
516 |
|
|
biffMaybeAddf(useBiff, NRRD, |
517 |
|
|
"%s: vector coefficient %d can't be infinite", |
518 |
|
|
me, dd); |
519 |
|
|
airMopError(mop); return 1; |
520 |
|
|
} |
521 |
|
|
} |
522 |
|
76 |
*hhP += length; |
523 |
|
76 |
airMopOkay(mop); |
524 |
|
76 |
return 0; |
525 |
|
76 |
} |
526 |
|
|
|
527 |
|
|
/* |
528 |
|
|
** public version of _nrrdSpaceVectorParse, which might not really be |
529 |
|
|
** needed, but given how _nrrdSpaceVectorParse currently wants a |
530 |
|
|
** char**, so it can move the pointer to point to the next space |
531 |
|
|
** vector to parse in a non-const string, this seems like a sane and |
532 |
|
|
** minimal effort option |
533 |
|
|
*/ |
534 |
|
|
int |
535 |
|
|
nrrdSpaceVectorParse(double dir[NRRD_SPACE_DIM_MAX], |
536 |
|
|
const char *_str, unsigned int spaceDim, int useBiff) { |
537 |
|
|
static const char me[]="nrrdSpaceVectorParse"; |
538 |
|
|
airArray *mop; |
539 |
|
|
char *str; |
540 |
|
|
|
541 |
|
|
mop = airMopNew(); |
542 |
|
|
str = airStrdup(_str); |
543 |
|
|
airMopAdd(mop, str, airFree, airMopAlways); |
544 |
|
|
if (!(dir && _str)) { |
545 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: got NULL pointer", me); |
546 |
|
|
airMopError(mop); return 1; |
547 |
|
|
} |
548 |
|
|
if (_nrrdSpaceVectorParse(dir, &str, spaceDim, useBiff)) { |
549 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble parsing", me); |
550 |
|
|
airMopError(mop); return 1; |
551 |
|
|
} |
552 |
|
|
|
553 |
|
|
airMopOkay(mop); |
554 |
|
|
return 0; |
555 |
|
|
} |
556 |
|
|
|
557 |
|
|
static int |
558 |
|
|
_nrrdReadNrrdParse_space_directions(FILE *file, Nrrd *nrrd, |
559 |
|
|
NrrdIoState *nio, int useBiff) { |
560 |
|
|
static const char me[]="_nrrdReadNrrdParse_space_directions"; |
561 |
|
|
unsigned int dd; |
562 |
|
22 |
char *info; |
563 |
|
|
|
564 |
|
|
AIR_UNUSED(file); |
565 |
|
11 |
info = nio->line + nio->pos; |
566 |
✗✓ |
11 |
_CHECK_HAVE_DIM; |
567 |
✗✓ |
11 |
_CHECK_HAVE_SPACE_DIM; |
568 |
|
|
|
569 |
✓✓ |
104 |
for (dd=0; dd<nrrd->dim; dd++) { |
570 |
✗✓✗✓
|
82 |
if (_nrrdSpaceVectorParse(nrrd->axis[dd].spaceDirection, |
571 |
|
41 |
&info, nrrd->spaceDim, useBiff)) { |
572 |
|
|
biffMaybeAddf(useBiff, NRRD, |
573 |
|
|
"%s: trouble getting space vector %d of %d", |
574 |
|
|
me, dd+1, nrrd->dim); |
575 |
|
|
return 1; |
576 |
|
|
} |
577 |
|
|
} |
578 |
✗✓ |
11 |
if (strlen(info) != strspn(info, _nrrdFieldSep)) { |
579 |
|
|
biffMaybeAddf(useBiff, NRRD, |
580 |
|
|
"%s: seem to have more than expected %d directions", |
581 |
|
|
me, nrrd->dim); |
582 |
|
|
return 1; |
583 |
|
|
} |
584 |
✗✓ |
11 |
if (_nrrdFieldCheck[nrrdField_space_directions](nrrd, useBiff)) { |
585 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
586 |
|
|
return 1; |
587 |
|
|
} |
588 |
|
11 |
return 0; |
589 |
|
11 |
} |
590 |
|
|
|
591 |
|
|
static int |
592 |
|
|
_nrrdReadNrrdParse_centers(FILE *file, Nrrd *nrrd, |
593 |
|
|
NrrdIoState *nio, int useBiff) { |
594 |
|
|
static const char me[]="_nrrdReadNrrdParse_centers"; |
595 |
|
|
unsigned int ai; |
596 |
|
30 |
char *tok, *info, *last; |
597 |
|
|
airArray *mop; |
598 |
|
|
|
599 |
|
|
AIR_UNUSED(file); |
600 |
|
15 |
mop = airMopNew(); |
601 |
|
15 |
info = airStrdup(nio->line + nio->pos); |
602 |
|
15 |
airMopAdd(mop, info, airFree, airMopAlways); |
603 |
✗✓ |
15 |
_CHECK_HAVE_DIM; |
604 |
✓✓✓✓
|
186 |
for (ai=0; ai<nrrd->dim; ai++) { |
605 |
|
62 |
tok = airStrtok(!ai ? info : NULL, _nrrdFieldSep, &last); |
606 |
✗✓ |
47 |
if (!tok) { |
607 |
|
|
biffMaybeAddf(useBiff, NRRD, |
608 |
|
|
"%s: couldn't extract string for center %d of %d", |
609 |
|
|
me, ai+1, nrrd->dim); |
610 |
|
|
airMopError(mop); return 1; |
611 |
|
|
} |
612 |
✓✓ |
47 |
if (!strcmp(tok, NRRD_UNKNOWN)) { |
613 |
|
8 |
nrrd->axis[ai].center = nrrdCenterUnknown; |
614 |
|
8 |
continue; |
615 |
|
|
} |
616 |
✗✓ |
39 |
if (!strcmp(tok, NRRD_NONE)) { |
617 |
|
|
nrrd->axis[ai].center = nrrdCenterUnknown; |
618 |
|
|
continue; |
619 |
|
|
} |
620 |
✗✓ |
39 |
if (!(nrrd->axis[ai].center = airEnumVal(nrrdCenter, tok))) { |
621 |
|
|
biffMaybeAddf(useBiff, NRRD, |
622 |
|
|
"%s: couldn't parse center \"%s\" for axis %d", |
623 |
|
|
me, tok, ai); |
624 |
|
|
airMopError(mop); return 1; |
625 |
|
|
} |
626 |
|
|
} |
627 |
✗✓ |
15 |
if (airStrtok(!ai ? info : NULL, _nrrdFieldSep, &last)) { |
628 |
|
|
biffMaybeAddf(useBiff, NRRD, |
629 |
|
|
"%s: seem to have more than expected %d centers", |
630 |
|
|
me, nrrd->dim); |
631 |
|
|
airMopError(mop); return 1; |
632 |
|
|
} |
633 |
✗✓ |
15 |
if (_nrrdFieldCheck[nrrdField_centers](nrrd, useBiff)) { |
634 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
635 |
|
|
airMopError(mop); return 1; |
636 |
|
|
} |
637 |
|
15 |
airMopOkay(mop); |
638 |
|
15 |
return 0; |
639 |
|
15 |
} |
640 |
|
|
|
641 |
|
|
static int |
642 |
|
|
_nrrdReadNrrdParse_kinds(FILE *file, Nrrd *nrrd, |
643 |
|
|
NrrdIoState *nio, int useBiff) { |
644 |
|
|
static const char me[]="_nrrdReadNrrdParse_kinds"; |
645 |
|
|
unsigned int ai; |
646 |
|
26 |
char *info, *tok, *last; |
647 |
|
|
airArray *mop; |
648 |
|
|
|
649 |
|
|
AIR_UNUSED(file); |
650 |
|
13 |
mop = airMopNew(); |
651 |
|
13 |
info = airStrdup(nio->line + nio->pos); |
652 |
|
13 |
airMopAdd(mop, info, airFree, airMopAlways); |
653 |
✗✓ |
13 |
_CHECK_HAVE_DIM; |
654 |
✓✓✓✓
|
168 |
for (ai=0; ai<nrrd->dim; ai++) { |
655 |
|
56 |
tok = airStrtok(!ai ? info : NULL, _nrrdFieldSep, &last); |
656 |
✗✓ |
43 |
if (!tok) { |
657 |
|
|
biffMaybeAddf(useBiff, NRRD, |
658 |
|
|
"%s: couldn't extract string for kind %d of %d", |
659 |
|
|
me, ai+1, nrrd->dim); |
660 |
|
|
airMopError(mop); return 1; |
661 |
|
|
} |
662 |
✗✓ |
43 |
if (!strcmp(tok, NRRD_UNKNOWN)) { |
663 |
|
|
nrrd->axis[ai].kind = nrrdKindUnknown; |
664 |
|
|
continue; |
665 |
|
|
} |
666 |
✗✓ |
43 |
if (!strcmp(tok, NRRD_NONE)) { |
667 |
|
|
nrrd->axis[ai].center = nrrdKindUnknown; |
668 |
|
|
continue; |
669 |
|
|
} |
670 |
✗✓ |
43 |
if (!(nrrd->axis[ai].kind = airEnumVal(nrrdKind, tok))) { |
671 |
|
|
biffMaybeAddf(useBiff, NRRD, |
672 |
|
|
"%s: couldn't parse \"%s\" kind %d of %d", |
673 |
|
|
me, tok, ai+1, nrrd->dim); |
674 |
|
|
airMopError(mop); return 1; |
675 |
|
|
} |
676 |
|
|
} |
677 |
✗✓ |
13 |
if (airStrtok(!ai ? info : NULL, _nrrdFieldSep, &last)) { |
678 |
|
|
biffMaybeAddf(useBiff, NRRD, |
679 |
|
|
"%s: seem to have more than expected %d kinds", |
680 |
|
|
me, nrrd->dim); |
681 |
|
|
airMopError(mop); return 1; |
682 |
|
|
} |
683 |
|
|
/* can't run this now because kinds can come before sizes, in which |
684 |
|
|
case the kind/size check in _nrrdFieldCheck_kinds will incorrectly |
685 |
|
|
flag an error ... |
686 |
|
|
if (_nrrdFieldCheck[nrrdField_kinds](nrrd, useBiff)) { |
687 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
688 |
|
|
airMopError(mop); return 1; |
689 |
|
|
} |
690 |
|
|
*/ |
691 |
|
13 |
airMopOkay(mop); |
692 |
|
13 |
return 0; |
693 |
|
13 |
} |
694 |
|
|
|
695 |
|
|
static char * |
696 |
|
|
_nrrdGetQuotedString(char **hP, int useBiff) { |
697 |
|
|
static const char me[]="_nrrdGetQuotedString"; |
698 |
|
26 |
char *h, *buff, *ret; |
699 |
|
|
airArray *buffArr; |
700 |
|
|
unsigned int pos; |
701 |
|
|
airPtrPtrUnion appu; |
702 |
|
|
|
703 |
|
13 |
h = *hP; |
704 |
|
|
/* skip past space */ |
705 |
|
|
/* printf("!%s: h |%s|\n", me, h);*/ |
706 |
|
13 |
h += strspn(h, _nrrdFieldSep); |
707 |
|
|
/* printf("!%s: h |%s|\n", me, h);*/ |
708 |
|
|
|
709 |
|
|
/* make sure we have something */ |
710 |
✓✓ |
13 |
if (!*h) { |
711 |
|
1 |
biffMaybeAddf(useBiff, NRRD, |
712 |
|
|
"%s: hit end of string before seeing opening \"", me); |
713 |
|
1 |
return NULL; |
714 |
|
|
} |
715 |
|
|
/* make sure we have a starting quote */ |
716 |
✗✓ |
12 |
if ('"' != *h) { |
717 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: didn't start with \"", me); |
718 |
|
|
return NULL; |
719 |
|
|
} |
720 |
|
12 |
h++; |
721 |
|
|
|
722 |
|
|
/* parse string until end quote */ |
723 |
|
12 |
buff = NULL; |
724 |
|
|
appu.c = &buff; |
725 |
|
12 |
buffArr = airArrayNew(appu.v, NULL, sizeof(char), 2); |
726 |
✗✓ |
12 |
if (!buffArr) { |
727 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: couldn't create airArray", me); |
728 |
|
|
return NULL; |
729 |
|
|
} |
730 |
|
12 |
pos = airArrayLenIncr(buffArr, 1); /* pos should get 0 */ |
731 |
✓✗ |
171704 |
while (h[pos]) { |
732 |
|
|
/* printf("!%s: h+%d |%s|\n", me, pos, h+pos); */ |
733 |
✓✓ |
85852 |
if ('\"' == h[pos]) { |
734 |
|
|
break; |
735 |
|
|
} |
736 |
✓✓✓✓
|
91599 |
if ('\\' == h[pos] && '\"' == h[pos+1]) { |
737 |
|
2901 |
h += 1; |
738 |
|
2901 |
} |
739 |
|
85840 |
buff[pos] = h[pos]; |
740 |
|
85840 |
pos = airArrayLenIncr(buffArr, 1); |
741 |
|
|
} |
742 |
✗✓ |
12 |
if ('\"' != h[pos]) { |
743 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: didn't see ending \" soon enough", me); |
744 |
|
|
return NULL; |
745 |
|
|
} |
746 |
|
12 |
h += pos + 1; |
747 |
|
12 |
buff[pos] = 0; |
748 |
|
|
|
749 |
|
12 |
ret = airStrdup(buff); |
750 |
|
12 |
airArrayNuke(buffArr); |
751 |
|
12 |
*hP = h; |
752 |
|
|
|
753 |
|
12 |
return ret; |
754 |
|
13 |
} |
755 |
|
|
|
756 |
|
|
static int |
757 |
|
|
_nrrdReadNrrdParse_labels(FILE *file, Nrrd *nrrd, |
758 |
|
|
NrrdIoState *nio, int useBiff) { |
759 |
|
|
static const char me[]="_nrrdReadNrrdParse_labels"; |
760 |
|
10 |
char *h; /* this is the "here" pointer which gradually progresses |
761 |
|
|
through all the labels (for all axes) */ |
762 |
|
|
unsigned int ai; |
763 |
|
|
char *info; |
764 |
|
|
|
765 |
|
|
AIR_UNUSED(file); |
766 |
|
|
/* because we have to correctly interpret quote marks, we |
767 |
|
|
can't simply rely on airParseStrS */ |
768 |
|
5 |
info = nio->line + nio->pos; |
769 |
|
|
/* printf("!%s: info |%s|\n", me, info); */ |
770 |
✗✓ |
5 |
_CHECK_HAVE_DIM; |
771 |
|
5 |
h = info; |
772 |
✓✓ |
28 |
for (ai=0; ai<nrrd->dim; ai++) { |
773 |
✗✓ |
9 |
if (!( nrrd->axis[ai].label = _nrrdGetQuotedString(&h, useBiff) )) { |
774 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: couldn't get get label %d of %d\n", |
775 |
|
|
me, ai+1, nrrd->dim); |
776 |
|
|
return 1; |
777 |
|
|
} |
778 |
|
|
} |
779 |
✗✓ |
5 |
if (strlen(h) != strspn(h, _nrrdFieldSep)) { |
780 |
|
|
biffMaybeAddf(useBiff, NRRD, |
781 |
|
|
"%s: seem to have more than expected %d labels", |
782 |
|
|
me, nrrd->dim); |
783 |
|
|
return 1; |
784 |
|
|
} |
785 |
✗✓ |
5 |
if (_nrrdFieldCheck[nrrdField_labels](nrrd, useBiff)) { |
786 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
787 |
|
|
return 1; |
788 |
|
|
} |
789 |
|
5 |
return 0; |
790 |
|
5 |
} |
791 |
|
|
|
792 |
|
|
static int |
793 |
|
|
_nrrdReadNrrdParse_units(FILE *file, Nrrd *nrrd, |
794 |
|
|
NrrdIoState *nio, int useBiff) { |
795 |
|
|
static const char me[]="_nrrdReadNrrdParse_units"; |
796 |
|
|
char *h; /* this is the "here" pointer which gradually progresses |
797 |
|
|
through all the units (for all axes) */ |
798 |
|
|
unsigned int ai; |
799 |
|
|
char *info; |
800 |
|
|
|
801 |
|
|
AIR_UNUSED(file); |
802 |
|
|
/* because we have to correctly interpret quote marks, we |
803 |
|
|
can't simply rely on airParseStrS */ |
804 |
|
|
info = nio->line + nio->pos; |
805 |
|
|
/* printf("!%s: info |%s|\n", me, info); */ |
806 |
|
|
_CHECK_HAVE_DIM; |
807 |
|
|
h = info; |
808 |
|
|
for (ai=0; ai<nrrd->dim; ai++) { |
809 |
|
|
if (!( nrrd->axis[ai].units = _nrrdGetQuotedString(&h, useBiff) )) { |
810 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: couldn't get get unit %d of %d\n", |
811 |
|
|
me, ai+1, nrrd->dim); |
812 |
|
|
return 1; |
813 |
|
|
} |
814 |
|
|
} |
815 |
|
|
if (strlen(h) != strspn(h, _nrrdFieldSep)) { |
816 |
|
|
biffMaybeAddf(useBiff, NRRD, |
817 |
|
|
"%s: seem to have more than expected %d units", |
818 |
|
|
me, nrrd->dim); |
819 |
|
|
return 1; |
820 |
|
|
} |
821 |
|
|
if (_nrrdFieldCheck[nrrdField_units](nrrd, useBiff)) { |
822 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
823 |
|
|
return 1; |
824 |
|
|
} |
825 |
|
|
return 0; |
826 |
|
|
} |
827 |
|
|
|
828 |
|
|
static int |
829 |
|
|
_nrrdReadNrrdParse_min(FILE *file, Nrrd *nrrd, |
830 |
|
|
NrrdIoState *nio, int useBiff) { |
831 |
|
|
|
832 |
|
|
AIR_UNUSED(file); |
833 |
|
|
AIR_UNUSED(nrrd); |
834 |
|
|
AIR_UNUSED(nio); |
835 |
|
|
AIR_UNUSED(useBiff); |
836 |
|
|
|
837 |
|
|
/* This field is no longer assumed to be anything meaningful, |
838 |
|
|
because nrrd->min no longer exists with the advent of NrrdRange. |
839 |
|
|
But, having the field is not an error, to not trip on older |
840 |
|
|
NRRD00.01 and NRRD0001 files which (legitimately) used it */ |
841 |
|
|
|
842 |
|
|
return 0; |
843 |
|
|
} |
844 |
|
|
|
845 |
|
|
static int |
846 |
|
|
_nrrdReadNrrdParse_max(FILE *file, Nrrd *nrrd, |
847 |
|
|
NrrdIoState *nio, int useBiff) { |
848 |
|
|
|
849 |
|
|
AIR_UNUSED(file); |
850 |
|
|
AIR_UNUSED(nrrd); |
851 |
|
|
AIR_UNUSED(nio); |
852 |
|
|
AIR_UNUSED(useBiff); |
853 |
|
|
|
854 |
|
|
/* nrrd->max no longer exists, see above */ |
855 |
|
|
|
856 |
|
|
return 0; |
857 |
|
|
} |
858 |
|
|
|
859 |
|
|
static int |
860 |
|
|
_nrrdReadNrrdParse_old_min(FILE *file, Nrrd *nrrd, |
861 |
|
|
NrrdIoState *nio, int useBiff) { |
862 |
|
|
static const char me[]="_nrrdReadNrrdParse_old_min"; |
863 |
|
|
char *info; |
864 |
|
|
|
865 |
|
|
AIR_UNUSED(file); |
866 |
|
|
info = nio->line + nio->pos; |
867 |
|
|
_PARSE_ONE_VAL(nrrd->oldMin, "%lg", "double"); |
868 |
|
|
if (_nrrdFieldCheck[nrrdField_old_min](nrrd, useBiff)) { |
869 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
870 |
|
|
return 1; |
871 |
|
|
} |
872 |
|
|
return 0; |
873 |
|
|
} |
874 |
|
|
|
875 |
|
|
static int |
876 |
|
|
_nrrdReadNrrdParse_old_max(FILE *file, Nrrd *nrrd, |
877 |
|
|
NrrdIoState *nio, int useBiff) { |
878 |
|
|
static const char me[]="_nrrdReadNrrdParse_old_max"; |
879 |
|
|
char *info; |
880 |
|
|
|
881 |
|
|
AIR_UNUSED(file); |
882 |
|
|
info = nio->line + nio->pos; |
883 |
|
|
_PARSE_ONE_VAL(nrrd->oldMax, "%lg", "double"); |
884 |
|
|
if (_nrrdFieldCheck[nrrdField_old_max](nrrd, useBiff)) { |
885 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
886 |
|
|
return 1; |
887 |
|
|
} |
888 |
|
|
return 0; |
889 |
|
|
} |
890 |
|
|
|
891 |
|
|
static int |
892 |
|
|
_nrrdReadNrrdParse_endian(FILE *file, Nrrd *nrrd, |
893 |
|
|
NrrdIoState *nio, int useBiff) { |
894 |
|
|
static const char me[]="_nrrdReadNrrdParse_endian"; |
895 |
|
|
char *info; |
896 |
|
|
|
897 |
|
|
AIR_UNUSED(file); |
898 |
|
|
AIR_UNUSED(nrrd); |
899 |
|
46 |
info = nio->line + nio->pos; |
900 |
✗✓ |
23 |
if (!(nio->endian = airEnumVal(airEndian, info))) { |
901 |
|
|
biffMaybeAddf(useBiff, NRRD, |
902 |
|
|
"%s: couldn't parse endian \"%s\"", me, info); |
903 |
|
|
return 1; |
904 |
|
|
} |
905 |
|
23 |
return 0; |
906 |
|
23 |
} |
907 |
|
|
|
908 |
|
|
static int |
909 |
|
|
_nrrdReadNrrdParse_encoding(FILE *file, Nrrd *nrrd, |
910 |
|
|
NrrdIoState *nio, int useBiff) { |
911 |
|
|
static const char me[]="_nrrdReadNrrdParse_encoding"; |
912 |
|
|
char *info; |
913 |
|
|
int etype; |
914 |
|
|
|
915 |
|
|
AIR_UNUSED(file); |
916 |
|
|
AIR_UNUSED(nrrd); |
917 |
|
46 |
info = nio->line + nio->pos; |
918 |
✗✓ |
23 |
if (!(etype = airEnumVal(nrrdEncodingType, info))) { |
919 |
|
|
biffMaybeAddf(useBiff, NRRD, |
920 |
|
|
"%s: couldn't parse encoding \"%s\"", me, info); |
921 |
|
|
return 1; |
922 |
|
|
} |
923 |
|
|
|
924 |
|
23 |
nio->encoding = nrrdEncodingArray[etype]; |
925 |
|
23 |
return 0; |
926 |
|
23 |
} |
927 |
|
|
|
928 |
|
|
static int |
929 |
|
|
_nrrdReadNrrdParse_line_skip(FILE *file, Nrrd *nrrd, |
930 |
|
|
NrrdIoState *nio, int useBiff) { |
931 |
|
|
static const char me[]="_nrrdReadNrrdParse_line_skip"; |
932 |
|
|
char *info; |
933 |
|
|
|
934 |
|
|
AIR_UNUSED(file); |
935 |
|
|
AIR_UNUSED(nrrd); |
936 |
|
|
info = nio->line + nio->pos; |
937 |
|
|
_PARSE_ONE_VAL(nio->lineSkip, "%u", "unsigned int"); |
938 |
|
|
/* now that its unsigned, what error checking can I do? |
939 |
|
|
if (!(0 <= nio->lineSkip)) { |
940 |
|
|
biffMaybeAddf(useBiff, NRRD, |
941 |
|
|
"%s: lineSkip value %d invalid", me, nio->lineSkip); |
942 |
|
|
return 1; |
943 |
|
|
} |
944 |
|
|
*/ |
945 |
|
|
return 0; |
946 |
|
|
} |
947 |
|
|
|
948 |
|
|
static int |
949 |
|
|
_nrrdReadNrrdParse_byte_skip(FILE *file, Nrrd *nrrd, |
950 |
|
|
NrrdIoState *nio, int useBiff) { |
951 |
|
|
static const char me[]="_nrrdReadNrrdParse_byte_skip"; |
952 |
|
|
char *info; |
953 |
|
|
|
954 |
|
|
AIR_UNUSED(file); |
955 |
|
|
AIR_UNUSED(nrrd); |
956 |
|
10 |
info = nio->line + nio->pos; |
957 |
✗✓ |
5 |
_PARSE_ONE_VAL(nio->byteSkip, "%ld", "long int"); |
958 |
|
|
/* this check is being removed to enable the undocumented |
959 |
|
|
(in the file format spec) ability to say "byte skip: -N-1" |
960 |
|
|
in order to skip backwards from EOF by N bytes |
961 |
|
|
** if (!(-1 <= nio->byteSkip)) { |
962 |
|
|
** biffMaybeAddf(useBiff, NRRD, |
963 |
|
|
** "%s: byteSkip value %ld invalid", me, nio->byteSkip); |
964 |
|
|
** return 1; |
965 |
|
|
** } |
966 |
|
|
*/ |
967 |
|
5 |
return 0; |
968 |
|
5 |
} |
969 |
|
|
|
970 |
|
|
static int |
971 |
|
|
_nrrdReadNrrdParse_keyvalue(FILE *file, Nrrd *nrrd, |
972 |
|
|
NrrdIoState *nio, int useBiff) { |
973 |
|
|
static const char me[]="_nrrdReadNrrdParse_keyvalue"; |
974 |
|
|
char *keysep, *line, *key, *value; |
975 |
|
|
|
976 |
|
|
AIR_UNUSED(file); |
977 |
|
|
/* we know this will find something */ |
978 |
|
6 |
line = airStrdup(nio->line + nio->pos); |
979 |
✗✓ |
3 |
if (!line) { |
980 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: can't allocate parse line", me); |
981 |
|
|
return 1; |
982 |
|
|
} |
983 |
|
3 |
keysep = strstr(line, ":="); |
984 |
✗✓ |
3 |
if (!keysep) { |
985 |
|
|
biffMaybeAddf(useBiff, NRRD, |
986 |
|
|
"%s: didn't see \":=\" key/value delimiter in \"%s\"", |
987 |
|
|
me, line); |
988 |
|
|
free(line); return 1; |
989 |
|
|
} |
990 |
|
3 |
keysep[0] = 0; |
991 |
|
3 |
keysep[1] = 0; |
992 |
|
|
key = line; |
993 |
|
3 |
value = keysep+2; |
994 |
|
|
|
995 |
|
|
/* convert escape sequences */ |
996 |
|
3 |
airUnescape(key); |
997 |
|
3 |
airUnescape(value); |
998 |
|
|
|
999 |
|
3 |
nrrdKeyValueAdd(nrrd, key, value); |
1000 |
|
|
|
1001 |
|
3 |
free(line); |
1002 |
|
3 |
return 0; |
1003 |
|
3 |
} |
1004 |
|
|
|
1005 |
|
|
static int |
1006 |
|
|
_nrrdReadNrrdParse_sample_units(FILE *file, Nrrd *nrrd, |
1007 |
|
|
NrrdIoState *nio, int useBiff) { |
1008 |
|
|
static const char me[]="_nrrdReadNrrdParse_sample_units"; |
1009 |
|
|
char *info; |
1010 |
|
|
|
1011 |
|
|
AIR_UNUSED(file); |
1012 |
|
|
info = nio->line + nio->pos; |
1013 |
|
|
|
1014 |
|
|
if (strlen(info) && !(nrrd->sampleUnits = airStrdup(info))) { |
1015 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1016 |
|
|
"%s: couldn't strdup() sampleUnits", me); |
1017 |
|
|
return 1; |
1018 |
|
|
} |
1019 |
|
|
if (_nrrdFieldCheck[nrrdField_sample_units](nrrd, useBiff)) { |
1020 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
1021 |
|
|
return 1; |
1022 |
|
|
} |
1023 |
|
|
return 0; |
1024 |
|
|
} |
1025 |
|
|
|
1026 |
|
|
static int |
1027 |
|
|
_nrrdReadNrrdParse_space(FILE *file, Nrrd *nrrd, |
1028 |
|
|
NrrdIoState *nio, int useBiff) { |
1029 |
|
|
static const char me[]="_nrrdReadNrrdParse_space"; |
1030 |
|
|
char *info; |
1031 |
|
|
int space; |
1032 |
|
|
|
1033 |
|
|
AIR_UNUSED(file); |
1034 |
|
16 |
info = nio->line + nio->pos; |
1035 |
✗✓ |
8 |
if (nio->seen[nrrdField_space_dimension]) { |
1036 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1037 |
|
|
"%s: can't specify space after specifying " |
1038 |
|
|
"space dimension (%d)", me, nrrd->spaceDim); |
1039 |
|
|
return 1; |
1040 |
|
|
} |
1041 |
✗✓ |
8 |
if (!(space = airEnumVal(nrrdSpace, info))) { |
1042 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1043 |
|
|
"%s: couldn't parse space \"%s\"", me, info); |
1044 |
|
|
return 1; |
1045 |
|
|
} |
1046 |
✗✓ |
8 |
if (nrrdSpaceSet(nrrd, space)) { |
1047 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
1048 |
|
|
return 1; |
1049 |
|
|
} |
1050 |
✗✓ |
8 |
if (_nrrdFieldCheck[nrrdField_space](nrrd, useBiff)) { |
1051 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
1052 |
|
|
return 1; |
1053 |
|
|
} |
1054 |
|
8 |
return 0; |
1055 |
|
8 |
} |
1056 |
|
|
|
1057 |
|
|
static int |
1058 |
|
|
_nrrdReadNrrdParse_space_dimension(FILE *file, Nrrd *nrrd, |
1059 |
|
|
NrrdIoState *nio, int useBiff) { |
1060 |
|
|
static const char me[]="_nrrdReadNrrdParse_space_dimension"; |
1061 |
|
|
char *info; |
1062 |
|
|
|
1063 |
|
|
AIR_UNUSED(file); |
1064 |
|
6 |
info = nio->line + nio->pos; |
1065 |
✗✓ |
3 |
if (nio->seen[nrrdField_space]) { |
1066 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1067 |
|
|
"%s: can't specify space dimension after specifying " |
1068 |
|
|
"space (%s)", me, airEnumStr(nrrdSpace, nrrd->space)); |
1069 |
|
|
return 1; |
1070 |
|
|
} |
1071 |
✗✓ |
3 |
_PARSE_ONE_VAL(nrrd->spaceDim, "%u", "unsigned int"); |
1072 |
✗✓ |
3 |
if (_nrrdFieldCheck[nrrdField_space_dimension](nrrd, useBiff)) { |
1073 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
1074 |
|
|
return 1; |
1075 |
|
|
} |
1076 |
|
3 |
return 0; |
1077 |
|
3 |
} |
1078 |
|
|
|
1079 |
|
|
static int |
1080 |
|
|
_nrrdReadNrrdParse_space_units(FILE *file, Nrrd *nrrd, |
1081 |
|
|
NrrdIoState *nio, int useBiff) { |
1082 |
|
|
static const char me[]="_nrrdReadNrrdParse_space_units"; |
1083 |
|
2 |
char *h; /* this is the "here" pointer which gradually progresses |
1084 |
|
|
through all the units (for all axes) */ |
1085 |
|
|
unsigned int ai; |
1086 |
|
|
char *info; |
1087 |
|
|
|
1088 |
|
|
AIR_UNUSED(file); |
1089 |
|
|
/* because we have to correctly interpret quote marks, we |
1090 |
|
|
can't simply rely on airParseStrS */ |
1091 |
|
1 |
info = nio->line + nio->pos; |
1092 |
|
|
/* printf("!%s: info |%s|\n", me, info); */ |
1093 |
✗✓ |
1 |
_CHECK_HAVE_SPACE_DIM; |
1094 |
|
1 |
h = info; |
1095 |
✓✓ |
8 |
for (ai=0; ai<nrrd->spaceDim; ai++) { |
1096 |
✗✓ |
3 |
if (!( nrrd->spaceUnits[ai] = _nrrdGetQuotedString(&h, useBiff) )) { |
1097 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: couldn't get get space unit %d of %d", |
1098 |
|
|
me, ai+1, nrrd->spaceDim); |
1099 |
|
|
return 1; |
1100 |
|
|
} |
1101 |
|
|
} |
1102 |
✗✓ |
1 |
if (_nrrdGetQuotedString(&h, AIR_FALSE)) { |
1103 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1104 |
|
|
"%s: seemed to have more than expected %d space units", |
1105 |
|
|
me, nrrd->spaceDim); |
1106 |
|
|
return 1; |
1107 |
|
|
} |
1108 |
✗✓ |
1 |
if (_nrrdFieldCheck[nrrdField_space_units](nrrd, useBiff)) { |
1109 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
1110 |
|
|
return 1; |
1111 |
|
|
} |
1112 |
|
1 |
return 0; |
1113 |
|
1 |
} |
1114 |
|
|
|
1115 |
|
|
static int |
1116 |
|
|
_nrrdReadNrrdParse_space_origin(FILE *file, Nrrd *nrrd, |
1117 |
|
|
NrrdIoState *nio, int useBiff) { |
1118 |
|
|
static const char me[]="_nrrdReadNrrdParse_space_origin"; |
1119 |
|
22 |
char *info; |
1120 |
|
|
|
1121 |
|
|
AIR_UNUSED(file); |
1122 |
|
11 |
info = nio->line + nio->pos; |
1123 |
|
|
|
1124 |
✗✓ |
11 |
_CHECK_HAVE_SPACE_DIM; |
1125 |
|
|
|
1126 |
✗✓ |
11 |
if (_nrrdSpaceVectorParse(nrrd->spaceOrigin, &info, |
1127 |
|
|
nrrd->spaceDim, useBiff)) { |
1128 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1129 |
|
|
"%s: couldn't parse origin \"%s\"", me, info); |
1130 |
|
|
return 1; |
1131 |
|
|
} |
1132 |
✗✓ |
11 |
if (_nrrdFieldCheck[nrrdField_space_origin](nrrd, useBiff)) { |
1133 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
1134 |
|
|
return 1; |
1135 |
|
|
} |
1136 |
|
11 |
return 0; |
1137 |
|
11 |
} |
1138 |
|
|
|
1139 |
|
|
static int |
1140 |
|
|
_nrrdReadNrrdParse_measurement_frame(FILE *file, Nrrd *nrrd, |
1141 |
|
|
NrrdIoState *nio, int useBiff) { |
1142 |
|
|
static const char me[]="_nrrdReadNrrdParse_measurement_frame"; |
1143 |
|
16 |
double colvec[NRRD_SPACE_DIM_MAX]; |
1144 |
|
|
unsigned int dd, ii; |
1145 |
|
8 |
char *info; |
1146 |
|
|
|
1147 |
|
|
AIR_UNUSED(file); |
1148 |
|
8 |
info = nio->line + nio->pos; |
1149 |
|
|
|
1150 |
✗✓ |
8 |
_CHECK_HAVE_SPACE_DIM; |
1151 |
|
|
|
1152 |
✓✓ |
64 |
for (dd=0; dd<nrrd->spaceDim; dd++) { |
1153 |
|
|
/* we are going through the *columns* of the mf matrix */ |
1154 |
✗✓ |
24 |
if (_nrrdSpaceVectorParse(colvec, &info, nrrd->spaceDim, useBiff)) { |
1155 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1156 |
|
|
"%s: trouble getting space vector %d of %d", |
1157 |
|
|
me, dd+1, nrrd->spaceDim); |
1158 |
|
|
return 1; |
1159 |
|
|
} |
1160 |
✓✓ |
432 |
for (ii=0; ii<NRRD_SPACE_DIM_MAX; ii++) { |
1161 |
✓✓ |
576 |
nrrd->measurementFrame[dd][ii] = (ii < nrrd->spaceDim |
1162 |
|
72 |
? colvec[ii] |
1163 |
|
120 |
: AIR_NAN); |
1164 |
|
|
} |
1165 |
|
|
} |
1166 |
✗✓ |
8 |
if (strlen(info) != strspn(info, _nrrdFieldSep)) { |
1167 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1168 |
|
|
"%s: seem to have more than expected %d directions", |
1169 |
|
|
me, nrrd->spaceDim); |
1170 |
|
|
return 1; |
1171 |
|
|
} |
1172 |
✓✓ |
96 |
for (dd=nrrd->spaceDim; dd<NRRD_SPACE_DIM_MAX; dd++) { |
1173 |
✓✓ |
720 |
for (ii=0; ii<NRRD_SPACE_DIM_MAX; ii++) { |
1174 |
|
320 |
nrrd->measurementFrame[dd][ii] = AIR_NAN; |
1175 |
|
|
} |
1176 |
|
|
} |
1177 |
✗✓ |
8 |
if (_nrrdFieldCheck[nrrdField_measurement_frame](nrrd, useBiff)) { |
1178 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: trouble", me); |
1179 |
|
|
return 1; |
1180 |
|
|
} |
1181 |
|
8 |
return 0; |
1182 |
|
8 |
} |
1183 |
|
|
|
1184 |
|
|
int |
1185 |
|
|
_nrrdContainsPercentThisAndMore(const char *str, char thss) { |
1186 |
|
|
const char *hh, *tmp; |
1187 |
|
|
|
1188 |
|
|
tmp = str; |
1189 |
|
12 |
do { |
1190 |
|
6 |
hh = strchr(tmp, '%'); |
1191 |
✗✓✗✗
|
6 |
if (!( hh && hh[1] )) { |
1192 |
|
6 |
return 0; |
1193 |
|
|
} |
1194 |
|
|
if ('%' == hh[1]) { |
1195 |
|
|
/* its an escaped % */ |
1196 |
|
|
tmp = hh + 2; |
1197 |
|
|
} else { |
1198 |
|
|
break; |
1199 |
|
|
} |
1200 |
|
|
} while (tmp[0]); |
1201 |
|
|
hh++; |
1202 |
|
|
hh += strspn(hh, "0123456789"); |
1203 |
|
|
if (!( hh[0] == thss )) { |
1204 |
|
|
return 0; |
1205 |
|
|
} |
1206 |
|
|
hh += strcspn(hh, _nrrdFieldSep); |
1207 |
|
|
return !!hh; |
1208 |
|
6 |
} |
1209 |
|
|
|
1210 |
|
|
unsigned int |
1211 |
|
|
_nrrdDataFNNumber(NrrdIoState *nio) { |
1212 |
|
|
unsigned int ret; |
1213 |
|
|
int ii; |
1214 |
|
|
|
1215 |
✗✓ |
436 |
if (nio->dataFNFormat) { |
1216 |
|
|
/* datafiles given in iterator form; count number of values */ |
1217 |
|
|
ret = 0; |
1218 |
|
|
for (ii = nio->dataFNMin; |
1219 |
|
|
((nio->dataFNStep > 0 && ii <= nio->dataFNMax) |
1220 |
|
|
|| (nio->dataFNStep < 0 && ii >= nio->dataFNMax)); |
1221 |
|
|
ii += nio->dataFNStep) { |
1222 |
|
|
ret += 1; |
1223 |
|
|
} |
1224 |
✓✓ |
218 |
} else if (nio->dataFNArr->len) { |
1225 |
|
|
/* datafiles given as an explicit list, or as a single file name, |
1226 |
|
|
and in either case, nrrdDataFNAdd() is used to add them to |
1227 |
|
|
the dataFNArr */ |
1228 |
|
|
ret = nio->dataFNArr->len; |
1229 |
|
39 |
} else { |
1230 |
|
|
/* datafile is same as (attached) header file */ |
1231 |
|
|
ret = 1; |
1232 |
|
|
} |
1233 |
|
218 |
return ret; |
1234 |
|
|
} |
1235 |
|
|
|
1236 |
|
|
/* |
1237 |
|
|
** this always requires that the per-axis size fields have been set |
1238 |
|
|
*/ |
1239 |
|
|
int |
1240 |
|
|
_nrrdDataFNCheck(NrrdIoState *nio, Nrrd *nrrd, int useBiff) { |
1241 |
|
|
static const char me[]="_nrrdDataFNCheck"; |
1242 |
|
|
size_t pieceSize, pieceNum; |
1243 |
|
|
char stmp[AIR_STRLEN_SMALL]; |
1244 |
|
|
|
1245 |
|
|
if (!nio->seen[nrrdField_sizes]) { |
1246 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: sorry, currently can't handle " |
1247 |
|
|
"multiple detached data files without first knowing " |
1248 |
|
|
"the \"%s\" field", |
1249 |
|
|
me, airEnumStr(nrrdField, nrrdField_sizes)); |
1250 |
|
|
return 1; |
1251 |
|
|
} |
1252 |
|
|
if (nio->dataFileDim < nrrd->dim) { |
1253 |
|
|
/* this requires that the per-axis size fields have been set */ |
1254 |
|
|
_nrrdSplitSizes(&pieceSize, &pieceNum, nrrd, nio->dataFileDim); |
1255 |
|
|
if (pieceNum != _nrrdDataFNNumber(nio)) { |
1256 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1257 |
|
|
"%s: expected %s filenames (of %u-D pieces) " |
1258 |
|
|
"but got %u", me, |
1259 |
|
|
airSprintSize_t(stmp, pieceNum), nio->dataFileDim, |
1260 |
|
|
_nrrdDataFNNumber(nio)); |
1261 |
|
|
return 1; |
1262 |
|
|
} |
1263 |
|
|
} else { |
1264 |
|
|
/* we're getting data in "slabs" with the same dimension as the |
1265 |
|
|
nrrd, so for simplicity we assume that they're all equal size */ |
1266 |
|
|
if (_nrrdDataFNNumber(nio) > nrrd->axis[nrrd->dim-1].size) { |
1267 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1268 |
|
|
"%s: can't have more pieces (%u) than axis %u " |
1269 |
|
|
"slices (%s) when nrrd dimension and " |
1270 |
|
|
"datafile dimension are both %u", me, |
1271 |
|
|
_nrrdDataFNNumber(nio), |
1272 |
|
|
nrrd->dim-1, |
1273 |
|
|
airSprintSize_t(stmp, nrrd->axis[nrrd->dim-1].size), |
1274 |
|
|
nrrd->dim); |
1275 |
|
|
return 1; |
1276 |
|
|
} |
1277 |
|
|
if ((double)nrrd->axis[nrrd->dim-1].size/_nrrdDataFNNumber(nio) |
1278 |
|
|
!= nrrd->axis[nrrd->dim-1].size/_nrrdDataFNNumber(nio)) { |
1279 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1280 |
|
|
"%s: number of datafiles (%d) doesn't divide into " |
1281 |
|
|
"number of axis %u slices (%s)", me, |
1282 |
|
|
(int)_nrrdDataFNNumber(nio), nrrd->dim-1, |
1283 |
|
|
airSprintSize_t(stmp, nrrd->axis[nrrd->dim-1].size)); |
1284 |
|
|
return 1; |
1285 |
|
|
} |
1286 |
|
|
} |
1287 |
|
|
return 0; |
1288 |
|
|
} |
1289 |
|
|
|
1290 |
|
|
/* |
1291 |
|
|
** Sat Jan 29 16:44:50 EST 2005: this used to "open the separate |
1292 |
|
|
** datafile, and set the FILE* in nio->dataFile, which otherwise will |
1293 |
|
|
** stay NULL", but now we support multiple detached data files. So. |
1294 |
|
|
** |
1295 |
|
|
** The job of this function is to map the "data file" specification to |
1296 |
|
|
** one or more filenames that can be passed direction to fopen for |
1297 |
|
|
** reading in the data. This involves parsing the various formats for |
1298 |
|
|
** identifying multiple data files, and possibly prefixing them with |
1299 |
|
|
** nio->path. |
1300 |
|
|
*/ |
1301 |
|
|
static int |
1302 |
|
|
_nrrdReadNrrdParse_data_file(FILE *ffile, Nrrd *nrrd, |
1303 |
|
|
NrrdIoState *nio, int useBiff) { |
1304 |
|
|
static const char me[]="_nrrdReadNrrdParse_data_file"; |
1305 |
|
|
char *info, *nums; |
1306 |
|
12 |
unsigned int linelen, tmp; |
1307 |
|
|
airArray *mop; |
1308 |
|
|
|
1309 |
|
6 |
mop = airMopNew(); |
1310 |
|
6 |
info = airStrdup(nio->line + nio->pos); |
1311 |
✗✓ |
6 |
if (!info) { |
1312 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: couldn't copy line!", me); |
1313 |
|
|
return 1; |
1314 |
|
|
} |
1315 |
|
6 |
airMopAdd(mop, info, airFree, airMopAlways); |
1316 |
|
|
|
1317 |
|
|
/* HEY: this change should be made someday |
1318 |
|
|
if (_nrrdContainsPercentThisAndMore(info, 'd') |
1319 |
|
|
|| _nrrdContainsPercentThisAndMore(info, 'u')) { */ |
1320 |
✗✓ |
6 |
if (_nrrdContainsPercentThisAndMore(info, 'd')) { |
1321 |
|
|
/* ---------------------------------------------------------- */ |
1322 |
|
|
/* --------- format.%d <min> <max> <step> [<dim>] ----------- */ |
1323 |
|
|
/* ---------------------------------------------------------- */ |
1324 |
|
|
size_t sspn; |
1325 |
|
|
_CHECK_HAVE_DIM; |
1326 |
|
|
nums = info + strcspn(info, _nrrdFieldSep); |
1327 |
|
|
sspn = strspn(nums, _nrrdFieldSep); |
1328 |
|
|
nums[0] = 0; /* terminate so that format is now in info */ |
1329 |
|
|
nums += sspn; |
1330 |
|
|
if (!( 3 == sscanf(nums, "%d %d %d",&(nio->dataFNMin), |
1331 |
|
|
&(nio->dataFNMax), &(nio->dataFNStep)) )) { |
1332 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1333 |
|
|
"%s: couldn't parse three ints (min, max, step) after " |
1334 |
|
|
"data filename template", me); |
1335 |
|
|
airMopError(mop); return 1; |
1336 |
|
|
} |
1337 |
|
|
if ( 4 == sscanf(nums, "%d %d %d %u", &(nio->dataFNMin), |
1338 |
|
|
&(nio->dataFNMax), &(nio->dataFNStep), |
1339 |
|
|
&(nio->dataFileDim)) ) { |
1340 |
|
|
if (!AIR_IN_CL(1, nio->dataFileDim, nrrd->dim)) { |
1341 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1342 |
|
|
"%s: datafile dimension %u outside valid range [1,%u]", |
1343 |
|
|
me, nio->dataFileDim, nrrd->dim); |
1344 |
|
|
airMopError(mop); return 1; |
1345 |
|
|
} |
1346 |
|
|
} else { |
1347 |
|
|
nio->dataFileDim = nrrd->dim-1; |
1348 |
|
|
} |
1349 |
|
|
if (0 == nio->dataFNStep) { |
1350 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1351 |
|
|
"%s: file number step must be non-zero", me); |
1352 |
|
|
airMopError(mop); return 1; |
1353 |
|
|
} |
1354 |
|
|
if ((nio->dataFNMax - nio->dataFNMin)*(nio->dataFNStep) < 0) { |
1355 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1356 |
|
|
"%s: file number max %d not approached from min %d " |
1357 |
|
|
"by step %d", me, |
1358 |
|
|
nio->dataFNMax, nio->dataFNMin, nio->dataFNStep); |
1359 |
|
|
airMopError(mop); return 1; |
1360 |
|
|
} |
1361 |
|
|
if (!( nio->dataFNFormat = airStrdup(info) )) { |
1362 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1363 |
|
|
"%s: couldn't copy data filename format", me); |
1364 |
|
|
airMopError(mop); return 1; |
1365 |
|
|
} |
1366 |
|
|
if (_nrrdDataFNCheck(nio, nrrd, useBiff)) { |
1367 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1368 |
|
|
"%s: trouble with number of datafiles", me); |
1369 |
|
|
airMopError(mop); return 1; |
1370 |
|
|
} |
1371 |
✓✗✗✓
|
12 |
} else if (!strncmp(info, NRRD_LIST_FLAG, strlen(NRRD_LIST_FLAG)) || |
1372 |
|
6 |
!strncmp(info, NRRD_SKIPLIST_FLAG, strlen(NRRD_SKIPLIST_FLAG))) { |
1373 |
|
|
int skiplist; |
1374 |
|
|
unsigned int lineidx; |
1375 |
|
|
/* ---------------------------------------------------------- */ |
1376 |
|
|
/* -------------------- LIST or SKIPLIST -------------------- */ |
1377 |
|
|
/* ---------------------------------------------------------- */ |
1378 |
|
|
_CHECK_HAVE_DIM; |
1379 |
|
|
skiplist = !strncmp(info, NRRD_SKIPLIST_FLAG, strlen(NRRD_SKIPLIST_FLAG)); |
1380 |
|
|
if (_nrrdHeaderCheck(nrrd, nio, AIR_TRUE)) { |
1381 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: NRRD header is incomplete. " |
1382 |
|
|
"\"%s\" data file specification must be " |
1383 |
|
|
"contiguous with end of header!", me, |
1384 |
|
|
skiplist ? NRRD_SKIPLIST_FLAG : NRRD_LIST_FLAG); |
1385 |
|
|
airMopError(mop); return 1; |
1386 |
|
|
} |
1387 |
|
|
info += strlen(skiplist ? NRRD_SKIPLIST_FLAG : NRRD_LIST_FLAG); |
1388 |
|
|
if (info[0]) { |
1389 |
|
|
if (1 == sscanf(info, "%u", &(nio->dataFileDim))) { |
1390 |
|
|
if (!AIR_IN_CL(1, nio->dataFileDim, nrrd->dim)) { |
1391 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: datafile dimension %u outside " |
1392 |
|
|
"valid range [1,%u]", |
1393 |
|
|
me, nio->dataFileDim, nrrd->dim); |
1394 |
|
|
airMopError(mop); return 1; |
1395 |
|
|
} |
1396 |
|
|
} else { |
1397 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: couldn't parse info after " |
1398 |
|
|
"\"%s\" as an int", me, |
1399 |
|
|
skiplist ? NRRD_SKIPLIST_FLAG : NRRD_LIST_FLAG); |
1400 |
|
|
airMopError(mop); return 1; |
1401 |
|
|
} |
1402 |
|
|
} else { |
1403 |
|
|
/* nothing after NRRD_LIST_FLAG or NRRD_SKIPLIST_FLAG, |
1404 |
|
|
so dataFileDim is implicit */ |
1405 |
|
|
nio->dataFileDim = nrrd->dim-1; |
1406 |
|
|
} |
1407 |
|
|
/* read in all the datafile names */ |
1408 |
|
|
lineidx = 0; |
1409 |
|
|
do { |
1410 |
|
|
/* yes, nio->line is re-used/over-written here, but I don't |
1411 |
|
|
think that's a problem */ |
1412 |
|
|
if (_nrrdOneLine(&linelen, nio, ffile)) { |
1413 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1414 |
|
|
"%s: trouble getting file name line %u", me, lineidx); |
1415 |
|
|
airMopError(mop); return 1; |
1416 |
|
|
} |
1417 |
|
|
if (linelen > 0) { |
1418 |
|
|
/* we got a non-empty line */ |
1419 |
|
|
if (skiplist) { |
1420 |
|
|
char *lhere; |
1421 |
|
|
long int oneskip; |
1422 |
|
|
if (1 != airSingleSscanf(nio->line, "%ld", &oneskip)) { |
1423 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1424 |
|
|
"%s: couldn't parse skip on list line %u", |
1425 |
|
|
me, lineidx); |
1426 |
|
|
airMopError(mop); return 1; |
1427 |
|
|
} |
1428 |
|
|
lhere = strchr(nio->line, ' '); |
1429 |
|
|
if (!lhere) { |
1430 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: didn't see space after " |
1431 |
|
|
"skip on list line %u", me, lineidx); |
1432 |
|
|
airMopError(mop); return 1; |
1433 |
|
|
} |
1434 |
|
|
lhere++; |
1435 |
|
|
if (!(lhere[0])) { |
1436 |
|
|
biffMaybeAddf(useBiff, NRRD, "%s: didn't see filename after " |
1437 |
|
|
"skip and space on list line %u", me, lineidx); |
1438 |
|
|
airMopError(mop); return 1; |
1439 |
|
|
} |
1440 |
|
|
airArrayLenIncr(nio->dataFSkipArr, 1); |
1441 |
|
|
nio->dataFSkip[lineidx] = oneskip; |
1442 |
|
|
airArrayLenIncr(nio->dataFNArr, 1); |
1443 |
|
|
nio->dataFN[lineidx] = airStrdup(lhere); |
1444 |
|
|
} else { |
1445 |
|
|
airArrayLenIncr(nio->dataFNArr, 1); |
1446 |
|
|
nio->dataFN[lineidx] = airStrdup(nio->line); |
1447 |
|
|
} |
1448 |
|
|
} |
1449 |
|
|
++lineidx; |
1450 |
|
|
} while (linelen > 0); |
1451 |
|
|
if (_nrrdDataFNCheck(nio, nrrd, useBiff)) { |
1452 |
|
|
biffMaybeAddf(useBiff, NRRD, |
1453 |
|
|
"%s: trouble with number of datafiles", me); |
1454 |
|
|
airMopError(mop); return 1; |
1455 |
|
|
} |
1456 |
|
|
} else { |
1457 |
|
|
/* ---------------------------------------------------------- */ |
1458 |
|
|
/* -------------------- (single filename) ------------------- */ |
1459 |
|
|
/* ---------------------------------------------------------- */ |
1460 |
|
|
/* there is apparently only a single detached data file; for |
1461 |
|
|
this its okay to not yet know nrrd->dim */ |
1462 |
|
6 |
tmp = airArrayLenIncr(nio->dataFNArr, 1); |
1463 |
|
6 |
nio->dataFN[tmp] = airStrdup(info); |
1464 |
|
6 |
nio->dataFileDim = 0; |
1465 |
|
|
} |
1466 |
|
6 |
airMopOkay(mop); |
1467 |
|
6 |
return 0; |
1468 |
|
6 |
} |
1469 |
|
|
|
1470 |
|
|
/* |
1471 |
|
|
******** nrrdFieldInfoParse[NRRD_FIELD_MAX+1]() |
1472 |
|
|
** |
1473 |
|
|
** These are all for parsing the stuff AFTER the colon |
1474 |
|
|
*/ |
1475 |
|
|
int |
1476 |
|
|
(*nrrdFieldInfoParse[NRRD_FIELD_MAX+1])(FILE *, Nrrd *, |
1477 |
|
|
NrrdIoState *, int) = { |
1478 |
|
|
_nrrdReadNrrdParse_nonfield, |
1479 |
|
|
_nrrdReadNrrdParse_comment, |
1480 |
|
|
_nrrdReadNrrdParse_content, |
1481 |
|
|
_nrrdReadNrrdParse_number, |
1482 |
|
|
_nrrdReadNrrdParse_type, |
1483 |
|
|
_nrrdReadNrrdParse_block_size, |
1484 |
|
|
_nrrdReadNrrdParse_dimension, |
1485 |
|
|
_nrrdReadNrrdParse_space, |
1486 |
|
|
_nrrdReadNrrdParse_space_dimension, |
1487 |
|
|
_nrrdReadNrrdParse_sizes, |
1488 |
|
|
_nrrdReadNrrdParse_spacings, |
1489 |
|
|
_nrrdReadNrrdParse_thicknesses, |
1490 |
|
|
_nrrdReadNrrdParse_axis_mins, |
1491 |
|
|
_nrrdReadNrrdParse_axis_maxs, |
1492 |
|
|
_nrrdReadNrrdParse_space_directions, |
1493 |
|
|
_nrrdReadNrrdParse_centers, |
1494 |
|
|
_nrrdReadNrrdParse_kinds, |
1495 |
|
|
_nrrdReadNrrdParse_labels, |
1496 |
|
|
_nrrdReadNrrdParse_units, |
1497 |
|
|
_nrrdReadNrrdParse_min, |
1498 |
|
|
_nrrdReadNrrdParse_max, |
1499 |
|
|
_nrrdReadNrrdParse_old_min, |
1500 |
|
|
_nrrdReadNrrdParse_old_max, |
1501 |
|
|
_nrrdReadNrrdParse_endian, |
1502 |
|
|
_nrrdReadNrrdParse_encoding, |
1503 |
|
|
_nrrdReadNrrdParse_line_skip, |
1504 |
|
|
_nrrdReadNrrdParse_byte_skip, |
1505 |
|
|
_nrrdReadNrrdParse_keyvalue, |
1506 |
|
|
_nrrdReadNrrdParse_sample_units, |
1507 |
|
|
_nrrdReadNrrdParse_space_units, |
1508 |
|
|
_nrrdReadNrrdParse_space_origin, |
1509 |
|
|
_nrrdReadNrrdParse_measurement_frame, |
1510 |
|
|
_nrrdReadNrrdParse_data_file |
1511 |
|
|
}; |
1512 |
|
|
|
1513 |
|
|
/* kernel parsing is all in kernel.c */ |
1514 |
|
|
|