1 /*
2 NrrdIO: stand-alone code for basic nrrd functionality
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 software is provided 'as-is', without any express or implied
8 warranty. In no event will the authors be held liable for any
9 damages arising from the use of this software.
10
11 Permission is granted to anyone to use this software for any
12 purpose, including commercial applications, and to alter it and
13 redistribute it freely, subject to the following restrictions:
14
15 1. The origin of this software must not be misrepresented; you must
16 not claim that you wrote the original software. If you use this
17 software in a product, an acknowledgment in the product
18 documentation would be appreciated but is not required.
19
20 2. Altered source versions must be plainly marked as such, and must
21 not be misrepresented as being the original software.
22
23 3. This notice may not be removed or altered from any source distribution.
24 */
25
26 #include "NrrdIO.h"
27 #include "privateNrrd.h"
28
29 static int
_nrrdEncodingRaw_available(void)30 _nrrdEncodingRaw_available(void) {
31
32 return AIR_TRUE;
33 }
34
35 static int
_nrrdEncodingRaw_read(FILE * file,void * data,size_t elementNum,Nrrd * nrrd,NrrdIoState * nio)36 _nrrdEncodingRaw_read(FILE *file, void *data, size_t elementNum,
37 Nrrd *nrrd, NrrdIoState *nio) {
38 static const char me[]="_nrrdEncodingRaw_read";
39 size_t ret, bsize;
40 int fd, dio, car;
41 long savePos;
42 char *data_c;
43 size_t elementSize, maxChunkSize, remainderValue, chunkSize;
44 size_t retTmp;
45 char stmp[3][AIR_STRLEN_SMALL];
46
47 bsize = nrrdElementSize(nrrd)*elementNum;
48 if (nio->format->usesDIO) {
49 fd = fileno(file);
50 dio = airDioTest(fd, data, bsize);
51 } else {
52 fd = -1;
53 dio = airNoDio_format;
54 }
55 if (airNoDio_okay == dio) {
56 if (2 <= nrrdStateVerboseIO) {
57 fprintf(stderr, "with direct I/O ... ");
58 }
59 ret = airDioRead(fd, data, bsize);
60 if (ret != bsize) {
61 biffAddf(NRRD, "%s: airDioRead got read only %s of %sbytes "
62 "(%g%% of expected)", me,
63 airSprintSize_t(stmp[0], ret),
64 airSprintSize_t(stmp[1], bsize),
65 100.0*AIR_CAST(double, ret)/AIR_CAST(double, bsize));
66 return 1;
67 }
68 } else {
69 if (2 <= nrrdStateVerboseIO) {
70 if (AIR_DIO && nio->format->usesDIO) {
71 fprintf(stderr, "with fread(), not DIO: %s ...", airNoDioErr(dio));
72 }
73 }
74
75 /* HEY: There's a bug in fread/fwrite in gcc 4.2.1 (with SnowLeopard).
76 When it reads/writes a >=2GB data array, it pretends to succeed
77 (i.e. the return value is the right number) but it hasn't
78 actually read/written the data. The work-around is to loop
79 over the data, reading/writing 1GB (or smaller) chunks. */
80 ret = 0;
81 data_c = (char *)data;
82 elementSize = nrrdElementSize(nrrd);
83 maxChunkSize = 1024 * 1024 * 1024 / elementSize;
84 while(ret < elementNum) {
85 remainderValue = elementNum-ret;
86 if (remainderValue < maxChunkSize) {
87 chunkSize = remainderValue;
88 } else {
89 chunkSize = maxChunkSize;
90 }
91 retTmp =
92 fread(&(data_c[ret*elementSize]), elementSize, chunkSize, file);
93 ret += retTmp;
94 if (retTmp != chunkSize) {
95 biffAddf(NRRD, "%s: fread got only %s %s-sized things, not %s "
96 "(%g%% of expected)", me,
97 airSprintSize_t(stmp[0], ret),
98 airSprintSize_t(stmp[1], nrrdElementSize(nrrd)),
99 airSprintSize_t(stmp[2], elementNum),
100 100.0*AIR_CAST(double, ret)/AIR_CAST(double, elementNum));
101 return 1;
102 }
103 }
104
105 car = fgetc(file);
106 if (EOF != car) {
107 if (1 <= nrrdStateVerboseIO) {
108 fprintf(stderr, "%s: WARNING: finished reading raw data, "
109 "but file not at EOF\n", me);
110 }
111 ungetc(car, file);
112 }
113 if (2 <= nrrdStateVerboseIO && nio->byteSkip && stdin != file) {
114 savePos = ftell(file);
115 if (!fseek(file, 0, SEEK_END)) {
116 double frac = (AIR_CAST(double, bsize)
117 /AIR_CAST(double, ftell(file) + 1));
118 fprintf(stderr, "(%s: used %g%% of file for nrrd data)\n", me,
119 100.0*frac);
120 fseek(file, savePos, SEEK_SET);
121 }
122 }
123 }
124
125 return 0;
126 }
127
128 static int
_nrrdEncodingRaw_write(FILE * file,const void * data,size_t elementNum,const Nrrd * nrrd,NrrdIoState * nio)129 _nrrdEncodingRaw_write(FILE *file, const void *data, size_t elementNum,
130 const Nrrd *nrrd, NrrdIoState *nio) {
131 static const char me[]="_nrrdEncodingRaw_write";
132 int fd, dio;
133 size_t ret, bsize;
134 const char *data_c;
135 size_t elementSize, maxChunkSize, remainderValue, chunkSize;
136 size_t retTmp;
137 char stmp[3][AIR_STRLEN_SMALL];
138
139 bsize = nrrdElementSize(nrrd)*elementNum;
140 if (nio->format->usesDIO) {
141 fd = fileno(file);
142 dio = airDioTest(fd, data, bsize);
143 } else {
144 fd = -1;
145 dio = airNoDio_format;
146 }
147 if (airNoDio_okay == dio) {
148 if (2 <= nrrdStateVerboseIO) {
149 fprintf(stderr, "with direct I/O ... ");
150 }
151 ret = airDioWrite(fd, data, bsize);
152 if (ret != bsize) {
153 biffAddf(NRRD, "%s: airDioWrite wrote only %s of %s bytes "
154 "(%g%% of expected)", me,
155 airSprintSize_t(stmp[0], ret),
156 airSprintSize_t(stmp[1], bsize),
157 100.0*AIR_CAST(double, ret)/AIR_CAST(double, bsize));
158 return 1;
159 }
160 } else {
161 if (2 <= nrrdStateVerboseIO) {
162 if (AIR_DIO && nio->format->usesDIO) {
163 fprintf(stderr, "with fread(), not DIO: %s ...", airNoDioErr(dio));
164 }
165 }
166
167 /* HEY: There's a bug in fread/fwrite in gcc 4.2.1 (with SnowLeopard).
168 When it reads/writes a >=2GB data array, it pretends to succeed
169 (i.e. the return value is the right number) but it hasn't
170 actually read/written the data. The work-around is to loop
171 over the data, reading/writing 1GB (or smaller) chunks. */
172 ret = 0;
173 data_c = AIR_CAST(const char *, data);
174 elementSize = nrrdElementSize(nrrd);
175 maxChunkSize = 1024 * 1024 * 1024 / elementSize;
176 while(ret < elementNum) {
177 remainderValue = elementNum-ret;
178 if (remainderValue < maxChunkSize) {
179 chunkSize = remainderValue;
180 } else {
181 chunkSize = maxChunkSize;
182 }
183 retTmp =
184 fwrite(&(data_c[ret*elementSize]), elementSize, chunkSize, file);
185 ret += retTmp;
186 if (retTmp != chunkSize) {
187 biffAddf(NRRD, "%s: fwrite wrote only %s %s-sized things, not %s "
188 "(%g%% of expected)", me,
189 airSprintSize_t(stmp[0], ret),
190 airSprintSize_t(stmp[1], nrrdElementSize(nrrd)),
191 airSprintSize_t(stmp[2], elementNum),
192 100.0*AIR_CAST(double, ret)/AIR_CAST(double, elementNum));
193 return 1;
194 }
195 }
196
197 fflush(file);
198 /*
199 if (ferror(file)) {
200 biffAddf(NRRD, "%s: ferror returned non-zero", me);
201 return 1;
202 }
203 */
204 }
205 return 0;
206 }
207
208 const NrrdEncoding
209 _nrrdEncodingRaw = {
210 "raw", /* name */
211 "raw", /* suffix */
212 AIR_TRUE, /* endianMatters */
213 AIR_FALSE, /* isCompression */
214 _nrrdEncodingRaw_available,
215 _nrrdEncodingRaw_read,
216 _nrrdEncodingRaw_write
217 };
218
219 const NrrdEncoding *const
220 nrrdEncodingRaw = &_nrrdEncodingRaw;
221