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 |
|
|
**** NONE of the nrrdKeyValue functions use biff. |
29 |
|
|
**** They don't use them now, and they never should. |
30 |
|
|
**** Unless I change my mind. |
31 |
|
|
***/ |
32 |
|
|
|
33 |
|
|
/* |
34 |
|
|
******** nrrdKeyValueSize |
35 |
|
|
** |
36 |
|
|
** returns the number of key/value pairs in a nrrd |
37 |
|
|
*/ |
38 |
|
|
unsigned int |
39 |
|
|
nrrdKeyValueSize(const Nrrd *nrrd) { |
40 |
|
|
|
41 |
✗✓ |
2 |
if (!nrrd) { |
42 |
|
|
return 0; |
43 |
|
|
} |
44 |
|
1 |
return nrrd->kvpArr->len; |
45 |
|
1 |
} |
46 |
|
|
|
47 |
|
|
/* |
48 |
|
|
******** nrrdKeyValueIndex |
49 |
|
|
** |
50 |
|
|
** given an int in [0 .. #key/value pairs - 1], sets *keyP and *valueP |
51 |
|
|
** to put to the corresponding key and value. |
52 |
|
|
** |
53 |
|
|
** NOTE: whether or not *keyP and *valueP are set to pointers to memory |
54 |
|
|
** "inside" the nrrd struct (pointers which you had better not free()!) |
55 |
|
|
** is controlled by nrrdStateKeyValueReturnInternalPointers, which defaults |
56 |
|
|
** to AIR_FALSE |
57 |
|
|
*/ |
58 |
|
|
void |
59 |
|
|
nrrdKeyValueIndex(const Nrrd *nrrd, char **keyP, char **valueP, |
60 |
|
|
unsigned int ki) { |
61 |
|
|
|
62 |
|
|
if (!( nrrd && keyP && valueP && ki < nrrd->kvpArr->len )) { |
63 |
|
|
if (keyP) { |
64 |
|
|
*keyP = NULL; |
65 |
|
|
} |
66 |
|
|
if (valueP) { |
67 |
|
|
*valueP = NULL; |
68 |
|
|
} |
69 |
|
|
return; |
70 |
|
|
} |
71 |
|
|
if (nrrdStateKeyValueReturnInternalPointers) { |
72 |
|
|
*keyP = nrrd->kvp[0 + 2*ki]; |
73 |
|
|
*valueP = nrrd->kvp[1 + 2*ki]; |
74 |
|
|
} else { |
75 |
|
|
*keyP = airStrdup(nrrd->kvp[0 + 2*ki]); |
76 |
|
|
*valueP = airStrdup(nrrd->kvp[1 + 2*ki]); |
77 |
|
|
} |
78 |
|
|
return; |
79 |
|
|
} |
80 |
|
|
|
81 |
|
|
static unsigned int |
82 |
|
|
_kvpIdxFind(const Nrrd *nrrd, const char *key, int *found) { |
83 |
|
|
unsigned int nk, ki, ret; |
84 |
|
|
|
85 |
|
226 |
nk = nrrd->kvpArr->len; |
86 |
✓✓ |
1492 |
for (ki=0; ki<nk; ki++) { |
87 |
✓✗ |
633 |
if (!strcmp(nrrd->kvp[0 + 2*ki], key)) { |
88 |
|
|
break; |
89 |
|
|
} |
90 |
|
|
} |
91 |
✗✓ |
113 |
if (ki<nk) { |
92 |
|
|
ret = ki; |
93 |
|
|
*found = AIR_TRUE; |
94 |
|
|
} else { |
95 |
|
|
ret = UINT_MAX; |
96 |
|
113 |
*found = AIR_FALSE; |
97 |
|
|
} |
98 |
|
113 |
return ret; |
99 |
|
|
} |
100 |
|
|
|
101 |
|
|
void |
102 |
|
|
nrrdKeyValueClear(Nrrd *nrrd) { |
103 |
|
|
unsigned int nk, ki; |
104 |
|
|
|
105 |
✗✓ |
4192 |
if (!nrrd) { |
106 |
|
|
return; |
107 |
|
|
} |
108 |
|
|
|
109 |
|
2096 |
nk = nrrd->kvpArr->len; |
110 |
✓✓ |
4418 |
for (ki=0; ki<nk; ki++) { |
111 |
|
113 |
nrrd->kvp[0 + 2*ki] = (char *)airFree(nrrd->kvp[0 + 2*ki]); |
112 |
|
113 |
nrrd->kvp[1 + 2*ki] = (char *)airFree(nrrd->kvp[1 + 2*ki]); |
113 |
|
|
} |
114 |
|
2096 |
airArrayLenSet(nrrd->kvpArr, 0); |
115 |
|
|
|
116 |
|
2096 |
return; |
117 |
|
2096 |
} |
118 |
|
|
|
119 |
|
|
int |
120 |
|
|
nrrdKeyValueErase(Nrrd *nrrd, const char *key) { |
121 |
|
|
unsigned int nk, ki; |
122 |
|
|
int found; |
123 |
|
|
|
124 |
|
|
if (!( nrrd && key )) { |
125 |
|
|
/* got NULL pointer */ |
126 |
|
|
return 1; |
127 |
|
|
} |
128 |
|
|
ki = _kvpIdxFind(nrrd, key, &found); |
129 |
|
|
if (!found) { |
130 |
|
|
return 0; |
131 |
|
|
} |
132 |
|
|
nrrd->kvp[0 + 2*ki] = (char *)airFree(nrrd->kvp[0 + 2*ki]); |
133 |
|
|
nrrd->kvp[1 + 2*ki] = (char *)airFree(nrrd->kvp[1 + 2*ki]); |
134 |
|
|
nk = nrrd->kvpArr->len; |
135 |
|
|
for (; ki<nk-1; ki++) { |
136 |
|
|
nrrd->kvp[0 + 2*ki] = nrrd->kvp[0 + 2*(ki+1)]; |
137 |
|
|
nrrd->kvp[1 + 2*ki] = nrrd->kvp[1 + 2*(ki+1)]; |
138 |
|
|
} |
139 |
|
|
airArrayLenIncr(nrrd->kvpArr, -1); |
140 |
|
|
|
141 |
|
|
return 0; |
142 |
|
|
} |
143 |
|
|
|
144 |
|
|
/* |
145 |
|
|
******** nrrdKeyValueAdd |
146 |
|
|
** |
147 |
|
|
** This will COPY the given strings, and so does not depend on |
148 |
|
|
** them existing past the return of this function |
149 |
|
|
** |
150 |
|
|
** NOTE: Despite what might be most logical, there is no effort made |
151 |
|
|
** here to cleanup key or value, including any escaping or filtering |
152 |
|
|
** that might be warranted for white space other than \n |
153 |
|
|
** |
154 |
|
|
** does NOT use BIFF |
155 |
|
|
*/ |
156 |
|
|
int |
157 |
|
|
nrrdKeyValueAdd(Nrrd *nrrd, const char *key, const char *value) { |
158 |
|
|
unsigned int ki; |
159 |
|
226 |
int found; |
160 |
|
|
|
161 |
✗✓ |
113 |
if (!( nrrd && key && value )) { |
162 |
|
|
/* got NULL pointer */ |
163 |
|
|
return 1; |
164 |
|
|
} |
165 |
✗✓ |
113 |
if (!strlen(key)) { |
166 |
|
|
/* reject empty keys */ |
167 |
|
|
return 1; |
168 |
|
|
} |
169 |
|
113 |
ki = _kvpIdxFind(nrrd, key, &found); |
170 |
✗✓ |
113 |
if (found) { |
171 |
|
|
/* over-writing value for an existing key, so have to free old value */ |
172 |
|
|
airFree(nrrd->kvp[1 + 2*ki]); |
173 |
|
|
nrrd->kvp[1 + 2*ki] = airStrdup(value); |
174 |
|
|
} else { |
175 |
|
|
/* adding value for a new key */ |
176 |
|
113 |
ki = airArrayLenIncr(nrrd->kvpArr, 1); |
177 |
|
113 |
nrrd->kvp[0 + 2*ki] = airStrdup(key); |
178 |
|
113 |
nrrd->kvp[1 + 2*ki] = airStrdup(value); |
179 |
|
|
} |
180 |
|
113 |
return 0; |
181 |
|
113 |
} |
182 |
|
|
|
183 |
|
|
/* |
184 |
|
|
******** nrrdKeyValueGet |
185 |
|
|
** |
186 |
|
|
** NOTE: whether or not *keyP and *valueP are set to pointers to memory |
187 |
|
|
** "inside" the nrrd struct (pointers which you had better not free()!) |
188 |
|
|
** is controlled by nrrdStateKeyValueReturnInternalPointers, which defaults |
189 |
|
|
** to AIR_FALSE |
190 |
|
|
** |
191 |
|
|
** does NOT use BIFF |
192 |
|
|
*/ |
193 |
|
|
char * |
194 |
|
|
nrrdKeyValueGet(const Nrrd *nrrd, const char *key) { |
195 |
|
|
char *ret; |
196 |
|
|
unsigned int ki; |
197 |
|
|
int found; |
198 |
|
|
|
199 |
|
|
if (!( nrrd && key )) { |
200 |
|
|
/* got NULL pointer */ |
201 |
|
|
return NULL; |
202 |
|
|
} |
203 |
|
|
ki = _kvpIdxFind(nrrd, key, &found); |
204 |
|
|
if (found) { |
205 |
|
|
if (nrrdStateKeyValueReturnInternalPointers) { |
206 |
|
|
ret = nrrd->kvp[1 + 2*ki]; |
207 |
|
|
} else { |
208 |
|
|
ret = airStrdup(nrrd->kvp[1 + 2*ki]); |
209 |
|
|
} |
210 |
|
|
} else { |
211 |
|
|
ret = NULL; |
212 |
|
|
} |
213 |
|
|
return ret; |
214 |
|
|
} |
215 |
|
|
|
216 |
|
|
/* |
217 |
|
|
** Does the escaping of special characters in a string that |
218 |
|
|
** is being written either to "FILE *file" or "char *dst" |
219 |
|
|
** (WHICH IS ASSUMED to be allocated to be big enough!) |
220 |
|
|
** Which characters to escape should be put in string "toescape" |
221 |
|
|
** currently supported: \n \ " |
222 |
|
|
** Also, converts characters in "tospace" to a space. Being in |
223 |
|
|
** toescape trumps being in tospace, so tospace can be harmlessly |
224 |
|
|
** set to, say, AIR_WHITESPACE. |
225 |
|
|
** |
226 |
|
|
** accident of history that this function is in this file |
227 |
|
|
*/ |
228 |
|
|
void |
229 |
|
|
_nrrdWriteEscaped(FILE *file, char *dst, const char *str, |
230 |
|
|
const char *toescape, const char *tospace) { |
231 |
|
|
/* static const char me[]="_nrrdWriteEscaped"; */ |
232 |
|
|
size_t ci, gslen; /* given strlen */ |
233 |
|
|
|
234 |
|
28 |
gslen = strlen(str); |
235 |
✓✓ |
257832 |
for (ci=0; ci<gslen; ci++) { |
236 |
|
|
char cc; |
237 |
|
128902 |
cc = str[ci]; |
238 |
✓✓ |
128902 |
if (strchr(toescape, cc)) { |
239 |
✓✓✓✓
|
134565 |
switch(cc) { |
240 |
|
|
case '\n': |
241 |
✓✗ |
1411 |
if (file) { |
242 |
|
1411 |
fprintf(file, "\\n"); |
243 |
|
1411 |
} else { |
244 |
|
|
strcat(dst, "\\n"); |
245 |
|
|
} |
246 |
|
|
break; |
247 |
|
|
case '\\': |
248 |
✓✗ |
1429 |
if (file) { |
249 |
|
1429 |
fprintf(file, "\\\\"); |
250 |
|
1429 |
} else { |
251 |
|
|
strcat(dst, "\\\\"); |
252 |
|
|
} |
253 |
|
|
break; |
254 |
|
|
case '"': |
255 |
✗✓ |
2901 |
if (file) { |
256 |
|
|
fprintf(file, "\\\""); |
257 |
|
|
} else { |
258 |
|
2901 |
strcat(dst, "\\\""); |
259 |
|
|
} |
260 |
|
|
break; |
261 |
|
|
} |
262 |
|
|
} else { |
263 |
✓✓ |
123161 |
if (strchr(tospace, cc)) { |
264 |
|
|
cc = ' '; |
265 |
|
6885 |
} |
266 |
✓✓ |
123161 |
if (file) { |
267 |
|
40252 |
fputc(cc, file); |
268 |
|
40252 |
} else { |
269 |
|
|
size_t dsln; |
270 |
|
82909 |
dsln = strlen(dst); |
271 |
|
82909 |
dst[dsln++] = cc; |
272 |
|
82909 |
dst[dsln] = '\0'; |
273 |
|
|
} |
274 |
|
|
} |
275 |
|
|
} |
276 |
|
|
return; |
277 |
|
14 |
} |
278 |
|
|
|
279 |
|
|
/* |
280 |
|
|
** _nrrdKeyValueWrite |
281 |
|
|
** |
282 |
|
|
** writes a given key and value to a file, starting with the given |
283 |
|
|
** prefix (if non-NULL), and ending with "\n" |
284 |
|
|
*/ |
285 |
|
|
int |
286 |
|
|
_nrrdKeyValueWrite(FILE *file, char **stringP, const char *prefix, |
287 |
|
|
const char *key, const char *value) { |
288 |
|
|
|
289 |
✗✓ |
6 |
if (!( (file || stringP) && key && value )) { |
290 |
|
|
return 1; |
291 |
|
|
} |
292 |
✗✓ |
3 |
if (stringP) { |
293 |
|
|
/* 2*strlen() because at worst all characters will be escaped */ |
294 |
|
|
*stringP = AIR_CALLOC(airStrlen(prefix) + 2*airStrlen(key) |
295 |
|
|
+ strlen(":=") + 2*airStrlen(value) |
296 |
|
|
+ strlen("\n") + 1, char); |
297 |
|
|
/* HEY error checking? */ |
298 |
|
|
} |
299 |
✗✓ |
3 |
if (prefix) { |
300 |
|
|
if (file) { |
301 |
|
|
fprintf(file, "%s", prefix); |
302 |
|
|
} else { |
303 |
|
|
strcat(*stringP, prefix); |
304 |
|
|
} |
305 |
|
|
} |
306 |
✓✗ |
3 |
if (file) { |
307 |
|
3 |
_nrrdWriteEscaped(file, NULL, key, "\n\\", _NRRD_WHITESPACE_NOTAB); |
308 |
|
3 |
fprintf(file, ":="); |
309 |
|
3 |
_nrrdWriteEscaped(file, NULL, value, "\n\\", _NRRD_WHITESPACE_NOTAB); |
310 |
|
3 |
fprintf(file, "\n"); |
311 |
|
3 |
} else { |
312 |
|
|
_nrrdWriteEscaped(NULL, *stringP, key, "\n\\", _NRRD_WHITESPACE_NOTAB); |
313 |
|
|
strcat(*stringP, ":="); |
314 |
|
|
_nrrdWriteEscaped(NULL, *stringP, value, "\n\\", _NRRD_WHITESPACE_NOTAB); |
315 |
|
|
strcat(*stringP, "\n"); |
316 |
|
|
} |
317 |
|
3 |
return 0; |
318 |
|
3 |
} |
319 |
|
|
|
320 |
|
|
/* |
321 |
|
|
******** nrrdKeyValueCopy() |
322 |
|
|
** |
323 |
|
|
** copies key/value pairs from one nrrd to another |
324 |
|
|
** Existing key/value pairs in nout are blown away |
325 |
|
|
*/ |
326 |
|
|
int |
327 |
|
|
nrrdKeyValueCopy(Nrrd *nout, const Nrrd *nin) { |
328 |
|
|
char *key, *value; |
329 |
|
|
unsigned int ki; |
330 |
|
|
|
331 |
✗✓ |
246 |
if (!(nout && nin)) { |
332 |
|
|
/* got NULL pointer */ |
333 |
|
|
return 1; |
334 |
|
|
} |
335 |
✗✓ |
123 |
if (nout == nin) { |
336 |
|
|
/* can't satisfy semantics of copying with nout==nin */ |
337 |
|
|
return 2; |
338 |
|
|
} |
339 |
|
|
|
340 |
|
123 |
nrrdKeyValueClear(nout); |
341 |
✓✓ |
252 |
for (ki=0; ki<nin->kvpArr->len; ki++) { |
342 |
|
3 |
key = nin->kvp[0 + 2*ki]; |
343 |
|
3 |
value = nin->kvp[1 + 2*ki]; |
344 |
✗✓ |
3 |
if (nrrdKeyValueAdd(nout, key, value)) { |
345 |
|
|
return 3; |
346 |
|
|
} |
347 |
|
|
} |
348 |
|
|
|
349 |
|
123 |
return 0; |
350 |
|
123 |
} |