GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/nrrd/parseNrrd.c Lines: 283 629 45.0 %
Date: 2017-05-26 Branches: 141 356 39.6 %

Line Branch Exec Source
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