Bug Summary

File:src/nrrd/read.c
Location:line 159, column 19
Description:Dereference of undefined pointer value

Annotated Source Code

1/*
2 Teem: Tools to process and visualize scientific data and images .
3 Copyright (C) 2013, 2012, 2011, 2010, 2009 University of Chicago
4 Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann
5 Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public License
9 (LGPL) as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11 The terms of redistributing and/or modifying this software also
12 include exceptions to the LGPL that facilitate static linking.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with this library; if not, write to Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22*/
23
24#include "nrrd.h"
25#include "privateNrrd.h"
26
27#if TEEM_BZIP21
28#include <bzlib.h>
29#endif
30
31/* The "/ *Teem:" (without space) comments in here are an experiment */
32
33char _nrrdRelativePathFlag[] = "./";
34char _nrrdFieldSep[] = " \t";
35char _nrrdLineSep[] = "\r\n";
36char _nrrdNoSpaceVector[] = "none";
37char _nrrdTextSep[] = " ,\t";
38
39/*
40** return length of next "line" in nio->headerStringRead
41*/
42unsigned int
43_nrrdHeaderStringOneLineStrlen(NrrdIoState *nio) {
44
45 return AIR_CAST(unsigned int,((unsigned int)(strcspn(nio->headerStringRead + nio->headerStrpos
, _nrrdLineSep)))
46 strcspn(nio->headerStringRead + nio->headerStrpos, _nrrdLineSep))((unsigned int)(strcspn(nio->headerStringRead + nio->headerStrpos
, _nrrdLineSep)))
;
47}
48
49/*
50** read next "line" in nio->headerStringRead
51*/
52unsigned int
53_nrrdHeaderStringOneLine(NrrdIoState *nio) {
54 unsigned int len1, len2;
55
56 len1 = _nrrdHeaderStringOneLineStrlen(nio);
57 strncpy(nio->line, nio->headerStringRead + nio->headerStrpos, len1)__builtin___strncpy_chk (nio->line, nio->headerStringRead
+ nio->headerStrpos, len1, __builtin_object_size (nio->
line, 2 > 1 ? 1 : 0))
;
58 nio->line[len1] = '\0';
59 nio->headerStrpos += len1;
60 len2 = AIR_CAST(unsigned int,((unsigned int)(strspn(nio->headerStringRead + nio->headerStrpos
, _nrrdLineSep)))
61 strspn(nio->headerStringRead + nio->headerStrpos, _nrrdLineSep))((unsigned int)(strspn(nio->headerStringRead + nio->headerStrpos
, _nrrdLineSep)))
;
62 nio->headerStrpos += len2;
63 return len1;
64}
65
66/*
67** _nrrdOneLine
68**
69** wrapper around airOneLine; does re-allocation of line buffer
70** ("line") in the NrrdIoState if needed. The return value semantics
71** are similar, except that what airOneLine would return, we put
72** in *lenP. If there is an error (airOneLine returned 0,
73** something couldn't be allocated), *lenP is set to 0, and
74** we return 1. HITTING EOF IS NOT ACTUALLY AN ERROR, see code
75** below. Otherwise we return 0.
76**
77** Does use biff
78*/
79int
80_nrrdOneLine(unsigned int *lenP, NrrdIoState *nio, FILE *file) {
81 static const char me[]="_nrrdOneLine";
82 char **line;
4
'line' declared without an initial value
83 airArray *mop, *lineArr;
84 airPtrPtrUnion appu;
85 unsigned int lineIdx, len, needLen;
86
87 if (!( lenP && nio && (file || nio->headerStringRead))) {
5
Taking false branch
88 biffAddf(NRRDnrrdBiffKey, "%s: got NULL pointer (%p, %p, %p/%p)", me,
89 AIR_CAST(void*, lenP)((void*)(lenP)), AIR_CAST(void*, nio)((void*)(nio)),
90 AIR_CAST(void*, file)((void*)(file)), nio->headerStringRead);
91 return 1;
92 }
93 if (0 == nio->lineLen) {
6
Taking false branch
94 /* nio->line hasn't been allocated for anything */
95 nio->lineLen = 3;
96 nio->line = (char*)malloc(nio->lineLen);
97 if (!nio->line) {
98 biffAddf(NRRDnrrdBiffKey, "%s: couldn't alloc %d-char line\n", me, nio->lineLen);
99 *lenP = 0; return 1;
100 }
101 }
102 if (file) {
7
Taking true branch
103 len = airOneLine(file, nio->line, nio->lineLen);
104 } else {
105 /* NOTE: NULL-ity error check above makes this safe */
106 needLen = _nrrdHeaderStringOneLineStrlen(nio);
107 if (needLen+1 > nio->lineLen) {
108 nio->lineLen = needLen+1;
109 airFree(nio->line); /* lose previous allocated line */
110 nio->line = (char*)malloc(nio->lineLen);
111 if (!nio->line) {
112 biffAddf(NRRDnrrdBiffKey, "%s: couldn't alloc %d-char line\n",
113 me, nio->lineLen);
114 *lenP = 0; return 1;
115 }
116 }
117 len = _nrrdHeaderStringOneLine(nio);
118 }
119 if (len <= nio->lineLen) {
8
Taking false branch
120 /* otherwise we hit EOF (or end of nio->headerStringRead) before a
121 newline, or the line (possibly empty) fit within the nio->line,
122 neither of which is an error here */
123 *lenP = len;
124 } else {
125 /* line didn't fit in buffer, so we have to increase line
126 buffer size and put the line together in pieces */
127 /* NOTE: this will never happen when reading from nio->headerStringRead */
128 appu.cp = &line;
129 lineArr = airArrayNew(appu.v, NULL((void*)0), sizeof(char *), 1);
130 if (!lineArr) {
9
Assuming 'lineArr' is non-null
10
Taking false branch
131 biffAddf(NRRDnrrdBiffKey, "%s: couldn't allocate airArray", me);
132 *lenP = 0; return 1;
133 }
134 airArrayPointerCB(lineArr, airNull, airFree);
135 mop = airMopNew();
136 airMopAdd(mop, lineArr, (airMopper)airArrayNuke, airMopAlways);
137 while (len == nio->lineLen+1) {
11
Loop condition is false. Execution continues on line 154
138 lineIdx = airArrayLenIncr(lineArr, 1);
139 if (!lineArr->data) {
140 biffAddf(NRRDnrrdBiffKey, "%s: couldn't increment line buffer array", me);
141 *lenP = 0; airMopError(mop); return 1;
142 }
143 line[lineIdx] = nio->line;
144 nio->lineLen *= 2;
145 nio->line = (char*)malloc(nio->lineLen);
146 if (!nio->line) {
147 biffAddf(NRRDnrrdBiffKey, "%s: couldn't alloc %d-char line\n",
148 me, nio->lineLen);
149 *lenP = 0; airMopError(mop); return 1;
150 }
151 len = airOneLine(file, nio->line, nio->lineLen);
152 }
153 /* last part did fit in nio->line buffer, also save this into line[] */
154 lineIdx = airArrayLenIncr(lineArr, 1);
155 if (!lineArr->data) {
12
Taking false branch
156 biffAddf(NRRDnrrdBiffKey, "%s: couldn't increment line buffer array", me);
157 *lenP = 0; airMopError(mop); return 1;
158 }
159 line[lineIdx] = nio->line;
13
Dereference of undefined pointer value
160 nio->lineLen *= 3; /* for good measure */
161 nio->line = (char*)malloc(nio->lineLen);
162 if (!nio->line) {
163 biffAddf(NRRDnrrdBiffKey, "%s: couldn't alloc %d-char line\n", me, nio->lineLen);
164 *lenP = 0; airMopError(mop); return 1;
165 }
166 /* now concatenate everything into a new nio->line */
167 strcpy(nio->line, "")__builtin___strcpy_chk (nio->line, "", __builtin_object_size
(nio->line, 2 > 1 ? 1 : 0))
;
168 for (lineIdx=0; lineIdx<lineArr->len; lineIdx++) {
169 strcat(nio->line, line[lineIdx])__builtin___strcat_chk (nio->line, line[lineIdx], __builtin_object_size
(nio->line, 2 > 1 ? 1 : 0))
;
170 }
171 /* HEY: API is bad: *lenP should be a size_t pointer! */
172 *lenP = AIR_UINT(strlen(nio->line))((unsigned int)(strlen(nio->line))) + 1;
173 airMopError(mop);
174 }
175 return 0;
176}
177
178/*
179** _nrrdCalloc()
180**
181** allocates the data for the array, but only if necessary (as informed by
182** nio->oldData and nio->oldDataSize).
183**
184** as a recent feature, this will handle the extra work of allocating
185** memory in the special way required for direct IO, if possible. For
186** this to work, though, the FILE *file has to be passed. Since file
187** is not otherwise needed, it can be passed as NULL for non-direct-IO
188** situations. In any case, if the directIO-compatible allocation fails
189** its not error, and we revert to regular allocation.
190**
191** NOTE: this assumes the checking that is done by _nrrdHeaderCheck
192*/
193int
194_nrrdCalloc(Nrrd *nrrd, NrrdIoState *nio, FILE *file) {
195 static const char me[]="_nrrdCalloc";
196 size_t needDataSize;
197 int fd;
198
199 needDataSize = nrrdElementNumber(nrrd)*nrrdElementSize(nrrd);
200 if (nio->oldData && needDataSize == nio->oldDataSize) {
201 /* re-use old data */
202 nrrd->data = nio->oldData;
203 /* its not an error to have a directIO-incompatible pointer, so
204 there's no other error checking to do here */
205 } else {
206 nrrd->data = airFree(nrrd->data);
207 fd = file ? fileno(file) : -1;
208 if (nrrdEncodingRaw == nio->encoding
209 && -1 != fd
210 && airNoDio_okay == airDioTest(fd, NULL((void*)0), needDataSize)) {
211 nrrd->data = airDioMalloc(needDataSize, fd);
212 }
213 if (!nrrd->data) {
214 /* directIO-compatible allocation wasn't tried, or it failed */
215 nrrd->data = malloc(needDataSize);
216 }
217 if (!nrrd->data) {
218 char stmp1[AIR_STRLEN_SMALL(128+1)], stmp2[AIR_STRLEN_SMALL(128+1)];
219 biffAddf(NRRDnrrdBiffKey, "%s: couldn't allocate %s things of size %s", me,
220 airSprintSize_t(stmp1, nrrdElementNumber(nrrd)),
221 airSprintSize_t(stmp2, nrrdElementSize(nrrd)));
222 return 1;
223 }
224 }
225 /* make it look like it came from calloc(), as used by nrrdNew() */
226 memset(nrrd->data, 0, needDataSize)__builtin___memset_chk (nrrd->data, 0, needDataSize, __builtin_object_size
(nrrd->data, 0))
;
227 return 0;
228}
229
230/*
231******** nrrdLineSkip
232**
233** public for the sake of things like "unu make"
234** uses the NrrdIoState for its line buffer (used by _nrrdOneLine)
235*/
236int
237nrrdLineSkip(FILE *dataFile, NrrdIoState *nio) {
238 static const char me[]="nrrdLineSkip";
239 unsigned int lsi, skipRet;
240
241 /* For compressed data: If you don't actually have ascii headers on
242 top of your gzipped data then you will potentially huge lines
243 while _nrrdOneLine looks for line terminations. Quoting Gordon:
244 "Garbage in, Garbage out." */
245
246 if (!( dataFile && nio )) {
1
Taking false branch
247 biffAddf(NRRDnrrdBiffKey, "%s: got NULL pointer", me);
248 return 1;
249 }
250
251 for (lsi=0; lsi<nio->lineSkip; lsi++) {
2
Loop condition is true. Entering loop body
252 if (_nrrdOneLine(&skipRet, nio, dataFile)) {
3
Calling '_nrrdOneLine'
253 biffAddf(NRRDnrrdBiffKey, "%s: error skipping line %u of %u",
254 me, lsi+1, nio->lineSkip);
255 return 1;
256 }
257 if (!skipRet) {
258 biffAddf(NRRDnrrdBiffKey, "%s: hit EOF skipping line %u of %u",
259 me, lsi+1, nio->lineSkip);
260 return 1;
261 }
262 }
263 return 0;
264}
265
266int
267_nrrdByteSkipSkip(FILE *dataFile, Nrrd *nrrd, NrrdIoState *nio, long int byteSkip) {
268 static const char me[]="nrrdByteSkipSkip";
269 int skipRet;
270 size_t bsize;
271
272 if (!( dataFile && nrrd && nio )) {
273 biffAddf(NRRDnrrdBiffKey, "%s: got NULL pointer", me);
274 return 1;
275 }
276 if (nio->encoding->isCompression) {
277 biffAddf(NRRDnrrdBiffKey, "%s: this function can't work with compressed "
278 "encoding %s", me, nio->encoding->name);
279 return 1;
280 }
281 if (byteSkip < 0) {
282 long backwards;
283 if (nrrdEncodingRaw != nio->encoding) {
284 biffAddf(NRRDnrrdBiffKey, "%s: this function can do backwards byte skip only "
285 "in %s encoding, not %s", me,
286 nrrdEncodingRaw->name, nio->encoding->name);
287 return 1;
288 }
289 if (stdin__stdinp == dataFile) {
290 biffAddf(NRRDnrrdBiffKey, "%s: can't fseek on stdin", me);
291 return 1;
292 }
293 bsize = nrrdElementNumber(nrrd)/_nrrdDataFNNumber(nio);
294 bsize *= nrrdElementSize(nrrd);
295 /* backwards is (positive) number of bytes AFTER data that we ignore */
296 backwards = -byteSkip - 1;
297 /* HEY what if bsize fits in size_t but not in (signed) long? */
298 if (fseek(dataFile, -AIR_CAST(long, bsize)((long)(bsize)) - backwards, SEEK_END2)) {
299 char stmp[AIR_STRLEN_SMALL(128+1)];
300 biffAddf(NRRDnrrdBiffKey, "%s: failed to fseek(dataFile, %s, SEEK_END)", me,
301 airSprintSize_t(stmp, bsize));
302 return 1;
303 }
304 if (nrrdStateVerboseIO >= 2) {
305 fprintf(stderr__stderrp, "(%s: actually skipped %d bytes)\n",
306 me, (int)ftell(dataFile));
307 }
308 } else {
309 if ((stdin__stdinp == dataFile) || (-1==fseek(dataFile, byteSkip, SEEK_CUR1))) {
310 long skipi;
311 /* fseek failed, perhaps because we're reading stdin, so
312 we revert to consuming the input one byte at a time */
313 for (skipi=0; skipi<byteSkip; skipi++) {
314 skipRet = fgetc(dataFile);
315 if (EOF(-1) == skipRet) {
316 biffAddf(NRRDnrrdBiffKey, "%s: hit EOF skipping byte %ld of %ld",
317 me, skipi, byteSkip);
318 return 1;
319 }
320 }
321 }
322 }
323 return 0;
324}
325
326/*
327******** nrrdByteSkip
328**
329** public for the sake of things like "unu make"
330** uses nio for information about how much data should actually be skipped
331** with negative byteSkip
332*/
333int
334nrrdByteSkip(FILE *dataFile, Nrrd *nrrd, NrrdIoState *nio) {
335 static const char me[]="nrrdByteSkip";
336
337 if (!( dataFile && nrrd && nio )) {
338 biffAddf(NRRDnrrdBiffKey, "%s: got NULL pointer", me);
339 return 1;
340 }
341 /* HEY: with the advent of NRRD0006 per-file skips, maybe this is
342 the function that should be public */
343 if (_nrrdByteSkipSkip(dataFile, nrrd, nio, nio->byteSkip)) {
344 biffAddf(NRRDnrrdBiffKey, "%s: trouble", me);
345 return 1;
346 }
347
348 return 0;
349}
350
351/*
352** _nrrdRead()
353**
354** read in nrrd from a given file *OR* given string. The main job of
355** this function is to start reading the file/string, to determine the
356** format, and then call the appropriate format's reader. This means
357** that the various encoding (data) readers can assume that
358** nio->format is usefully set.
359**
360** If (file), the only input information that nio is used for is
361** nio->path, so that detached header-relative data files can be
362** found. If (string), the headerStr-related fields in the _nio will
363** be set/used
364*/
365int
366_nrrdRead(Nrrd *nrrd, FILE *file, const char *string, NrrdIoState *_nio) {
367 static const char me[]="_nrrdRead";
368 unsigned int llen;
369 NrrdIoState *nio;
370 int nfi;
371 airArray *mop;
372
373 /* sanity check, for good measure */
374 if (!nrrdSanity()) {
375 biffAddf(NRRDnrrdBiffKey, "%s: sanity check FAILED: have to fix and re-compile",
376 me);
377 return 1;
378 }
379
380 if (!((file || string) && nrrd)) {
381 biffAddf(NRRDnrrdBiffKey, "%s: got NULL pointer", me);
382 return 1;
383 }
384 if (file && string) {
385 biffAddf(NRRDnrrdBiffKey, "%s: can't read from both file and string", me);
386 return 1;
387 }
388 mop = airMopNew();
389 if (_nio) {
390 nio = _nio;
391 } else {
392 nio = nrrdIoStateNew();
393 if (!nio) {
394 biffAddf(NRRDnrrdBiffKey, "%s: couldn't alloc I/O struct", me);
395 return 1;
396 }
397 airMopAdd(mop, nio, (airMopper)nrrdIoStateNix, airMopAlways);
398 }
399
400 /* remember old data pointer and allocated size. Whether or not to
401 free() this memory will be decided later */
402 nio->oldData = nrrd->data;
403 nio->oldDataSize = (nio->oldData
404 ? nrrdElementNumber(nrrd)*nrrdElementSize(nrrd)
405 : 0);
406 /*
407 fprintf(stderr, "!%s: nio->oldData = %p, oldDataSize = %d\n", me,
408 nio->oldData, (int)(nio->oldDataSize));
409 */
410 nrrd->data = NULL((void*)0);
411
412 /* initialize given nrrd (but we have thwarted freeing existing memory) */
413 nrrdInit(nrrd);
414
415 /* tell the nio where to find the string to read from */
416 nio->headerStringRead = string;
417
418 if (_nrrdOneLine(&llen, nio, file)) {
419 biffAddf(NRRDnrrdBiffKey, "%s: error getting first line (containing \"magic\")",
420 me);
421 airMopError(mop); return 1;
422 }
423 if (!llen) {
424 biffAddf(NRRDnrrdBiffKey, "%s: immediately hit EOF", me);
425 airMopError(mop); return 1;
426 }
427
428 nio->format = nrrdFormatUnknown;
429 for (nfi = nrrdFormatTypeUnknown+1;
430 nfi < nrrdFormatTypeLast;
431 nfi++) {
432 if (nrrdFormatArray[nfi]->contentStartsLike(nio)) {
433 nio->format = nrrdFormatArray[nfi];
434 break;
435 }
436 }
437 if (nrrdFormatUnknown == nio->format) {
438 char linestart[AIR_STRLEN_SMALL(128+1)], stmp[AIR_STRLEN_SMALL(128+1)];
439 airStrcpy(linestart, AIR_STRLEN_SMALL(128+1), nio->line);
440 if (strlen(linestart) != strlen(nio->line)) {
441 biffAddf(NRRDnrrdBiffKey, "%s: couldn't parse (length %s) line starting "
442 "with \"%s\" as magic or beginning of any recognized format",
443 me, airSprintSize_t(stmp, strlen(nio->line)), linestart);
444 } else {
445 biffAddf(NRRDnrrdBiffKey, "%s: couldn't parse \"%s\" as magic or beginning "
446 "of any recognized format", me, nio->line);
447 }
448 airMopError(mop); return 1;
449 }
450 if (string && nrrdFormatNRRD != nio->format) {
451 biffAddf(NRRDnrrdBiffKey, "%s: sorry, can only read %s files from strings (not %s)",
452 me, nrrdFormatNRRD->name, nio->format->name);
453 airMopError(mop); return 1;
454 }
455
456 /* try to read the file */
457 if (nio->format->read(file, nrrd, nio)) {
458 biffAddf(NRRDnrrdBiffKey, "%s: trouble reading %s file", me, nio->format->name);
459 airMopError(mop); return 1;
460 }
461
462 /* reshape up grayscale images, if desired */
463 if (nio->format->isImage && 2 == nrrd->dim && nrrdStateGrayscaleImage3D) {
464 if (nrrdAxesInsert(nrrd, nrrd, 0)) {
465 biffAddf(NRRDnrrdBiffKey, "%s:", me);
466 return 1;
467 }
468 }
469
470 /* free prior memory if we didn't end up using it */
471 /* HEY: could actually do a check on the nio to refine this */
472 if (nio->oldData != nrrd->data) {
473 nio->oldData = airFree(nio->oldData);
474 nio->oldDataSize = 0;
475 }
476
477 /* finally, make sure that what we're returning isn't malformed somehow,
478 except that we (probably stupidly) allow nrrd->data to be NULL, given
479 the possibility of using nio->skipData */
480 if (_nrrdCheck(nrrd, AIR_FALSE0, AIR_TRUE1)) {
481 biffAddf(NRRDnrrdBiffKey, "%s: problem with nrrd after reading", me);
482 return 1;
483 }
484
485 airMopOkay(mop);
486 return 0;
487}
488
489/*
490******** nrrdRead()
491**
492** now just a wrapper around _nrrdRead(); reads a NRRD from a FILE *
493*/
494int
495nrrdRead(Nrrd *nrrd, FILE *file, NrrdIoState *_nio) {
496 static const char me[]="nrrdRead";
497
498 if (_nrrdRead(nrrd, file, NULL((void*)0), _nio)) {
499 biffAddf(NRRDnrrdBiffKey, "%s: trouble", me);
500 return 1;
501 }
502 return 0;
503}
504
505/*
506******** nrrdStringRead()
507**
508** also a wrapper around _nrrdRead(); reads a NRRD from a char *.
509**
510** Because the same underlying _nrrdRead() is used, the same semantics
511** about using existing nrrd->data when possible applies, as does the
512** action of nrrdStateGrayscaleImage3D
513*/
514int
515nrrdStringRead(Nrrd *nrrd, const char *string, NrrdIoState *_nio) {
516 static const char me[]="nrrdRead";
517
518 if (_nrrdRead(nrrd, NULL((void*)0), string, _nio)) {
519 biffAddf(NRRDnrrdBiffKey, "%s: trouble", me);
520 return 1;
521 }
522 return 0;
523}
524
525/*
526** _nrrdSplitName()
527**
528** splits a file name into a path and a base filename. The path
529** separator is '/', but there is a hack (thanks Torsten Rohlfing)
530** which allows '\' to work on Windows. The division between the path
531** and the base is the last path separator in the file name. The path
532** is everything prior to this, and base is everything after (so the
533** base does NOT start with the path separator). If there is not a
534** '/' in the name, or if a path separator appears as the last
535** character, then the path is set to ".", and the name is copied into
536** base.
537*/
538void
539_nrrdSplitName(char **dirP, char **baseP, const char *name) {
540 char *where;
541
542 if (dirP) {
543 *dirP = (char *)airFree(*dirP);
544 }
545 if (baseP) {
546 *baseP = (char *)airFree(*baseP);
547 }
548 where = strrchr(name, '/');
549#ifdef _WIN32
550 /* Deal with Windows "\" path separators; thanks to Torsten Rohlfing */
551 if ( !where || (strrchr(name, '\\') > where) ) {
552 where = strrchr(name, '\\');
553 }
554#endif
555 /* we found a valid break if the last directory character
556 is somewhere in the string except the last character */
557 if (where && airStrlen(where) > 1) {
558 if (dirP) {
559 *dirP = airStrdup(name);
560 (*dirP)[where - name] = 0;
561 }
562 if (baseP) {
563 *baseP = airStrdup(where + 1);
564 }
565 } else {
566 /* if the name had no slash, its in the current directory, which
567 means that we need to explicitly store "." as the header
568 directory in case we have header-relative data. */
569 if (dirP) {
570 *dirP = airStrdup(".");
571 }
572 if (baseP) {
573 *baseP = airStrdup(name);
574 }
575 }
576 return;
577}
578
579/*
580******** nrrdLoad()
581**
582**
583**
584** call tree for this, to help figure out what's going on
585**
586** read.c/nrrdLoad
587** | read.c/_nrrdSplitName
588** | read.c/nrrdRead
589** | nio->format->read
590** = formatNRRD.c/_nrrdFormatNRRD_read:
591** | read.c/_nrrdOneLine
592** | parseNrrd.c/_nrrdReadNrrdParseField
593** | parseNrrd.c/nrrdFieldInfoParse[]
594** = parseNrrd.c/_nrrdReadNrrdParse_data_file
595** | fopen(dataName)
596** | formatNRRD.c/_nrrdHeaderCheck
597** | read.c/nrrdLineSkip
598** | read.c/nrrdByteSkip
599** | nio->encoding->read
600** = encodingRaw.c/_nrrdEncodingRaw_read
601** | read.c/_nrrdCalloc
602** | formatNRRD.c/nrrdSwapEndian
603** | miscAir.c/airFclose
604**
605** (more documentation here)
606**
607** sneakiness: returns 2 if the reason for problem was a failed fopen().
608**
609*/
610int /*Teem: biff if (ret) */
611nrrdLoad(Nrrd *nrrd, const char *filename, NrrdIoState *nio) {
612 static const char me[]="nrrdLoad";
613 FILE *file;
614 airArray *mop;
615
616 if (!(nrrd && filename)) {
617 biffAddf(NRRDnrrdBiffKey, "%s: got NULL pointer", me);
618 return 1;
619 }
620 mop = airMopNew();
621 if (!nio) {
622 nio = nrrdIoStateNew();
623 if (!nio) {
624 biffAddf(NRRDnrrdBiffKey, "%s: couldn't alloc I/O struct", me);
625 return 1;
626 }
627 airMopAdd(mop, nio, (airMopper)nrrdIoStateNix, airMopAlways);
628 }
629
630 /* we save the directory of the filename given to us so that if it turns
631 out that this is a detached header with a header-relative data file,
632 then we will know how to find the data file */
633 _nrrdSplitName(&(nio->path), NULL((void*)0), filename);
634 /* printf("!%s: |%s|%s|\n", me, nio->dir, nio->base); */
635
636 if (!( file = airFopen(filename, stdin__stdinp, "rb") )) {
637 biffAddf(NRRDnrrdBiffKey, "%s: fopen(\"%s\",\"rb\") failed: %s",
638 me, filename, strerror(errno(*__error())));
639 airMopError(mop); return 2;
640 }
641 airMopAdd(mop, file, (airMopper)airFclose, airMopOnError);
642 /* non-error exiting is handled below */
643
644 if (nrrdRead(nrrd, file, nio)) {
645 biffAddf(NRRDnrrdBiffKey, "%s: trouble reading \"%s\"", me, filename);
646 airMopError(mop); return 1;
647 }
648
649 if (nrrdFormatNRRD == nio->format
650 && nio->keepNrrdDataFileOpen
651 && file == nio->dataFile ) {
652 /* we have to keep the datafile open. If was attached, we can't
653 close file, because that is the datafile. If was detached,
654 file != nio->dataFile, so we can close file. */
655 } else {
656 /* always close non-NRRD files */
657 airFclose(file);
658 }
659
660 airMopOkay(mop);
661 return 0;
662}
663
664int
665nrrdLoadMulti(Nrrd *const *nin, unsigned int ninLen,
666 const char *fnameFormat,
667 unsigned int numStart, NrrdIoState *nio) {
668 static const char me[]="nrrdLoadMulti";
669 char *fname;
670 airArray *mop;
671 unsigned int nii;
672
673 if (!(nin && fnameFormat)) {
674 biffAddf(NRRDnrrdBiffKey, "%s: got NULL pointer", me);
675 return 1;
676 }
677 if (!( _nrrdContainsPercentThisAndMore(fnameFormat, 'u') )) {
678 biffAddf(NRRDnrrdBiffKey, "%s: given format \"%s\" doesn't seem to "
679 "have the \"%%u\" conversion specification to sprintf "
680 "an unsigned int\n", me, fnameFormat);
681 return 1;
682 }
683
684 mop = airMopNew();
685 /* should be big enough for the number replacing the format sequence */
686 fname = AIR_CAST(char *, malloc(strlen(fnameFormat) + 128))((char *)(malloc(strlen(fnameFormat) + 128)));
687 if (!(fname)) {
688 biffAddf(NRRDnrrdBiffKey, "%s: couldn't allocate local fname buffer", me);
689 airMopError(mop); return 1;
690 }
691 airMopAdd(mop, fname, airFree, airMopAlways);
692
693 for (nii=0; nii<ninLen; nii++) {
694 unsigned int num;
695 num = numStart + nii;
696 sprintf(fname, fnameFormat, num)__builtin___sprintf_chk (fname, 0, __builtin_object_size (fname
, 2 > 1 ? 1 : 0), fnameFormat, num)
;
697 if (nrrdLoad(nin[nii], fname, nio)) {
698 biffAddf(NRRDnrrdBiffKey, "%s: trouble loading nin[%u] from %s", me, nii, fname);
699 airMopError(mop); return 1;
700 }
701 /* HEY: GLK hopes that the nio doesn't have any state that needs
702 resetting, but we can't call nrrdIoStateInit() because that
703 would negate the purpose of sending in the nio for all but the
704 first saved nrrd */
705 }
706
707 airMopOkay(mop);
708 return 0;
709}