Bug Summary

File:src/nrrd/parseNrrd.c
Location:line 739, column 15
Description:Array access (from variable 'buff') results in a null pointer dereference

Annotated Source Code

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*/
32int
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_FALSE0;
37
38 next = nio->line + nio->pos;
39
40 /* determining if the line is a comment is simple */
41 if (NRRD_COMMENT_CHAR'#' == next[0]) {
42 return nrrdField_comment;
43 }
44
45 if (!( buff = airStrdup(next) )) {
46 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%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 colon = strstr(buff, ": ");
59 noField = !colon;
60 if (colon) {
61 *colon = '\0';
62 badField = ( nrrdField_unknown == (fld = airEnumVal(nrrdField, buff)) );
63 }
64 if (noField || badField) {
65 keysep = strstr(buff, ":=");
66 if (!keysep) {
67 if (noField) {
68 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
69 "%s: didn't see \": \" or \":=\" in line",
70 me);
71 } else {
72 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
73 "%s: failed to parse \"%s\" as field identifier",
74 me, buff);
75 }
76 free(buff); return nrrdField_unknown;
77 }
78
79 free(buff);
80 ret = nrrdField_keyvalue;
81 } else {
82
83 /* *colon = '\0'; */
84 /* else we successfully parsed a field identifier */
85 next += strlen(buff) + 2;
86 free(buff);
87
88 /* skip whitespace prior to start of first field descriptor */
89 next += strspn(next, _nrrdFieldSep);
90 nio->pos = AIR_CAST(int, next - nio->line)((int)(next - nio->line));
91
92 ret = fld;
93 }
94 return ret;
95}
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
105static int
106_nrrdReadNrrdParse_nonfield(FILE *file, Nrrd *nrrd,
107 NrrdIoState *nio, int useBiff) {
108 AIR_UNUSED(file)(void)(file);
109 AIR_UNUSED(nrrd)(void)(nrrd);
110 AIR_UNUSED(nio)(void)(nio);
111 AIR_UNUSED(useBiff)(void)(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
124static 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)(void)(file);
131 info = nio->line + nio->pos;
132 /* this skips the '#' at nio->line[nio->pos] and any other ' ' and '#' */
133 if (nrrdCommentAdd(nrrd, info)) {
134 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble adding comment", me);
135 return 1;
136 }
137 return 0;
138}
139
140static 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)(void)(file);
147 info = nio->line + nio->pos;
148 if (strlen(info) && !(nrrd->content = airStrdup(info))) {
149 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: couldn't strdup() content", me);
150 return 1;
151 }
152 return 0;
153}
154
155static 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)(void)(file);
170 AIR_UNUSED(nrrd)(void)(nrrd);
171 AIR_UNUSED(nio)(void)(nio);
172 AIR_UNUSED(useBiff)(void)(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
187static 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)(void)(file);
194 info = nio->line + nio->pos;
195 if (!(nrrd->type = airEnumVal(nrrdType, info))) {
196 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: couldn't parse type \"%s\"", me, info);
197 return 1;
198 }
199 if (_nrrdFieldCheck[nrrdField_type](nrrd, useBiff)) {
200 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
201 return 1;
202 }
203 return 0;
204}
205
206#define _PARSE_ONE_VAL(FIELD, CONV, TYPE)if (1 != airSingleSscanf(info, CONV, &(FIELD))) { biffMaybeAddf
(useBiff, nrrdBiffKey, "%s: couldn't parse " TYPE " from \"%s\""
, me, info); return 1; }
\
207 if (1 != airSingleSscanf(info, CONV, &(FIELD))) { \
208 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: couldn't parse " TYPE \
209 " from \"%s\"", me, info); \
210 return 1; \
211 }
212
213static 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)(void)(file);
220 info = nio->line + nio->pos;
221 if (1 != airSingleSscanf(info, "%z", &(nrrd->blockSize))) {
222 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%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
230static 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)(void)(file);
237 info = nio->line + nio->pos;
238 _PARSE_ONE_VAL(nrrd->dim, "%u", "unsigned int")if (1 != airSingleSscanf(info, "%u", &(nrrd->dim))) { biffMaybeAddf
(useBiff, nrrdBiffKey, "%s: couldn't parse " "unsigned int" " from \"%s\""
, me, info); return 1; }
;
239 if (_nrrdFieldCheck[nrrdField_dimension](nrrd, useBiff)) {
240 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
241 return 1;
242 }
243 return 0;
244}
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_DIMif (0 == nrrd->dim) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: don't yet have a valid dimension"
, me); return 1; }
\
252 if (0 == nrrd->dim) { \
253 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, \
254 "%s: don't yet have a valid dimension", me); \
255 return 1; \
256 }
257
258#define _CHECK_HAVE_SPACE_DIMif (0 == nrrd->spaceDim) { biffMaybeAddf(useBiff, nrrdBiffKey
, "%s: don't yet have a valid space dimension", me); return 1
; }
\
259 if (0 == nrrd->spaceDim) { \
260 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, \
261 "%s: don't yet have a valid space dimension", me); \
262 return 1; \
263 }
264
265#define _CHECK_GOT_ALL_VALUESif (nrrd->dim != ret) { biffMaybeAddf(useBiff, nrrdBiffKey
, "%s: parsed %d values, but dimension is %d", me, ret, nrrd->
dim); return 1; }
\
266 if (nrrd->dim != ret) { \
267 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, \
268 "%s: parsed %d values, but dimension is %d", \
269 me, ret, nrrd->dim); \
270 return 1; \
271 }
272
273static 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 size_t val[NRRD_DIM_MAX16];
279 char *info;
280
281 AIR_UNUSED(file)(void)(file);
282 info = nio->line + nio->pos;
283 _CHECK_HAVE_DIMif (0 == nrrd->dim) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: don't yet have a valid dimension"
, me); return 1; }
;
284 ret = airParseStrZ(val, info, _nrrdFieldSep, nrrd->dim);
285 _CHECK_GOT_ALL_VALUESif (nrrd->dim != ret) { biffMaybeAddf(useBiff, nrrdBiffKey
, "%s: parsed %d values, but dimension is %d", me, ret, nrrd->
dim); return 1; }
;
286 nrrdAxisInfoSet_nva(nrrd, nrrdAxisInfoSize, val);
287 /* HEY: this is a very imperfect check of excess info */
288 if (nrrd->dim+1 == airParseStrZ(val, info, _nrrdFieldSep, nrrd->dim+1)) {
289 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
290 "%s: seem to have more than expected %d sizes",
291 me, nrrd->dim);
292 return 1;
293 }
294 if (_nrrdFieldCheck[nrrdField_sizes](nrrd, useBiff)) {
295 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
296 return 1;
297 }
298 return 0;
299}
300
301static 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_MAX16];
307 char *info;
308
309 AIR_UNUSED(file)(void)(file);
310 info = nio->line + nio->pos;
311 _CHECK_HAVE_DIMif (0 == nrrd->dim) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: don't yet have a valid dimension"
, me); return 1; }
;
312 ret = airParseStrD(val, info, _nrrdFieldSep, nrrd->dim);
313 _CHECK_GOT_ALL_VALUESif (nrrd->dim != ret) { biffMaybeAddf(useBiff, nrrdBiffKey
, "%s: parsed %d values, but dimension is %d", me, ret, nrrd->
dim); return 1; }
;
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, NRRDnrrdBiffKey,
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, NRRDnrrdBiffKey, "%s: trouble", me);
324 return 1;
325 }
326 return 0;
327}
328
329static 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_MAX16];
335 char *info;
336
337 AIR_UNUSED(file)(void)(file);
338 info = nio->line + nio->pos;
339 _CHECK_HAVE_DIMif (0 == nrrd->dim) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: don't yet have a valid dimension"
, me); return 1; }
;
340 ret = airParseStrD(val, info, _nrrdFieldSep, nrrd->dim);
341 _CHECK_GOT_ALL_VALUESif (nrrd->dim != ret) { biffMaybeAddf(useBiff, nrrdBiffKey
, "%s: parsed %d values, but dimension is %d", me, ret, nrrd->
dim); return 1; }
;
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, NRRDnrrdBiffKey,
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, NRRDnrrdBiffKey, "%s: trouble", me);
352 return 1;
353 }
354 return 0;
355}
356
357static 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 double val[NRRD_DIM_MAX16];
363 char *info;
364
365 AIR_UNUSED(file)(void)(file);
366 info = nio->line + nio->pos;
367 _CHECK_HAVE_DIMif (0 == nrrd->dim) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: don't yet have a valid dimension"
, me); return 1; }
;
368 ret = airParseStrD(val, info, _nrrdFieldSep, nrrd->dim);
369 _CHECK_GOT_ALL_VALUESif (nrrd->dim != ret) { biffMaybeAddf(useBiff, nrrdBiffKey
, "%s: parsed %d values, but dimension is %d", me, ret, nrrd->
dim); return 1; }
;
370 nrrdAxisInfoSet_nva(nrrd, nrrdAxisInfoMin, val);
371 /* HEY: this is a very imperfect check of excess info */
372 if (nrrd->dim+1 == airParseStrD(val, info, _nrrdFieldSep, nrrd->dim+1)) {
373 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
374 "%s: seem to have more than expected %d axis mins",
375 me, nrrd->dim);
376 return 1;
377 }
378 if (_nrrdFieldCheck[nrrdField_axis_mins](nrrd, useBiff)) {
379 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
380 return 1;
381 }
382 return 0;
383}
384
385static 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 double val[NRRD_DIM_MAX16];
391 char *info;
392
393 AIR_UNUSED(file)(void)(file);
394 info = nio->line + nio->pos;
395 _CHECK_HAVE_DIMif (0 == nrrd->dim) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: don't yet have a valid dimension"
, me); return 1; }
;
396 ret = airParseStrD(val, info, _nrrdFieldSep, nrrd->dim);
397 _CHECK_GOT_ALL_VALUESif (nrrd->dim != ret) { biffMaybeAddf(useBiff, nrrdBiffKey
, "%s: parsed %d values, but dimension is %d", me, ret, nrrd->
dim); return 1; }
;
398 nrrdAxisInfoSet_nva(nrrd, nrrdAxisInfoMax, val);
399 /* HEY: this is a very imperfect check of excess info */
400 if (nrrd->dim+1 == airParseStrD(val, info, _nrrdFieldSep, nrrd->dim+1)) {
401 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
402 "%s: seem to have more than expected %d axis maxs",
403 me, nrrd->dim);
404 return 1;
405 }
406 if (_nrrdFieldCheck[nrrdField_axis_maxs](nrrd, useBiff)) {
407 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
408 return 1;
409 }
410 return 0;
411}
412
413static int
414_nrrdSpaceVectorParse(double val[NRRD_SPACE_DIM_MAX8],
415 char **hhP, unsigned int spaceDim, int useBiff) {
416 static const char me[]="_nrrdSpaceVectorParse";
417 char *hh, *buff, sep[]=",)";
418 airArray *mop;
419 unsigned int ret, dd;
420 size_t length;
421
422 mop = airMopNew();
423
424 hh = *hhP;
425 /* skip past space */
426 length = strspn(hh, _nrrdFieldSep);
427 hh += length;
428
429 /* make sure we have something */
430 if (!*hh) {
431 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
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 if ( (strstr(hh, _nrrdNoSpaceVector) == hh) ) {
437 if (!hh[strlen(_nrrdNoSpaceVector)]
438 || strchr(_nrrdFieldSep, hh[strlen(_nrrdNoSpaceVector)])) {
439 /* yes, we got the non-vector */
440 for (dd=0; dd<spaceDim; dd++) {
441 val[dd] = AIR_NAN(airFloatQNaN.f);
442 }
443 length += strlen(_nrrdNoSpaceVector);
444 } else {
445 /* we got something that started out looking like the non-vector */
446 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
447 "%s: couldn't parse non-vector \"%s\"", me, hh);
448 airMopError(mop); return 1;
449 }
450 } else {
451 /* this isn't a non-vector */
452 /* make sure we have an open paren */
453 if ('(' != *hh) {
454 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
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 if (!(buff = airStrdup(hh))) {
461 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
462 "%s: couldn't allocate local buffer", me);
463 airMopError(mop); return 1;
464 }
465 airMopAdd(mop, buff, airFree, airMopAlways);
466 /* scan for close paren */
467 hh = buff+1;
468 while (*hh) {
469 if (')' == *hh) {
470 break;
471 } else {
472 hh++;
473 }
474 }
475 if (')' != *hh) {
476 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
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 *(hh+1) = 0;
483 length += strlen(buff);
484 /* see if we have too many fields */
485 ret = airStrntok(buff+1, sep);
486 if (ret > spaceDim) {
487 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
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 ret = airParseStrD(val, buff+1, ",", spaceDim);
494 if (spaceDim != ret) {
495 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
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 for (dd=spaceDim; dd<NRRD_SPACE_DIM_MAX8; dd++) {
503 val[dd] = AIR_NAN(airFloatQNaN.f);
504 }
505 /* make sure all coefficients exist or not together */
506 for (dd=1; dd<spaceDim; dd++) {
507 if (!!AIR_EXISTS(val[0])(((int)(!((val[0]) - (val[0]))))) ^ !!AIR_EXISTS(val[dd])(((int)(!((val[dd]) - (val[dd])))))) {
508 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%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 for (dd=0; dd<spaceDim; dd++) {
515 if (airIsInf_d(val[dd])) {
516 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
517 "%s: vector coefficient %d can't be infinite",
518 me, dd);
519 airMopError(mop); return 1;
520 }
521 }
522 *hhP += length;
523 airMopOkay(mop);
524 return 0;
525}
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*/
534int
535nrrdSpaceVectorParse(double dir[NRRD_SPACE_DIM_MAX8],
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, NRRDnrrdBiffKey, "%s: got NULL pointer", me);
546 airMopError(mop); return 1;
547 }
548 if (_nrrdSpaceVectorParse(dir, &str, spaceDim, useBiff)) {
549 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble parsing", me);
550 airMopError(mop); return 1;
551 }
552
553 airMopOkay(mop);
554 return 0;
555}
556
557static 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 char *info;
563
564 AIR_UNUSED(file)(void)(file);
565 info = nio->line + nio->pos;
566 _CHECK_HAVE_DIMif (0 == nrrd->dim) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: don't yet have a valid dimension"
, me); return 1; }
;
567 _CHECK_HAVE_SPACE_DIMif (0 == nrrd->spaceDim) { biffMaybeAddf(useBiff, nrrdBiffKey
, "%s: don't yet have a valid space dimension", me); return 1
; }
;
568
569 for (dd=0; dd<nrrd->dim; dd++) {
570 if (_nrrdSpaceVectorParse(nrrd->axis[dd].spaceDirection,
571 &info, nrrd->spaceDim, useBiff)) {
572 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
573 "%s: trouble getting space vector %d of %d",
574 me, dd+1, nrrd->dim);
575 return 1;
576 }
577 }
578 if (strlen(info) != strspn(info, _nrrdFieldSep)) {
579 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
580 "%s: seem to have more than expected %d directions",
581 me, nrrd->dim);
582 return 1;
583 }
584 if (_nrrdFieldCheck[nrrdField_space_directions](nrrd, useBiff)) {
585 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
586 return 1;
587 }
588 return 0;
589}
590
591static 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 char *tok, *info, *last;
597 airArray *mop;
598
599 AIR_UNUSED(file)(void)(file);
600 mop = airMopNew();
601 info = airStrdup(nio->line + nio->pos);
602 airMopAdd(mop, info, airFree, airMopAlways);
603 _CHECK_HAVE_DIMif (0 == nrrd->dim) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: don't yet have a valid dimension"
, me); return 1; }
;
604 for (ai=0; ai<nrrd->dim; ai++) {
605 tok = airStrtok(!ai ? info : NULL((void*)0), _nrrdFieldSep, &last);
606 if (!tok) {
607 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
608 "%s: couldn't extract string for center %d of %d",
609 me, ai+1, nrrd->dim);
610 airMopError(mop); return 1;
611 }
612 if (!strcmp(tok, NRRD_UNKNOWN"???")) {
613 nrrd->axis[ai].center = nrrdCenterUnknown;
614 continue;
615 }
616 if (!strcmp(tok, NRRD_NONE"none")) {
617 nrrd->axis[ai].center = nrrdCenterUnknown;
618 continue;
619 }
620 if (!(nrrd->axis[ai].center = airEnumVal(nrrdCenter, tok))) {
621 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
622 "%s: couldn't parse center \"%s\" for axis %d",
623 me, tok, ai);
624 airMopError(mop); return 1;
625 }
626 }
627 if (airStrtok(!ai ? info : NULL((void*)0), _nrrdFieldSep, &last)) {
628 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
629 "%s: seem to have more than expected %d centers",
630 me, nrrd->dim);
631 airMopError(mop); return 1;
632 }
633 if (_nrrdFieldCheck[nrrdField_centers](nrrd, useBiff)) {
634 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
635 airMopError(mop); return 1;
636 }
637 airMopOkay(mop);
638 return 0;
639}
640
641static 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 char *info, *tok, *last;
647 airArray *mop;
648
649 AIR_UNUSED(file)(void)(file);
650 mop = airMopNew();
651 info = airStrdup(nio->line + nio->pos);
652 airMopAdd(mop, info, airFree, airMopAlways);
653 _CHECK_HAVE_DIMif (0 == nrrd->dim) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: don't yet have a valid dimension"
, me); return 1; }
;
654 for (ai=0; ai<nrrd->dim; ai++) {
655 tok = airStrtok(!ai ? info : NULL((void*)0), _nrrdFieldSep, &last);
656 if (!tok) {
657 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
658 "%s: couldn't extract string for kind %d of %d",
659 me, ai+1, nrrd->dim);
660 airMopError(mop); return 1;
661 }
662 if (!strcmp(tok, NRRD_UNKNOWN"???")) {
663 nrrd->axis[ai].kind = nrrdKindUnknown;
664 continue;
665 }
666 if (!strcmp(tok, NRRD_NONE"none")) {
667 nrrd->axis[ai].center = nrrdKindUnknown;
668 continue;
669 }
670 if (!(nrrd->axis[ai].kind = airEnumVal(nrrdKind, tok))) {
671 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
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 if (airStrtok(!ai ? info : NULL((void*)0), _nrrdFieldSep, &last)) {
678 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
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 airMopOkay(mop);
692 return 0;
693}
694
695static char *
696_nrrdGetQuotedString(char **hP, int useBiff) {
697 static const char me[]="_nrrdGetQuotedString";
698 char *h, *buff, *ret;
699 airArray *buffArr;
700 unsigned int pos;
701 airPtrPtrUnion appu;
702
703 h = *hP;
704 /* skip past space */
705 /* printf("!%s: h |%s|\n", me, h);*/
706 h += strspn(h, _nrrdFieldSep);
707 /* printf("!%s: h |%s|\n", me, h);*/
708
709 /* make sure we have something */
710 if (!*h) {
3
Taking false branch
711 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
712 "%s: hit end of string before seeing opening \"", me);
713 return NULL((void*)0);
714 }
715 /* make sure we have a starting quote */
716 if ('"' != *h) {
4
Taking false branch
717 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: didn't start with \"", me);
718 return NULL((void*)0);
719 }
720 h++;
721
722 /* parse string until end quote */
723 buff = NULL((void*)0);
5
Null pointer value stored to 'buff'
724 appu.c = &buff;
725 buffArr = airArrayNew(appu.v, NULL((void*)0), sizeof(char), 2);
726 if (!buffArr) {
6
Assuming 'buffArr' is non-null
7
Taking false branch
727 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: couldn't create airArray", me);
728 return NULL((void*)0);
729 }
730 pos = airArrayLenIncr(buffArr, 1); /* pos should get 0 */
731 while (h[pos]) {
8
Loop condition is true. Entering loop body
732 /* printf("!%s: h+%d |%s|\n", me, pos, h+pos); */
733 if ('\"' == h[pos]) {
9
Taking false branch
734 break;
735 }
736 if ('\\' == h[pos] && '\"' == h[pos+1]) {
737 h += 1;
738 }
739 buff[pos] = h[pos];
10
Array access (from variable 'buff') results in a null pointer dereference
740 pos = airArrayLenIncr(buffArr, 1);
741 }
742 if ('\"' != h[pos]) {
743 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: didn't see ending \" soon enough", me);
744 return NULL((void*)0);
745 }
746 h += pos + 1;
747 buff[pos] = 0;
748
749 ret = airStrdup(buff);
750 airArrayNuke(buffArr);
751 *hP = h;
752
753 return ret;
754}
755
756static int
757_nrrdReadNrrdParse_labels(FILE *file, Nrrd *nrrd,
758 NrrdIoState *nio, int useBiff) {
759 static const char me[]="_nrrdReadNrrdParse_labels";
760 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)(void)(file);
766 /* because we have to correctly interpret quote marks, we
767 can't simply rely on airParseStrS */
768 info = nio->line + nio->pos;
769 /* printf("!%s: info |%s|\n", me, info); */
770 _CHECK_HAVE_DIMif (0 == nrrd->dim) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: don't yet have a valid dimension"
, me); return 1; }
;
771 h = info;
772 for (ai=0; ai<nrrd->dim; ai++) {
773 if (!( nrrd->axis[ai].label = _nrrdGetQuotedString(&h, useBiff) )) {
774 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: couldn't get get label %d of %d\n",
775 me, ai+1, nrrd->dim);
776 return 1;
777 }
778 }
779 if (strlen(h) != strspn(h, _nrrdFieldSep)) {
780 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
781 "%s: seem to have more than expected %d labels",
782 me, nrrd->dim);
783 return 1;
784 }
785 if (_nrrdFieldCheck[nrrdField_labels](nrrd, useBiff)) {
786 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
787 return 1;
788 }
789 return 0;
790}
791
792static 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)(void)(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_DIMif (0 == nrrd->dim) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: don't yet have a valid dimension"
, me); return 1; }
;
807 h = info;
808 for (ai=0; ai<nrrd->dim; ai++) {
809 if (!( nrrd->axis[ai].units = _nrrdGetQuotedString(&h, useBiff) )) {
810 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%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, NRRDnrrdBiffKey,
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, NRRDnrrdBiffKey, "%s: trouble", me);
823 return 1;
824 }
825 return 0;
826}
827
828static int
829_nrrdReadNrrdParse_min(FILE *file, Nrrd *nrrd,
830 NrrdIoState *nio, int useBiff) {
831
832 AIR_UNUSED(file)(void)(file);
833 AIR_UNUSED(nrrd)(void)(nrrd);
834 AIR_UNUSED(nio)(void)(nio);
835 AIR_UNUSED(useBiff)(void)(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
845static int
846_nrrdReadNrrdParse_max(FILE *file, Nrrd *nrrd,
847 NrrdIoState *nio, int useBiff) {
848
849 AIR_UNUSED(file)(void)(file);
850 AIR_UNUSED(nrrd)(void)(nrrd);
851 AIR_UNUSED(nio)(void)(nio);
852 AIR_UNUSED(useBiff)(void)(useBiff);
853
854 /* nrrd->max no longer exists, see above */
855
856 return 0;
857}
858
859static 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)(void)(file);
866 info = nio->line + nio->pos;
867 _PARSE_ONE_VAL(nrrd->oldMin, "%lg", "double")if (1 != airSingleSscanf(info, "%lg", &(nrrd->oldMin))
) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: couldn't parse "
"double" " from \"%s\"", me, info); return 1; }
;
868 if (_nrrdFieldCheck[nrrdField_old_min](nrrd, useBiff)) {
869 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
870 return 1;
871 }
872 return 0;
873}
874
875static 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)(void)(file);
882 info = nio->line + nio->pos;
883 _PARSE_ONE_VAL(nrrd->oldMax, "%lg", "double")if (1 != airSingleSscanf(info, "%lg", &(nrrd->oldMax))
) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: couldn't parse "
"double" " from \"%s\"", me, info); return 1; }
;
884 if (_nrrdFieldCheck[nrrdField_old_max](nrrd, useBiff)) {
885 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
886 return 1;
887 }
888 return 0;
889}
890
891static 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)(void)(file);
898 AIR_UNUSED(nrrd)(void)(nrrd);
899 info = nio->line + nio->pos;
900 if (!(nio->endian = airEnumVal(airEndian, info))) {
901 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
902 "%s: couldn't parse endian \"%s\"", me, info);
903 return 1;
904 }
905 return 0;
906}
907
908static 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)(void)(file);
916 AIR_UNUSED(nrrd)(void)(nrrd);
917 info = nio->line + nio->pos;
918 if (!(etype = airEnumVal(nrrdEncodingType, info))) {
919 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
920 "%s: couldn't parse encoding \"%s\"", me, info);
921 return 1;
922 }
923
924 nio->encoding = nrrdEncodingArray[etype];
925 return 0;
926}
927
928static 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)(void)(file);
935 AIR_UNUSED(nrrd)(void)(nrrd);
936 info = nio->line + nio->pos;
937 _PARSE_ONE_VAL(nio->lineSkip, "%u", "unsigned int")if (1 != airSingleSscanf(info, "%u", &(nio->lineSkip))
) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: couldn't parse "
"unsigned int" " from \"%s\"", me, info); return 1; }
;
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
948static 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)(void)(file);
955 AIR_UNUSED(nrrd)(void)(nrrd);
956 info = nio->line + nio->pos;
957 _PARSE_ONE_VAL(nio->byteSkip, "%ld", "long int")if (1 != airSingleSscanf(info, "%ld", &(nio->byteSkip)
)) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: couldn't parse "
"long int" " from \"%s\"", me, info); return 1; }
;
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 return 0;
968}
969
970static 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)(void)(file);
977 /* we know this will find something */
978 line = airStrdup(nio->line + nio->pos);
979 if (!line) {
980 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: can't allocate parse line", me);
981 return 1;
982 }
983 keysep = strstr(line, ":=");
984 if (!keysep) {
985 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
986 "%s: didn't see \":=\" key/value delimiter in \"%s\"",
987 me, line);
988 free(line); return 1;
989 }
990 keysep[0] = 0;
991 keysep[1] = 0;
992 key = line;
993 value = keysep+2;
994
995 /* convert escape sequences */
996 airUnescape(key);
997 airUnescape(value);
998
999 nrrdKeyValueAdd(nrrd, key, value);
1000
1001 free(line);
1002 return 0;
1003}
1004
1005static 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)(void)(file);
1012 info = nio->line + nio->pos;
1013
1014 if (strlen(info) && !(nrrd->sampleUnits = airStrdup(info))) {
1015 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
1016 "%s: couldn't strdup() sampleUnits", me);
1017 return 1;
1018 }
1019 if (_nrrdFieldCheck[nrrdField_sample_units](nrrd, useBiff)) {
1020 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
1021 return 1;
1022 }
1023 return 0;
1024}
1025
1026static 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)(void)(file);
1034 info = nio->line + nio->pos;
1035 if (nio->seen[nrrdField_space_dimension]) {
1036 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
1037 "%s: can't specify space after specifying "
1038 "space dimension (%d)", me, nrrd->spaceDim);
1039 return 1;
1040 }
1041 if (!(space = airEnumVal(nrrdSpace, info))) {
1042 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
1043 "%s: couldn't parse space \"%s\"", me, info);
1044 return 1;
1045 }
1046 if (nrrdSpaceSet(nrrd, space)) {
1047 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
1048 return 1;
1049 }
1050 if (_nrrdFieldCheck[nrrdField_space](nrrd, useBiff)) {
1051 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
1052 return 1;
1053 }
1054 return 0;
1055}
1056
1057static 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)(void)(file);
1064 info = nio->line + nio->pos;
1065 if (nio->seen[nrrdField_space]) {
1066 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
1067 "%s: can't specify space dimension after specifying "
1068 "space (%s)", me, airEnumStr(nrrdSpace, nrrd->space));
1069 return 1;
1070 }
1071 _PARSE_ONE_VAL(nrrd->spaceDim, "%u", "unsigned int")if (1 != airSingleSscanf(info, "%u", &(nrrd->spaceDim)
)) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: couldn't parse "
"unsigned int" " from \"%s\"", me, info); return 1; }
;
1072 if (_nrrdFieldCheck[nrrdField_space_dimension](nrrd, useBiff)) {
1073 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
1074 return 1;
1075 }
1076 return 0;
1077}
1078
1079static int
1080_nrrdReadNrrdParse_space_units(FILE *file, Nrrd *nrrd,
1081 NrrdIoState *nio, int useBiff) {
1082 static const char me[]="_nrrdReadNrrdParse_space_units";
1083 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)(void)(file);
1089 /* because we have to correctly interpret quote marks, we
1090 can't simply rely on airParseStrS */
1091 info = nio->line + nio->pos;
1092 /* printf("!%s: info |%s|\n", me, info); */
1093 _CHECK_HAVE_SPACE_DIMif (0 == nrrd->spaceDim) { biffMaybeAddf(useBiff, nrrdBiffKey
, "%s: don't yet have a valid space dimension", me); return 1
; }
;
1094 h = info;
1095 for (ai=0; ai<nrrd->spaceDim; ai++) {
1
Loop condition is true. Entering loop body
1096 if (!( nrrd->spaceUnits[ai] = _nrrdGetQuotedString(&h, useBiff) )) {
2
Calling '_nrrdGetQuotedString'
1097 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: couldn't get get space unit %d of %d",
1098 me, ai+1, nrrd->spaceDim);
1099 return 1;
1100 }
1101 }
1102 if (_nrrdGetQuotedString(&h, AIR_FALSE0)) {
1103 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
1104 "%s: seemed to have more than expected %d space units",
1105 me, nrrd->spaceDim);
1106 return 1;
1107 }
1108 if (_nrrdFieldCheck[nrrdField_space_units](nrrd, useBiff)) {
1109 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
1110 return 1;
1111 }
1112 return 0;
1113}
1114
1115static int
1116_nrrdReadNrrdParse_space_origin(FILE *file, Nrrd *nrrd,
1117 NrrdIoState *nio, int useBiff) {
1118 static const char me[]="_nrrdReadNrrdParse_space_origin";
1119 char *info;
1120
1121 AIR_UNUSED(file)(void)(file);
1122 info = nio->line + nio->pos;
1123
1124 _CHECK_HAVE_SPACE_DIMif (0 == nrrd->spaceDim) { biffMaybeAddf(useBiff, nrrdBiffKey
, "%s: don't yet have a valid space dimension", me); return 1
; }
;
1125
1126 if (_nrrdSpaceVectorParse(nrrd->spaceOrigin, &info,
1127 nrrd->spaceDim, useBiff)) {
1128 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
1129 "%s: couldn't parse origin \"%s\"", me, info);
1130 return 1;
1131 }
1132 if (_nrrdFieldCheck[nrrdField_space_origin](nrrd, useBiff)) {
1133 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
1134 return 1;
1135 }
1136 return 0;
1137}
1138
1139static int
1140_nrrdReadNrrdParse_measurement_frame(FILE *file, Nrrd *nrrd,
1141 NrrdIoState *nio, int useBiff) {
1142 static const char me[]="_nrrdReadNrrdParse_measurement_frame";
1143 double colvec[NRRD_SPACE_DIM_MAX8];
1144 unsigned int dd, ii;
1145 char *info;
1146
1147 AIR_UNUSED(file)(void)(file);
1148 info = nio->line + nio->pos;
1149
1150 _CHECK_HAVE_SPACE_DIMif (0 == nrrd->spaceDim) { biffMaybeAddf(useBiff, nrrdBiffKey
, "%s: don't yet have a valid space dimension", me); return 1
; }
;
1151
1152 for (dd=0; dd<nrrd->spaceDim; dd++) {
1153 /* we are going through the *columns* of the mf matrix */
1154 if (_nrrdSpaceVectorParse(colvec, &info, nrrd->spaceDim, useBiff)) {
1155 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
1156 "%s: trouble getting space vector %d of %d",
1157 me, dd+1, nrrd->spaceDim);
1158 return 1;
1159 }
1160 for (ii=0; ii<NRRD_SPACE_DIM_MAX8; ii++) {
1161 nrrd->measurementFrame[dd][ii] = (ii < nrrd->spaceDim
1162 ? colvec[ii]
1163 : AIR_NAN(airFloatQNaN.f));
1164 }
1165 }
1166 if (strlen(info) != strspn(info, _nrrdFieldSep)) {
1167 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
1168 "%s: seem to have more than expected %d directions",
1169 me, nrrd->spaceDim);
1170 return 1;
1171 }
1172 for (dd=nrrd->spaceDim; dd<NRRD_SPACE_DIM_MAX8; dd++) {
1173 for (ii=0; ii<NRRD_SPACE_DIM_MAX8; ii++) {
1174 nrrd->measurementFrame[dd][ii] = AIR_NAN(airFloatQNaN.f);
1175 }
1176 }
1177 if (_nrrdFieldCheck[nrrdField_measurement_frame](nrrd, useBiff)) {
1178 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: trouble", me);
1179 return 1;
1180 }
1181 return 0;
1182}
1183
1184int
1185_nrrdContainsPercentThisAndMore(const char *str, char thss) {
1186 const char *hh, *tmp;
1187
1188 tmp = str;
1189 do {
1190 hh = strchr(tmp, '%');
1191 if (!( hh && hh[1] )) {
1192 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}
1209
1210unsigned int
1211_nrrdDataFNNumber(NrrdIoState *nio) {
1212 unsigned int ret;
1213 int ii;
1214
1215 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 } 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 } else {
1230 /* datafile is same as (attached) header file */
1231 ret = 1;
1232 }
1233 return ret;
1234}
1235
1236/*
1237** this always requires that the per-axis size fields have been set
1238*/
1239int
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(128+1)];
1244
1245 if (!nio->seen[nrrdField_sizes]) {
1246 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%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, NRRDnrrdBiffKey,
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, NRRDnrrdBiffKey,
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, NRRDnrrdBiffKey,
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*/
1301static 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 unsigned int linelen, tmp;
1307 airArray *mop;
1308
1309 mop = airMopNew();
1310 info = airStrdup(nio->line + nio->pos);
1311 if (!info) {
1312 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: couldn't copy line!", me);
1313 return 1;
1314 }
1315 airMopAdd(mop, info, airFree, airMopAlways);
1316
1317 /* HEY: this change should be made someday
1318 if (_nrrdContainsPercentThisAndMore(info, 'd')
1319 || _nrrdContainsPercentThisAndMore(info, 'u')) { */
1320 if (_nrrdContainsPercentThisAndMore(info, 'd')) {
1321 /* ---------------------------------------------------------- */
1322 /* --------- format.%d <min> <max> <step> [<dim>] ----------- */
1323 /* ---------------------------------------------------------- */
1324 size_t sspn;
1325 _CHECK_HAVE_DIMif (0 == nrrd->dim) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: don't yet have a valid dimension"
, me); return 1; }
;
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, NRRDnrrdBiffKey,
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)((1) <= (nio->dataFileDim) && (nio->dataFileDim
) <= (nrrd->dim))
) {
1341 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
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, NRRDnrrdBiffKey,
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, NRRDnrrdBiffKey,
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, NRRDnrrdBiffKey,
1363 "%s: couldn't copy data filename format", me);
1364 airMopError(mop); return 1;
1365 }
1366 if (_nrrdDataFNCheck(nio, nrrd, useBiff)) {
1367 biffMaybeAddf(useBiff, NRRDnrrdBiffKey,
1368 "%s: trouble with number of datafiles", me);
1369 airMopError(mop); return 1;
1370 }
1371 } else if (!strncmp(info, NRRD_LIST_FLAG"LIST", strlen(NRRD_LIST_FLAG"LIST")) ||
1372 !strncmp(info, NRRD_SKIPLIST_FLAG"SKIPLIST", strlen(NRRD_SKIPLIST_FLAG"SKIPLIST"))) {
1373 int skiplist;
1374 unsigned int lineidx;
1375 /* ---------------------------------------------------------- */
1376 /* -------------------- LIST or SKIPLIST -------------------- */
1377 /* ---------------------------------------------------------- */
1378 _CHECK_HAVE_DIMif (0 == nrrd->dim) { biffMaybeAddf(useBiff, nrrdBiffKey, "%s: don't yet have a valid dimension"
, me); return 1; }
;
1379 skiplist = !strncmp(info, NRRD_SKIPLIST_FLAG"SKIPLIST", strlen(NRRD_SKIPLIST_FLAG"SKIPLIST"));
1380 if (_nrrdHeaderCheck(nrrd, nio, AIR_TRUE1)) {
1381 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%s: NRRD header is incomplete. "
1382 "\"%s\" data file specification must be "
1383 "contiguous with end of header!", me,
1384 skiplist ? NRRD_SKIPLIST_FLAG"SKIPLIST" : NRRD_LIST_FLAG"LIST");
1385 airMopError(mop); return 1;
1386 }
1387 info += strlen(skiplist ? NRRD_SKIPLIST_FLAG"SKIPLIST" : NRRD_LIST_FLAG"LIST");
1388 if (info[0]) {
1389 if (1 == sscanf(info, "%u", &(nio->dataFileDim))) {
1390 if (!AIR_IN_CL(1, nio->dataFileDim, nrrd->dim)((1) <= (nio->dataFileDim) && (nio->dataFileDim
) <= (nrrd->dim))
) {
1391 biffMaybeAddf(useBiff, NRRDnrrdBiffKey, "%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, NRRDnrrdBiffKey, "%s: couldn't parse info after "
1398 "\"%s\" as an int", me,
1399 skiplist ? NRRD_SKIPLIST_FLAG"SKIPLIST" : NRRD_LIST_FLAG"LIST");
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, NRRDnrrdBiffKey,
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, NRRDnrrdBiffKey,
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, NRRDnrrdBiffKey, "%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, NRRDnrrdBiffKey, "%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, NRRDnrrdBiffKey,
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 tmp = airArrayLenIncr(nio->dataFNArr, 1);
1463 nio->dataFN[tmp] = airStrdup(info);
1464 nio->dataFileDim = 0;
1465 }
1466 airMopOkay(mop);
1467 return 0;
1468}
1469
1470/*
1471******** nrrdFieldInfoParse[NRRD_FIELD_MAX+1]()
1472**
1473** These are all for parsing the stuff AFTER the colon
1474*/
1475int
1476(*nrrdFieldInfoParse[NRRD_FIELD_MAX32+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