GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/nrrd/simple.c Lines: 271 606 44.7 %
Date: 2017-05-26 Branches: 175 397 44.1 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2015, 2014, 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
#include <limits.h>
28
29
/* The "/ *Teem:" (without space) comments in here are an experiment */
30
31
const char *
32
nrrdBiffKey = "nrrd";
33
34
/*
35
******** nrrdSpaceDimension
36
**
37
** returns expected dimension of given space (from nrrdSpace* enum), or,
38
** 0 if there is no expected dimension.
39
**
40
** The expected behavior here is to return 0 for nrrdSpaceUnknown, because
41
** that is the right answer, not because its an error of any kind.
42
*/
43
unsigned int
44
nrrdSpaceDimension(int space) {
45
  static const char me[]="nrrdSpaceDimension";
46
  unsigned int ret;
47
48
62198
  if (!( AIR_IN_OP(nrrdSpaceUnknown, space, nrrdSpaceLast) )) {
49
    /* they gave us invalid or unknown space */
50
    return 0;
51
  }
52



31099
  switch (space) {
53
  case nrrdSpaceRightUp:
54
  case nrrdSpaceRightDown:
55
    ret = 2;
56
    break;
57
  case nrrdSpaceRightAnteriorSuperior:
58
  case nrrdSpaceLeftAnteriorSuperior:
59
  case nrrdSpaceLeftPosteriorSuperior:
60
  case nrrdSpaceScannerXYZ:
61
  case nrrdSpace3DRightHanded:
62
  case nrrdSpace3DLeftHanded:
63
    ret = 3;
64
31099
    break;
65
  case nrrdSpaceRightAnteriorSuperiorTime:
66
  case nrrdSpaceLeftAnteriorSuperiorTime:
67
  case nrrdSpaceLeftPosteriorSuperiorTime:
68
  case nrrdSpaceScannerXYZTime:
69
  case nrrdSpace3DRightHandedTime:
70
  case nrrdSpace3DLeftHandedTime:
71
    ret = 4;
72
    break;
73
  default:
74
    fprintf(stderr, "%s: PANIC: nrrdSpace %d not implemented!\n", me, space);
75
    ret = UINT_MAX; /* exit(1); */
76
    break;
77
  }
78
31099
  return ret;
79
31099
}
80
81
/*
82
******** nrrdSpaceSet
83
**
84
** What to use to set space, when a value from nrrdSpace enum is known,
85
** or, to nullify all space-related information when passed nrrdSpaceUnknown
86
*/
87
int
88
nrrdSpaceSet(Nrrd *nrrd, int space) {
89
  static const char me[]="nrrdSpaceSet";
90
  unsigned axi, saxi;
91
92
94
  if (!nrrd) {
93
    biffAddf(NRRD, "%s: got NULL pointer", me);
94
    return 1;
95
  }
96
47
  if (nrrdSpaceUnknown == space) {
97
    nrrd->space = nrrdSpaceUnknown;
98
    nrrd->spaceDim = 0;
99
    for (axi=0; axi<NRRD_DIM_MAX; axi++) {
100
      nrrdSpaceVecSetNaN(nrrd->axis[axi].spaceDirection);
101
    }
102
    for (saxi=0; saxi<NRRD_SPACE_DIM_MAX; saxi++) {
103
      airFree(nrrd->spaceUnits[saxi]);
104
      nrrd->spaceUnits[saxi] = NULL;
105
    }
106
    nrrdSpaceVecSetNaN(nrrd->spaceOrigin);
107
  } else {
108
47
    if (airEnumValCheck(nrrdSpace, space)) {
109
      biffAddf(NRRD, "%s: given space (%d) not valid", me, space);
110
      return 1;
111
    }
112
47
    nrrd->space = space;
113
47
    nrrd->spaceDim = nrrdSpaceDimension(space);
114
  }
115
47
  return 0;
116
47
}
117
118
/*
119
******** nrrdSpaceDimensionSet
120
**
121
** What to use to set space, based on spaceDim alone (nrrd->space set to
122
** nrrdSpaceUnknown)
123
*/
124
int
125
nrrdSpaceDimensionSet(Nrrd *nrrd, unsigned int spaceDim) {
126
  static const char me[]="nrrdSpaceDimensionSet";
127
128
  if (!nrrd) {
129
    biffAddf(NRRD, "%s: got NULL pointer", me);
130
    return 1;
131
  }
132
  if (!( spaceDim <= NRRD_SPACE_DIM_MAX )) {
133
    biffAddf(NRRD, "%s: given spaceDim (%u) not valid", me, spaceDim);
134
    return 1;
135
  }
136
  nrrd->space = nrrdSpaceUnknown;
137
  nrrd->spaceDim = spaceDim;
138
  return 0;
139
}
140
141
/*
142
******** nrrdSpaceOriginGet
143
**
144
** retrieves the spaceOrigin from given nrrd, and returns spaceDim
145
** Indices 0 through spaceDim-1 are set in given vector[] to coords
146
** of space origin, and all further indices are set to NaN. That is,
147
** this really does write to all NRRD_SPACE_DIM_MAX elements of vector[]
148
*/
149
unsigned int
150
nrrdSpaceOriginGet(const Nrrd *nrrd,
151
                   double vector[NRRD_SPACE_DIM_MAX]) {
152
  unsigned int sdi, ret;
153
154
1388
  if (nrrd && vector) {
155
5552
    for (sdi=0; sdi<nrrd->spaceDim; sdi++) {
156
2082
      vector[sdi] = nrrd->spaceOrigin[sdi];
157
    }
158
8328
    for (sdi=nrrd->spaceDim; sdi<NRRD_SPACE_DIM_MAX; sdi++) {
159
3470
      vector[sdi] = AIR_NAN;
160
    }
161
694
    ret = nrrd->spaceDim;
162
694
  } else {
163
    ret = 0;
164
  }
165
694
  return ret;
166
}
167
168
/*
169
******** nrrdSpaceOriginSet
170
**
171
** convenience function for setting spaceOrigin.
172
** Note: space (or spaceDim) must be already set.
173
** The given "vector" is only read for spaceDim elements
174
**
175
** returns 1 if there were problems, 0 otherwise
176
*/
177
int
178
nrrdSpaceOriginSet(Nrrd *nrrd, const double *vector) {
179
  static const char me[]="nrrdSpaceOriginSet";
180
  unsigned int sdi;
181
182
78
  if (!( nrrd && vector )) {
183
    biffAddf(NRRD, "%s: got NULL pointer", me);
184
    return 1;
185
  }
186

78
  if (!( 0 < nrrd->spaceDim && nrrd->spaceDim <= NRRD_SPACE_DIM_MAX )) {
187
    biffAddf(NRRD, "%s: set spaceDim %d not valid", me, nrrd->spaceDim);
188
    return 1;
189
  }
190
191
312
  for (sdi=0; sdi<nrrd->spaceDim; sdi++) {
192
117
    nrrd->spaceOrigin[sdi] = vector[sdi];
193
  }
194
468
  for (sdi=nrrd->spaceDim; sdi<NRRD_SPACE_DIM_MAX; sdi++) {
195
195
    nrrd->spaceOrigin[sdi] = AIR_NAN;
196
  }
197
39
  return 0;
198
39
}
199
200
/*
201
******** nrrdOriginCalculate
202
**
203
** makes an effort to calculate something like an "origin" (as in
204
** nrrd->spaceOrigin) from the per-axis min, max, or spacing, when
205
** there is no real space information.  Like the spaceOrigin, this
206
** location is supposed to be THE CENTER of the first sample.  To
207
** avoid making assumptions about the nrrd or the caller, a default
208
** sample centering (defaultCenter) has to be provided (use either
209
** nrrdCenterNode or nrrdCenterCell).  The axes that are used
210
** for the origin calculation have to be given explicitly- but they
211
** are likely the return of nrrdDomainAxesGet
212
**
213
** The computed origin is put into the given vector (origin).  The return
214
** value takes on values from the nrrdOriginStatus* enum:
215
**
216
** nrrdOriginStatusUnknown:        invalid arguments (e.g. NULL pointer, or
217
**                                 axis values out of range)
218
**
219
** nrrdOriginStatusDirection:      the chosen axes have spaceDirection set,
220
**                                 which means caller should instead be using
221
**                                 nrrdSpaceOriginGet
222
**
223
** nrrdOriginStatusNoMin:          can't compute "origin" without axis->min
224
**
225
** nrrdOriginStatusNoMaxOrSpacing: can't compute origin without (axis->min
226
**                                 and) either axis->max or axis->spacing
227
**
228
** nrrdOriginStatusOkay:           all is well
229
*/
230
int
231
nrrdOriginCalculate(const Nrrd *nrrd,
232
                    unsigned int *axisIdx, unsigned int axisIdxNum,
233
                    int defaultCenter, double *origin) {
234
  const NrrdAxisInfo *axis[NRRD_SPACE_DIM_MAX];
235
  int center, okay, gotSpace, gotMin, gotMaxOrSpacing;
236
  unsigned int ai;
237
  double min, spacing;
238
239
#define ERROR \
240
  if (origin) { \
241
    for (ai=0; ai<axisIdxNum; ai++) { \
242
      origin[ai] = AIR_NAN; \
243
    } \
244
  }
245
246
  if (!( nrrd
247
         && (nrrdCenterCell == defaultCenter
248
             || nrrdCenterNode == defaultCenter)
249
         && origin )) {
250
    ERROR;
251
    return nrrdOriginStatusUnknown;
252
  }
253
254
  okay = AIR_TRUE;
255
  for (ai=0; ai<axisIdxNum; ai++) {
256
    okay &= axisIdx[ai] < nrrd->dim;
257
  }
258
  if (!okay) {
259
    ERROR;
260
    return nrrdOriginStatusUnknown;
261
  }
262
263
  /* learn axisInfo pointers */
264
  for (ai=0; ai<axisIdxNum; ai++) {
265
    axis[ai] = nrrd->axis + axisIdx[ai];
266
  }
267
268
  gotSpace = AIR_FALSE;
269
  for (ai=0; ai<axisIdxNum; ai++) {
270
    gotSpace |= AIR_EXISTS(axis[ai]->spaceDirection[0]);
271
  }
272
  if (nrrd->spaceDim > 0 && gotSpace) {
273
    ERROR;
274
    return nrrdOriginStatusDirection;
275
  }
276
277
  gotMin = AIR_TRUE;
278
  for (ai=0; ai<axisIdxNum; ai++) {
279
    gotMin &= AIR_EXISTS(axis[0]->min);
280
  }
281
  if (!gotMin) {
282
    ERROR;
283
    return nrrdOriginStatusNoMin;
284
  }
285
286
  gotMaxOrSpacing = AIR_TRUE;
287
  for (ai=0; ai<axisIdxNum; ai++) {
288
    gotMaxOrSpacing &= (AIR_EXISTS(axis[ai]->max)
289
                        || AIR_EXISTS(axis[ai]->spacing));
290
  }
291
  if (!gotMaxOrSpacing) {
292
    ERROR;
293
    return nrrdOriginStatusNoMaxOrSpacing;
294
  }
295
296
  for (ai=0; ai<axisIdxNum; ai++) {
297
    size_t size;
298
    double denom;
299
    size = axis[ai]->size;
300
    min = axis[ai]->min;
301
    center = (nrrdCenterUnknown != axis[ai]->center
302
              ? axis[ai]->center
303
              : defaultCenter);
304
    denom = AIR_CAST(double, nrrdCenterCell == center ? size : size-1);
305
    spacing = (AIR_EXISTS(axis[ai]->spacing)
306
               ? axis[ai]->spacing
307
               : (axis[ai]->max - min)/denom);
308
    origin[ai] = min + (nrrdCenterCell == center ? spacing/2 : 0);
309
  }
310
  return nrrdOriginStatusOkay;
311
}
312
313
void
314
nrrdSpaceVecCopy(double dst[NRRD_SPACE_DIM_MAX],
315
                  const double src[NRRD_SPACE_DIM_MAX]) {
316
  unsigned int ii;
317
318
3952
  for (ii=0; ii<NRRD_SPACE_DIM_MAX; ii++) {
319
1664
    dst[ii] = src[ii];
320
  }
321
208
}
322
323
/*
324
** NOTE: since this was created until Wed Sep 21 13:34:17 EDT 2005,
325
** nrrdSpaceVecScaleAdd2 and nrrdSpaceVecScale would treat a
326
** non-existent vector coefficient as 0.0.  The reason for this had
327
** to do with how the function is used.  For example, in nrrdCrop
328
**
329
**   _nrrdSpaceVecCopy(nout->spaceOrigin, nin->spaceOrigin);
330
**   for (ai=0; ai<nin->dim; ai++) {
331
**      _nrrdSpaceVecScaleAdd2(nout->spaceOrigin,
332
**                             1.0, nout->spaceOrigin,
333
**                             min[ai], nin->axis[ai].spaceDirection);
334
**   }
335
**
336
** but the problem with this is that non-spatial axes end up clobbering
337
** the existance of otherwise existing spaceOrigin and spaceDirections.
338
** It was decided, however, that this logic should be outside the
339
** arithmetic functions below, not inside.  NOTE: the old functionality
340
** is stuck in ITK 2.2, via NrrdIO.
341
*/
342
343
void
344
nrrdSpaceVecScaleAdd2(double sum[NRRD_SPACE_DIM_MAX],
345
                       double sclA, const double vecA[NRRD_SPACE_DIM_MAX],
346
                       double sclB, const double vecB[NRRD_SPACE_DIM_MAX]) {
347
  unsigned int ii;
348
349
1368
  for (ii=0; ii<NRRD_SPACE_DIM_MAX; ii++) {
350
576
    sum[ii] = sclA*vecA[ii] + sclB*vecB[ii];
351
  }
352
72
}
353
354
void
355
nrrdSpaceVecScale(double out[NRRD_SPACE_DIM_MAX],
356
                   double scl, const double vec[NRRD_SPACE_DIM_MAX]) {
357
  unsigned int ii;
358
359
39558
  for (ii=0; ii<NRRD_SPACE_DIM_MAX; ii++) {
360
16656
    out[ii] = scl*vec[ii];
361
  }
362
2082
}
363
364
double
365
nrrdSpaceVecNorm(unsigned int sdim, const double vec[NRRD_SPACE_DIM_MAX]) {
366
  unsigned int di;
367
  double nn;
368
369
  nn = 0;
370
18954
  for (di=0; di<sdim; di++) {
371
6318
    nn += vec[di]*vec[di];
372
  }
373
2106
  return sqrt(nn);
374
}
375
376
void
377
nrrdSpaceVecSetNaN(double vec[NRRD_SPACE_DIM_MAX]) {
378
  unsigned int di;
379
380
  for (di=0; di<NRRD_SPACE_DIM_MAX; di++) {
381
    vec[di] = AIR_NAN;
382
  }
383
  return;
384
}
385
386
/* ---- BEGIN non-NrrdIO */
387
388
void
389
nrrdSpaceVecSetZero(double vec[NRRD_SPACE_DIM_MAX]) {
390
  int di;
391
392
  for (di=0; di<NRRD_SPACE_DIM_MAX; di++) {
393
    vec[di] = 0;
394
  }
395
  return;
396
}
397
/* ---- END non-NrrdIO */
398
399
/*
400
** _nrrdContentGet
401
**
402
** ALLOCATES a string for the content of a given nrrd
403
** panics if allocation failed
404
*/
405
char *
406
_nrrdContentGet(const Nrrd *nin) {
407
  static const char me[]="_nrrdContentGet";
408
  char *ret;
409
410

1395
  ret = ((nin && nin->content)
411
164
         ? airStrdup(nin->content)
412
115
         : airStrdup(nrrdStateUnknownContent));
413
279
  if (!ret) {
414
    fprintf(stderr, "%s: PANIC: content strdup failed!\n", me);
415
    return NULL;
416
  }
417
279
  return ret;
418
279
}
419
420
int
421
_nrrdContentSet_nva(Nrrd *nout, const char *func,
422
                    char *content, const char *format, va_list arg) {
423
  static const char me[]="_nrrdContentSet_nva";
424
  char *buff;
425
426
540
  if (nrrdStateDisableContent) {
427
    /* we kill content always */
428
    nout->content = (char *)airFree(nout->content);
429
    return 0;
430
  }
431
270
  buff = (char *)malloc(128*AIR_STRLEN_HUGE);
432
270
  if (!buff) {
433
    biffAddf(NRRD, "%s: couln't alloc buffer!", me);
434
    return 1;
435
  }
436
270
  nout->content = (char *)airFree(nout->content);
437
438
  /* we are currently praying that this won't overflow the "buff" array */
439
  /* HEY: replace with vsnprintf or whatever when its available */
440
270
  vsprintf(buff, format, arg);
441
442
270
  nout->content = (char *)calloc(strlen("(,)")
443
270
                                 + airStrlen(func)
444
270
                                 + 1                      /* '(' */
445
270
                                 + airStrlen(content)
446
270
                                 + 1                      /* ',' */
447
270
                                 + airStrlen(buff)
448
270
                                 + 1                      /* ')' */
449
270
                                 + 1, sizeof(char));      /* '\0' */
450
270
  if (!nout->content) {
451
    biffAddf(NRRD, "%s: couln't alloc output content!", me);
452
    airFree(buff); return 1;
453
  }
454
270
  sprintf(nout->content, "%s(%s%s%s)", func, content,
455
          airStrlen(buff) ? "," : "", buff);
456
270
  airFree(buff);  /* no NULL assignment, else compile warnings */
457
270
  return 0;
458
270
}
459
460
int
461
_nrrdContentSet_va(Nrrd *nout, const char *func,
462
                   char *content, const char *format, ...) {
463
  static const char me[]="_nrrdContentSet_va";
464
34
  va_list ap;
465
466
17
  va_start(ap, format);
467
17
  if (_nrrdContentSet_nva(nout, func, content, format, ap)) {
468
    biffAddf(NRRD, "%s:", me);
469
    free(content); return 1;
470
  }
471
17
  va_end(ap);
472
473
  /* free(content);  */
474
17
  return 0;
475
17
}
476
477
/*
478
******** nrrdContentSet
479
**
480
** Kind of like sprintf, but for the content string of the nrrd.
481
**
482
** Whether or not we write a new content for an old nrrd ("nin") with
483
** NULL content is decided here, according to
484
** nrrdStateAlwaysSetContent.
485
**
486
** Does the string allocation and some attempts at error detection.
487
** Does allow nout==nin, which requires some care.
488
*/
489
int
490
nrrdContentSet_va(Nrrd *nout, const char *func,
491
                  const Nrrd *nin, const char *format, ...) {
492
  static const char me[]="nrrdContentSet_va";
493
506
  va_list ap;
494
  char *content;
495
496
253
  if (!(nout && func && nin && format)) {
497
    biffAddf(NRRD, "%s: got NULL pointer", me);
498
    return 1;
499
  }
500
253
  if (nrrdStateDisableContent) {
501
    /* we kill content always */
502
    nout->content = (char *)airFree(nout->content);
503
    return 0;
504
  }
505
253
  if (!nin->content && !nrrdStateAlwaysSetContent) {
506
    /* there's no input content, and we're not supposed to invent any
507
       content, so after freeing nout's content we're done */
508
    nout->content = (char *)airFree(nout->content);
509
    return 0;
510
  }
511
  /* we copy the input nrrd content first, before blowing away the
512
     output content, in case nout == nin */
513
253
  content = _nrrdContentGet(nin);
514
253
  va_start(ap, format);
515
253
  if (_nrrdContentSet_nva(nout, func, content, format, ap)) {
516
    biffAddf(NRRD, "%s:", me);
517
    va_end(ap); free(content); return 1;
518
  }
519
253
  va_end(ap);
520
253
  free(content);
521
522
253
  return 0;
523
253
}
524
525
/*
526
******** nrrdDescribe
527
**
528
** writes verbose description of nrrd to given file
529
*/
530
void
531
nrrdDescribe(FILE *file, const Nrrd *nrrd) {
532
  unsigned int ai;
533
  char stmp[AIR_STRLEN_SMALL];
534
535
  if (file && nrrd) {
536
    fprintf(file, "Nrrd at 0x%p:\n", AIR_CVOIDP(nrrd));
537
    fprintf(file, "Data at 0x%p is %s elements of type %s.\n", nrrd->data,
538
            airSprintSize_t(stmp, nrrdElementNumber(nrrd)),
539
            airEnumStr(nrrdType, nrrd->type));
540
    if (nrrdTypeBlock == nrrd->type) {
541
      fprintf(file, "The blocks have size %s\n",
542
              airSprintSize_t(stmp, nrrd->blockSize));
543
    }
544
    if (airStrlen(nrrd->content)) {
545
      fprintf(file, "Content = \"%s\"\n", nrrd->content);
546
    }
547
    fprintf(file, "%d-dimensional array, with axes:\n", nrrd->dim);
548
    for (ai=0; ai<nrrd->dim; ai++) {
549
      if (airStrlen(nrrd->axis[ai].label)) {
550
        fprintf(file, "%d: (\"%s\") ", ai, nrrd->axis[ai].label);
551
      } else {
552
        fprintf(file, "%d: ", ai);
553
      }
554
      fprintf(file, "%s-centered, size=%s, ",
555
              airEnumStr(nrrdCenter, nrrd->axis[ai].center),
556
              airSprintSize_t(stmp, nrrd->axis[ai].size));
557
      airSinglePrintf(file, NULL, "spacing=%lg, \n", nrrd->axis[ai].spacing);
558
      airSinglePrintf(file, NULL, "thickness=%lg, \n",
559
                      nrrd->axis[ai].thickness);
560
      airSinglePrintf(file, NULL, "    axis(Min,Max) = (%lg,",
561
                       nrrd->axis[ai].min);
562
      airSinglePrintf(file, NULL, "%lg)\n", nrrd->axis[ai].max);
563
      if (airStrlen(nrrd->axis[ai].units)) {
564
        fprintf(file, "units=%s, \n", nrrd->axis[ai].units);
565
      }
566
    }
567
    /*
568
    airSinglePrintf(file, NULL, "The min, max values are %lg",
569
                     nrrd->min);
570
    airSinglePrintf(file, NULL, ", %lg\n", nrrd->max);
571
    */
572
    airSinglePrintf(file, NULL, "The old min, old max values are %lg",
573
                     nrrd->oldMin);
574
    airSinglePrintf(file, NULL, ", %lg\n", nrrd->oldMax);
575
    /* fprintf(file, "hasNonExist = %d\n", nrrd->hasNonExist); */
576
    if (nrrd->cmtArr->len) {
577
      fprintf(file, "Comments:\n");
578
      for (ai=0; ai<nrrd->cmtArr->len; ai++) {
579
        fprintf(file, "%s\n", nrrd->cmt[ai]);
580
      }
581
    }
582
    fprintf(file, "\n");
583
  }
584
}
585
586
int
587
nrrdSpaceVecExists(unsigned int sdim, const double vec[NRRD_SPACE_DIM_MAX]) {
588
  int exists;
589
  unsigned int ii;
590
591
  exists = AIR_EXISTS(vec[0]);
592
  for (ii=1; ii<sdim; ii++) {
593
    exists &= AIR_EXISTS(vec[ii]);
594
  }
595
  return exists;
596
}
597
598
/*
599
** asserts all the properties associated with orientation information
600
**
601
** The most important part of this is asserting the per-axis mutual
602
** exclusion of min/max/spacing/units versus using spaceDirection.
603
*/
604
static int
605
_nrrdFieldCheckSpaceInfo(const Nrrd *nrrd, int useBiff) {
606
  static const char me[]="_nrrdFieldCheckSpaceInfo";
607
  unsigned int dd, ii;
608
  int exists;
609
610

97312
  if (!( !nrrd->space || !airEnumValCheck(nrrdSpace, nrrd->space) )) {
611
    biffMaybeAddf(useBiff, NRRD, "%s: space %d invalid",
612
                  me, nrrd->space);
613
    return 1;
614
  }
615
33130
  if (!( nrrd->spaceDim <= NRRD_SPACE_DIM_MAX )) {
616
    biffMaybeAddf(useBiff, NRRD, "%s: space dimension %d is outside "
617
                  "valid range [0,NRRD_SPACE_DIM_MAX] = [0,%d]",
618
                  me, nrrd->dim, NRRD_SPACE_DIM_MAX);
619
    return 1;
620
  }
621

66260
  if (nrrd->spaceDim) {
622
65042
    if (nrrd->space) {
623
31052
      if (nrrdSpaceDimension(nrrd->space) != nrrd->spaceDim) {
624
        biffMaybeAddf(useBiff, NRRD,
625
                      "%s: space %s has dimension %d but spaceDim is %d",
626
                      me, airEnumStr(nrrdSpace, nrrd->space),
627
                      nrrdSpaceDimension(nrrd->space), nrrd->spaceDim);
628
        return 1;
629
      }
630
    }
631
    /* check that all coeffs of spaceOrigin have consistent existance */
632
31912
    exists = AIR_EXISTS(nrrd->spaceOrigin[0]);
633
255296
    for (ii=0; ii<nrrd->spaceDim; ii++) {
634
95736
      if (exists ^ AIR_EXISTS(nrrd->spaceOrigin[ii])) {
635
        biffMaybeAddf(useBiff, NRRD,
636
                      "%s: existance of space origin coefficients must "
637
                      "be consistent (val[0] not like val[%d])", me, ii);
638
        return 1;
639
      }
640
    }
641
    /* check that all coeffs of measurementFrame have consistent existance */
642
31912
    exists = AIR_EXISTS(nrrd->measurementFrame[0][0]);
643
255296
    for (dd=0; dd<nrrd->spaceDim; dd++) {
644
765888
      for (ii=0; ii<nrrd->spaceDim; ii++) {
645
287208
        if (exists ^ AIR_EXISTS(nrrd->measurementFrame[dd][ii])) {
646
          biffMaybeAddf(useBiff, NRRD,
647
                        "%s: existance of measurement frame coefficients "
648
                        "must be consistent: [col][row] [%d][%d] not "
649
                        "like [0][0])", me, dd, ii);
650
          return 1;
651
        }
652
      }
653
    }
654
    /* check on space directions */
655
260320
    for (dd=0; dd<nrrd->dim; dd++) {
656
98248
      exists = AIR_EXISTS(nrrd->axis[dd].spaceDirection[0]);
657
589488
      for (ii=1; ii<nrrd->spaceDim; ii++) {
658
196496
        if (exists ^ AIR_EXISTS(nrrd->axis[dd].spaceDirection[ii])) {
659
          biffMaybeAddf(useBiff, NRRD,
660
                        "%s: existance of space direction %d coefficients "
661
                        "must be consistent (val[0] not like val[%d])", me,
662
                        dd, ii); return 1;
663
        }
664
      }
665
98248
      if (exists) {
666
191406
        if (AIR_EXISTS(nrrd->axis[dd].min)
667
191406
            || AIR_EXISTS(nrrd->axis[dd].max)
668
191406
            || AIR_EXISTS(nrrd->axis[dd].spacing)
669
191406
            || !!airStrlen(nrrd->axis[dd].units)) {
670
          biffMaybeAddf(useBiff, NRRD,
671
                        "%s: axis[%d] has a direction vector, and so can't "
672
                        "have min, max, spacing, or units set", me, dd);
673
          return 1;
674
        }
675
      }
676
    }
677
  } else {
678
    /* else there's not supposed to be anything in "space" */
679
1218
    if (nrrd->space) {
680
      biffMaybeAddf(useBiff, NRRD,
681
                    "%s: space %s can't be set with spaceDim %d",
682
                    me, airEnumStr(nrrdSpace, nrrd->space),
683
                    nrrd->spaceDim);
684
      return 1;
685
    }
686
    /* -------- */
687
    exists = AIR_FALSE;
688
21924
    for (dd=0; dd<NRRD_SPACE_DIM_MAX; dd++) {
689
9744
      exists |= !!airStrlen(nrrd->spaceUnits[dd]);
690
    }
691
1218
    if (exists) {
692
      biffMaybeAddf(useBiff, NRRD,
693
                    "%s: spaceDim is 0, but space units is set", me);
694
      return 1;
695
    }
696
    /* -------- */
697
    exists = AIR_FALSE;
698
21924
    for (dd=0; dd<NRRD_SPACE_DIM_MAX; dd++) {
699
9744
      exists |= AIR_EXISTS(nrrd->spaceOrigin[dd]);
700
    }
701
1218
    if (exists) {
702
      biffMaybeAddf(useBiff, NRRD,
703
                    "%s: spaceDim is 0, but space origin is set", me);
704
      return 1;
705
    }
706
    /* -------- */
707
    exists = AIR_FALSE;
708
21924
    for (dd=0; dd<NRRD_SPACE_DIM_MAX; dd++) {
709
331296
      for (ii=0; ii<NRRD_DIM_MAX; ii++) {
710
155904
        exists |= AIR_EXISTS(nrrd->axis[ii].spaceDirection[dd]);
711
      }
712
    }
713
1218
    if (exists) {
714
      biffMaybeAddf(useBiff, NRRD,
715
                    "%s: spaceDim is 0, but space directions are set", me);
716
      return 1;
717
    }
718
  }
719
33130
  return 0;
720
33130
}
721
722
/* --------------------- per-field checks ----------------
723
**
724
** Strictly speacking, these checks only apply to the nrrd itself, not
725
** to a potentially incomplete nrrd in the process of being read, so
726
** the NrrdIoState stuff is not an issue.  This limits the utility of
727
** these to the field parsers for handling the more complex state
728
** involved in parsing some of the NRRD fields (like units).
729
**
730
** return 0 if it is valid, and 1 if there is an error
731
*/
732
733
static int
734
_nrrdFieldCheck_noop(const Nrrd *nrrd, int useBiff) {
735
736
  AIR_UNUSED(nrrd);
737
  AIR_UNUSED(useBiff);
738
72776
  return 0;
739
}
740
741
static int
742
_nrrdFieldCheck_type(const Nrrd *nrrd, int useBiff) {
743
  static const char me[]="_nrrdFieldCheck_type";
744
745
6662
  if (airEnumValCheck(nrrdType, nrrd->type)) {
746
    biffMaybeAddf(useBiff, NRRD,
747
                  "%s: type (%d) is not valid", me, nrrd->type);
748
    return 1;
749
  }
750
3331
  return 0;
751
3331
}
752
753
static int
754
_nrrdFieldCheck_block_size(const Nrrd *nrrd, int useBiff) {
755
  static const char me[]="_nrrdFieldCheck_block_size";
756
6616
  char stmp[AIR_STRLEN_SMALL];
757
758

3308
  if (nrrdTypeBlock == nrrd->type && (!(0 < nrrd->blockSize)) ) {
759
    biffMaybeAddf(useBiff, NRRD,
760
                  "%s: type is %s but nrrd->blockSize (%s) invalid", me,
761
                  airEnumStr(nrrdType, nrrdTypeBlock),
762
                  airSprintSize_t(stmp, nrrd->blockSize)); return 1;
763
  }
764

6616
  if (nrrdTypeBlock != nrrd->type && (0 < nrrd->blockSize)) {
765
    biffMaybeAddf(useBiff, NRRD,
766
                  "%s: type is %s (not block) but blockSize is %s", me,
767
                  airEnumStr(nrrdType, nrrd->type),
768
                  airSprintSize_t(stmp, nrrd->blockSize));
769
    return 1;
770
  }
771
3308
  return 0;
772
3308
}
773
774
static int
775
_nrrdFieldCheck_dimension(const Nrrd *nrrd, int useBiff) {
776
  static const char me[]="_nrrdFieldCheck_dimension";
777
778

9993
  if (!AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX)) {
779
    biffMaybeAddf(useBiff, NRRD,
780
                  "%s: dimension %u is outside valid range [1,%d]",
781
                  me, nrrd->dim, NRRD_DIM_MAX);
782
    return 1;
783
  }
784
3331
  return 0;
785
3331
}
786
787
static int
788
_nrrdFieldCheck_space(const Nrrd *nrrd, int useBiff) {
789
  static const char me[]="_nrrdFieldCheck_space";
790
791
6632
  if (_nrrdFieldCheckSpaceInfo(nrrd, useBiff)) {
792
    biffMaybeAddf(useBiff, NRRD, "%s: trouble", me);
793
    return 1;
794
  }
795
3316
  return 0;
796
3316
}
797
798
static int
799
_nrrdFieldCheck_space_dimension(const Nrrd *nrrd, int useBiff) {
800
  static const char me[]="_nrrdFieldCheck_space_dimension";
801
802
6622
  if (_nrrdFieldCheckSpaceInfo(nrrd, useBiff)) {
803
    biffMaybeAddf(useBiff, NRRD, "%s: trouble", me);
804
    return 1;
805
  }
806
3311
  return 0;
807
3311
}
808
809
static int
810
_nrrdFieldCheck_sizes(const Nrrd *nrrd, int useBiff) {
811
  static const char me[]="_nrrdFieldCheck_sizes";
812
6662
  size_t size[NRRD_DIM_MAX];
813
814
3331
  nrrdAxisInfoGet_nva(nrrd, nrrdAxisInfoSize, size);
815
3331
  if (_nrrdSizeCheck(size, nrrd->dim, useBiff)) {
816
    biffMaybeAddf(useBiff, NRRD, "%s: trouble with array sizes", me);
817
    return 1;
818
  }
819
3331
  return 0;
820
3331
}
821
822
static int
823
_nrrdFieldCheck_spacings(const Nrrd *nrrd, int useBiff) {
824
  static const char me[]="_nrrdFieldCheck_spacings";
825
6616
  double val[NRRD_DIM_MAX];
826
  unsigned int ai;
827
828
3308
  nrrdAxisInfoGet_nva(nrrd, nrrdAxisInfoSpacing, val);
829
26722
  for (ai=0; ai<nrrd->dim; ai++) {
830

20106
    if (!( !airIsInf_d(val[ai]) && (airIsNaN(val[ai]) || (0 != val[ai])) )) {
831
      biffMaybeAddf(useBiff, NRRD,
832
                    "%s: axis %d spacing (%g) invalid", me, ai, val[ai]);
833
      return 1;
834
    }
835
  }
836
3308
  if (_nrrdFieldCheckSpaceInfo(nrrd, useBiff)) {
837
    biffMaybeAddf(useBiff, NRRD, "%s: trouble", me);
838
    return 1;
839
  }
840
3308
  return 0;
841
3308
}
842
843
static int
844
_nrrdFieldCheck_thicknesses(const Nrrd *nrrd, int useBiff) {
845
  static const char me[]="_nrrdFieldCheck_thicknesses";
846
6616
  double val[NRRD_DIM_MAX];
847
  unsigned int ai;
848
849
3308
  nrrdAxisInfoGet_nva(nrrd, nrrdAxisInfoThickness, val);
850
26722
  for (ai=0; ai<nrrd->dim; ai++) {
851
    /* note that unlike spacing, we allow zero thickness,
852
       but it makes no sense to be negative */
853

20106
    if (!( !airIsInf_d(val[ai]) && (airIsNaN(val[ai]) || (0 <= val[ai])) )) {
854
      biffMaybeAddf(useBiff, NRRD,
855
                    "%s: axis %d thickness (%g) invalid", me, ai, val[ai]);
856
      return 1;
857
    }
858
  }
859
3308
  return 0;
860
3308
}
861
862
static int
863
_nrrdFieldCheck_axis_mins(const Nrrd *nrrd, int useBiff) {
864
  static const char me[]="_nrrdFieldCheck_axis_mins";
865
6624
  double val[NRRD_DIM_MAX];
866
  unsigned int ai;
867
  int ret;
868
869
3312
  nrrdAxisInfoGet_nva(nrrd, nrrdAxisInfoMin, val);
870
26742
  for (ai=0; ai<nrrd->dim; ai++) {
871
10059
    if ((ret=airIsInf_d(val[ai]))) {
872
      biffMaybeAddf(useBiff, NRRD, "%s: axis %d min %sinf invalid",
873
                    me, ai, 1==ret ? "+" : "-");
874
      return 1;
875
    }
876
  }
877
3312
  if (_nrrdFieldCheckSpaceInfo(nrrd, useBiff)) {
878
    biffMaybeAddf(useBiff, NRRD, "%s: trouble", me);
879
    return 1;
880
  }
881
  /* HEY: contemplate checking min != max, but what about stub axes ... */
882
3312
  return 0;
883
3312
}
884
885
static int
886
_nrrdFieldCheck_axis_maxs(const Nrrd *nrrd, int useBiff) {
887
  static const char me[]="_nrrdFieldCheck_axis_maxs";
888
6624
  double val[NRRD_DIM_MAX];
889
  unsigned int ai;
890
  int ret;
891
892
3312
  nrrdAxisInfoGet_nva(nrrd, nrrdAxisInfoMax, val);
893
26742
  for (ai=0; ai<nrrd->dim; ai++) {
894
10059
    if ((ret=airIsInf_d(val[ai]))) {
895
      biffMaybeAddf(useBiff, NRRD, "%s: axis %d max %sinf invalid",
896
                    me, ai, 1==ret ? "+" : "-");
897
      return 1;
898
    }
899
  }
900
3312
  if (_nrrdFieldCheckSpaceInfo(nrrd, useBiff)) {
901
    biffMaybeAddf(useBiff, NRRD, "%s: trouble", me);
902
    return 1;
903
  }
904
  /* HEY: contemplate checking min != max, but what about stub axes ... */
905
3312
  return 0;
906
3312
}
907
908
static int
909
_nrrdFieldCheck_space_directions(const Nrrd *nrrd, int useBiff) {
910
  static const char me[]="_nrrdFieldCheck_space_directions";
911
912
6638
  if (_nrrdFieldCheckSpaceInfo(nrrd, useBiff)) {
913
    biffMaybeAddf(useBiff, NRRD, "%s: space info problem", me);
914
    return 1;
915
  }
916
3319
  return 0;
917
3319
}
918
919
static int
920
_nrrdFieldCheck_centers(const Nrrd *nrrd, int useBiff) {
921
  static const char me[]="_nrrdFieldCheck_centers";
922
  unsigned int ai;
923
6646
  int val[NRRD_DIM_MAX];
924
925
3323
  nrrdAxisInfoGet_nva(nrrd, nrrdAxisInfoCenter, val);
926
26846
  for (ai=0; ai<nrrd->dim; ai++) {
927
16973
    if (!( nrrdCenterUnknown == val[ai]
928
16973
           || !airEnumValCheck(nrrdCenter, val[ai]) )) {
929
      biffMaybeAddf(useBiff, NRRD, "%s: axis %d center %d invalid",
930
                    me, ai, val[ai]);
931
      return 1;
932
    }
933
  }
934
3323
  return 0;
935
3323
}
936
937
static int
938
_nrrdFieldCheck_kinds(const Nrrd *nrrd, int useBiff) {
939
  static const char me[]="_nrrdFieldCheck_kinds";
940
6616
  int val[NRRD_DIM_MAX];
941
  unsigned int wantLen, ai;
942
943
3308
  nrrdAxisInfoGet_nva(nrrd, nrrdAxisInfoKind, val);
944
26722
  for (ai=0; ai<nrrd->dim; ai++) {
945
16239
    if (!( nrrdKindUnknown == val[ai]
946
16239
           || !airEnumValCheck(nrrdKind, val[ai]) )) {
947
      biffMaybeAddf(useBiff, NRRD,
948
                    "%s: axis %d kind %d invalid", me, ai, val[ai]);
949
      return 1;
950
    }
951
10053
    wantLen = nrrdKindSize(val[ai]);
952

10149
    if (wantLen && wantLen != nrrd->axis[ai].size) {
953
      char stmp[AIR_STRLEN_SMALL];
954
      biffMaybeAddf(useBiff, NRRD,
955
                    "%s: axis %d kind %s requires size %u, but have %s", me,
956
                    ai, airEnumStr(nrrdKind, val[ai]), wantLen,
957
                    airSprintSize_t(stmp, nrrd->axis[ai].size));
958
      return 1;
959
    }
960
  }
961
3308
  return 0;
962
3308
}
963
964
static int
965
_nrrdFieldCheck_labels(const Nrrd *nrrd, int useBiff) {
966
  /* char me[]="_nrrdFieldCheck_labels"; */
967
968
  AIR_UNUSED(nrrd);
969
  AIR_UNUSED(useBiff);
970
971
  /* don't think there's anything to do here: the label strings are
972
     either NULL (which is okay) or non-NULL, but we have no restrictions
973
     on the validity of the strings */
974
975
6626
  return 0;
976
}
977
978
static int
979
_nrrdFieldCheck_units(const Nrrd *nrrd, int useBiff) {
980
  static const char me[]="_nrrdFieldCheck_units";
981
982
  /* as with labels- the strings themselves don't need checking themselves */
983
  /* but per-axis units cannot be set for axes with space directions ... */
984
6616
  if (_nrrdFieldCheckSpaceInfo(nrrd, useBiff)) {
985
    biffMaybeAddf(useBiff, NRRD, "%s: space info problem", me);
986
    return 1;
987
  }
988
3308
  return 0;
989
3308
}
990
991
static int
992
_nrrdFieldCheck_old_min(const Nrrd *nrrd, int useBiff) {
993
  static const char me[]="_nrrdFieldCheck_old_min";
994
  int ret;
995
996
6616
  if ((ret=airIsInf_d(nrrd->oldMin))) {
997
    biffMaybeAddf(useBiff, NRRD,
998
                  "%s: old min %sinf invalid", me, 1==ret ? "+" : "-");
999
    return 1;
1000
  }
1001
  /* oldMin == oldMax is perfectly valid */
1002
3308
  return 0;
1003
3308
}
1004
1005
static int
1006
_nrrdFieldCheck_old_max(const Nrrd *nrrd, int useBiff) {
1007
  static const char me[]="_nrrdFieldCheck_old_max";
1008
  int ret;
1009
1010
6616
  if ((ret=airIsInf_d(nrrd->oldMax))) {
1011
    biffMaybeAddf(useBiff, NRRD,
1012
                  "%s: old max %sinf invalid", me, 1==ret ? "+" : "-");
1013
    return 1;
1014
  }
1015
  /* oldMin == oldMax is perfectly valid */
1016
3308
  return 0;
1017
3308
}
1018
1019
static int
1020
_nrrdFieldCheck_keyvalue(const Nrrd *nrrd, int useBiff) {
1021
  /* char me[]="_nrrdFieldCheck_keyvalue"; */
1022
1023
  AIR_UNUSED(nrrd);
1024
  AIR_UNUSED(useBiff);
1025
1026
  /* nrrdKeyValueAdd() ensures that keys aren't repeated,
1027
     not sure what other kind of checking can be done */
1028
1029
6616
  return 0;
1030
}
1031
1032
static int
1033
_nrrdFieldCheck_space_units(const Nrrd *nrrd, int useBiff) {
1034
  static const char me[]="_nrrdFieldCheck_space_units";
1035
1036
  /* not sure if there's anything to specifically check for the
1037
     space units themselves ... */
1038
6618
  if (_nrrdFieldCheckSpaceInfo(nrrd, useBiff)) {
1039
    biffMaybeAddf(useBiff, NRRD, "%s: space info problem", me);
1040
    return 1;
1041
  }
1042
3309
  return 0;
1043
3309
}
1044
1045
static int
1046
_nrrdFieldCheck_space_origin(const Nrrd *nrrd, int useBiff) {
1047
  static const char me[]="_nrrdFieldCheck_space_origin";
1048
1049
  /* pre-Fri Feb 11 04:25:36 EST 2005, I thought that
1050
     the spaceOrigin must be known to describe the
1051
     space/orientation stuff, but that's too restrictive,
1052
     which is why below says AIR_FALSE instead of AIR_TRUE */
1053
6638
  if (_nrrdFieldCheckSpaceInfo(nrrd, useBiff)) {
1054
    biffMaybeAddf(useBiff, NRRD, "%s: space info problem", me);
1055
    return 1;
1056
  }
1057
3319
  return 0;
1058
3319
}
1059
1060
static int
1061
_nrrdFieldCheck_measurement_frame(const Nrrd *nrrd, int useBiff) {
1062
  static const char me[]="_nrrdFieldCheck_measurement_frame";
1063
1064
6632
  if (_nrrdFieldCheckSpaceInfo(nrrd, useBiff)) {
1065
    biffMaybeAddf(useBiff, NRRD, "%s: space info problem", me);
1066
    return 1;
1067
  }
1068
3316
  return 0;
1069
3316
}
1070
1071
int
1072
(*_nrrdFieldCheck[NRRD_FIELD_MAX+1])(const Nrrd *, int useBiff) = {
1073
  _nrrdFieldCheck_noop,           /* nonfield */
1074
  _nrrdFieldCheck_noop,           /* comment */
1075
  _nrrdFieldCheck_noop,           /* content */
1076
  _nrrdFieldCheck_noop,           /* number */
1077
  _nrrdFieldCheck_type,
1078
  _nrrdFieldCheck_block_size,
1079
  _nrrdFieldCheck_dimension,
1080
  _nrrdFieldCheck_space,
1081
  _nrrdFieldCheck_space_dimension,
1082
  _nrrdFieldCheck_sizes,
1083
  _nrrdFieldCheck_spacings,
1084
  _nrrdFieldCheck_thicknesses,
1085
  _nrrdFieldCheck_axis_mins,
1086
  _nrrdFieldCheck_axis_maxs,
1087
  _nrrdFieldCheck_space_directions,
1088
  _nrrdFieldCheck_centers,
1089
  _nrrdFieldCheck_kinds,
1090
  _nrrdFieldCheck_labels,
1091
  _nrrdFieldCheck_units,
1092
  _nrrdFieldCheck_noop,           /* min */
1093
  _nrrdFieldCheck_noop,           /* max */
1094
  _nrrdFieldCheck_old_min,
1095
  _nrrdFieldCheck_old_max,
1096
  _nrrdFieldCheck_noop,           /* endian */
1097
  _nrrdFieldCheck_noop,           /* encoding */
1098
  _nrrdFieldCheck_noop,           /* line_skip */
1099
  _nrrdFieldCheck_noop,           /* byte_skip */
1100
  _nrrdFieldCheck_keyvalue,
1101
  _nrrdFieldCheck_noop,           /* sample units */
1102
  _nrrdFieldCheck_space_units,
1103
  _nrrdFieldCheck_space_origin,
1104
  _nrrdFieldCheck_measurement_frame,
1105
  _nrrdFieldCheck_noop,           /* data_file */
1106
};
1107
1108
int
1109
_nrrdCheck(const Nrrd *nrrd, int checkData, int useBiff) {
1110
  static const char me[]="_nrrdCheck";
1111
  int fi;
1112
1113
6616
  if (!nrrd) {
1114
    biffMaybeAddf(useBiff, NRRD, "%s: got NULL pointer", me);
1115
    return 1;
1116
  }
1117
3308
  if (checkData) {
1118
1201
    if (!(nrrd->data)) {
1119
      biffMaybeAddf(useBiff, NRRD, "%s: nrrd %p has NULL data pointer",
1120
                    me, AIR_CVOIDP(nrrd));
1121
      return 1;
1122
    }
1123
  }
1124
218328
  for (fi=nrrdField_unknown+1; fi<nrrdField_last; fi++) {
1125
    /* yes, this will call _nrrdFieldCheckSpaceInfo() many many times */
1126
105856
    if (_nrrdFieldCheck[fi](nrrd, AIR_TRUE)) {
1127
      biffMaybeAddf(useBiff, NRRD, "%s: trouble with %s field", me,
1128
                    airEnumStr(nrrdField, fi));
1129
      return 1;
1130
    }
1131
  }
1132
3308
  return 0;
1133
3308
}
1134
1135
/*
1136
******** nrrdCheck()
1137
**
1138
** does some consistency checks for things that can go wrong in a nrrd
1139
** returns non-zero if there is a problem, zero if no problem.
1140
**
1141
** You might think that this should be merged with _nrrdHeaderCheck(),
1142
** but that is really only for testing sufficiency of information
1143
** required to do the data reading.
1144
*/
1145
int /*Teem: biff if (ret) */
1146
nrrdCheck(const Nrrd *nrrd) {
1147
  static const char me[]="nrrdCheck";
1148
1149
2402
  if (_nrrdCheck(nrrd, AIR_TRUE, AIR_TRUE)) {
1150
    biffAddf(NRRD, "%s: trouble", me);
1151
    return 1;
1152
  }
1153
1201
  return 0;
1154
1201
}
1155
1156
/*
1157
******** nrrdSameSize()
1158
**
1159
** returns 1 iff given two nrrds have same dimension and axes sizes.
1160
** This does NOT look at the type of the elements.
1161
**
1162
** The intended user of this is someone who really wants the nrrds to be
1163
** the same size, so that if they aren't, some descriptive (error) message
1164
** can be generated according to useBiff
1165
*/
1166
int /*Teem: biff?2 if (!ret) */
1167
nrrdSameSize(const Nrrd *n1, const Nrrd *n2, int useBiff) {
1168
  static const char me[]="nrrdSameSize";
1169
  unsigned int ai;
1170
2
  char stmp[2][AIR_STRLEN_SMALL];
1171
1172
1
  if (!(n1 && n2)) {
1173
    biffMaybeAddf(useBiff, NRRD, "%s: got NULL pointer", me);
1174
    return 0;
1175
  }
1176
1
  if (n1->dim != n2->dim) {
1177
    biffMaybeAddf(useBiff, NRRD, "%s: n1->dim (%u) != n2->dim (%u)",
1178
                  me, n1->dim, n2->dim);
1179
    return 0;
1180
  }
1181
8
  for (ai=0; ai<n1->dim; ai++) {
1182
3
    if (n1->axis[ai].size != n2->axis[ai].size) {
1183
      biffMaybeAddf(useBiff, NRRD, "%s: n1->axis[%d].size (%s) "
1184
                    "!= n2->axis[%d].size (%s)", me, ai,
1185
                    airSprintSize_t(stmp[0], n1->axis[ai].size), ai,
1186
                    airSprintSize_t(stmp[1], n2->axis[ai].size));
1187
      return 0;
1188
    }
1189
  }
1190
1
  return 1;
1191
1
}
1192
1193
/*
1194
******** nrrdElementSize()
1195
**
1196
** So just how many bytes long is one element in this nrrd?  This is
1197
** needed (over the simple nrrdTypeSize[] array) because some nrrds
1198
** may be of "block" type, and because it does bounds checking on
1199
** nrrd->type.  Returns 0 if given a bogus nrrd->type, or if the block
1200
** size isn't greater than zero (in which case it sets nrrd->blockSize
1201
** to 0, just out of spite).  This function never returns a negative
1202
** value; using (!nrrdElementSize(nrrd)) is a sufficient check for
1203
** invalidity.
1204
**
1205
** Besides learning how many bytes long one element is, this function
1206
** is useful as a way of detecting an invalid blocksize on a block nrrd.
1207
*/
1208
size_t
1209
nrrdElementSize (const Nrrd *nrrd) {
1210
1211

5199
  if (!( nrrd && !airEnumValCheck(nrrdType, nrrd->type) )) {
1212
    return 0;
1213
  }
1214
1733
  if (nrrdTypeBlock != nrrd->type) {
1215
1733
    return nrrdTypeSize[nrrd->type];
1216
  }
1217
  /* else its block type */
1218
  if (nrrd->blockSize > 0) {
1219
    return nrrd->blockSize;
1220
  }
1221
  /* else we got an invalid block size */
1222
  /* nrrd->blockSize = 0; */
1223
  return 0;
1224
1733
}
1225
1226
/*
1227
******** nrrdElementNumber()
1228
**
1229
** takes the place of old "nrrd->num": the number of elements in the
1230
** nrrd, which is just the product of the axis sizes.  A return of 0
1231
** means there's a problem.  Negative numbers are never returned.
1232
**
1233
** does NOT use biff
1234
*/
1235
size_t
1236
nrrdElementNumber (const Nrrd *nrrd) {
1237
2106
  size_t num, size[NRRD_DIM_MAX];
1238
  unsigned int ai;
1239
1240
1053
  if (!nrrd) {
1241
    return 0;
1242
  }
1243
  /* else */
1244
1053
  nrrdAxisInfoGet_nva(nrrd, nrrdAxisInfoSize, size);
1245
1053
  if (_nrrdSizeCheck(size, nrrd->dim, AIR_FALSE)) {
1246
    /* the nrrd's size information is invalid, can't proceed */
1247
    return 0;
1248
  }
1249
  num = 1;
1250
7640
  for (ai=0; ai<nrrd->dim; ai++) {
1251
    /* negative numbers and overflow were caught by _nrrdSizeCheck() */
1252
2767
    num *= size[ai];
1253
  }
1254
1053
  return num;
1255
1053
}
1256
1257
/*
1258
** obviously, this requires that the per-axis size fields have been set
1259
*/
1260
void
1261
_nrrdSplitSizes(size_t *pieceSize, size_t *pieceNum, Nrrd *nrrd,
1262
                unsigned int split) {
1263
  unsigned int ai;
1264
  size_t size[NRRD_DIM_MAX];
1265
1266
  nrrdAxisInfoGet_nva(nrrd, nrrdAxisInfoSize, size);
1267
  *pieceSize = 1;
1268
  for (ai=0; ai<split; ai++) {
1269
    *pieceSize *= size[ai];
1270
  }
1271
  *pieceNum = 1;
1272
  for (ai=split; ai<nrrd->dim; ai++) {
1273
    *pieceNum *= size[ai];
1274
  }
1275
  return;
1276
}
1277
1278
/*
1279
******** nrrdHasNonExistSet()
1280
**
1281
** This function will always (assuming type is valid) set the value of
1282
** nrrd->hasNonExist to either nrrdNonExistTrue or nrrdNonExistFalse,
1283
** and it will return that value.  For lack of a more sophisticated
1284
** policy, blocks are currently always considered to be existent
1285
** values (because nrrdTypeIsIntegral[nrrdTypeBlock] is currently true).
1286
** This function will ALWAYS determine the correct answer and set the
1287
** value of nrrd->hasNonExist: it ignores the value of
1288
** nrrd->hasNonExist on the input nrrd.  Exception: if nrrd is null or
1289
** type is bogus, no action is taken and nrrdNonExistUnknown is
1290
** returned.
1291
**
1292
** Because this will return either nrrdNonExistTrue or nrrdNonExistFalse,
1293
** and because the C boolean value of these are true and false (respectively),
1294
** it is possible (and encouraged) to use the return of this function
1295
** as the expression of a conditional:
1296
**
1297
**   if (nrrdHasNonExistSet(nrrd)) {
1298
**     ... handle existance of non-existent values ...
1299
**   }
1300
*/
1301
/*
1302
int
1303
nrrdHasNonExistSet(Nrrd *nrrd) {
1304
  size_t I, N;
1305
  float val;
1306
1307
  if (!( nrrd && !airEnumValCheck(nrrdType, nrrd->type) ))
1308
    return nrrdNonExistUnknown;
1309
1310
  if (nrrdTypeIsIntegral[nrrd->type]) {
1311
    nrrd->hasNonExist = nrrdNonExistFalse;
1312
  } else {
1313
    nrrd->hasNonExist = nrrdNonExistFalse;
1314
    N = nrrdElementNumber(nrrd);
1315
    for (I=0; I<N; I++) {
1316
      val = nrrdFLookup[nrrd->type](nrrd->data, I);
1317
      if (!AIR_EXISTS(val)) {
1318
        nrrd->hasNonExist = nrrdNonExistTrue;
1319
        break;
1320
      }
1321
    }
1322
  }
1323
  return nrrd->hasNonExist;
1324
}
1325
*/
1326
1327
static int
1328
_nrrdCheckEnums(void) {
1329
  static const char me[]="_nrrdCheckEnums";
1330
  char which[AIR_STRLEN_SMALL];
1331
1332
  if (nrrdFormatTypeLast-1 != NRRD_FORMAT_TYPE_MAX) {
1333
    strcpy(which, "nrrdFormat"); goto err;
1334
  }
1335
  if (nrrdTypeLast-1 != NRRD_TYPE_MAX) {
1336
    strcpy(which, "nrrdType"); goto err;
1337
  }
1338
  if (nrrdEncodingTypeLast-1 != NRRD_ENCODING_TYPE_MAX) {
1339
    strcpy(which, "nrrdEncodingType"); goto err;
1340
  }
1341
  if (nrrdCenterLast-1 != NRRD_CENTER_MAX) {
1342
    strcpy(which, "nrrdCenter"); goto err;
1343
  }
1344
  if (nrrdAxisInfoLast-1 != NRRD_AXIS_INFO_MAX) {
1345
    strcpy(which, "nrrdAxisInfo"); goto err;
1346
  }
1347
  /* can't really check on endian enum */
1348
  if (nrrdField_last-1 != NRRD_FIELD_MAX) {
1349
    strcpy(which, "nrrdField"); goto err;
1350
  }
1351
  if (nrrdHasNonExistLast-1 != NRRD_HAS_NON_EXIST_MAX) {
1352
    strcpy(which, "nrrdHasNonExist"); goto err;
1353
  }
1354
  /* ---- BEGIN non-NrrdIO */
1355
  if (nrrdBoundaryLast-1 != NRRD_BOUNDARY_MAX) {
1356
    strcpy(which, "nrrdBoundary"); goto err;
1357
  }
1358
  if (nrrdMeasureLast-1 != NRRD_MEASURE_MAX) {
1359
    strcpy(which, "nrrdMeasure"); goto err;
1360
  }
1361
  if (nrrdUnaryOpLast-1 != NRRD_UNARY_OP_MAX) {
1362
    strcpy(which, "nrrdUnaryOp"); goto err;
1363
  }
1364
  if (nrrdBinaryOpLast-1 != NRRD_BINARY_OP_MAX) {
1365
    strcpy(which, "nrrdBinaryOp"); goto err;
1366
  }
1367
  if (nrrdTernaryOpLast-1 != NRRD_TERNARY_OP_MAX) {
1368
    strcpy(which, "nrrdTernaryOp"); goto err;
1369
  }
1370
  /* ---- END non-NrrdIO */
1371
1372
  /* no errors so far */
1373
  return 0;
1374
1375
 err:
1376
  biffAddf(NRRD, "%s: Last vs. MAX incompatibility for %s enum", me, which);
1377
  return 1;
1378
40
}
1379
1380
/*
1381
****** nrrdSanity
1382
**
1383
** makes sure that all the basic assumptions of nrrd hold for
1384
** the architecture/etc which we're currently running on.
1385
**
1386
** returns 1 if all is okay, 0 if there is a problem
1387
*/
1388
int /*Teem: biff if (!ret) */
1389
nrrdSanity(void) {
1390
  static const char me[]="nrrdSanity";
1391
  int aret, type;
1392
  size_t maxsize;
1393
  airLLong tmpLLI;
1394
  airULLong tmpULLI;
1395
  static int _nrrdSanity = 0;
1396
1397
54
  if (_nrrdSanity) {
1398
    /* we've been through this once before and things looked okay ... */
1399
    /* Is this thread-safe?  I think so.  If we assume that any two
1400
       threads are going to compute the same value, isn't it the case
1401
       that, at worse, both of them will go through all the tests and
1402
       then set _nrrdSanity to the same thing? */
1403
7
    return 1;
1404
  }
1405
1406
20
  aret = airSanity();
1407
20
  if (aret != airInsane_not) {
1408
    biffAddf(NRRD, "%s: airSanity() failed: %s", me,
1409
             airInsaneErr(aret));
1410
    return 0;
1411
  }
1412
1413
  /* ---- BEGIN non-NrrdIO */
1414
  /* Odd: this sanity checker isn't part of airSanity, nor can it be
1415
     without adding to airInsaneErr's list of what can go wrong, but
1416
     someone should be calling it, since we have no other correctness
1417
     test of the Mersenne-Twister code within Teem (not counting the
1418
     CTests in teem/Testing) */
1419
20
  if (!airRandMTSanity()) {
1420
    biffAddf(NRRD, "%s: airRandMTSanity failed", me);
1421
    return 0;
1422
  }
1423
  /* ---- END non-NrrdIO */
1424
1425
20
  if (airEnumValCheck(nrrdEncodingType, nrrdDefaultWriteEncodingType)) {
1426
    biffAddf(NRRD,
1427
             "%s: nrrdDefaultWriteEncodingType (%d) not in valid "
1428
             "range [%d,%d]", me, nrrdDefaultWriteEncodingType,
1429
             nrrdEncodingTypeUnknown+1, nrrdEncodingTypeLast-1);
1430
    return 0;
1431
  }
1432
20
  if (airEnumValCheck(nrrdCenter, nrrdDefaultCenter)) {
1433
    biffAddf(NRRD,
1434
             "%s: nrrdDefaultCenter (%d) not in valid range [%d,%d]",
1435
             me, nrrdDefaultCenter,
1436
             nrrdCenterUnknown+1, nrrdCenterLast-1);
1437
    return 0;
1438
  }
1439
  /* ---- BEGIN non-NrrdIO */
1440
20
  if (!( nrrdTypeDefault == nrrdDefaultResampleType
1441
20
         || !airEnumValCheck(nrrdType, nrrdDefaultResampleType) )) {
1442
    biffAddf(NRRD,
1443
             "%s: nrrdDefaultResampleType (%d) not in valid range [%d,%d]",
1444
             me, nrrdDefaultResampleType,
1445
             nrrdTypeUnknown, nrrdTypeLast-1);
1446
    return 0;
1447
  }
1448
20
  if (airEnumValCheck(nrrdBoundary, nrrdDefaultResampleBoundary)) {
1449
    biffAddf(NRRD, "%s: nrrdDefaultResampleBoundary (%d) "
1450
             "not in valid range [%d,%d]",
1451
             me, nrrdDefaultResampleBoundary,
1452
             nrrdBoundaryUnknown+1, nrrdBoundaryLast-1);
1453
    return 0;
1454
  }
1455
20
  if (airEnumValCheck(nrrdType, nrrdStateMeasureType)) {
1456
    biffAddf(NRRD,
1457
             "%s: nrrdStateMeasureType (%d) not in valid range [%d,%d]",
1458
             me, nrrdStateMeasureType,
1459
             nrrdTypeUnknown+1, nrrdTypeLast-1);
1460
    return 0;
1461
  }
1462
20
  if (airEnumValCheck(nrrdType, nrrdStateMeasureHistoType)) {
1463
    biffAddf(NRRD,
1464
             "%s: nrrdStateMeasureHistoType (%d) not in "
1465
             "valid range [%d,%d]", me, nrrdStateMeasureType,
1466
             nrrdTypeUnknown+1, nrrdTypeLast-1);
1467
    return 0;
1468
  }
1469
  /* ---- END non-NrrdIO */
1470
1471
20
  if (!( nrrdTypeSize[nrrdTypeChar] == sizeof(char)
1472




180
         && nrrdTypeSize[nrrdTypeUChar] == sizeof(unsigned char)
1473
20
         && nrrdTypeSize[nrrdTypeShort] == sizeof(short)
1474
20
         && nrrdTypeSize[nrrdTypeUShort] == sizeof(unsigned short)
1475
20
         && nrrdTypeSize[nrrdTypeInt] == sizeof(int)
1476
20
         && nrrdTypeSize[nrrdTypeUInt] == sizeof(unsigned int)
1477
20
         && nrrdTypeSize[nrrdTypeLLong] == sizeof(airLLong)
1478
20
         && nrrdTypeSize[nrrdTypeULLong] == sizeof(airULLong)
1479
20
         && nrrdTypeSize[nrrdTypeFloat] == sizeof(float)
1480
20
         && nrrdTypeSize[nrrdTypeDouble] == sizeof(double) )) {
1481
    biffAddf(NRRD, "%s: sizeof() for nrrd types has problem: "
1482
             "expected (%u,%u,%u,%u,%u,%u,%u,%u,%u,%u) "
1483
             "but got (%u,%u,%u,%u,%u,%u,%u,%u,%u,%u)", me,
1484
             AIR_CAST(unsigned int, nrrdTypeSize[nrrdTypeChar]),
1485
             AIR_CAST(unsigned int, nrrdTypeSize[nrrdTypeUChar]),
1486
             AIR_CAST(unsigned int, nrrdTypeSize[nrrdTypeShort]),
1487
             AIR_CAST(unsigned int, nrrdTypeSize[nrrdTypeUShort]),
1488
             AIR_CAST(unsigned int, nrrdTypeSize[nrrdTypeInt]),
1489
             AIR_CAST(unsigned int, nrrdTypeSize[nrrdTypeUInt]),
1490
             AIR_CAST(unsigned int, nrrdTypeSize[nrrdTypeLLong]),
1491
             AIR_CAST(unsigned int, nrrdTypeSize[nrrdTypeULLong]),
1492
             AIR_CAST(unsigned int, nrrdTypeSize[nrrdTypeFloat]),
1493
             AIR_CAST(unsigned int, nrrdTypeSize[nrrdTypeDouble]),
1494
             AIR_CAST(unsigned int, sizeof(char)),
1495
             AIR_CAST(unsigned int, sizeof(unsigned char)),
1496
             AIR_CAST(unsigned int, sizeof(short)),
1497
             AIR_CAST(unsigned int, sizeof(unsigned short)),
1498
             AIR_CAST(unsigned int, sizeof(int)),
1499
             AIR_CAST(unsigned int, sizeof(unsigned int)),
1500
             AIR_CAST(unsigned int, sizeof(airLLong)),
1501
             AIR_CAST(unsigned int, sizeof(airULLong)),
1502
             AIR_CAST(unsigned int, sizeof(float)),
1503
             AIR_CAST(unsigned int, sizeof(double)));
1504
    return 0;
1505
  }
1506
1507
  /* check on NRRD_TYPE_SIZE_MAX */
1508
  maxsize = 0;
1509
440
  for (type=nrrdTypeUnknown+1; type<=nrrdTypeLast-2; type++) {
1510
600
    maxsize = AIR_MAX(maxsize, nrrdTypeSize[type]);
1511
  }
1512
20
  if (maxsize != NRRD_TYPE_SIZE_MAX) {
1513
    biffAddf(NRRD,
1514
             "%s: actual max type size is %u != %u == NRRD_TYPE_SIZE_MAX",
1515
             me, AIR_CAST(unsigned int, maxsize), NRRD_TYPE_SIZE_MAX);
1516
    return 0;
1517
  }
1518
1519
  /* check on NRRD_TYPE_BIGGEST */
1520
20
  if (maxsize != sizeof(NRRD_TYPE_BIGGEST)) {
1521
    biffAddf(NRRD, "%s: actual max type size is %u != "
1522
             "%u == sizeof(NRRD_TYPE_BIGGEST)",
1523
             me, AIR_CAST(unsigned int, maxsize),
1524
             AIR_CAST(unsigned int, sizeof(NRRD_TYPE_BIGGEST)));
1525
    return 0;
1526
  }
1527
1528
  /* nrrd-defined min/max values for 64-bit integral types */
1529
  /* NOTE: because signed integral overflow is undefined in C, the tests for
1530
     signed long long no longer use overflow (and an assumption of two's
1531
     complement representation) to assess the correctness of NRRD_LLONG_MAX
1532
     and NRRD_LLONG_MIN.  We merely test that these values can be stored,
1533
     which we do via indirect (perhaps needlessly so) means.
1534
     (h/t Sean McBride for pointing this out) */
1535
20
  tmpLLI = _nrrdLLongMaxHelp(_nrrdLLongMaxHelp(_NRRD_LLONG_MAX_HELP));
1536
20
  if (!( tmpLLI > 0 && NRRD_LLONG_MAX == tmpLLI )) {
1537
    biffAddf(NRRD, "%s: long long int can't hold NRRD_LLONG_MAX ("
1538
             AIR_LLONG_FMT ")", me,
1539
             NRRD_LLONG_MAX);
1540
    return 0;
1541
  }
1542
20
  tmpLLI = _nrrdLLongMinHelp(_nrrdLLongMinHelp(_NRRD_LLONG_MIN_HELP));
1543
20
  if (!( tmpLLI < 0 && NRRD_LLONG_MIN == tmpLLI )) {
1544
    biffAddf(NRRD, "%s: long long int can't hold NRRD_LLONG_MIN ("
1545
             AIR_LLONG_FMT ")", me,
1546
             NRRD_LLONG_MIN);
1547
    return 0;
1548
  }
1549
20
  tmpULLI = _nrrdULLongMaxHelp(NRRD_ULLONG_MAX);
1550
20
  if (tmpULLI != 0) {
1551
    biffAddf(NRRD,
1552
             "%s: unsigned long long int max (" AIR_ULLONG_FMT
1553
             ") incorrect", me, NRRD_ULLONG_MAX);
1554
    return 0;
1555
  }
1556
1557
20
  if (_nrrdCheckEnums()) {
1558
    biffAddf(NRRD, "%s: problem with enum definition", me);
1559
    return 0;
1560
  }
1561
1562
  if (!( NRRD_DIM_MAX >= 3 )) {
1563
    biffAddf(NRRD,
1564
             "%s: NRRD_DIM_MAX == %u seems awfully small, doesn't it?",
1565
             me, NRRD_DIM_MAX);
1566
    return 0;
1567
  }
1568
1569
20
  if (!nrrdTypeIsIntegral[nrrdTypeBlock]) {
1570
    biffAddf(NRRD,
1571
             "%s: nrrdTypeInteger[nrrdTypeBlock] is not true, things "
1572
             "could get wacky", me);
1573
    return 0;
1574
  }
1575
1576
  /* HEY: any other assumptions built into Teem? */
1577
1578
20
  _nrrdSanity = 1;
1579
20
  return 1;
1580
27
}
1581
1582
/* ---- BEGIN non-NrrdIO */
1583
1584
void
1585
nrrdSanityOrDie(const char *me) {
1586
  char *err;
1587
1588
  if (!nrrdSanity()) {
1589
    fprintf(stderr, "******************************************\n");
1590
    fprintf(stderr, "******************************************\n");
1591
    fprintf(stderr, "\n");
1592
    fprintf(stderr, "  %s: Nrrd sanity check failed.\n", me);
1593
    fprintf(stderr, "\n");
1594
    fprintf(stderr, "  This probably means that there was an error\n");
1595
    fprintf(stderr, "  in the configuration, compilation, or basic\n");
1596
    fprintf(stderr, "  variable definitions used for building Teem.\n");
1597
    fprintf(stderr, "  Error message:\n");
1598
    fprintf(stderr, "%s\n", err = biffGetDone(NRRD));
1599
    fprintf(stderr, "\n");
1600
    fprintf(stderr, "******************************************\n");
1601
    fprintf(stderr, "******************************************\n");
1602
    free(err);
1603
    exit(1);
1604
  }
1605
}
1606
1607
void
1608
nrrdSetZero(Nrrd *nout) {
1609
1610
  if (!_nrrdCheck(nout, AIR_TRUE, AIR_FALSE)) {
1611
    memset(nout->data, 0, nrrdElementNumber(nout)*nrrdElementSize(nout));
1612
  }
1613
  return;
1614
}
1615
1616
void
1617
nrrdSetNaN(Nrrd *nout) {
1618
1619
  if (_nrrdCheck(nout, AIR_TRUE, AIR_FALSE)) {
1620
    /* bad nrrd, oh well */
1621
    return;
1622
  }
1623
  /* HEY if Half is ever added we'll have to check for it here */
1624
  size_t II, NN = nrrdElementNumber(nout);
1625
  if (nrrdTypeFloat == nout->type) {
1626
    float *ff = AIR_CAST(float *, nout->data);
1627
    for (II=0; II<NN; II++) {
1628
      ff[II] = AIR_NAN;
1629
    }
1630
  } else if (nrrdTypeDouble == nout->type) {
1631
    double *dd = AIR_CAST(double *, nout->data);
1632
    for (II=0; II<NN; II++) {
1633
      dd[II] = AIR_NAN;
1634
    }
1635
  }
1636
  return;
1637
}
1638
/* ---- END non-NrrdIO */