GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/nrrd/methodsNrrd.c Lines: 490 666 73.6 %
Date: 2017-05-26 Branches: 249 412 60.4 %

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
Wed Sep 14 05:55:40 EDT 2005: these are no longer used
29
void
30
nrrdPeripheralInit(Nrrd *nrrd) {
31
32
  nrrdBasicInfoInit(nrrd,
33
                    NRRD_BASIC_INFO_DATA_BIT
34
                    | NRRD_BASIC_INFO_TYPE_BIT
35
                    | NRRD_BASIC_INFO_BLOCKSIZE_BIT
36
                    | NRRD_BASIC_INFO_DIMENSION_BIT
37
                    | NRRD_BASIC_INFO_CONTENT_BIT
38
                    | NRRD_BASIC_INFO_COMMENTS_BIT
39
                    | NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT);
40
  return;
41
}
42
43
int
44
nrrdPeripheralCopy(Nrrd *nout, const Nrrd *nin) {
45
46
  nrrdBasicInfoCopy(nout, nin,
47
                    NRRD_BASIC_INFO_DATA_BIT
48
                    | NRRD_BASIC_INFO_TYPE_BIT
49
                    | NRRD_BASIC_INFO_BLOCKSIZE_BIT
50
                    | NRRD_BASIC_INFO_DIMENSION_BIT
51
                    | NRRD_BASIC_INFO_CONTENT_BIT
52
                    | NRRD_BASIC_INFO_COMMENTS_BIT
53
                    | NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT);
54
  return 0;
55
}
56
*/
57
58
/* ---- BEGIN non-NrrdIO */
59
const int
60
nrrdPresent = 42;
61
62
/* ------------------------------------------------------------ */
63
64
NrrdBoundarySpec *
65
nrrdBoundarySpecNew(void) {
66
  NrrdBoundarySpec *ret;
67
68
26
  ret = AIR_CALLOC(1, NrrdBoundarySpec);
69
13
  if (ret) {
70
13
    ret->boundary = nrrdBoundaryUnknown;
71
13
    ret->padValue = AIR_NAN;
72
13
  }
73
13
  return ret;
74
}
75
76
NrrdBoundarySpec *
77
nrrdBoundarySpecNix(NrrdBoundarySpec *bspec) {
78
79
58
  return airFree(bspec);
80
}
81
82
/* NOTE: this doesn't do a validity check! */
83
NrrdBoundarySpec *
84
nrrdBoundarySpecCopy(const NrrdBoundarySpec *bspec) {
85
  NrrdBoundarySpec *ret;
86
87
4
  if (bspec) {
88
2
    ret = nrrdBoundarySpecNew();
89
2
    ret->boundary = bspec->boundary;
90
2
    ret->padValue = bspec->padValue;
91
2
  } else {
92
    ret = NULL;
93
  }
94
2
  return ret;
95
}
96
97
int
98
nrrdBoundarySpecCheck(const NrrdBoundarySpec *bspec) {
99
  static const char me[]="nrrdBoundarySpecCheck";
100
101
28
  if (!bspec) {
102
    biffAddf(NRRD, "%s: got NULL pointer", me);
103
    return 1;
104
  }
105
14
  if (airEnumValCheck(nrrdBoundary, bspec->boundary)) {
106
2
    biffAddf(NRRD, "%s: %d is not a valid %s value", me,
107
1
             bspec->boundary, nrrdBoundary->name);
108
1
    return 1;
109
  }
110
13
  if (nrrdBoundaryPad == bspec->boundary) {
111
7
    if (!AIR_EXISTS(bspec->padValue)) {
112
2
      biffAddf(NRRD, "%s: need existing pad value (not %g) with %s %s",
113
1
               me, bspec->padValue, nrrdBoundary->name,
114
1
               airEnumStr(nrrdBoundary, nrrdBoundaryPad));
115
1
      return 1;
116
    }
117
  }
118
12
  return 0;
119
14
}
120
121
int
122
nrrdBoundarySpecParse(NrrdBoundarySpec *bspec, const char *_str) {
123
  static const char me[]="nrrdBoundarySpecParse";
124
  char *str, *parm;
125
  airArray *mop;
126
127
42
  if (!(bspec && _str)) {
128
    biffAddf(NRRD, "%s: got NULL pointer", me);
129
    return 1;
130
  }
131
21
  str = airStrdup(_str);
132
21
  if (!str) {
133
    biffAddf(NRRD, "%s: couldn't copy string", me);
134
    return 1;
135
  }
136
21
  mop = airMopNew();
137
21
  airMopAdd(mop, str, airFree, airMopAlways);
138
21
  parm = strchr(str, ':');
139
21
  if (parm) {
140
12
    *parm = '\0';
141
12
    parm++;
142
12
  }
143
21
  bspec->boundary = airEnumVal(nrrdBoundary, str);
144
21
  if (nrrdBoundaryUnknown == bspec->boundary) {
145
4
    biffAddf(NRRD, "%s: couldn't parse %s as a %s", me,
146
2
             str, nrrdBoundary->name);
147
2
    airMopError(mop); return 1;
148
  }
149
19
  if (parm) {
150
12
    if (nrrdBoundaryPad != bspec->boundary) {
151
2
      biffAddf(NRRD, "%s: can only have parms for %s (not %s)", me,
152
1
               airEnumStr(nrrdBoundary, nrrdBoundaryPad),
153
1
               airEnumStr(nrrdBoundary, bspec->boundary));
154
1
      airMopError(mop); return 1;
155
    }
156
11
    if (1 != sscanf(parm, "%lg", &(bspec->padValue))) {
157
2
      biffAddf(NRRD, "%s: couldn't parse \"%s\" as double", me, parm);
158
2
      airMopError(mop); return 1;
159
    }
160
9
    if (!AIR_EXISTS(bspec->padValue)) {
161
1
      biffAddf(NRRD, "%s: need existant pad value (not %g)", me,
162
               bspec->padValue);
163
1
      airMopError(mop); return 1;
164
    }
165
  } else {
166
7
    if (nrrdBoundaryPad == bspec->boundary) {
167
2
      biffAddf(NRRD, "%s: need padValue parm for %s", me,
168
1
               airEnumStr(nrrdBoundary, nrrdBoundaryPad));
169
1
      airMopError(mop); return 1;
170
    }
171
6
    bspec->padValue = AIR_NAN;
172
  }
173
14
  airMopOkay(mop);
174
14
  return 0;
175
21
}
176
177
int
178
nrrdBoundarySpecSprint(char str[AIR_STRLEN_LARGE],
179
                       const NrrdBoundarySpec *bspec) {
180
  static const char me[]="nrrdBoundarySpecSprint";
181
  char *out;
182
183
20
  if (!( str && bspec )) {
184
    biffAddf(NRRD, "%s: got NULL pointer", me);
185
    return 1;
186
  }
187
10
  if (nrrdBoundarySpecCheck(bspec)) {
188
    biffAddf(NRRD, "%s: problem", me);
189
    return 1;
190
  }
191
  out = str;
192
10
  sprintf(out, "%s", airEnumStr(nrrdBoundary, bspec->boundary));
193
10
  out += strlen(out);
194
10
  if (nrrdBoundaryPad == bspec->boundary) {
195
4
    sprintf(out, ":%.17g", bspec->padValue);
196
4
  }
197
10
  return 0;
198
10
}
199
200
int
201
nrrdBoundarySpecCompare(const NrrdBoundarySpec *aa,
202
                        const NrrdBoundarySpec *bb,
203
                        int *differ, char explain[AIR_STRLEN_LARGE]) {
204
  static const char me[]="nrrdBoundarySpecEqual";
205
206
10
  if (!differ) {
207
    biffAddf(NRRD, "%s: got NULL pointer", me);
208
    return 1;
209
  }
210
5
  if (!!aa != !!bb) {
211
    if (explain) {
212
      sprintf(explain, "NULL-ities differ: %s != %s",
213
              aa ? "non-NULL" : "NULL",
214
              bb ? "non-NULL" : "NULL");
215
    }
216
    *differ = 1; return 0;
217
  }
218
5
  if (!aa) {
219
    /* got two NULL boundary specs ==> equal */
220
4
    *differ = 0; return 0;
221
  }
222
1
  if (aa->boundary != bb->boundary) {
223
    if (explain) {
224
      sprintf(explain, "boundaries differ: %s != %s",
225
              airEnumStr(nrrdBoundary, aa->boundary),
226
              airEnumStr(nrrdBoundary, bb->boundary));
227
    }
228
    *differ = 1; return 0;
229
  }
230
1
  if (nrrdBoundaryPad == aa->boundary) {
231
1
    if (aa->padValue != bb->padValue) {
232
      if (explain) {
233
        sprintf(explain, "padValue differ: %.17g != %.17g",
234
                aa->padValue, bb->padValue);
235
      }
236
      *differ = 1; return 0;
237
    }
238
  }
239
1
  *differ = 0;
240
1
  return 0;
241
5
}
242
243
/* ---- END non-NrrdIO */
244
/* ------------------------------------------------------------ */
245
246
void
247
nrrdIoStateInit(NrrdIoState *nio) {
248
249
78
  if (nio) {
250
39
    nio->path = (char *)airFree(nio->path);
251
39
    nio->base = (char *)airFree(nio->base);
252
39
    nio->line = (char *)airFree(nio->line);
253
39
    nio->dataFNFormat = (char *)airFree(nio->dataFNFormat);
254
    /* the way IO to/from strings works, I don't think this should be freed */
255
39
    nio->headerStringRead = NULL;
256
39
    nio->headerStringWrite = NULL;
257
39
    airArrayLenSet(nio->dataFNArr, 0);
258
39
    airArrayLenSet(nio->dataFSkipArr, 0);
259
    /* closing this is always someone else's responsibility */
260
39
    nio->headerFile = NULL;
261
39
    nio->dataFile = NULL;
262
39
    nio->dataFileDim = 0;
263
39
    nio->dataFNMin = 0;
264
39
    nio->dataFNMax = 0;
265
39
    nio->dataFNStep = 0;
266
39
    nio->dataFNIndex = 0;
267
39
    nio->lineLen = 0;
268
39
    nio->pos = 0;
269
39
    nio->endian = airEndianUnknown;
270
39
    nio->lineSkip = 0;
271
39
    nio->headerStrlen = 0;
272
39
    nio->headerStrpos = 0;
273
39
    nio->byteSkip = 0;
274
39
    memset(nio->seen, 0, (NRRD_FIELD_MAX+1)*sizeof(int));
275
39
    nio->detachedHeader = AIR_FALSE;
276
39
    nio->bareText = nrrdDefaultWriteBareText;
277
39
    nio->charsPerLine = nrrdDefaultWriteCharsPerLine;
278
39
    nio->valsPerLine = nrrdDefaultWriteValsPerLine;
279
39
    nio->skipData = AIR_FALSE;
280
39
    nio->skipFormatURL = AIR_FALSE;
281
39
    nio->keepNrrdDataFileOpen = AIR_FALSE;
282
39
    nio->zlibLevel = -1;
283
39
    nio->zlibStrategy = nrrdZlibStrategyDefault;
284
39
    nio->bzip2BlockSize = -1;
285
39
    nio->learningHeaderStrlen = AIR_FALSE;
286
39
    nio->oldData = NULL;
287
39
    nio->oldDataSize = 0;
288
39
    nio->format = nrrdFormatUnknown;
289
39
    nio->encoding = nrrdEncodingUnknown;
290
39
  }
291
39
  return;
292
}
293
294
NrrdIoState *
295
nrrdIoStateNew(void) {
296
  NrrdIoState *nio;
297
298
78
  nio = (NrrdIoState *)calloc(1, sizeof(NrrdIoState));
299
39
  if (nio) {
300
    airPtrPtrUnion appu;
301
302
39
    nio->path = NULL;
303
39
    nio->base = NULL;
304
39
    nio->line = NULL;
305
39
    nio->dataFNFormat = NULL;
306
39
    nio->dataFN = NULL;
307
39
    nio->headerStringRead = NULL;
308
39
    nio->headerStringWrite = NULL;
309
39
    appu.cp = &(nio->dataFN);
310
39
    nio->dataFNArr = airArrayNew(appu.v, NULL,
311
                                 sizeof(char *), NRRD_FILENAME_INCR);
312
39
    airArrayPointerCB(nio->dataFNArr, airNull, airFree);
313
39
    nio->dataFSkip = NULL;
314
39
    appu.li = &(nio->dataFSkip);
315
39
    nio->dataFSkipArr = airArrayNew(appu.v, NULL,
316
                                    sizeof(long int), NRRD_FILENAME_INCR);
317
39
    nio->format = nrrdFormatUnknown;
318
39
    nio->encoding = nrrdEncodingUnknown;
319
39
    nrrdIoStateInit(nio);
320
39
  }
321
39
  return nio;
322
}
323
324
NrrdIoState *
325
nrrdIoStateNix(NrrdIoState *nio) {
326
327
78
  nio->path = (char *)airFree(nio->path);
328
39
  nio->base = (char *)airFree(nio->base);
329
39
  nio->line = (char *)airFree(nio->line);
330
39
  nio->dataFNFormat = (char *)airFree(nio->dataFNFormat);
331
39
  nio->dataFNArr = airArrayNuke(nio->dataFNArr);
332
39
  nio->dataFSkipArr = airArrayNuke(nio->dataFSkipArr);
333
  /* the NrrdIoState never owned nio->oldData; we don't free it */
334
39
  airFree(nio);  /* no NULL assignment, else compile warnings */
335
39
  return NULL;
336
}
337
338
/* ---- BEGIN non-NrrdIO */
339
340
/* ------------------------------------------------------------ */
341
342
void
343
_nrrdResampleInfoInit(NrrdResampleInfo *info) {
344
  int i, d;
345
346
35
  for (d=0; d<NRRD_DIM_MAX; d++) {
347
16
    info->kernel[d] = NULL;
348
16
    info->samples[d] = 0;
349
16
    info->parm[d][0] = nrrdDefaultKernelParm0;
350

384
    for (i=1; i<NRRD_KERNEL_PARMS_NUM; i++)
351
240
      info->parm[d][i] = AIR_NAN;
352
16
    info->min[d] = info->max[d] = AIR_NAN;
353
  }
354
1
  info->boundary = nrrdDefaultResampleBoundary;
355
1
  info->type = nrrdDefaultResampleType;
356
1
  info->renormalize = nrrdDefaultResampleRenormalize;
357
1
  info->round = nrrdDefaultResampleRound;
358
1
  info->clamp = nrrdDefaultResampleClamp;
359
1
  info->cheap = nrrdDefaultResampleCheap;
360
1
  info->padValue = nrrdDefaultResamplePadValue;
361
1
}
362
363
NrrdResampleInfo *
364
nrrdResampleInfoNew(void) {
365
  NrrdResampleInfo *info;
366
367
2
  info = (NrrdResampleInfo*)(calloc(1, sizeof(NrrdResampleInfo)));
368
1
  if (info) {
369
    /* explicitly sets pointers to NULL */
370
1
    _nrrdResampleInfoInit(info);
371
1
  }
372
1
  return info;
373
}
374
375
NrrdResampleInfo *
376
nrrdResampleInfoNix(NrrdResampleInfo *info) {
377
378
2
  info = (NrrdResampleInfo *)airFree(info);
379
1
  return NULL;
380
}
381
382
/* ------------------------------------------------------------ */
383
384
NrrdKernelSpec *
385
nrrdKernelSpecNew(void) {
386
  NrrdKernelSpec *ksp;
387
  int i;
388
389
2082
  ksp = (NrrdKernelSpec *)calloc(1, sizeof(NrrdKernelSpec));
390
1041
  if (ksp) {
391
1041
    ksp->kernel = NULL;
392
18738
    for (i=0; i<NRRD_KERNEL_PARMS_NUM; i++) {
393
8328
      ksp->parm[i] = airNaN();  /* valgrind complained about AIR_NAN at -O2 */
394
    }
395
  }
396
1041
  return ksp;
397
}
398
399
NrrdKernelSpec *
400
nrrdKernelSpecCopy(const NrrdKernelSpec *oldKsp) {
401
  NrrdKernelSpec *ksp=NULL;
402
403
1044
  if (oldKsp) {
404
206
    ksp = (NrrdKernelSpec *)calloc(1, sizeof(NrrdKernelSpec));
405
206
    if (ksp) {
406
206
      memcpy(ksp, oldKsp, sizeof(NrrdKernelSpec));
407
206
    }
408
  }
409
522
  return ksp;
410
}
411
412
NrrdKernelSpec *
413
nrrdKernelSpecNix(NrrdKernelSpec *ksp) {
414
415
5480
  ksp = (NrrdKernelSpec *)airFree(ksp);
416
2740
  return NULL;
417
}
418
419
void
420
nrrdKernelSpecSet(NrrdKernelSpec *ksp, const NrrdKernel *k,
421
                  const double kparm[NRRD_KERNEL_PARMS_NUM]) {
422
  unsigned int p;
423
424
2800
  if (ksp && k && kparm) {
425
1400
    ksp->kernel = k;
426
5830
    for (p=0; p<(k->numParm); p++) {
427
1515
      ksp->parm[p] = kparm[p];
428
    }
429
  }
430
1400
}
431
432
void
433
nrrdKernelParmSet(const NrrdKernel **kP, double kparm[NRRD_KERNEL_PARMS_NUM],
434
                  NrrdKernelSpec *ksp) {
435
  int p;
436
437
  if (kP && kparm && ksp) {
438
    *kP = ksp->kernel;
439
    for (p=0; p<NRRD_KERNEL_PARMS_NUM; p++) {
440
      kparm[p] = ksp->parm[p];
441
    }
442
  }
443
}
444
445
/* ---- END non-NrrdIO */
446
447
/* ------------------------------------------------------------ */
448
449
/* see axis.c for axis-specific "methods" */
450
451
/* ------------------------------------------------------------ */
452
453
/*
454
******** nrrdBasicInfoInit
455
**
456
** resets "basic" (per-array) information
457
** formerly nrrdPeripheralInit
458
**
459
** the bitflag communicates which fields should *not* be initialized
460
*/
461
void
462
nrrdBasicInfoInit(Nrrd *nrrd, int bitflag) {
463
  int dd, ee;
464
465
2780
  if (!nrrd) {
466
    return;
467
  }
468
469
1390
  if (!(NRRD_BASIC_INFO_DATA_BIT & bitflag)) {
470
1241
    nrrd->data = airFree(nrrd->data);
471
1241
  }
472
1390
  if (!(NRRD_BASIC_INFO_TYPE_BIT & bitflag)) {
473
1373
    nrrd->type = nrrdTypeUnknown;
474
1373
  }
475
1390
  if (!(NRRD_BASIC_INFO_BLOCKSIZE_BIT & bitflag)) {
476
1373
    nrrd->blockSize = 0;
477
1373
  }
478
1390
  if (!(NRRD_BASIC_INFO_DIMENSION_BIT & bitflag)) {
479
1373
    nrrd->dim = 0;
480
1373
  }
481
1390
  if (!(NRRD_BASIC_INFO_CONTENT_BIT & bitflag)) {
482
1373
    nrrd->content = (char *)airFree(nrrd->content);
483
1373
  }
484
1390
  if (!(NRRD_BASIC_INFO_SAMPLEUNITS_BIT & bitflag)) {
485
1373
    nrrd->sampleUnits = (char *)airFree(nrrd->sampleUnits);
486
1373
  }
487
1390
  if (!(NRRD_BASIC_INFO_SPACE_BIT & bitflag)) {
488
1373
    nrrd->space = nrrdSpaceUnknown;
489
1373
    nrrd->spaceDim = 0;
490
1373
  }
491
1390
  if (!(NRRD_BASIC_INFO_SPACEDIMENSION_BIT & bitflag)) {
492
1373
    nrrd->space = nrrdSpaceUnknown;
493
1373
    nrrd->spaceDim = 0;
494
1373
  }
495
1390
  if (!(NRRD_BASIC_INFO_SPACEUNITS_BIT & bitflag)) {
496
24714
    for (dd=0; dd<NRRD_SPACE_DIM_MAX; dd++) {
497
10984
      nrrd->spaceUnits[dd] = (char *)airFree(nrrd->spaceUnits[dd]);
498
    }
499
  }
500
1390
  if (!(NRRD_BASIC_INFO_SPACEORIGIN_BIT & bitflag)) {
501
24714
    for (dd=0; dd<NRRD_SPACE_DIM_MAX; dd++) {
502
10984
      nrrd->spaceOrigin[dd] = AIR_NAN;
503
    }
504
  }
505
1390
  if (!(NRRD_BASIC_INFO_MEASUREMENTFRAME_BIT & bitflag)) {
506
24714
    for (dd=0; dd<NRRD_SPACE_DIM_MAX; dd++) {
507
197712
      for (ee=0; ee<NRRD_SPACE_DIM_MAX; ee++) {
508
87872
        nrrd->measurementFrame[dd][ee] = AIR_NAN;
509
      }
510
    }
511
  }
512
1390
  if (!(NRRD_BASIC_INFO_OLDMIN_BIT & bitflag)) {
513
1390
    nrrd->oldMin = AIR_NAN;
514
1390
  }
515
1390
  if (!(NRRD_BASIC_INFO_OLDMAX_BIT & bitflag)) {
516
1390
    nrrd->oldMax = AIR_NAN;
517
1390
  }
518
1390
  if (!(NRRD_BASIC_INFO_COMMENTS_BIT & bitflag)) {
519
1365
    nrrdCommentClear(nrrd);
520
1365
  }
521
1390
  if (!(NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT & bitflag)) {
522
1365
    nrrdKeyValueClear(nrrd);
523
1365
  }
524
1390
  return;
525
1390
}
526
527
/*
528
******** nrrdBasicInfoCopy
529
**
530
** copies "basic" (per-array) information
531
** formerly known as nrrdPeripheralCopy, which was not used consistently
532
**
533
** the bitflag communicates which fields should *not* be copied
534
*/
535
int
536
nrrdBasicInfoCopy(Nrrd *dest, const Nrrd *src, int bitflag) {
537
  static const char me[]="nrrdBasicInfoCopy";
538
  unsigned int dd, ee;
539
540
798
  if (!( dest && src ))
541
    return 0;
542
399
  if (dest == src) {
543
    /* nothing to do */
544
8
    return 0;
545
  }
546
547
391
  if (!(NRRD_BASIC_INFO_DATA_BIT & bitflag)) {
548
    dest->data = src->data;
549
  }
550
391
  if (!(NRRD_BASIC_INFO_TYPE_BIT & bitflag)) {
551
131
    dest->type = src->type;
552
131
  }
553
391
  if (!(NRRD_BASIC_INFO_BLOCKSIZE_BIT & bitflag)) {
554
140
    dest->blockSize = src->blockSize;
555
140
  }
556
391
  if (!(NRRD_BASIC_INFO_DIMENSION_BIT & bitflag)) {
557
131
    dest->dim = src->dim;
558
131
  }
559
391
  if (!(NRRD_BASIC_INFO_CONTENT_BIT & bitflag)) {
560
131
    dest->content = (char *)airFree(dest->content);
561
131
    dest->content = airStrdup(src->content);
562

181
    if (src->content && !dest->content) {
563
      biffAddf(NRRD, "%s: couldn't copy content", me);
564
      return 1;
565
    }
566
  }
567
391
  if (!(NRRD_BASIC_INFO_SAMPLEUNITS_BIT & bitflag)) {
568
383
    dest->sampleUnits = (char *)airFree(dest->sampleUnits);
569
383
    dest->sampleUnits = airStrdup(src->sampleUnits);
570

383
    if (src->sampleUnits && !dest->sampleUnits) {
571
      biffAddf(NRRD, "%s: couldn't copy sampleUnits", me);
572
      return 1;
573
    }
574
  }
575
391
  if (!(NRRD_BASIC_INFO_SPACE_BIT & bitflag)) {
576
391
    dest->space = src->space;
577
391
  }
578
391
  if (!(NRRD_BASIC_INFO_SPACEDIMENSION_BIT & bitflag)) {
579
391
    dest->spaceDim = src->spaceDim;
580
391
  }
581
391
  if (!(NRRD_BASIC_INFO_SPACEUNITS_BIT & bitflag)) {
582
2450
    for (dd=0; dd<src->spaceDim; dd++) {
583
834
      dest->spaceUnits[dd] = (char *)airFree(dest->spaceUnits[dd]);
584
834
      dest->spaceUnits[dd] = airStrdup(src->spaceUnits[dd]);
585

837
      if (src->spaceUnits[dd] && !dest->spaceUnits[dd]) {
586
        biffAddf(NRRD, "%s: couldn't copy spaceUnits[%d]", me, dd);
587
        return 1;
588
      }
589
    }
590
5370
    for (dd=src->spaceDim; dd<NRRD_SPACE_DIM_MAX; dd++) {
591
2294
      dest->spaceUnits[dd] = (char *)airFree(dest->spaceUnits[dd]);
592
    }
593
  }
594
391
  if (!(NRRD_BASIC_INFO_SPACEORIGIN_BIT & bitflag)) {
595
3726
    for (dd=0; dd<NRRD_SPACE_DIM_MAX; dd++) {
596
1656
      if (dd <= src->spaceDim-1) {
597
1186
        dest->spaceOrigin[dd] = src->spaceOrigin[dd];
598
1186
      } else {
599
470
        dest->spaceOrigin[dd] = AIR_NAN;
600
      }
601
    }
602
  }
603
391
  if (!(NRRD_BASIC_INFO_MEASUREMENTFRAME_BIT & bitflag)) {
604
7038
    for (dd=0; dd<NRRD_SPACE_DIM_MAX; dd++) {
605
56304
      for (ee=0; ee<NRRD_SPACE_DIM_MAX; ee++) {
606

38928
        if (dd <= src->spaceDim-1 && ee <= src->spaceDim-1) {
607
9734
          dest->measurementFrame[dd][ee] = src->measurementFrame[dd][ee];
608
9734
        } else {
609
15290
          dest->measurementFrame[dd][ee] = AIR_NAN;
610
        }
611
      }
612
    }
613
5370
    for (dd=src->spaceDim; dd<NRRD_SPACE_DIM_MAX; dd++) {
614
2294
      dest->spaceOrigin[dd] = AIR_NAN;
615
    }
616
  }
617
391
  if (!(NRRD_BASIC_INFO_OLDMIN_BIT & bitflag)) {
618
381
    dest->oldMin = src->oldMin;
619
381
  }
620
391
  if (!(NRRD_BASIC_INFO_OLDMAX_BIT & bitflag)) {
621
381
    dest->oldMax = src->oldMax;
622
381
  }
623
391
  if (!(NRRD_BASIC_INFO_COMMENTS_BIT & bitflag)) {
624
123
    if (nrrdCommentCopy(dest, src)) {
625
      biffAddf(NRRD, "%s: trouble copying comments", me);
626
      return 1;
627
    }
628
  }
629
391
  if (!(NRRD_BASIC_INFO_KEYVALUEPAIRS_BIT & bitflag)) {
630
123
    if (nrrdKeyValueCopy(dest, src)) {
631
      biffAddf(NRRD, "%s: trouble copying key/value pairs", me);
632
      return 1;
633
    }
634
  }
635
391
  return 0;
636
399
}
637
638
/*
639
******* nrrdInit
640
**
641
** initializes a nrrd to default state.  All nrrd functions in the
642
** business of initializing a nrrd struct use this function.  Mostly
643
** just sets values to 0, NaN, "", NULL, or Unknown
644
*/
645
void
646
nrrdInit(Nrrd *nrrd) {
647
  int ii;
648
649
2482
  if (nrrd) {
650
1241
    nrrdBasicInfoInit(nrrd, NRRD_BASIC_INFO_NONE);
651
42194
    for (ii=0; ii<NRRD_DIM_MAX; ii++) {
652
19856
      _nrrdAxisInfoInit(nrrd->axis + ii);
653
    }
654
  }
655
  return;
656
1241
}
657
658
/*
659
******** nrrdNew()
660
**
661
** creates and initializes a Nrrd
662
**
663
** this does NOT use biff
664
*/
665
Nrrd *
666
nrrdNew(void) {
667
  int ii;
668
  Nrrd *nrrd;
669
  airPtrPtrUnion appu;
670
671
1216
  nrrd = (Nrrd*)(calloc(1, sizeof(Nrrd)));
672
608
  if (!nrrd) {
673
    return NULL;
674
  }
675
676
  /* explicitly set pointers to NULL, since calloc isn't officially
677
     guaranteed to do that.  */
678
608
  nrrd->data = NULL;
679
20672
  for (ii=0; ii<NRRD_DIM_MAX; ii++) {
680
9728
    _nrrdAxisInfoNewInit(nrrd->axis + ii);
681
  }
682
10944
  for (ii=0; ii<NRRD_SPACE_DIM_MAX; ii++) {
683
4864
    nrrd->spaceUnits[ii] = NULL;
684
  }
685
608
  nrrd->content = NULL;
686
608
  nrrd->sampleUnits = NULL;
687
688
  /* create comment airArray (even though it starts empty) */
689
608
  nrrd->cmt = NULL;
690
608
  appu.cp = &(nrrd->cmt);
691
608
  nrrd->cmtArr = airArrayNew(appu.v, NULL, sizeof(char *), NRRD_COMMENT_INCR);
692
608
  if (!nrrd->cmtArr) {
693
    return NULL;
694
  }
695
608
  airArrayPointerCB(nrrd->cmtArr, airNull, airFree);
696
697
  /* create key/value airArray (even thought it starts empty) */
698
608
  nrrd->kvp = NULL;
699
608
  appu.cp = &(nrrd->kvp);
700
608
  nrrd->kvpArr = airArrayNew(appu.v, NULL,
701
                             2*sizeof(char *), NRRD_KEYVALUE_INCR);
702
608
  if (!nrrd->kvpArr) {
703
    return NULL;
704
  }
705
  /* key/value airArray uses no callbacks for now */
706
707
  /* finish initializations */
708
608
  nrrdInit(nrrd);
709
710
608
  return nrrd;
711
608
}
712
713
/*
714
******** nrrdNix()
715
**
716
** does nothing with the array data inside, just does whatever is needed
717
** to free the nrrd itself
718
**
719
** returns NULL
720
**
721
** this does NOT use biff
722
*/
723
Nrrd *
724
nrrdNix(Nrrd *nrrd) {
725
  int ii;
726
727
1216
  if (nrrd) {
728
20672
    for (ii=0; ii<NRRD_DIM_MAX; ii++) {
729
9728
      _nrrdAxisInfoInit(&(nrrd->axis[ii]));
730
    }
731
10944
    for (ii=0; ii<NRRD_SPACE_DIM_MAX; ii++) {
732
4864
      nrrd->spaceUnits[ii] = (char *)airFree(nrrd->spaceUnits[ii]);
733
    }
734
608
    nrrd->content = (char *)airFree(nrrd->content);
735
608
    nrrd->sampleUnits = (char *)airFree(nrrd->sampleUnits);
736
608
    nrrdCommentClear(nrrd);
737
608
    nrrd->cmtArr = airArrayNix(nrrd->cmtArr);
738
608
    nrrdKeyValueClear(nrrd);
739
608
    nrrd->kvpArr = airArrayNix(nrrd->kvpArr);
740
608
    airFree(nrrd);
741
608
  }
742
608
  return NULL;
743
}
744
745
/*
746
******** nrrdEmpty()
747
**
748
** frees data inside nrrd AND resets all its state, so its the
749
** same as what comes from nrrdNew().  This includes free()ing
750
** any comments.
751
*/
752
Nrrd *
753
nrrdEmpty(Nrrd *nrrd) {
754
755
1216
  if (nrrd) {
756
608
    nrrd->data = airFree(nrrd->data);
757
608
    nrrdInit(nrrd);
758
608
  }
759
608
  return nrrd;
760
}
761
762
/*
763
******** nrrdNuke()
764
**
765
** blows away the nrrd and everything inside
766
**
767
** always returns NULL
768
*/
769
Nrrd *
770
nrrdNuke(Nrrd *nrrd) {
771
772
1216
  if (nrrd) {
773
608
    nrrdEmpty(nrrd);
774
608
    nrrdNix(nrrd);
775
608
  }
776
608
  return NULL;
777
}
778
779
/* ------------------------------------------------------------ */
780
781
int
782
_nrrdSizeCheck(const size_t *size, unsigned int dim, int useBiff) {
783
  static const char me[]="_nrrdSizeCheck";
784
  size_t num, pre;
785
  unsigned int ai;
786
787
  pre = num = 1;
788
49591
  for (ai=0; ai<dim; ai++) {
789
16274
    if (!size[ai]) {
790
      biffMaybeAddf(useBiff, NRRD, "%s: axis %u size is zero!", me, ai);
791
      return 1;
792
    }
793
16274
    num *= size[ai];
794
16274
    if (num/size[ai] != pre) {
795
      biffMaybeAddf(useBiff, NRRD,
796
                    "%s: total # of elements too large to be represented in "
797
                    "type size_t, so too large for current architecture", me);
798
      return 1;
799
    }
800
16274
    pre *= size[ai];
801
  }
802
5681
  return 0;
803
5681
}
804
805
/*
806
******** nrrdWrap_nva()
807
**
808
** wraps a given Nrrd around a given array
809
**
810
** we don't touch any of the peripheral information (content, comments,
811
** blocksize, min/max) because it is entirely reasonable to be setting
812
** this before or after this call.  "type" could be passed as
813
** nrrdTypeBlock, in which case it is the user's responsibility to
814
** set nrrd->blockSize at some other time.
815
*/
816
int
817
nrrdWrap_nva(Nrrd *nrrd, void *data, int type,
818
             unsigned int dim, const size_t *size) {
819
  static const char me[]="nrrdWrap_nva";
820
821
1298
  if (!(nrrd && size)) {
822
    biffAddf(NRRD, "%s: got NULL pointer", me);
823
    return 1;
824
  }
825
649
  nrrd->data = data;
826
649
  nrrd->type = type;
827
649
  nrrd->dim = dim;
828
649
  if (_nrrdSizeCheck(size, dim, AIR_TRUE)) {
829
    biffAddf(NRRD, "%s:", me);
830
    return 1;
831
  }
832
649
  nrrdAxisInfoSet_nva(nrrd, nrrdAxisInfoSize, size);
833
649
  return 0;
834
649
}
835
836
/*
837
******** nrrdWrap_va()
838
**
839
** Minimal var args wrapper around nrrdWrap_nva, with the advantage of
840
** taking all the axes sizes as the var args.
841
**
842
** This is THE BEST WAY to wrap a nrrd around existing raster data,
843
** assuming that the dimension is known at compile time.
844
**
845
** If successful, returns 0, otherwise, 1.
846
** This does use biff.
847
*/
848
int
849
nrrdWrap_va(Nrrd *nrrd, void *data, int type, unsigned int dim, ...) {
850
  static const char me[]="nrrdWrap_va";
851
  va_list ap;
852
  size_t size[NRRD_DIM_MAX];
853
  unsigned int ai;
854
855
  if (!(nrrd && data)) {
856
    biffAddf(NRRD, "%s: got NULL pointer", me);
857
    return 1;
858
  }
859
  va_start(ap, dim);
860
  for (ai=0; ai<dim; ai++) {
861
    size[ai] = va_arg(ap, size_t);
862
  }
863
  va_end(ap);
864
865
  return nrrdWrap_nva(nrrd, data, type, dim, size);
866
}
867
868
/*
869
void
870
_nrrdTraverse(Nrrd *nrrd) {
871
  char *test, tval;
872
  size_t I, N;
873
  int S;
874
875
  N = nrrdElementNumber(nrrd);
876
  S = nrrdElementSize(nrrd);
877
  tval = 0;
878
  test = nrrd->data;
879
  for (I=0; I<N*S; I++) {
880
    tval += test[I];
881
  }
882
}
883
*/
884
885
int
886
_nrrdCopy(Nrrd *nout, const Nrrd *nin, int bitflag) {
887
  static const char me[]="_nrrdCopy";
888
262
  size_t size[NRRD_DIM_MAX];
889
890
131
  if (!(nin && nout)) {
891
    biffAddf(NRRD, "%s: got NULL pointer", me);
892
    return 1;
893
  }
894
131
  if (nout == nin) {
895
    /* its not the case that we have nothing to do- the semantics of
896
       copying cannot be achieved if the input and output nrrd are
897
       the same; this is an error */
898
    biffAddf(NRRD, "%s: nout==nin disallowed", me);
899
    return 1;
900
  }
901
131
  if (!nrrdElementSize(nin)) {
902
    biffAddf(NRRD, "%s: input nrrd reports zero element size!", me);
903
    return 1;
904
  }
905
131
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size);
906

262
  if (nin->data) {
907
262
    if (nrrdMaybeAlloc_nva(nout, nin->type, nin->dim, size)) {
908
      biffAddf(NRRD, "%s: couldn't allocate data", me);
909
      return 1;
910
    }
911
131
    memcpy(nout->data, nin->data,
912
           nrrdElementNumber(nin)*nrrdElementSize(nin));
913
131
  } else {
914
    /* someone is trying to copy structs without data, fine fine fine */
915
    if (nrrdWrap_nva(nout, NULL, nin->type, nin->dim, size)) {
916
      biffAddf(NRRD, "%s: couldn't wrap NULL data", me);
917
      return 1;
918
    }
919
  }
920
131
  nrrdAxisInfoCopy(nout, nin, NULL, NRRD_AXIS_INFO_SIZE_BIT);
921
  /* if nin->data non-NULL (second branch above), this will
922
     harmlessly unset and set type and dim */
923
131
  nrrdBasicInfoInit(nout, NRRD_BASIC_INFO_DATA_BIT | bitflag);
924
131
  if (nrrdBasicInfoCopy(nout, nin, NRRD_BASIC_INFO_DATA_BIT | bitflag)) {
925
    biffAddf(NRRD, "%s: trouble copying basic info", me);
926
    return 1;
927
  }
928
929
131
  return 0;
930
131
}
931
932
/*
933
******** nrrdCopy
934
**
935
** copy method for nrrds.  nout will end up as an "exact" copy of nin.
936
** New space for data is allocated here, and output nrrd points to it.
937
** Comments from old are added to comments for new, so these are also
938
** newly allocated.  nout->ptr is not set, nin->ptr is not read.
939
*/
940
int
941
nrrdCopy(Nrrd *nout, const Nrrd *nin) {
942
  static const char me[]="nrrdCopy";
943
944
246
  if (_nrrdCopy(nout, nin, NRRD_BASIC_INFO_NONE)) {
945
    biffAddf(NRRD, "%s:", me);
946
    return 1;
947
  }
948
123
  return 0;
949
123
}
950
951
/*
952
******** nrrdAlloc_nva()
953
**
954
** allocates data array and sets information.  If this is a block type
955
** nrrd, it is necessary to set nrrd->blockSize PRIOR to calling
956
** this function.
957
**
958
** This function will always allocate more memory (via calloc), but
959
** it will free() nrrd->data if it is non-NULL when passed in.
960
**
961
** This function takes the same "don't mess with peripheral information"
962
** attitude as nrrdWrap().
963
**
964
** Note to Gordon: don't get clever and change ANY axis-specific
965
** information here.  It may be very convenient to set that before
966
** nrrdAlloc or nrrdMaybeAlloc
967
**
968
** Note: This function DOES use biff
969
*/
970
int
971
nrrdAlloc_nva(Nrrd *nrrd, int type, unsigned int dim, const size_t *size) {
972
  static const char me[]="nrrdAlloc_nva";
973
  size_t num, esize;
974
1202
  char stmp[2][AIR_STRLEN_SMALL];
975
976
601
  if (!(nrrd && size)) {
977
    biffAddf(NRRD, "%s: got NULL pointer", me);
978
    return 1;
979
  }
980
601
  if (airEnumValCheck(nrrdType, type)) {
981
    biffAddf(NRRD, "%s: type (%d) is invalid", me, type);
982
    return 1;
983
  }
984
601
  if (nrrdTypeBlock == type) {
985
    if (!(0 < nrrd->blockSize)) {
986
      biffAddf(NRRD, "%s: given nrrd->blockSize %s invalid", me,
987
               airSprintSize_t(stmp[0], nrrd->blockSize));
988
      return 1;
989
    }
990
  }
991
601
  if (!AIR_IN_CL(1, dim, NRRD_DIM_MAX)) {
992
    biffAddf(NRRD, "%s: dim (%d) not in valid range [1,%d]",
993
             me, dim, NRRD_DIM_MAX);
994
    return 1;
995
  }
996
997
601
  nrrd->data = airFree(nrrd->data);
998
601
  if (nrrdWrap_nva(nrrd, NULL, type, dim, size)) {
999
    biffAddf(NRRD, "%s:", me);
1000
    return 1 ;
1001
  }
1002
601
  num = nrrdElementNumber(nrrd);
1003
601
  esize = nrrdElementSize(nrrd);
1004
601
  nrrd->data = calloc(num, esize);
1005
601
  if (!(nrrd->data)) {
1006
    biffAddf(NRRD, "%s: calloc(%s,%s) failed", me,
1007
             airSprintSize_t(stmp[0], num),
1008
             airSprintSize_t(stmp[1], esize));
1009
    return 1 ;
1010
  }
1011
1012
601
  return 0;
1013
601
}
1014
1015
/*
1016
******** nrrdAlloc_va()
1017
**
1018
** Handy wrapper around nrrdAlloc_nva, which takes, as its vararg list,
1019
** all the axes sizes.
1020
*/
1021
int
1022
nrrdAlloc_va(Nrrd *nrrd, int type, unsigned int dim, ...) {
1023
  static const char me[]="nrrdAlloc_va";
1024
2
  size_t size[NRRD_DIM_MAX];
1025
  unsigned int ai;
1026
1
  va_list ap;
1027
1028
1
  if (!nrrd) {
1029
    biffAddf(NRRD, "%s: got NULL pointer", me);
1030
    return 1;
1031
  }
1032
1
  va_start(ap, dim);
1033
4
  for (ai=0; ai<dim; ai++) {
1034
3
    size[ai] = va_arg(ap, size_t);
1035
  }
1036
1
  va_end(ap);
1037
1
  if (nrrdAlloc_nva(nrrd, type, dim, size)) {
1038
    biffAddf(NRRD, "%s:", me);
1039
    return 1;
1040
  }
1041
1
  return 0;
1042
1
}
1043
1044
1045
/*
1046
** _nrrdMaybeAllocMaybeZero_nva
1047
**
1048
** New implementation of nrrdMaybeAlloc_nva, but now with ability
1049
** to control whether or not to zero out when re-allocation wasn't needed
1050
**
1051
** HEY: should consider making this a public function, but GLK couldn't
1052
** think of a name that wasn't silly
1053
*/
1054
int
1055
_nrrdMaybeAllocMaybeZero_nva(Nrrd *nrrd, int type,
1056
                             unsigned int dim, const size_t *size,
1057
                             int zeroWhenNoAlloc) {
1058
  static const char me[]="nrrdMaybeAllocMaybeZero_nva";
1059
  size_t sizeWant, sizeHave, numWant, elementSizeWant;
1060
  int need;
1061
  unsigned int ai;
1062
1063
1296
  if (!nrrd) {
1064
    biffAddf(NRRD, "%s: got NULL pointer", me);
1065
    return 1;
1066
  }
1067
648
  if (airEnumValCheck(nrrdType, type)) {
1068
    biffAddf(NRRD, "%s: type (%d) is invalid", me, type);
1069
    return 1;
1070
  }
1071
648
  if (nrrdTypeBlock == type) {
1072
    if (nrrdTypeBlock == nrrd->type) {
1073
      biffAddf(NRRD, "%s: can't change from one block nrrd to another", me);
1074
      return 1;
1075
    }
1076
    if (!(0 < nrrd->blockSize)) {
1077
      char stmp[AIR_STRLEN_SMALL];
1078
      biffAddf(NRRD, "%s: given nrrd->blockSize %s invalid", me,
1079
               airSprintSize_t(stmp, nrrd->blockSize));
1080
      return 1;
1081
    }
1082
    elementSizeWant = nrrd->blockSize;
1083
  } else {
1084
648
    elementSizeWant = nrrdTypeSize[type];
1085
  }
1086
648
  if (_nrrdSizeCheck(size, dim, AIR_TRUE)) {
1087
    biffAddf(NRRD, "%s:", me);
1088
    return 1;
1089
  }
1090
1091
648
  if (!(nrrd->data)) {
1092
    need = 1;
1093
563
  } else {
1094
    numWant = 1;
1095
584
    for (ai=0; ai<dim; ai++) {
1096
207
      numWant *= size[ai];
1097
    }
1098
85
    if (!nrrdElementSize(nrrd)) {
1099
      biffAddf(NRRD, "%s: nrrd reports zero element size!", me);
1100
      return 1;
1101
    }
1102
85
    sizeHave = nrrdElementNumber(nrrd) * nrrdElementSize(nrrd);
1103
    /* fprintf(stderr, "##%s: sizeHave = %d * %d = %d\n", me,
1104
            (int)(nrrdElementNumber(nrrd)),
1105
            (int)(nrrdElementSize(nrrd)), (int)sizeHave); */
1106
85
    sizeWant = numWant * elementSizeWant;
1107
    /* fprintf(stderr, "##%s: sizeWant = %d * %d = %d\n", me,
1108
            (int)(numWant),
1109
            (int)(elementSizeWant), (int)sizeWant); */
1110
85
    need = sizeHave != sizeWant;
1111
    /* fprintf(stderr, "##%s: need = %d\n", me, need); */
1112
  }
1113
648
  if (need) {
1114
600
    if (nrrdAlloc_nva(nrrd, type, dim, size)) {
1115
      biffAddf(NRRD, "%s:", me);
1116
      return 1;
1117
    }
1118
  } else {
1119
    /* size is already exactly what we want */
1120
48
    if (nrrdWrap_nva(nrrd, nrrd->data, type, dim, size)) {
1121
      biffAddf(NRRD, "%s:", me);
1122
      return 1;
1123
    }
1124
    /* but we may have to initialize memory */
1125
48
    if (zeroWhenNoAlloc) {
1126
40
      memset(nrrd->data, 0, nrrdElementNumber(nrrd)*nrrdElementSize(nrrd));
1127
40
    }
1128
  }
1129
1130
648
  return 0;
1131
648
}
1132
1133
/*
1134
******** nrrdMaybeAlloc_nva
1135
**
1136
** NOTE: this is now just a wrapper around _nrrdMaybeAllocMaybeZero_nva;
1137
** below info referred to original implementation.
1138
**
1139
** calls nrrdAlloc_nva if the requested space is different than
1140
** what is currently held
1141
**
1142
** also subscribes to the "don't mess with peripheral information" philosophy
1143
*/
1144
int
1145
nrrdMaybeAlloc_nva(Nrrd *nrrd, int type,
1146
                   unsigned int dim, const size_t *size) {
1147
  static const char me[]="nrrdMaybeAlloc_nva";
1148
  int ret;
1149
1262
  ret = _nrrdMaybeAllocMaybeZero_nva(nrrd, type, dim, size,
1150
                                     AIR_TRUE);
1151
631
  if (ret) {
1152
    biffAddf(NRRD, "%s: trouble", me);
1153
  }
1154
631
  return ret;
1155
}
1156
1157
/*
1158
******** nrrdMaybeAlloc_va()
1159
**
1160
** Handy wrapper around nrrdAlloc, which takes, as its vararg list
1161
** all the axes sizes, thereby calculating the total number.
1162
*/
1163
int
1164
nrrdMaybeAlloc_va(Nrrd *nrrd, int type, unsigned int dim, ...) {
1165
  static const char me[]="nrrdMaybeAlloc_va";
1166
372
  size_t size[NRRD_DIM_MAX];
1167
  unsigned int ai;
1168
186
  va_list ap;
1169
1170
186
  if (!nrrd) {
1171
    biffAddf(NRRD, "%s: got NULL pointer", me);
1172
    return 1;
1173
  }
1174
186
  va_start(ap, dim);
1175
1226
  for (ai=0; ai<dim; ai++) {
1176
1281
    size[ai] = va_arg(ap, size_t);
1177
  }
1178
186
  va_end(ap);
1179
186
  if (nrrdMaybeAlloc_nva(nrrd, type, dim, size)) {
1180
    biffAddf(NRRD, "%s:", me);
1181
    return 1;
1182
  }
1183
186
  return 0;
1184
186
}
1185
1186
/* ---- BEGIN non-NrrdIO */
1187
1188
/*
1189
** nrrdCompare
1190
**
1191
** walks through all fields of the two nrrds to see if they contain
1192
** the same information.  So, this doesn't compare any pointer values,
1193
** only the contents of things.
1194
**
1195
** Unlike strcmp(), the return value from this can't be the indication
1196
** of the difference, because we'd have to return a value even in the
1197
** case of an error, which would be be strange.  GLK briefly tried
1198
** created a new #define _NRRD_ERROR_RETURN for this purpose (with
1199
** leet-speak value 32202), but its just a bad idea.
1200
**
1201
** NOTE: the structure of this code is very similar to that of
1202
** nrrdAxisInfoCompare, and any improvements here should be reflected there
1203
*/
1204
int
1205
nrrdCompare(const Nrrd *ninA, const Nrrd *ninB,
1206
            int onlyData, double epsilon,
1207
            int *differ, char explain[AIR_STRLEN_LARGE]) {
1208
  static const char me[]="nrrdCompare";
1209
  size_t numA, numB;
1210
  unsigned int axi, saxi;
1211
1212
20
  if (!(ninA && ninB && differ)) {
1213
    biffAddf(NRRD, "%s: got NULL pointer (%p, %p, or %p)", me,
1214
             AIR_CVOIDP(ninA), AIR_CVOIDP(ninB), AIR_VOIDP(differ));
1215
    return 1;
1216
  }
1217
1218
10
  if (explain) {
1219
10
    strcpy(explain, "");
1220
10
  }
1221
10
  if (!onlyData) {
1222
10
    if (ninA->dim != ninB->dim) {
1223
      *differ = ninA->dim < ninB->dim ? -1 : 1;
1224
      if (explain) {
1225
        sprintf(explain, "nin{A,B}->dim %u %s %u",
1226
                ninA->dim, *differ < 0 ? "<" : ">", ninB->dim);
1227
      }
1228
      return 0;
1229
    }
1230
  }
1231
10
  if (ninA->type != ninB->type) {
1232
    *differ = ninA->type < ninB->type ? -1 : 1;
1233
    if (explain) {
1234
      sprintf(explain, "nin{A,B}->type %s %s %s",
1235
              airEnumStr(nrrdType, ninA->type), *differ < 0 ? "<" : ">",
1236
              airEnumStr(nrrdType, ninB->type));
1237
    }
1238
    return 0;
1239
  }
1240
10
  numA = nrrdElementNumber(ninA);
1241
10
  numB = nrrdElementNumber(ninB);
1242
10
  if (numA != numB) {
1243
    char stmp1[AIR_STRLEN_SMALL], stmp2[AIR_STRLEN_SMALL];
1244
    *differ = numA < numB ? -1 : 1;
1245
    sprintf(explain, "element # {A,B} %s %s %s",
1246
            airSprintSize_t(stmp1, numA), *differ < 0 ? "<" : ">",
1247
            airSprintSize_t(stmp2, numB));
1248
    return 0;
1249
  }
1250
  /* this will always set *differ */
1251
10
  if (nrrdArrayCompare(ninA->type, ninA->data, ninB->data, numA,
1252
                       epsilon, differ, explain)) {
1253
    biffAddf(NRRD, "%s: problem comparing values", me);
1254
    return 1;
1255
  }
1256

20
  if (onlyData || *differ) {
1257
    /* If caller only cared about data values,
1258
       we're done whether or not they were different.
1259
       else, if the data values are different, we're done.
1260
       The explanation of any difference in values is
1261
       already in "explain" (if non-NULL) */
1262
    return 0;
1263
  }
1264
1265
60
  for (axi=0; axi<ninA->dim; axi++) {
1266
    /* this always sets *differ */
1267
20
    if (nrrdAxisInfoCompare(ninA->axis + axi, ninB->axis + axi,
1268
                            differ, explain)) {
1269
      biffAddf(NRRD, "%s: problem comparing axis %u", me, axi);
1270
      return 1;
1271
    }
1272
20
    if (*differ) {
1273
      char tmpexplain[AIR_STRLEN_LARGE];
1274
      /* the explanation, if wanted, is in "explain", but we add context */
1275
      sprintf(tmpexplain, "(axis %u) %s", axi, explain);
1276
      airStrcpy(explain, AIR_STRLEN_LARGE, tmpexplain);
1277
      return 0;
1278
    }
1279
  }
1280
1281
#define STRING_COMPARE(VAL, STR)                                      \
1282
  *differ = airStrcmp(ninA->VAL, ninB->VAL);                          \
1283
  if (*differ) {                                                      \
1284
    if (explain) {                                                    \
1285
      /* can't print whole string because of fixed-size of explain */ \
1286
      sprintf(explain, "ninA->%s %s ninB->%s",                        \
1287
              STR, *differ < 0 ? "<" : ">", STR);                     \
1288
    }                                                                 \
1289
    return 0;                                                         \
1290
  }
1291
1292

10
  STRING_COMPARE(content, "content");
1293

10
  STRING_COMPARE(sampleUnits, "sampleUnits");
1294
10
  if (ninA->space != ninB->space) {
1295
    *differ = ninA->space < ninB->space ? -1 : 1;
1296
    if (explain) {
1297
      sprintf(explain, "ninA->space %s %s ninB->space %s",
1298
              airEnumStr(nrrdSpace, ninA->space),
1299
              *differ < 0 ? "<" : ">",
1300
              airEnumStr(nrrdSpace, ninB->space));
1301
    }
1302
    return 0;
1303
  }
1304
10
  if (ninA->spaceDim != ninB->spaceDim) {
1305
    *differ = ninA->spaceDim < ninB->spaceDim ? -1 : 1;
1306
    if (explain) {
1307
      sprintf(explain, "ninA->spaceDim %u %s ninB->spaceDim %u",
1308
              ninA->spaceDim, *differ < 0 ? "<" : ">", ninB->spaceDim);
1309
    }
1310
    return 0;
1311
  }
1312
10
  if (ninA->blockSize != ninB->blockSize) {
1313
    *differ = ninA->blockSize < ninB->blockSize ? -1 : 1;
1314
    if (explain) {
1315
      char stmp1[AIR_STRLEN_SMALL], stmp2[AIR_STRLEN_SMALL];
1316
      sprintf(explain, "ninA->blockSize %s %s ninB->blockSize %s",
1317
              airSprintSize_t(stmp1, ninA->blockSize),
1318
              *differ < 0 ? "<" : ">",
1319
              airSprintSize_t(stmp2, ninB->blockSize));
1320
    }
1321
    return 0;
1322
  }
1323
1324
#define DOUBLE_COMPARE(VAL, STR)                                       \
1325
  *differ = _nrrdDblcmp(ninA->VAL, ninB->VAL);                         \
1326
  if (*differ) {                                                       \
1327
    if (explain) {                                                     \
1328
      sprintf(explain, "ninA->%s %.17g %s ninB->%s %.17g",             \
1329
              STR, ninA->VAL, *differ < 0 ? "<" : ">",                 \
1330
              STR, ninB->VAL);                                         \
1331
    }                                                                  \
1332
    return 0;                                                          \
1333
  }
1334
1335
180
  for (saxi=0; saxi<NRRD_SPACE_DIM_MAX; saxi++) {
1336
80
    char stmp[AIR_STRLEN_SMALL];
1337
    unsigned int saxj;
1338
80
    sprintf(stmp, "spaceOrigin[%u]", saxi);
1339

80
    DOUBLE_COMPARE(spaceOrigin[saxi], stmp);
1340
80
    sprintf(stmp, "spaceUnits[%u]", saxi);
1341

80
    STRING_COMPARE(spaceUnits[saxi], stmp);
1342
1440
    for (saxj=0; saxj<NRRD_SPACE_DIM_MAX; saxj++) {
1343
640
      sprintf(stmp, "measurementFrame[%u][%u]", saxi, saxj);
1344

640
      DOUBLE_COMPARE(measurementFrame[saxi][saxj], stmp);
1345
    }
1346
160
  }
1347

10
  DOUBLE_COMPARE(oldMin, "oldMin");
1348

10
  DOUBLE_COMPARE(oldMax, "oldMax");
1349
#undef DOUBLE_COMPARE
1350
1351
10
  if (ninA->cmtArr->len != ninB->cmtArr->len) {
1352
    *differ = ninA->cmtArr->len < ninB->cmtArr->len ? -1 : 1;
1353
    if (explain) {
1354
      sprintf(explain, "ninA # comments %u %s ninB # comments %u",
1355
              ninA->cmtArr->len, *differ < 0 ? "<" : ">", ninB->cmtArr->len);
1356
    }
1357
    return 0;
1358
  } else {
1359
    unsigned int ii;
1360
10
    char stmp[AIR_STRLEN_SMALL];
1361
44
    for (ii=0; ii<ninA->cmtArr->len; ii++) {
1362
12
      sprintf(stmp, "comment[%u]", ii);
1363

12
      STRING_COMPARE(cmt[ii], stmp);
1364
    }
1365
20
  }
1366
10
  if (ninA->kvpArr->len != ninB->kvpArr->len) {
1367
    *differ = ninA->kvpArr->len < ninB->kvpArr->len ? -1 : 1;
1368
    if (explain) {
1369
      sprintf(explain, "ninA # key/values %u %s ninB # key/values %u",
1370
              ninA->kvpArr->len, *differ < 0 ? "<" : ">", ninB->kvpArr->len);
1371
    }
1372
    return 0;
1373
  } else {
1374
    unsigned int ii;
1375
10
    char stmp[AIR_STRLEN_SMALL];
1376
32
    for (ii=0; ii<ninA->kvpArr->len; ii++) {
1377
6
      sprintf(stmp, "key/value key[%u]", ii);
1378

6
      STRING_COMPARE(kvp[2*ii + 0], stmp);
1379
6
      sprintf(stmp, "key/value value[%u]", ii);
1380

6
      STRING_COMPARE(kvp[2*ii + 1], stmp);
1381
    }
1382
20
  }
1383
#undef STRING_COMPARE
1384
  /* ninA->ptr and ninB->ptr are not to be accessed */
1385
1386
  /* if we've gotten this far, all fields were equal */
1387
10
  *differ = 0;
1388
10
  return 0;
1389
10
}
1390
1391
/*
1392
******** nrrdPPM()
1393
**
1394
** for making a nrrd suitable for holding PPM data
1395
**
1396
** "don't mess with peripheral information"
1397
*/
1398
int
1399
nrrdPPM(Nrrd *ppm, size_t sx, size_t sy) {
1400
  static const char me[]="nrrdPPM";
1401
  char stmp[2][AIR_STRLEN_SMALL];
1402
1403
  if (nrrdMaybeAlloc_va(ppm, nrrdTypeUChar, 3,
1404
                        AIR_CAST(size_t, 3), sx, sy)) {
1405
    biffAddf(NRRD, "%s: couldn't allocate %s x %s 24-bit image", me,
1406
             airSprintSize_t(stmp[0], sx),
1407
             airSprintSize_t(stmp[1], sy));
1408
    return 1;
1409
  }
1410
  return 0;
1411
}
1412
1413
/*
1414
******** nrrdPGM()
1415
**
1416
** for making a nrrd suitable for holding PGM data
1417
**
1418
** "don't mess with peripheral information"
1419
*/
1420
int
1421
nrrdPGM(Nrrd *pgm, size_t sx, size_t sy) {
1422
  static const char me[]="nrrdPGM";
1423
  char stmp[2][AIR_STRLEN_SMALL];
1424
1425
  if (nrrdMaybeAlloc_va(pgm, nrrdTypeUChar, 2,
1426
                        sx, sy)) {
1427
    biffAddf(NRRD, "%s: couldn't allocate %s x %s 8-bit image", me,
1428
             airSprintSize_t(stmp[0], sx),
1429
             airSprintSize_t(stmp[1], sy));
1430
    return 1;
1431
  }
1432
  return 0;
1433
}
1434
1435
/* ---- END non-NrrdIO */