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