1 #include <stdio.h>
2 #include <ctype.h>
3 #include <string.h>
4 #include "gifti_io.h"
5
6 #define GXML_MIN_BSIZE 2048
7 #define GXML_DEF_BSIZE 32768
8
9 /* local prototypes */
10 static int append_to_cdata (gxml_data *, const char *, int);
11 static int append_to_data (gxml_data *, const char *, int);
12 static int append_to_data_ascii(gxml_data *, const char *, int);
13 static int append_to_data_b64 (gxml_data *, char*,long long,const char*, int);
14 /*
15 static int append_to_data_b64gz(gxml_data *, const char *, int);
16 */
17
18 static int add_label_rgba (gxml_data *, giiLabelTable *, float *);
19 static int append_to_xform (gxml_data *, const char *, int);
20 static int apply_da_list_order (gxml_data *, const int *, int);
21 static int int_compare (const void * v0, const void * v1);
22 static int copy_b64_data (gxml_data *, const char *, char *, int, int*);
23 static int decode_ascii (gxml_data*,char*,int,int,void*,long long*,int*);
24 static int decode_b64 (gxml_data*, char*, int, char *, long long *);
25 static int disp_gxml_data (char *, gxml_data *, int);
26 static int ename2type (const char *);
27 static int epush (gxml_data *, int, const char *, const char **);
28 static int epop (gxml_data *, int, const char *);
29 static int free_xd_data (gxml_data *);
30 static int get_label_attrs (gxml_data *, const char **, int *, float *);
31 static int init_gxml_data (gxml_data *, int, const int *, int);
32 static int partial_buf_size (long long);
33
34 static int push_gifti (gxml_data *, const char **);
35 static int push_meta (gxml_data *);
36 static int push_md (gxml_data *);
37 static int push_name (gxml_data *);
38 static int push_value (gxml_data *);
39 static int push_LT (gxml_data *);
40 static int push_label (gxml_data *, const char **);
41 static int push_darray (gxml_data *, const char **);
42 static int push_cstm (gxml_data *);
43 static int push_data (gxml_data *);
44 static int push_dspace (gxml_data *);
45 static int push_xspace (gxml_data *);
46 static int push_xform (gxml_data *);
47 static int reset_xml_buf (gxml_data *, char **, int *);
48
49 static void show_attrs (gxml_data *,int,const char **);
50 static void show_depth (int, int, FILE *);
51 static void show_enames (FILE *);
52 static int show_stack (char *, gxml_data *);
53
54 static int short_sorted_da_list(gxml_data *dp, const int * dalist, int len);
55 static int stack_is_valid (gxml_data *);
56 static int whitespace_len (const char *, int);
57 static int update_xml_buf_size (gxml_data *, long long);
58 static int update_partial_buffer(char **, int *, long long, int);
59
60 static int count_bad_b64_chars (const char *, int);
61 static int show_bad_b64_chars (const char *, int);
62
63 static giiMetaData * find_current_MetaData(gxml_data *, int);
64
65 #ifndef XMLCALL
66 /* XMLCALL was added to expat in version 1.95.7 to define a calling convention,
67 * as cdecl
68 */
69 #if defined(XML_USE_MSC_EXTENSIONS)
70 #define XMLCALL __cdecl
71 #elif defined(__GNUC__) && defined(__i386)
72 #define XMLCALL __attribute__((cdecl))
73 #else
74 #define XMLCALL
75 #endif
76 #endif /* not defined XMLCALL */
77
78 #ifndef XML_STATUS_ERROR
79 #define XML_STATUS_ERROR 0
80 #endif
81 #ifndef XML_STATUS_OK
82 #define XML_STATUS_OK 1
83 #endif
84
85 static void XMLCALL cb_start_ele (void *, const char *, const char **);
86 static void XMLCALL cb_end_ele (void *, const char *);
87 static void XMLCALL cb_char (void *, const char *, int);
88 static void XMLCALL cb_instr (void *, const char *, const char *);
89 static void XMLCALL cb_comment (void *, const char *);
90 static void XMLCALL cb_cdata_start (void *);
91 static void XMLCALL cb_cdata_end (void *);
92 static void XMLCALL cb_default (void *, const char *, int);
93 static void XMLCALL cb_xml_dec (void *, const char *, const char * , int);
94 static void XMLCALL cb_start_doctype(void *, const char *, const char *,
95 const char *, int);
96 static void XMLCALL cb_end_doctype (void *);
97 static void XMLCALL cb_elem_dec (void *, const char *, XML_Content *);
98 static XML_Parser init_xml_parser (void *);
99
100 /* writing functions */
101 static int gxml_write_gifti (gxml_data *, FILE *);
102 static int gxml_write_preamble (FILE *);
103
104 static int ewrite_text_ele (int, const char *, const char *,
105 int, int, FILE *);
106 static int ewrite_coordsys (gxml_data *, giiCoordSystem *, FILE *);
107 static int ewrite_data (gxml_data *, giiDataArray *, FILE *);
108 static int ewrite_data_line (void *, int, long long, long long,
109 int, FILE *);
110 static int ewrite_double_line (double *, int, int, FILE *);
111 static int ewrite_int_attr (const char *, int, int, int, FILE *);
112 static int ewrite_long_long_attr (const char *, long long, int, int, FILE *);
113 static int ewrite_str_attr (const char*, const char*, int, int, FILE*);
114 static int ewrite_darray (gxml_data *, giiDataArray *, FILE *);
115 static int ewrite_ex_atrs (gxml_data *, nvpairs *, int, int, FILE *);
116 static int ewrite_LT (gxml_data*, giiLabelTable*, int, FILE*);
117 static int ewrite_meta (gxml_data *, giiMetaData *, FILE *);
118
119 static int gxml_disp_b64_data (const char *, const void *, int, FILE *);
120
121 /* these should match GXML_ETYPE_* defines */
122 static char * enames[GXML_MAX_ELEN] = {
123 "Invalid", "GIFTI", "MetaData", "MD", "Name", "Value", "LabelTable",
124 "Label", "DataArray", "CoordinateSystemTransformMatrix", "Data",
125 "DataSpace", "TransformedSpace", "MatrixData", "CDATA"
126 };
127
128 /* ---------------------------------------------------------------------- */
129 /* GIFTI XML global struct and access functions */
130 static gxml_data GXD = {
131 1, /* verb, default to 1 (0 means quiet) */
132 1, /* dstore, flag whether to store data */
133 3, /* indent, spaces per indent level */
134 GXML_DEF_BSIZE, /* buf_size, allocated for XML parsing */
135 GIFTI_B64_CHECK_SKIPNCOUNT, /* b64_check, for b64 errors */
136 1, /* assume it is okay to update metadata */
137 GZ_DEFAULT_COMPRESSION, /* zlevel, compress level, -1..9 */
138 1, /* perm_by_iord: permute by index order */
139
140 NULL, /* da_list, list of DA indices to store */
141 0, /* da_len, length of da_list */
142 0, /* da_ind, current index into da_list */
143
144 0, /* eleDA, number of DA elements found */
145 0, /* expDA, number of DA elements expected */
146 0, /* b64_errors, number of errors found */
147 0, /* errors, number of encountered errors */
148 0, /* skip depth (at positive depth, 0 is clear) */
149 0, /* depth, current stack depth */
150 {0}, /* stack, ints, max depth GXML_MAX_DEPTH */
151
152 0, /* dind, index into decoded data array */
153 0, /* clen, length of current CDATA string */
154 0, /* xlen, length of current xform buffer */
155 0, /* dlen, length of current Data buffer */
156 0, /* doff, offset into current data buffer */
157 0, /* zlen, length of compression buffer */
158 NULL, /* cdata, CDATA char pointer */
159 NULL, /* xdata, xform buffer pointer */
160 NULL, /* ddata, Data buffer pointer */
161 NULL, /* zdata, compression buffer pointer */
162 NULL /* gim, gifti_image *, for results */
163 };
164
165 #ifndef HAVE_ZLIB /* so we can print a callback message once per file */
166 static int g_first_zlib_err_msg = 1;
167 #endif
168
169 /*--- Base64 binary encoding and decoding tables ---*/
170
171 /* encoding: converting values 0-63 to characters */
172 static unsigned char b64_encode_table[64] = {
173 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 26 upper case */
174 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
175 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
176 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', /* 26 lower case */
177 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
178 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
179 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', /* 10 digits */
180 '+', '/'
181 };
182
183 /* decoding: converting characters A-Z, a-z, 0-9, +, /, to integers 0-63
184 * (other characters are considered invalid, though '=' is mapped to 0,
185 * to account for the end of input (didn't Arnold make a movie about that?))
186 */
187 static unsigned char b64_decode_table[256] = {
188 128, 128, 128, 128, 128, 128, 128, 128, /* 0 - 7 */
189 128, 128, 128, 128, 128, 128, 128, 128, /* 8 - 15 */
190 128, 128, 128, 128, 128, 128, 128, 128, /* 16 - 23 */
191 128, 128, 128, 128, 128, 128, 128, 128, /* 24 - 31 */
192 128, 128, 128, 128, 128, 128, 128, 128, /* 32 - 39 */
193
194 /* d['+'] = d[43] = 62, d['/'] = d[47] = 63 */
195 128, 128, 128, 62, 128, 128, 128, 63, /* 40 - 47 */
196
197 /* d['0'] = d[48] = 52, ... d['9'] = 61, d['='] = 0 */
198 52, 53, 54, 55, 56, 57, 58, 59, /* 48 - 55 */
199 60, 61, 128, 128, 128, 0, 128, 128, /* 56 - 63 */
200
201 /* d['A'] = d[65] = 0, ... d['Z'] = 25 */
202 128, 0, 1, 2, 3, 4, 5, 6, /* 64 - 71 */
203 7, 8, 9, 10, 11, 12, 13, 14, /* 72 - 79 */
204 15, 16, 17, 18, 19, 20, 21, 22, /* 80 - 87 */
205 23, 24, 25, 128, 128, 128, 128, 128, /* 88 - 95 */
206
207 /* d['a'] = d[97] = 26, ... d['a'] = 51 */
208 128, 26, 27, 28, 29, 30, 31, 32, /* 96 - 103 */
209 33, 34, 35, 36, 37, 38, 39, 40, /* 104 - 111 */
210 41, 42, 43, 44, 45, 46, 47, 48, /* 112 - 119 */
211 49, 50, 51, 128, 128, 128, 128, 128, /* 120 - 127 */
212
213 /* ... and the rest, are heeere in deecode liiiiiist! poor Mary Ann :( */
214 128, 128, 128, 128, 128, 128, 128, 128, /* 128 - 135 */
215 128, 128, 128, 128, 128, 128, 128, 128, /* 136 - 143 */
216 128, 128, 128, 128, 128, 128, 128, 128, /* 144 - 151 */
217 128, 128, 128, 128, 128, 128, 128, 128, /* 152 - 159 */
218 128, 128, 128, 128, 128, 128, 128, 128, /* 160 - 167 */
219 128, 128, 128, 128, 128, 128, 128, 128, /* 168 - 175 */
220 128, 128, 128, 128, 128, 128, 128, 128, /* 176 - 183 */
221 128, 128, 128, 128, 128, 128, 128, 128, /* 184 - 191 */
222 128, 128, 128, 128, 128, 128, 128, 128, /* 192 - 199 */
223 128, 128, 128, 128, 128, 128, 128, 128, /* 200 - 207 */
224 128, 128, 128, 128, 128, 128, 128, 128, /* 208 - 215 */
225 128, 128, 128, 128, 128, 128, 128, 128, /* 216 - 223 */
226 128, 128, 128, 128, 128, 128, 128, 128, /* 224 - 231 */
227 128, 128, 128, 128, 128, 128, 128, 128, /* 232 - 239 */
228 128, 128, 128, 128, 128, 128, 128, 128, /* 240 - 247 */
229 128, 128, 128, 128, 128, 128, 128, 128 /* 248 - 255 */
230 };
231
232 /* note: the buffer needs to be large enough to contain any contiguous
233 piece of (CDATA?) text, o.w. it will require parsing in pieces */
gxml_read_image(const char * fname,int read_data,const int * dalist,int dalen)234 gifti_image * gxml_read_image(const char * fname, int read_data,
235 const int * dalist, int dalen)
236 {
237 gxml_data * xd = &GXD; /* point to global struct */
238 XML_Parser parser;
239 unsigned blen;
240 FILE * fp;
241 char * buf = NULL;
242 int bsize; /* be sure it doesn't change at some point */
243 int done = 0, pcount = 1;
244
245 if( init_gxml_data(xd, 0, dalist, dalen) ) /* reset non-user variables */
246 return NULL;
247
248 xd->dstore = read_data; /* store for global access */
249
250 if( !fname ) {
251 fprintf(stderr,"** gxml_read_image: missing filename\n");
252 return NULL;
253 }
254
255 fp = fopen(fname, "r");
256 if( !fp ) {
257 fprintf(stderr,"** failed to open GIFTI XML file '%s'\n", fname);
258 return NULL;
259 }
260
261 /* create a new buffer */
262 bsize = 0;
263 if( reset_xml_buf(xd, &buf, &bsize) ) { fclose(fp); return NULL; }
264
265 if(xd->verb > 1) {
266 fprintf(stderr,"-- reading gifti image '%s'\n", fname);
267 if(xd->da_list) fprintf(stderr," (length %d DA list)\n", xd->da_len);
268 fprintf(stderr,"-- using %d byte XML buffer\n",bsize);
269 if(xd->verb > 4) show_enames(stderr);
270 }
271
272 /* allocate return structure */
273 xd->gim = (gifti_image *)calloc(1,sizeof(gifti_image));
274 if( !xd->gim ) {
275 fprintf(stderr,"** failed to alloc initial gifti_image\n");
276 free(buf);
277 return NULL;
278 }
279
280 /* create parser, init handlers */
281 parser = init_xml_parser((void *)xd);
282
283 while( !done )
284 {
285 if( reset_xml_buf(xd, &buf, &bsize) ) /* fail out */
286 { gifti_free_image(xd->gim); xd->gim = NULL; break; }
287
288 blen = fread(buf, 1, bsize, fp);
289 done = blen < bsize;
290
291 if(xd->verb > 3) fprintf(stderr,"-- XML_Parse # %d\n", pcount);
292 pcount++;
293 if( XML_Parse(parser, buf, blen, done) == XML_STATUS_ERROR) {
294 fprintf(stderr,"** %s at line %u\n",
295 XML_ErrorString(XML_GetErrorCode(parser)),
296 (unsigned int)XML_GetCurrentLineNumber(parser));
297 gifti_free_image(xd->gim);
298 xd->gim = NULL;
299 break;
300 }
301 }
302
303 if(xd->verb > 1) {
304 if(xd->gim)
305 fprintf(stderr,"-- have gifti image '%s', "
306 "(%d DA elements = %lld MB)\n",
307 fname, xd->gim->numDA, gifti_gim_DA_size(xd->gim,1));
308 else fprintf(stderr,"** gifti image '%s', failure\n", fname);
309 }
310
311 fclose(fp);
312 if( buf ) free(buf); /* parser buffer */
313 XML_ParserFree(parser);
314
315 if( dalist && xd->da_list )
316 if( apply_da_list_order(xd, dalist, dalen) ) {
317 fprintf(stderr,"** failed apply_da_list_order\n");
318 gifti_free_image(xd->gim);
319 xd->gim = NULL;
320 }
321
322 free_xd_data(xd); /* free data buffers */
323
324 /* if auto-permute, convert to row major order (appropriate for C) */
325 if( xd->perm_by_iord && read_data ) {
326 if( gifti_convert_ind_ord(xd->gim, GIFTI_IND_ORD_ROW_MAJOR) > 0 )
327 if( xd->verb > 0 )
328 fprintf(stderr,"++ converted data to row major order: %s\n",fname);
329 }
330
331 return xd->gim;
332 }
333
334
335 /* note: the buffer needs to be large enough to contain any contiguous
336 piece of (CDATA?) text, o.w. it will require parsing in pieces */
gxml_read_image_buf(const char * buf_in,long long bin_len,const int * dalist,int dalen)337 gifti_image * gxml_read_image_buf(const char * buf_in, long long bin_len,
338 const int * dalist, int dalen)
339 {
340 gxml_data * xd = &GXD; /* point to global struct */
341 XML_Parser parser;
342 long long bin_remain = bin_len; /* remaining bytes to process */
343 const char * bin_ptr = buf_in; /* current buffer location */
344 const char * fname = "FROM_BUFFER";
345 unsigned blen;
346 char * buf = NULL;
347 int bsize; /* be sure it doesn't change at some point */
348 int done = 0, pcount = 1;
349
350 if( init_gxml_data(xd, 0, dalist, dalen) ) /* reset non-user variables */
351 return NULL;
352
353 xd->dstore = 1; /* store for global access */
354
355 if( !buf_in || bin_len < 0 ) {
356 fprintf(stderr,"** gxml_read_image_buf: missing buffer\n");
357 return NULL;
358 }
359
360 /* create a new buffer */
361 bsize = 0;
362 if( reset_xml_buf(xd, &buf, &bsize) ) return NULL;
363
364 if(xd->verb > 1) {
365 fprintf(stderr,"-- reading gifti image '%s'\n", fname);
366 if(xd->da_list) fprintf(stderr," (length %d DA list)\n", xd->da_len);
367 fprintf(stderr,"-- using %d byte XML buffer\n",bsize);
368 if(xd->verb > 4) show_enames(stderr);
369 }
370
371 /* allocate return structure */
372 xd->gim = (gifti_image *)calloc(1,sizeof(gifti_image));
373 if( !xd->gim ) {
374 fprintf(stderr,"** failed to alloc initial gifti_image\n");
375 free(buf);
376 return NULL;
377 }
378
379 /* create parser, init handlers */
380 parser = init_xml_parser((void *)xd);
381
382 while( !done )
383 {
384 if( reset_xml_buf(xd, &buf, &bsize) ) /* fail out */
385 { gifti_free_image(xd->gim); xd->gim = NULL; break; }
386
387 /*--- replace fread with buffer copy ---*/
388
389 /* decide how much to copy and copy */
390 if( bin_remain >= bsize ) blen = bsize;
391 else blen = bin_remain;
392
393 memcpy(buf, bin_ptr, bsize);
394
395 /* update bytes remaining to process and decide if done */
396 bin_remain -= bsize;
397 done = bin_remain <= 0;
398
399 if(xd->verb > 3) fprintf(stderr,"-- XML_Parse # %d\n", pcount);
400 pcount++;
401 if( XML_Parse(parser, buf, blen, done) == XML_STATUS_ERROR) {
402 fprintf(stderr,"** %s at line %u\n",
403 XML_ErrorString(XML_GetErrorCode(parser)),
404 (unsigned int)XML_GetCurrentLineNumber(parser));
405 gifti_free_image(xd->gim);
406 xd->gim = NULL;
407 break;
408 }
409 }
410
411 if(xd->verb > 1) {
412 if(xd->gim)
413 fprintf(stderr,"-- have gifti image '%s', "
414 "(%d DA elements = %lld MB)\n",
415 fname, xd->gim->numDA, gifti_gim_DA_size(xd->gim,1));
416 else fprintf(stderr,"** gifti image '%s', failure\n", fname);
417 }
418
419 if( buf ) free(buf); /* parser buffer */
420 XML_ParserFree(parser);
421
422 if( dalist && xd->da_list )
423 if( apply_da_list_order(xd, dalist, dalen) ) {
424 fprintf(stderr,"** failed apply_da_list_order\n");
425 gifti_free_image(xd->gim);
426 xd->gim = NULL;
427 }
428
429 free_xd_data(xd); /* free data buffers */
430
431 return xd->gim;
432 }
433
434
435 /* free da_list and buffers */
free_xd_data(gxml_data * xd)436 static int free_xd_data(gxml_data * xd)
437 {
438 if( xd->da_list ){ free(xd->da_list); xd->da_list = NULL; }
439
440 if( xd->xdata ){ free(xd->xdata); xd->xdata = NULL; } /* xform matrix */
441 if( xd->zdata) { free(xd->zdata); xd->zdata = NULL; } /* compress buff */
442 if( xd->ddata ){ free(xd->ddata); xd->ddata = NULL; } /* Data buffer */
443
444 return 0;
445 }
446
447
448 /* verify that the current lengths match
449 * create a new list of NULL DA pointers
450 * create a 'taken' list, matching xd->da_len (but unset)
451 * for each index, if it is not set, find one and copy
452 */
apply_da_list_order(gxml_data * xd,const int * orig,int len)453 static int apply_da_list_order(gxml_data * xd, const int * orig, int len)
454 {
455 giiDataArray ** newlist;
456 int * taken; /* whether xd->da_list[i] was used */
457 int newc, oldc, errors = 0, nDA;
458
459 if( !xd || !xd->gim || !orig || len <= 0 || !xd->da_list || xd->da_len<=0 )
460 return 0; /* do nothing, or start small, diversionary fire, hmmm... */
461
462 nDA = xd->gim->numDA; /* this may replace da_len */
463 if( nDA <= 0 ) return 0;
464
465 /* create new DA list */
466 newlist = (giiDataArray **)malloc(len * sizeof(giiDataArray *));
467 if(!newlist){ fprintf(stderr,"** ADLO: no alloc for DAlist\n"); return 1; }
468
469 /* create taken list (of all 0) */
470 taken = (int *)calloc(nDA, sizeof(int));
471 if(!taken){ fprintf(stderr,"** ADLO: no alloc for taken\n"); return 1; }
472
473 /* insert pointers to current or copied DA */
474 for( newc = 0; newc < len; newc++ ) {
475 newlist[newc] = NULL; /* in case there are failures */
476
477 /* find old index in da_list */
478 for( oldc = 0; oldc < nDA; oldc++ )
479 if( xd->da_list[oldc] == orig[newc] )
480 break;
481 if( oldc >= nDA ) { /* should never happen */
482 fprintf(stderr,"** ADLO: failed to find index %d in da_list\n",
483 orig[newc]);
484 errors++;
485 continue;
486 } else if ( xd->verb > 3 )
487 fprintf(stderr,"++ found orig index %d at sorted list %d\n",
488 orig[newc], oldc);
489
490 /* either steal the pointer or copy the DA */
491 if( !taken[oldc] ) {
492 taken[oldc] = 1; /* mark it as taken */
493 newlist[newc] = xd->gim->darray[oldc];
494 } else { /* we must make a new copy */
495 newlist[newc] = gifti_copy_DataArray( xd->gim->darray[oldc], 1);
496 if( ! newlist[newc] ) errors++;
497 }
498 }
499
500 /* at this point, we should be good, but check... */
501
502 /* if anything has not been taken, free them and fail */
503 for( oldc = 0; oldc < nDA; oldc++ ) {
504 if( !taken[oldc] ) {
505 fprintf(stderr,"** ADLO: taken list is not all set\n");
506 errors++;
507 free(xd->gim->darray[oldc]);
508 }
509 }
510 free(taken); /* we're done with that */
511
512 /* free old DA list, since all the pointers are free'd or taken */
513 free(xd->gim->darray);
514 xd->gim->darray = newlist;
515 xd->gim->numDA = len;
516
517 /* last check for errors, is the current darray filled? */
518 for( newc = 0; newc < len; newc++ )
519 if( ! xd->gim->darray[newc] ) {
520 fprintf(stderr,"** ADLO: copied darray not full\n");
521 errors++;
522 }
523
524 return errors; /* we just need to free gim on return */
525 }
526
527
528 /* return 0 on success */
gxml_write_image(gifti_image * gim,const char * fname,int write_data)529 int gxml_write_image(gifti_image * gim, const char * fname, int write_data)
530 {
531 gxml_data * xd = &GXD; /* point to global struct */
532 FILE * fp;
533
534 if( !gim ) {
535 fprintf(stderr,"** GXML write: no gifti_image\n");
536 return 1;
537 } else if ( !fname ) {
538 fprintf(stderr,"** GXML write: no filename\n");
539 return 1;
540 }
541
542 if(GXD.verb > 1) {
543 fprintf(stderr,"++ writing gifti image (%s data) to '%s'",
544 write_data?"with":"no", fname);
545 if( write_data )
546 fprintf(stderr," (%d DA elements = %lld MB)",
547 gim->numDA, gifti_gim_DA_size(gim,1));
548 fputc('\n', stderr);
549 }
550
551 #ifndef HAVE_ZLIB /* if the data is to be compressed, fail */
552 if( gim->darray && gim->darray[0] &&
553 gim->darray[0]->encoding == GIFTI_ENCODING_B64GZ ) {
554 fprintf(stderr,"** no ZLIB for compression...\n");
555 gifti_set_atr_in_DAs(gim, "Encoding", "Base64Binary", NULL, 0);
556 }
557 #endif
558
559 init_gxml_data(xd, 0, NULL, 0); /* reset non-user variables */
560 xd->dstore = write_data; /* store for global access */
561 xd->gim = gim;
562
563 /* note the library version */
564 if( xd->update_ok ) {
565 if( xd->verb > 2 )
566 fprintf(stderr,"++ setting GIFTI MD: gifticlib-version to %s\n",
567 gifticlib_version());
568 gifti_add_to_meta(&gim->meta,"gifticlib-version",gifticlib_version(),1);
569 }
570
571 fp = fopen(fname, "w");
572 if( !fp ) {
573 fprintf(stderr,"** failed to open '%s' for gifti write\n", fname);
574 return 1;
575 }
576
577 (void)gxml_write_gifti(xd, fp);
578
579 if( xd->xdata ){ free(xd->xdata); xd->xdata = NULL; }
580 if( xd->zdata) { free(xd->zdata); xd->zdata = NULL; }
581
582 fclose(fp);
583
584 return 0;
585 }
586
587
588 /*---------- accessor functions for user-controllable variables ----------*/
589 /*---------- (one can pass -1 to set the default value) ----------*/
590
591 /*! verb is the vebose level, with 0 meaning "only report errors" (up to 7) */
gxml_get_verb(void)592 int gxml_get_verb( void ){ return GXD.verb; }
gxml_set_verb(int val)593 int gxml_set_verb( int val )
594 {
595 if ( val == -1 ) GXD.verb = 1;
596 else if( val >= 0 ) GXD.verb = val;
597 return 0;
598 }
599
600 /*! the dstore flag controls whether data is read from a GIFTI file */
gxml_get_dstore(void)601 int gxml_get_dstore( void ){ return GXD.dstore; }
gxml_set_dstore(int val)602 int gxml_set_dstore( int val )
603 {
604 if( val ) GXD.dstore = 1; /* includes -1 as applying the default */
605 else GXD.dstore = 0;
606 return 0;
607 }
608
609 /*! indent is the number of spaces per indent level written to a GIFTI file */
gxml_get_indent(void)610 int gxml_get_indent( void ){ return GXD.indent; }
gxml_set_indent(int val)611 int gxml_set_indent( int val )
612 {
613 if ( val == -1 ) GXD.indent = 3;
614 else if ( val >= 0 ) GXD.indent = val;
615 else return 1; /* failure - no action */
616 return 0;
617 }
618
619 /*! buf_size is the size of the XML I/O buffer given to expat */
gxml_get_buf_size(void)620 int gxml_get_buf_size( void ){ return GXD.buf_size; }
gxml_set_buf_size(int val)621 int gxml_set_buf_size( int val )
622 {
623 if ( val == -1 ) GXD.buf_size = GXML_DEF_BSIZE;
624 else if ( val > 0 ) GXD.buf_size = val;
625 else return 1; /* failure - no action */
626 return 0;
627 }
628
629 /*! b64_check is the checking level for base64 binary data (see gifti_io.h) */
gxml_get_b64_check(void)630 int gxml_get_b64_check( void ){ return GXD.b64_check; }
gxml_set_b64_check(int val)631 int gxml_set_b64_check( int val ) /* -1 means apply default */
632 {
633 if( val == -1 )
634 GXD.b64_check = GIFTI_B64_CHECK_SKIPNCOUNT;
635 else if ( val > GIFTI_B64_CHECK_UNDEF && val <= GIFTI_B64_CHECK_MAX )
636 GXD.b64_check = val;
637 else return 1; /* failure - no action */
638 return 0;
639 }
640
641 /*! update_ok tells the library whether it is allowed to modify metadata */
gxml_get_update_ok(void)642 int gxml_get_update_ok( void ){ return GXD.update_ok; }
gxml_set_update_ok(int val)643 int gxml_set_update_ok( int val )
644 {
645 if ( val == -1 ) GXD.update_ok = 1; /* default is yes */
646 else if ( val >= 0 ) GXD.update_ok = val;
647 else return 1; /* failure - no action */
648 return 0;
649 }
650
651 /*! zlevel is the zlib compression level, with -1 implying the default
652 (of 6, I believe) and value levels being in {0..9} (with 0 meaning
653 no compression) */
gxml_get_zlevel(void)654 int gxml_get_zlevel( void ){ return GXD.zlevel; }
gxml_set_zlevel(int val)655 int gxml_set_zlevel( int val )
656 {
657 if( val == -1 )
658 GXD.zlevel = GZ_DEFAULT_COMPRESSION;
659 else if ( val >= 0 && val <= 9 )
660 GXD.zlevel = val;
661 else return 1; /* failure - no action */
662 return 0;
663 }
664
665 /*! perm_by_iord specifies whether to permute the data to row major
666 index order (since this is C) upon read
667 (-1 is used to initialize to the default) 28 Apr 2017 [rickr] */
gxml_get_perm_by_iord(void)668 int gxml_get_perm_by_iord( void ){ return GXD.perm_by_iord; }
gxml_set_perm_by_iord(int val)669 int gxml_set_perm_by_iord( int val )
670 {
671 if( val == -1 )
672 GXD.perm_by_iord = 1;
673 else if ( val >= 0 && val <= 1 )
674 GXD.perm_by_iord = val;
675 else return 1; /* failure - no action */
676 return 0;
677 }
678 /*----------------------- END accessor functions -----------------------*/
679
680
init_gxml_data(gxml_data * dp,int doall,const int * dalist,int len)681 static int init_gxml_data(gxml_data *dp, int doall, const int *dalist, int len)
682 {
683 int errs = 0;
684
685 if( doall ) { /* user modifiable - init all to defaults */
686 dp->verb = 1;
687 dp->dstore = 1;
688 dp->indent = 3;
689 dp->buf_size = GXML_DEF_BSIZE;
690 dp->b64_check = GIFTI_B64_CHECK_SKIPNCOUNT;
691 dp->update_ok = 1;
692 dp->zlevel = GZ_DEFAULT_COMPRESSION;
693 dp->perm_by_iord = 1;
694 }
695
696 if( dalist && len > 0 ) {
697 if( short_sorted_da_list(dp, dalist, len) ) errs++; /* continue */
698 } else {
699 dp->da_list = NULL;
700 dp->da_len = 0;
701 }
702 dp->da_ind = 0;
703
704 /* maybe show the user */
705 if( dp->verb > 2 )
706 disp_gxml_data("-- user opts: ", dp, dp->verb > 3);
707
708 dp->eleDA = 0;
709 dp->expDA = 0;
710 dp->b64_errors = 0;
711 dp->errors = 0;
712 dp->skip = 0;
713 dp->depth = 0;
714 memset(dp->stack, 0, sizeof(dp->stack));
715
716 dp->dind = 0;
717 dp->clen = 0;
718 dp->xlen = 0;
719 dp->dlen = 0;
720 dp->doff = 0;
721 dp->zlen = 0;
722 dp->cdata = NULL;
723 dp->xdata = NULL;
724 dp->ddata = NULL;
725 dp->zdata = NULL;
726 dp->gim = NULL;
727
728 #ifndef HAVE_ZLIB /* if we don't have this (and need it), print warnings */
729 g_first_zlib_err_msg = 1;
730 #endif
731
732 return errs;
733 }
734
short_sorted_da_list(gxml_data * dp,const int * dalist,int len)735 static int short_sorted_da_list(gxml_data *dp, const int * dalist, int len)
736 {
737 int * da_copy, c, cind;
738
739 /* first, duplicate list */
740 da_copy = (int *)malloc(len*sizeof(int));
741 if( !da_copy ) {
742 fprintf(stderr,"** cannot duplicate da_list of %d elements\n", len);
743 return 1;
744 }
745 for( c = 0; c < len; c++ ) da_copy[c] = dalist[c];
746
747 /* now sort */
748 qsort(da_copy, len, sizeof(int), int_compare);
749
750 /* remove duplicates */
751 for( c = 1, cind = 0; c < len; c++ ) {
752 if( da_copy[c] != da_copy[cind] ) {
753 cind++;
754 if( cind < c ) da_copy[cind] = da_copy[c];
755 }
756 }
757
758 dp->da_list = da_copy;
759 dp->da_len = cind+1;
760
761 if( dp->verb > 1 ) {
762 fprintf(stderr,"-- original da_list:");
763 for(c = 0; c < len; c++ )
764 fprintf(stderr," %d", dalist[c]);
765 fputc('\n', stderr);
766 fprintf(stderr,"++ unique, sorted da_list:");
767 for(c = 0; c < dp->da_len; c++ )
768 fprintf(stderr," %d", dp->da_list[c]);
769 fputc('\n', stderr);
770 }
771
772 return 0;
773 }
774
775 /* for qsort */
int_compare(const void * v0,const void * v1)776 static int int_compare(const void * v0, const void * v1)
777 {
778 int * i0 = (int *)v0;
779 int * i1 = (int *)v1;
780
781 if( *i0 < *i1 ) return -1;
782 if( *i0 == *i1 ) return 0;
783 return 1;
784 }
785
786 /* ---------------------------------------------------------------------- */
787
show_depth(int depth,int show,FILE * fp)788 static void show_depth( int depth, int show, FILE * fp )
789 {
790 if( show ) fprintf(fp, "%*s %02d ", 3*depth, "", depth);
791 else fprintf(fp, "%*s ", 3*depth, "");
792 }
793
show_enames(FILE * fp)794 static void show_enames( FILE * fp )
795 {
796 int c;
797 fprintf(fp, "-------------------------------\n"
798 "++ ename list :\n");
799 for( c = 0; c <= GXML_ETYPE_LAST; c++ )
800 fprintf(fp," %02d : %s\n", c, enames[c]);
801 fprintf(fp, "-------------------------------\n");
802 }
803
ename2type(const char * name)804 static int ename2type( const char * name )
805 {
806 int etype;
807 for( etype = GXML_ETYPE_LAST; etype > GXML_ETYPE_INVALID; etype-- )
808 if( !strcmp(name, enames[etype]) )
809 break;
810 return etype;
811 }
812
813 /* name should be null terminated */
epush(gxml_data * xd,int etype,const char * ename,const char ** attr)814 static int epush( gxml_data * xd, int etype, const char * ename,
815 const char ** attr )
816 {
817 if( xd->depth < 0 || xd->depth > GXML_MAX_DEPTH ) {
818 fprintf(stderr,"** push: stack depth %d out of [0,%d] range\n",
819 xd->depth, GXML_MAX_DEPTH);
820 xd->errors++;
821 return 1;
822 }
823
824 if( xd->verb > 4 ) { /* maybe we want to print something */
825 show_depth(xd->depth, 1, stderr);
826 fprintf(stderr,"++ push %02d: '%s'\n", etype, enames[etype]);
827 }
828
829 xd->stack[xd->depth] = etype;
830 xd->depth++;
831
832 /* if we are in a skip block, do nothing but monitor stack */
833 if( xd->skip ) {
834 if( xd->verb > 2 )
835 fprintf(stderr,"-- skip=%d, depth=%d, skipping element '%s'\n",
836 xd->skip, xd->depth, ename);
837 return 0;
838 }
839
840 /* determine whether we should enter a skip block */
841 if( etype == GXML_ETYPE_INVALID ) {
842 if(xd->verb > 0)
843 fprintf(stderr,"** pushed invalid element, '%s', skip depth %d\n",
844 ename, xd->depth);
845 xd->skip = xd->depth;
846 return 1;
847 }
848
849 if ( xd->verb > 5 ) show_stack("++ ", xd);
850 if( !stack_is_valid(xd) ) return 1;
851
852 /* call appropriate XML processing function */
853 switch( etype ) {
854 case GXML_ETYPE_GIFTI : return push_gifti (xd, attr);
855 case GXML_ETYPE_META : return push_meta (xd);
856 case GXML_ETYPE_MD : return push_md (xd);
857 case GXML_ETYPE_NAME : return push_name (xd);
858 case GXML_ETYPE_VALUE : return push_value (xd);
859 case GXML_ETYPE_LABELTABLE : return push_LT (xd);
860 case GXML_ETYPE_LABEL : return push_label (xd, attr);
861 case GXML_ETYPE_DATAARRAY : return push_darray(xd, attr);
862 case GXML_ETYPE_CSTM : return push_cstm (xd);
863 case GXML_ETYPE_DATA : return push_data (xd);
864 case GXML_ETYPE_DATASPACE : return push_dspace(xd);
865 case GXML_ETYPE_XFORMSPACE : return push_xspace(xd);
866 case GXML_ETYPE_MATRIXDATA : return push_xform (xd);
867 case GXML_ETYPE_CDATA : return 0; /* do nothing */
868 default:
869 fprintf(stderr,"** epush, unknow type '%s'\n",enames[etype]);
870 break;
871 }
872
873 return 1;
874 }
875
876 /* initialize the gifti_element and set attributes */
push_gifti(gxml_data * xd,const char ** attr)877 static int push_gifti(gxml_data * xd, const char ** attr )
878 {
879 gifti_image * gim;
880 int c;
881
882 if( !xd ) return 1;
883
884 /* be explicit with pointers (struct should be clear) */
885 gim = xd->gim;
886 gifti_clear_gifti_image(gim);
887
888 if( !attr ) return 0;
889
890 for(c = 0; attr[c]; c+= 2 )
891 if( gifti_str2attr_gifti(gim, attr[c], attr[c+1]) )
892 if( gifti_add_to_nvpairs(&gim->ex_atrs,attr[c],attr[c+1]) )
893 return 1;
894
895 if( xd->verb > 1 ) fprintf(stderr,"++ set %d GIFTI attr(s)\n",c/2);
896 if( xd->verb > 3 ) gifti_disp_gifti_image("push:", gim, 0);
897
898 /* now store any gim->numDA, and use gim to count as they are added */
899 if( gim->numDA >= 0 ) {
900 xd->expDA = gim->numDA;
901 gim->numDA = 0; /* clear for counting */
902 if( xd->verb > 1 )
903 fprintf(stderr,"-- expecting %d DA elements\n", xd->expDA);
904 }
905
906 return 0;
907 }
908
909 /* simply verify that we have not been here before */
push_meta(gxml_data * xd)910 static int push_meta(gxml_data * xd)
911 {
912 giiMetaData * md = find_current_MetaData(xd, 0);
913
914 if( md->length != 0 || md->name || md->value ) {
915 fprintf(stderr,"** push meta: already initialized??\n");
916 return 1;
917 }
918
919 return 0;
920 }
921
922 /* find the parent struct, and return its meta field */
find_current_MetaData(gxml_data * xd,int cdepth)923 static giiMetaData * find_current_MetaData(gxml_data * xd, int cdepth)
924 {
925 giiDataArray * da;
926 giiMetaData * md;
927 int da_ind, parent;
928
929 if( !xd || cdepth < 0 || xd->depth < (2+cdepth) ) {
930 fprintf(stderr,"FMeta: bad params (%p,%d)\n",(void *)xd,cdepth);
931 return NULL;
932 }
933
934 /* find the appropriate parent struct */
935 parent = xd->stack[xd->depth-2-cdepth];
936 if( parent == GXML_ETYPE_GIFTI )
937 md = &xd->gim->meta;
938 else if( parent == GXML_ETYPE_DATAARRAY ) {
939 if( !xd->gim->darray ) {
940 fprintf(stderr,"** FMeta: gim->darry not initialized\n");
941 return NULL;
942 }
943 da_ind = xd->gim->numDA-1;
944 da = xd->gim->darray[da_ind];
945 if( !da ) {
946 fprintf(stderr,"** FMeta: gim->darry[%d] not initialized\n",da_ind);
947 return NULL;
948 }
949 md = &da->meta;
950 } else {
951 fprintf(stderr,"** FMeta: child of invalid parent '%s'\n",
952 enames[parent]);
953 return NULL;
954 }
955
956 return md;
957 }
958
959 /* we will add a pair, so update length and allocate pointers */
push_md(gxml_data * xd)960 static int push_md(gxml_data * xd)
961 {
962 giiMetaData * md = find_current_MetaData(xd, 1); /* MD is 1 below */
963
964 if( !md ) return 1; /* error were printed */
965
966 md->length++;
967 md->name = (char **)realloc(md->name, md->length * sizeof(char *));
968 md->value = (char **)realloc(md->value, md->length * sizeof(char *));
969
970 if( !md->name || !md->value ) {
971 fprintf(stderr,"** failed to realloc %d MD pointers\n",md->length);
972 md->length = 0;
973 return 1;
974 }
975
976 /* and clear the new pointers */
977 md->name[md->length-1] = NULL;
978 md->value[md->length-1] = NULL;
979
980 return 0;
981 }
982
983 /* set cdata to the current meta->name address, and clear it */
push_name(gxml_data * xd)984 static int push_name(gxml_data * xd)
985 {
986 giiMetaData * md = find_current_MetaData(xd, 2); /* name is 2 below */
987
988 if( !md ) return 1;
989
990 xd->cdata = &md->name[md->length-1]; /* use cdata to fill */
991 *xd->cdata = NULL; /* init to empty */
992 xd->clen = 0;
993
994 return 0;
995 }
996
997 /* set cdata to the current meta->value address, and clear it */
push_value(gxml_data * xd)998 static int push_value(gxml_data * xd)
999 {
1000 giiMetaData * md = find_current_MetaData(xd, 2); /* value is 2 below */
1001
1002 if( !md ) return 1;
1003
1004 xd->cdata = &md->value[md->length-1]; /* use cdata to fill */
1005 *xd->cdata = NULL; /* init to empty */
1006 xd->clen = 0;
1007
1008 return 0;
1009 }
1010
1011 /* check that LT is currently empty */
push_LT(gxml_data * xd)1012 static int push_LT(gxml_data * xd)
1013 {
1014 giiLabelTable * lt = &xd->gim->labeltable;
1015
1016 if( lt->length || lt->key || lt->label ) {
1017 fprintf(stderr,"** multiple giiLabelTables?\n");
1018 }
1019
1020 return 0;
1021 }
1022
1023 /* increase LabelTable length by 1, and fill new entries
1024 * (note that the Key (or Index) attribute is required)
1025 *
1026 * 'Index' attribute has been replaced by 'Key' 7 Mar 2010 */
push_label(gxml_data * xd,const char ** attr)1027 static int push_label(gxml_data * xd, const char ** attr)
1028 {
1029 giiLabelTable * lt = &xd->gim->labeltable;
1030 float rgba[4]={0.0, 0.0, 0.0, 0.0};
1031 int key=0, rv;
1032
1033 lt->length++;
1034 lt->key = (int *)realloc(lt->key, lt->length * sizeof(int));
1035 lt->label = (char **)realloc(lt->label, lt->length * sizeof(char *));
1036
1037 if( !lt->key || !lt->label ) {
1038 fprintf(stderr,"** gifti alloc failure for label %d\n",lt->length);
1039 return 1;
1040 }
1041
1042 /* set key from the attributes */
1043 if( !attr ) {
1044 fprintf(stderr,"** Label %d missing attributes\n", lt->length-1);
1045 lt->key[lt->length-1] = 0;
1046 } else {
1047 /* get any known attributes */
1048 rv = get_label_attrs(xd, attr, &key, rgba);
1049 if ( rv == 1 ) {
1050 lt->key[lt->length-1] = key;
1051 } else if ( rv == 2 ) {
1052 lt->key[lt->length-1] = key;
1053 (void) add_label_rgba(xd, lt, rgba);
1054 } /* else error already printed */
1055 }
1056
1057 xd->cdata = lt->label + (lt->length-1); /* addr of newest (char *) */
1058 *xd->cdata = NULL; /* init to empty */
1059 xd->clen = 0;
1060
1061 return 0;
1062 }
1063
1064
1065 /* add the rgba entries to the LabelTable, length is already updated */
add_label_rgba(gxml_data * xd,giiLabelTable * lt,float * rgba)1066 static int add_label_rgba(gxml_data * xd, giiLabelTable * lt, float * rgba)
1067 {
1068 if( !xd || !lt || !rgba ) {
1069 fprintf(stderr,"** add_label_rgba, bad params\n");
1070 return 1;
1071 }
1072
1073 if( lt->length > 1 && !lt->rgba ) {
1074 fprintf(stderr,"** first RGBA at Label %d, so table is incomplete\n",
1075 lt->length-1);
1076 return 1;
1077 }
1078
1079 lt->rgba = (float *)realloc(lt->rgba, lt->length * 4 * sizeof(float));
1080 if( !lt->rgba ) {
1081 fprintf(stderr,"** failed to malloc rgba of length %d\n", lt->length);
1082 return 1;
1083 }
1084
1085 memcpy(lt->rgba + 4*(lt->length-1), rgba, 4*sizeof(float));
1086
1087 if(xd->verb > 4)
1088 fprintf(stderr,"-- adding Label RGBA %g %g %g %g\n",
1089 lt->rgba[0], lt->rgba[1], lt->rgba[2], lt->rgba[3]);
1090
1091 return 0;
1092 }
1093
1094 /* get key and RGBA attributes, if they exist
1095 * return 1 if key, 2 if key+rgba, 0 if neither, -1 on error */
get_label_attrs(gxml_data * xd,const char ** attr,int * key,float * rgba)1096 static int get_label_attrs(gxml_data * xd, const char ** attr, int * key,
1097 float * rgba)
1098 {
1099 giiLabelTable * lt = &xd->gim->labeltable;
1100 const char ** aptr;
1101 char * endp; /* for verifying float read */
1102 int found, lind;
1103
1104 if( !xd || !key || !rgba ) {
1105 fprintf(stderr,"** GLA: missing params\n");
1106 return -1;
1107 }
1108 if( !attr || !*attr ) return 0;
1109
1110 /* note label index */
1111 lind = lt->length - 1;
1112
1113 found = 0; /* bitmask, key,R,G,B,A (in 0..31, should end as 1 or 31) */
1114 for( aptr = attr; *aptr ; aptr += 2 ) {
1115 if( !aptr[1] ) {
1116 fprintf(stderr,"** label %d, attr %s, missing value\n",lind,*aptr);
1117 return -1;
1118 }
1119 if( !strcmp(*aptr, "Key") ) {
1120 *key = atoi(aptr[1]);
1121 found |= (1<<0);
1122 }
1123 else if( !strcmp(*aptr, "Index") ) { /* old form of Key */
1124 *key = atoi(aptr[1]);
1125 found |= (1<<0);
1126 }
1127 else if( !strcmp(*aptr, "Red") ) {
1128 rgba[0] = strtod(aptr[1], &endp);
1129 if( endp <= aptr[1] ) {
1130 fprintf(stderr,"** bad GIFTI label %d Red attr\n", lind);
1131 show_attrs(xd, GXML_ETYPE_LABEL, attr);
1132 return -1;
1133 }
1134 found |= (1<<1);
1135 }
1136 else if( !strcmp(*aptr, "Green") ) {
1137 rgba[1] = strtod(aptr[1], &endp);
1138 if( endp <= aptr[1] ) {
1139 fprintf(stderr,"** bad GIFTI label %d Green attr\n", lind);
1140 show_attrs(xd, GXML_ETYPE_LABEL, attr);
1141 return -1;
1142 }
1143 found |= (1<<2);
1144 }
1145 else if( !strcmp(*aptr, "Blue") ) {
1146 rgba[2] = strtod(aptr[1], &endp);
1147 if( endp <= aptr[1] ) {
1148 fprintf(stderr,"** bad GIFTI label %d Blue attr\n", lind);
1149 show_attrs(xd, GXML_ETYPE_LABEL, attr);
1150 return -1;
1151 }
1152 found |= (1<<3);
1153 }
1154 else if( !strcmp(*aptr, "Alpha") ) {
1155 rgba[3] = strtod(aptr[1], &endp);
1156 if( endp <= aptr[1] ) {
1157 fprintf(stderr,"** bad GIFTI label %d Alpha attr\n", lind);
1158 show_attrs(xd, GXML_ETYPE_LABEL, attr);
1159 return -1;
1160 }
1161 found |= (1<<4);
1162 } else {
1163 fprintf(stderr,"** unknown GIFTI label %d attr\n", lind);
1164 show_attrs(xd, GXML_ETYPE_LABEL, attr);
1165 return -1;
1166 }
1167 }
1168
1169 if( found == 0 ) {
1170 fprintf(stderr,"** GIFTI label %d, missing 'Key' attr\n", lind);
1171 return 0;
1172 } else if( found != 1 && found != 31 ) {
1173 fprintf(stderr,"** GIFTI label %d, partial attributes\n", lind);
1174 show_attrs(xd, GXML_ETYPE_LABEL, attr);
1175 return -1;
1176 }
1177
1178 if(xd->verb > 2) {
1179 if( found == 1 ) fprintf(stderr,"-- have Label Key %d\n", *key);
1180 else fprintf(stderr,"-- have Label Key %d, RGBA %g %g %g %g\n",
1181 *key, rgba[0], rgba[1], rgba[2], rgba[3]);
1182 }
1183
1184 if( found == 1 ) return 1;
1185 return 2;
1186 }
1187
1188
1189 /* initialize the gifti_element and set attributes */
push_darray(gxml_data * xd,const char ** attr)1190 static int push_darray(gxml_data * xd, const char ** attr)
1191 {
1192 giiDataArray * da;
1193
1194 /* maintain a count of the number seen */
1195 xd->eleDA++;
1196
1197 if( xd->da_list ) {
1198 if( (xd->da_ind < xd->da_len) &&
1199 (xd->da_list[xd->da_ind] == xd->eleDA-1) ) /* keeper */
1200 {
1201 if(xd->verb > 1) fprintf(stderr,"++ keeping DA[%d]\n",xd->eleDA-1);
1202 xd->da_ind++;
1203 } else {
1204 if(xd->verb > 1) fprintf(stderr,"++ skipping DA[%d]\n",xd->eleDA-1);
1205 xd->skip = xd->depth;
1206 return 1; /* return and skip this element */
1207 }
1208 }
1209
1210 if( gifti_add_empty_darray(xd->gim, 1) ) return 1;
1211
1212 da = xd->gim->darray[xd->gim->numDA-1]; /* get new pointer */
1213
1214 /* fill the struct from the attributes (store ex_atrs) */
1215 if( gifti_set_DA_atrs(da, attr, 0, 1) ) return 1;
1216 (void)gifti_valid_DataArray(da, xd->verb > 1);
1217
1218 /* make a request to potentially update the XML buffer size */
1219 if( da->nvals>0 && da->nbyper>0 )
1220 update_xml_buf_size(xd, da->nvals*da->nbyper);
1221
1222 if( xd->verb > 4 ) gifti_disp_DataArray("push:", da, 0);
1223
1224 return 0;
1225 }
1226
1227 /* check for base64 errors, needed uncompression, and byte swapping */
pop_darray(gxml_data * xd)1228 static int pop_darray(gxml_data * xd)
1229 {
1230 giiDataArray * da = xd->gim->darray[xd->gim->numDA-1]; /* current DA */
1231
1232 if( !da ) return 1;
1233
1234 /* check for and clear any b64 errors */
1235 if( xd->b64_errors > 0 ) {
1236 if( xd->b64_check == GIFTI_B64_CHECK_DETECT )
1237 fprintf(stderr,"** bad base64 chars found in DataArray[%d]\n",
1238 xd->gim->numDA-1);
1239 else if( xd->b64_check == GIFTI_B64_CHECK_COUNT ||
1240 xd->b64_check == GIFTI_B64_CHECK_SKIPNCOUNT )
1241 fprintf(stderr,"** %d bad base64 chars found in DataArray[%d]\n",
1242 xd->b64_errors, xd->gim->numDA-1);
1243 xd->b64_errors = 0;
1244 }
1245
1246 if( da->encoding == GIFTI_ENCODING_B64GZ && da->data ) {
1247 #ifdef HAVE_ZLIB /* for compiling, higher level test elsewhere */
1248 long long olen; /* to avoid warnings printing outlen */
1249 uLongf outlen = da->nvals*da->nbyper;
1250 int rv = 0;
1251
1252 /* unzip zdata to da->data */
1253
1254 if( xd->verb > 2 )
1255 fprintf(stderr,"-- uncompressing %lld bytes into %lld\n",
1256 xd->dind, (long long)outlen);
1257
1258 rv = uncompress(da->data, &outlen, (Bytef*)xd->zdata, xd->dind);
1259 olen = outlen;
1260
1261 if( rv != Z_OK ) {
1262 fprintf(stderr,"** uncompress fails for DA[%d]\n",xd->gim->numDA-1);
1263 if( rv == Z_MEM_ERROR )
1264 fprintf(stderr," (zlib failure, not enough memory)\n");
1265 else if ( rv == Z_BUF_ERROR )
1266 fprintf(stderr," (zlib failure, output buffer too short)\n");
1267 else if ( rv == Z_DATA_ERROR )
1268 fprintf(stderr," (zlib failure, corrupted data)\n");
1269 else if ( rv != Z_OK )
1270 fprintf(stderr," (zlib failure, unknown error %d)\n", rv);
1271 } else if ( xd->verb > 2 || (xd->verb > 1 && xd->gim->numDA == 1 ))
1272 fprintf(stderr,"-- uncompressed buffer (%.2f%% of %lld bytes)\n",
1273 100.0*xd->dind/olen, olen);
1274
1275 if( olen != da->nvals*da->nbyper ) {
1276 fprintf(stderr,"** uncompressed buf is %lld bytes, expected %lld\n",
1277 olen, da->nvals*da->nbyper);
1278 }
1279 #endif
1280
1281 xd->gim->compressed = 1; /* flag whether some data was compressed */
1282 }
1283
1284 /* possibly read data from an external file */
1285 if( da->ext_fname && *da->ext_fname )
1286 (void)gifti_read_extern_DA_data(da); /* nothing to do on failure */
1287
1288 /* possibly perform byte-swapping on data */
1289 if( da->data && da->encoding != GIFTI_ENCODING_ASCII ) {
1290 long long nvals;
1291 int swapsize;
1292
1293 gifti_datatype_sizes(da->datatype, NULL, &swapsize);
1294 if( swapsize <= 0 ) {
1295 fprintf(stderr,"** bad swapsize %d for dtype %d\n",
1296 swapsize, da->datatype);
1297 return 1;
1298 }
1299
1300 nvals = da->nvals * da->nbyper / swapsize;
1301 if( gifti_check_swap(da->data, da->endian, nvals, swapsize) )
1302 xd->gim->swapped = 1; /* flag that it happened */
1303 }
1304
1305 return 0;
1306 }
1307
1308
1309 /* make space for a new CS structure in the current DataArray */
push_cstm(gxml_data * xd)1310 static int push_cstm(gxml_data * xd)
1311 {
1312 giiDataArray * da = xd->gim->darray[xd->gim->numDA-1]; /* current DA */
1313
1314 if( da->intent != NIFTI_INTENT_POINTSET && xd->verb > 0 )
1315 fprintf(stderr,"** DA[%d] has coordsys with intent %s (should be %s)\n",
1316 xd->gim->numDA-1, gifti_intent_to_string(da->intent),
1317 gifti_intent_to_string(NIFTI_INTENT_POINTSET));
1318
1319 if( gifti_add_empty_CS(da) ) return 1;
1320
1321 return 0;
1322 }
1323
1324 /* verify the processing buffer space, alloc data space */
push_data(gxml_data * xd)1325 static int push_data(gxml_data * xd)
1326 {
1327 giiDataArray * da = xd->gim->darray[xd->gim->numDA-1]; /* current DA */
1328 int zsize;
1329
1330 xd->dind = 0; /* init for filling */
1331 xd->doff = 0;
1332
1333 if( ! xd->dstore ) {
1334 if( xd->verb > 3 )
1335 fprintf(stderr,"-- skipping data[%d]\n",xd->gim->numDA-1);
1336 xd->skip = xd->depth;
1337 return 1;
1338 }
1339
1340 if( update_partial_buffer(&xd->ddata, &xd->dlen, da->nbyper*da->nvals, 0) )
1341 return 1;
1342
1343 if( da->encoding == GIFTI_ENCODING_B64GZ ) {
1344
1345 #ifndef HAVE_ZLIB /* we don't know the encoding until push_darray */
1346 if( g_first_zlib_err_msg ) {
1347 fprintf(stderr,"** no ZLIB: skipping all compressed data\n");
1348 g_first_zlib_err_msg = 0;
1349 }
1350 xd->skip = xd->depth;
1351 return 1; /* return and skip this element */
1352 #endif
1353
1354 zsize = da->nbyper*da->nvals * 1.01 + 12; /* zlib.net */
1355
1356 if( xd->verb > 2 )
1357 fprintf(stderr,"++ creating extra zdata for zlib extraction\n");
1358 if( update_partial_buffer(&xd->zdata, &xd->zlen, zsize, 1) )
1359 return 1;
1360 }
1361
1362 /* allocate space for data */
1363 if( da->nvals <= 0 || da->nbyper <= 0 ) {
1364 fprintf(stderr,"** PD: bad vals,bytes = %u, %d\n",
1365 (unsigned)da->nvals,da->nbyper);
1366 return 1;
1367 }
1368
1369 da->data = calloc(da->nvals, da->nbyper);
1370 if( ! da->data ) {
1371 fprintf(stderr,"** PD: failed to alloc %lld bytes for darray[%d]\n",
1372 da->nvals*da->nbyper, xd->gim->numDA-1);
1373 return 1;
1374 } else if ( xd->verb > 3 )
1375 fprintf(stderr,"++ PD: alloc %lld bytes for darray[%d]\n",
1376 da->nvals*da->nbyper, xd->gim->numDA-1);
1377
1378 return 0;
1379 }
1380
1381 /* point cdata to the correct location and init */
push_dspace(gxml_data * xd)1382 static int push_dspace(gxml_data * xd)
1383 {
1384 int CSind = xd->gim->darray[xd->gim->numDA-1]->numCS-1;
1385 if( CSind < 0 ) {
1386 fprintf(stderr,"** PD: bad numCS %d in darray %d, skipping...",
1387 CSind+1, xd->gim->numDA-1);
1388 xd->skip = xd->depth;
1389 return 1;
1390 }
1391
1392 if( !xd->gim->darray[xd->gim->numDA-1]->coordsys[CSind] ) {
1393 fprintf(stderr,"** found dataspace without coordsys, skipping...\n");
1394 xd->skip = xd->depth;
1395 return 1;
1396 }
1397
1398 xd->cdata = &xd->gim->darray[xd->gim->numDA-1]->coordsys[CSind]->dataspace;
1399 *xd->cdata = NULL; /* init to empty */
1400 xd->clen = 0;
1401 return 0;
1402 }
1403
1404 /* point cdata to the correct location and init */
push_xspace(gxml_data * xd)1405 static int push_xspace(gxml_data * xd)
1406 {
1407 int CSind = xd->gim->darray[xd->gim->numDA-1]->numCS-1;
1408 if( CSind < 0 ) {
1409 fprintf(stderr,"** PX: bad numCS %d in darray %d, skipping...",
1410 CSind+1, xd->gim->numDA-1);
1411 xd->skip = xd->depth;
1412 return 1;
1413 }
1414
1415 if( !xd->gim->darray[xd->gim->numDA-1]->coordsys[CSind] ) {
1416 fprintf(stderr,"** found xformspace without coordsys, skipping...\n");
1417 xd->skip = xd->depth;
1418 return 1;
1419 }
1420
1421 xd->cdata = &xd->gim->darray[xd->gim->numDA-1]->coordsys[CSind]->xformspace;
1422 *xd->cdata = NULL; /* init to empty */
1423 xd->clen = 0;
1424 return 0;
1425 }
1426
1427 /* verify the processing buffer space */
push_xform(gxml_data * xd)1428 static int push_xform(gxml_data * xd)
1429 {
1430 int CSind = xd->gim->darray[xd->gim->numDA-1]->numCS-1;
1431 if( CSind < 0 ) {
1432 fprintf(stderr,"** PXform: bad numCS %d in darray %d, skipping...",
1433 CSind+1, xd->gim->numDA-1);
1434 xd->skip = xd->depth;
1435 return 1;
1436 }
1437
1438 if( !xd->gim->darray[xd->gim->numDA-1]->coordsys[CSind] ) {
1439 fprintf(stderr,"** found xform without coordsys, skipping...\n");
1440 xd->skip = xd->depth;
1441 return 1;
1442 }
1443
1444 /* just make sure we have a text buffer to work with */
1445 if( !xd->xdata || xd->xlen <= 0 ) {
1446 xd->xlen = 2048;
1447 xd->xdata = (char *)malloc(xd->xlen * sizeof(char));
1448 if( !xd->xdata ) {
1449 fprintf(stderr,"** cannot alloc %d bytes for xform\n",xd->xlen);
1450 return 1;
1451 }
1452 }
1453
1454 xd->dind = 0; /* init for filling */
1455 xd->doff = 0;
1456
1457 return 0;
1458 }
1459
epop(gxml_data * xd,int etype,const char * ename)1460 static int epop( gxml_data * xd, int etype, const char * ename )
1461 {
1462 giiDataArray * da;
1463
1464 xd->cdata = NULL; /* clear fields for future use */
1465 xd->clen = 0;
1466
1467 if( xd->skip == xd->depth ) { /* just completed skip element */
1468 if( xd->verb > 2 )
1469 fprintf(stderr,"-- popping skip element '%s' at depth %d\n",
1470 ename, xd->depth);
1471 xd->skip = 0; /* clear skip level */
1472 } else { /* may peform pop action for this element */
1473 switch( etype ) {
1474 default: /* do nothing special */
1475 break;
1476 case GXML_ETYPE_DATA :
1477 if(xd->verb>3)fprintf(stderr,"-- data dind = %lld\n",xd->dind);
1478 /* if we have not read data, but allocated for it, free */
1479 da = xd->gim->darray[xd->gim->numDA-1];
1480 if( da->data && xd->dind == 0 ) {
1481 if( xd->verb > 3 ) fprintf(stderr," (freeing data)\n");
1482 free(da->data);
1483 da->data = NULL;
1484 }
1485 break;
1486
1487 case GXML_ETYPE_DATAARRAY :
1488 pop_darray(xd);
1489 break;
1490
1491 case GXML_ETYPE_GIFTI :
1492 if(xd->eleDA != xd->expDA)
1493 fprintf(stderr,"** found %d DAs, expected %d\n",
1494 xd->eleDA, xd->expDA);
1495 else if(xd->da_list && (xd->da_len != xd->da_ind))
1496 fprintf(stderr,"** stored %d DAs, wanted %d\n",
1497 xd->da_ind, xd->da_len);
1498 if(xd->verb > 2)
1499 gifti_disp_gifti_image("pop:", xd->gim, xd->verb > 4);
1500
1501 if(xd->verb > 1) { /* check flags */
1502 if(xd->gim->swapped)
1503 fprintf(stderr,"++ data was byte-swapped\n");
1504 if(xd->gim->compressed)
1505 fprintf(stderr,"++ data was compressed\n");
1506 }
1507
1508 break;
1509 }
1510 }
1511
1512 xd->depth--;
1513
1514 if( xd->verb > 5 )
1515 {
1516 show_depth(xd->depth, 1, stderr);
1517 fprintf(stderr,"++ pop %02d : '%s'\n", etype, enames[etype]);
1518 }
1519
1520 if( xd->depth < 0 || xd->depth > GXML_MAX_DEPTH ) {
1521 fprintf(stderr,"** pop: stack depth %d out of [0,%d] range\n",
1522 xd->depth, GXML_MAX_DEPTH);
1523 xd->errors++;
1524 return -1;
1525 }
1526
1527 return 0;
1528 }
1529
1530 /* return the number of bytes of leading whitespace, up to a max of len */
whitespace_len(const char * str,int len)1531 static int whitespace_len(const char * str, int len)
1532 {
1533 int c;
1534 if( !str || !*str || len < 1 ) return 0;
1535 for( c = 0; c < len; c++ )
1536 if( !isspace(str[c]) ) return c;
1537
1538 return len;
1539 }
1540
show_attrs(gxml_data * xd,int etype,const char ** attr)1541 static void show_attrs(gxml_data * xd, int etype, const char ** attr)
1542 {
1543 int count;
1544 show_depth(xd->depth, 1, stderr);
1545 fprintf(stderr, ": element %s\n", enames[etype]);
1546 for( count = 0; attr[count]; count += 2 ){
1547 show_depth(xd->depth, 0, stderr);
1548 fprintf(stderr," attr: %s='%s'\n", attr[count], attr[count+1]);
1549 }
1550 }
1551
1552
cb_start_ele(void * udata,const char * ename,const char ** attr)1553 static void XMLCALL cb_start_ele(void *udata, const char *ename,
1554 const char **attr)
1555 {
1556 gxml_data * xd = (gxml_data *)udata;
1557 int etype;
1558
1559 etype = ename2type(ename);
1560 if( xd->verb > 3 ) show_attrs(xd, etype, attr);
1561
1562 /* process attributes and push() */
1563
1564 (void)epush(xd, etype, ename, attr);
1565 }
1566
1567 /* if ending Data, clear prev_end_check */
cb_end_ele(void * udata,const char * ename)1568 static void XMLCALL cb_end_ele(void *udata, const char * ename)
1569 {
1570 gxml_data * xd = (gxml_data *)udata;
1571
1572 epop(xd, ename2type(ename), ename);
1573 }
1574
1575 /* May divide Data, but apparently not attributes, perhaps because
1576 the Data section is longer than the buffer is wide.
1577
1578 if in Data:
1579 if prev_end_check
1580 if( ! char_is_whitespace(first) && concat_is_number() )
1581 concatencate as number to adjust previous number
1582 verify rest is whitespace
1583 return (we don't expect to start a new number)
1584 else
1585 apply previous number
1586 if( !char_is_whitespace(last) )
1587 store trailing non-space in concat_buf
1588 else
1589 prev_end_check = 0
1590 apply number (though it may change later)
1591 */
cb_char(void * udata,const char * cdata,int length)1592 static void XMLCALL cb_char(void *udata, const char * cdata, int length)
1593 {
1594 gxml_data * xd = (gxml_data *)udata;
1595 const char * str = cdata;
1596 int len = length, wlen = 0, parent;
1597
1598 if( xd->skip > 0 ) {
1599 if(xd->verb > 3) fprintf(stderr,"-- skipping char [%d]\n",len);
1600 return;
1601 }
1602
1603 /* act based on the parent type */
1604 parent = xd->stack[xd->depth-1];
1605 if( parent == GXML_ETYPE_CDATA ) parent = xd->stack[xd->depth-2];
1606
1607 if( parent != GXML_ETYPE_DATA ) wlen = whitespace_len(str,length);
1608
1609 switch( parent ) {
1610 case GXML_ETYPE_DATA :
1611 (void)append_to_data(xd, cdata, length);
1612 break;
1613 case GXML_ETYPE_MATRIXDATA :
1614 (void)append_to_xform(xd, cdata, length);
1615 break;
1616
1617 case GXML_ETYPE_GIFTI :
1618 case GXML_ETYPE_META :
1619 case GXML_ETYPE_MD :
1620 case GXML_ETYPE_LABELTABLE :
1621 case GXML_ETYPE_DATAARRAY :
1622 case GXML_ETYPE_CSTM :
1623 if( wlen != length && xd->verb ) {
1624 fprintf(stderr,"** invalid chars under %s: '%.*s'\n",
1625 enames[parent], length, cdata);
1626 }
1627 break;
1628
1629 case GXML_ETYPE_NAME :
1630 case GXML_ETYPE_VALUE :
1631 case GXML_ETYPE_LABEL :
1632 case GXML_ETYPE_DATASPACE :
1633 case GXML_ETYPE_XFORMSPACE :
1634 if( xd->verb > 4 )
1635 fprintf(stderr,"++ append cdata, parent %s\n",enames[parent]);
1636 /* append only if cdata 23 Fef 2016 [rdvincent] */
1637 if( xd->cdata )
1638 (void)append_to_cdata(xd, cdata, length);
1639 else if ( xd->verb > 4 )
1640 fprintf(stderr, " missing cdata...\n");
1641 break;
1642
1643 case GXML_ETYPE_CDATA :
1644 fprintf(stderr,"** CDATA is the parent of CDATA???\n");
1645 return;
1646
1647 default: /* drop through */
1648 fprintf(stderr,"** unknown parent of char: %d\n", parent);
1649 return;
1650 }
1651
1652 if( wlen == length ) { /* if it is all whitespace */
1653 if( xd->verb < 5 ) return;
1654 str = "whitespace"; /* just note the whitespace */
1655 len = strlen(str);
1656 }
1657
1658 if( xd->verb > 4 ) {
1659 show_depth(xd->depth, 1, stderr);
1660 if( parent == GXML_ETYPE_DATA && len > 40 ) len = 40;
1661 fprintf(stderr, "char[%d]: %.*s\n", length, len, str);
1662 }
1663 }
1664
1665
1666 /* ----------------------------------------------------------------------
1667 * xd->cdata points to one of:
1668 * md->name[k], md->value[k], lt->label[k],
1669 * da[k]->coordsys->dataspace, da[k]->coordsys->xformspace
1670 *
1671 * append the new data and null terminate
1672 * ---------------------------------------------------------------------- */
append_to_cdata(gxml_data * xd,const char * cdata,int len)1673 static int append_to_cdata(gxml_data * xd, const char * cdata, int len)
1674 {
1675 int offset;
1676 if( !xd || !cdata || len <= 0 ) {
1677 fprintf(stderr,"** A2CD, bad params (%p,%p,%d)\n",
1678 (void *)xd,(void *)cdata, len);
1679 return 1;
1680 }
1681 if( !*xd->cdata ) {
1682 offset = 0;
1683 xd->clen = len + 1; /* first time, alloc for null */
1684 }
1685 else {
1686 offset = xd->clen - 1;
1687 xd->clen += len;
1688 }
1689
1690 if( xd->verb > 4 )
1691 fprintf(stderr,"++ a2cdata, len %d, clen %d, data '%.*s'\n",
1692 len, xd->clen, len, cdata);
1693
1694 *xd->cdata = (char *)realloc(*xd->cdata, xd->clen*sizeof(char));
1695 if(!*xd->cdata) {
1696 fprintf(stderr,"** A2CD, failed to realloc %d bytes\n",xd->clen);
1697 return 1;
1698 }
1699
1700 memcpy(*xd->cdata + offset, cdata, len); /* append the new data */
1701 (*xd->cdata)[xd->clen-1] = '\0'; /* and null terminate */
1702
1703 return 0;
1704 }
1705
1706
1707 /* this must go to the data of the latest darray struct */
append_to_data(gxml_data * xd,const char * cdata,int len)1708 static int append_to_data(gxml_data * xd, const char * cdata, int len)
1709 {
1710 giiDataArray * da = xd->gim->darray[xd->gim->numDA-1]; /* current DA */
1711
1712 if( !da || !xd->dlen || !xd->ddata || xd->dind < 0 ) {
1713 fprintf(stderr,"** A2D: bad setup (%p,%d,%p,%lld)\n",
1714 (void *)da, xd->dlen, (void *)xd->ddata, xd->dind);
1715 return 1;
1716 } else if( !da->data ) {
1717 fprintf(stderr,"** A2D: no data allocated\n");
1718 return 1;
1719 }
1720
1721 switch( da->encoding ){
1722 case GIFTI_ENCODING_ASCII:
1723 return append_to_data_ascii(xd, cdata, len);
1724
1725 case GIFTI_ENCODING_B64BIN:
1726 return append_to_data_b64(xd, (char *)da->data,
1727 da->nvals*da->nbyper, cdata, len);
1728 case GIFTI_ENCODING_B64GZ:
1729 return append_to_data_b64(xd, xd->zdata, xd->zlen, cdata, len);
1730
1731 default:
1732 fprintf(stderr,"** A2D: invalid encoding value %d (%s)\n",
1733 da->encoding,
1734 gifti_list_index2string(gifti_encoding_list,da->encoding));
1735 return 1;
1736 }
1737 }
1738
1739
1740 /* decode the b64 data, inserting it into da->data
1741 *
1742 * use intermediate buffer (ddata), length dlen+1, reprocess length doff
1743 * ddata format, in bytes per section:
1744 * +------+----------+--------+---+
1745 * | doff | copy_len | unused | 1 | (last 1 assures null termination)
1746 * +------+----------+--------+---+
1747 *
1748 * - while there are bytes left to process (rem_bytes_in > 0)
1749 * copy_len = bytes to process now
1750 * copy that many bytes to ddata
1751 * rem_bytes_out = number of output bytes left to fill in da->data
1752 * doff = decode_b64(xd, ddata, doff, da->data+dind, &rem_bytes_out)
1753 * (returns number of unprocessed bytes, in [0..3])
1754 * if( doff > 0 ) mv last doff bytes to beginning of ddata
1755 * rem_bytes_in -= copy_len
1756 * dind = updated offset into output da->data buffer
1757 */
append_to_data_b64(gxml_data * xd,char * dest,long long tot_bytes,const char * cdata,int cdlen)1758 static int append_to_data_b64(gxml_data * xd, char * dest, long long tot_bytes,
1759 const char * cdata, int cdlen)
1760 {
1761 const char * cptr;
1762 long long rem_bytes_out; /* remaining length in darray->data */
1763 int rem_bytes_in = cdlen; /* remaining length in cdata */
1764 int copy_len, apply_len, unused;
1765
1766 if( xd->verb > 4 )
1767 fprintf(stderr,"++ appending %d base64 binary bytes to data\n",cdlen);
1768
1769 /* Copy cdata to local buffer in pieces, for storage of trailing
1770 characters from a previous call. Given that, processing data
1771 as is done with ASCII seems reasonable. */
1772 while( rem_bytes_in > 0 ) {
1773 /*--- prepare intermediate buffer ---*/
1774
1775 /* point to the current location */
1776 cptr = cdata + cdlen - rem_bytes_in;
1777
1778 /* decide how many bytes to copy (avail space w/max of rem_bytes_in) */
1779 copy_len = xd->dlen - xd->doff - 1;
1780 if( copy_len > rem_bytes_in ) {
1781 unused = copy_len - rem_bytes_in; /* unused at end of buffer */
1782 copy_len = rem_bytes_in;
1783 } else unused = 0;
1784
1785 /* copy the data to our intermediate buffer
1786 (if we allow bad characters, skipping them, do it here) */
1787 (void)copy_b64_data(xd, cptr, xd->ddata+xd->doff, copy_len, &apply_len);
1788
1789 /*--- process the data ---*/
1790
1791 /* note how many bytes remain to be computed */
1792 rem_bytes_out = tot_bytes - xd->dind;
1793 if(xd->verb > 5)
1794 fprintf(stderr,"-- %lld bytes left at offset %lld\n",
1795 rem_bytes_out, xd->dind);
1796
1797 /* convert to binary bytes */
1798 xd->doff = decode_b64(xd,
1799 xd->ddata, /* data source */
1800 xd->doff+apply_len, /* data length */
1801 dest + xd->dind, /* output destination */
1802 &rem_bytes_out /* nbytes left to fill */
1803 );
1804
1805 /*--- check results --- */
1806 if( xd->doff < 0 ) { xd->doff = 0; return 1; } /* error */
1807 if( xd->doff >= xd->dlen - 1 ) {
1808 if(xd->verb)
1809 fprintf(stderr,"** A2Db64: failed to process buffer\n");
1810 fprintf(stderr,"** rem = %d\n", xd->doff);
1811 xd->doff = 0; /* blow away the buffer and continue */
1812 }
1813
1814 /*--- adjust intermediate buffer ---*/
1815
1816 /* move any unused bytes to the beginning (last doff, before unused) */
1817 if( xd->doff > 0 ) {
1818 if( xd->verb > 5 )
1819 fprintf(stderr,"++ A2Db64: move %d bytes from %d (blen %d)\n",
1820 xd->doff, xd->dlen - unused - xd->doff, xd->dlen);
1821 /* (subtract unused+1, since 1 byte is saved for null */
1822 memmove(xd->ddata, xd->ddata+xd->dlen -(unused+1) - xd->doff,
1823 xd->doff);
1824 if( xd->verb > 6 )
1825 fprintf(stderr," bytes are '%.*s'\n",xd->doff,
1826 (char *)xd->ddata);
1827 }
1828
1829 /* adjust remaining bytes for next time */
1830 rem_bytes_in -= copy_len; /* more than apply_len, if bad chars */
1831 xd->dind = tot_bytes - rem_bytes_out;
1832 }
1833
1834 return 0;
1835 }
1836
1837 /* Copy the base64 data to the dest buffer, possibly noting, counting
1838 * and/or skipping any invalid characters, based on b64_check.
1839 *
1840 * return the number of bad characters noted
1841 */
copy_b64_data(gxml_data * xd,const char * src,char * dest,int src_len,int * dest_len)1842 static int copy_b64_data(gxml_data * xd, const char * src, char * dest,
1843 int src_len, int * dest_len)
1844 {
1845 const unsigned char * usrc = (const unsigned char *)src;
1846 int c, errs = 0, apply_len;
1847
1848 if( xd->verb > 1 ) { /* in verbose mode, perform automatic check */
1849 c = count_bad_b64_chars(src, src_len);
1850 if( c > 0 ) {
1851 fprintf(stderr, "CB64D: found %d bad b64 chars\n", c);
1852 if( xd->verb > 5 ) show_bad_b64_chars(src, src_len);
1853 }
1854 }
1855
1856 switch( xd->b64_check ){
1857 default:
1858 fprintf(stderr,"** CB64D: b64_check = %d\n", xd->b64_check);
1859 /* whine and fall through */
1860
1861 case GIFTI_B64_CHECK_NONE: /* basic case - just copy the data */
1862 memcpy(dest, src, src_len);
1863 apply_len = src_len;
1864 break;
1865
1866 case GIFTI_B64_CHECK_DETECT: /* check for existence of bad chars */
1867 for(c = 0; c < src_len; c++)
1868 if( b64_decode_table[usrc[c]] == (unsigned char)0x80 ) {
1869 errs++;
1870 break;
1871 }
1872 memcpy(dest, src, src_len);
1873 apply_len = src_len;
1874 break;
1875
1876 case GIFTI_B64_CHECK_COUNT: /* count bad characters */
1877 for(c = 0; c < src_len; c++)
1878 if( b64_decode_table[usrc[c]] == (unsigned char)0x80 )
1879 errs++;
1880 memcpy(dest, src, src_len);
1881 apply_len = src_len;
1882 break;
1883
1884 case GIFTI_B64_CHECK_SKIP: /* skip bad characters, but don't count */
1885 apply_len = 0;
1886 for(c = 0; c < src_len; c++){
1887 if( b64_decode_table[usrc[c]] != (unsigned char)0x80 )
1888 dest[apply_len++] = src[c];
1889 }
1890 break;
1891 case GIFTI_B64_CHECK_SKIPNCOUNT: /* skip and count bad characters */
1892 apply_len = 0;
1893 for(c = 0; c < src_len; c++){
1894 if( b64_decode_table[usrc[c]] == (unsigned char)0x80 )
1895 errs++;
1896 else
1897 dest[apply_len++] = src[c];
1898 }
1899 break;
1900 }
1901
1902 /* and null terminate */
1903 xd->ddata[xd->doff+apply_len] = '\0';
1904
1905 /* note length and any errors */
1906 *dest_len = apply_len;
1907 xd->b64_errors += errs;
1908
1909 return errs;
1910 }
1911
count_bad_b64_chars(const char * src,int len)1912 static int count_bad_b64_chars(const char * src, int len)
1913 {
1914 const unsigned char * usrc = (const unsigned char *)src;
1915 int c, bad = 0;
1916
1917 for(c = 0; c < len; c++)
1918 if( b64_decode_table[usrc[c]] == (unsigned char)0x80 )
1919 bad++;
1920
1921 return bad;
1922 }
1923
show_bad_b64_chars(const char * src,int len)1924 static int show_bad_b64_chars(const char * src, int len)
1925 {
1926 const unsigned char * usrc = (const unsigned char *)src;
1927 int c, bad = 0;
1928
1929 fprintf(stderr,"-- bad b64 chars:");
1930 for(c = 0; c < len; c++)
1931 if( b64_decode_table[usrc[c]] == (unsigned char)0x80 ) {
1932 bad++;
1933 fprintf(stderr," 0x%02x", usrc[c]);
1934 }
1935 if( bad ) fputc('\n', stderr);
1936 else fprintf(stderr," none");
1937
1938 return bad;
1939 }
1940
1941 /* this must go to the data of the latest darray struct */
append_to_data_ascii(gxml_data * xd,const char * cdata,int len)1942 static int append_to_data_ascii(gxml_data * xd, const char * cdata, int len)
1943 {
1944 static int mod_prev = 0;
1945 giiDataArray * da = xd->gim->darray[xd->gim->numDA-1]; /* current DA */
1946
1947 char * dptr;
1948 char * cptr;
1949 long long rem_vals;
1950 int rem_len = len, copy_len, unused;
1951 int type = da->datatype;
1952
1953 if( xd->verb > 4 )
1954 fprintf(stderr,"++ appending %d ASCII bytes to data\n",len);
1955
1956 /* if there is only whitespace, blow outta here */
1957 if( whitespace_len(cdata, len) == len ) { xd->doff = 0; return 0; }
1958
1959 /* Copy cdata to local buffer in pieces, for null termination and for
1960 storage of trailing characters that may need to be processed again
1961 (after more characters are read by the parser). */
1962 while( rem_len > 0 ) {
1963 /*--- prepare intermediate buffer ---*/
1964
1965 /* point to the current location */
1966 cptr = (char *)cdata + len - rem_len;
1967
1968 /* if we're looking at whitespace, any unused data is garbage */
1969 if( isspace(*cptr)) xd->doff = 0;
1970
1971 /* decide how many bytes to copy (avail space w/max of rem_len) */
1972 copy_len = xd->dlen - xd->doff - 1;
1973 if( copy_len > rem_len ) {
1974 unused = copy_len - rem_len; /* unused at end of buffer */
1975 copy_len = rem_len;
1976 } else unused = 0;
1977
1978 /* copy it to our buffer and null terminate */
1979 memcpy(xd->ddata+xd->doff, cptr, copy_len);
1980 xd->ddata[xd->doff+copy_len] = '\0';
1981
1982 /*--- process the ascii data ---*/
1983
1984 /* note how many values remain to be computed */
1985 rem_vals = da->nvals - xd->dind;
1986 if(xd->verb > 5)
1987 fprintf(stderr,"-- %lld vals left at offset %lld, nbyper %d\n",
1988 rem_vals, xd->dind, da->nbyper);
1989
1990 if( xd->dind == 0 ) mod_prev = 0; /* nothing to modify at first */
1991 dptr = (char *)da->data + (xd->dind)*da->nbyper;
1992 xd->doff = decode_ascii(xd,
1993 xd->ddata, /* data source */
1994 xd->doff+copy_len, /* data length */
1995 type, /* data type */
1996 dptr, /* starting destination */
1997 &rem_vals, /* nvals to read */
1998 &mod_prev /* can we mod previous val */
1999 );
2000
2001 /*--- check results --- */
2002 if( xd->doff < 0 ) { xd->doff = 0; return 1; } /* error */
2003 if( xd->doff >= xd->dlen - 1 ) {
2004 if(xd->verb) fprintf(stderr,"** A2D: failed to process buffer\n");
2005 fprintf(stderr,"** rem = %d\n", xd->doff);
2006 xd->doff = 0; /* blow away the buffer and continue */
2007 }
2008
2009 /*--- adjust intermediate buffer ---*/
2010
2011 /* move any unused bytes to the beginning (last doff, before unused) */
2012 if( xd->doff > 0 ) {
2013 if( xd->verb > 5 )
2014 fprintf(stderr,"++ A2D: move %d bytes from %d (blen %d)\n",
2015 xd->doff, xd->dlen - unused - xd->doff, xd->dlen);
2016 /* (subtract unused+1, since 1 byte is saved for null */
2017 memmove(xd->ddata, xd->ddata+xd->dlen -(unused+1) - xd->doff,
2018 xd->doff);
2019 if( xd->verb > 6 )
2020 fprintf(stderr," bytes are '%.*s'\n",xd->doff,
2021 (char *)xd->ddata);
2022 }
2023
2024 /* adjust rem_len for next time */
2025 rem_len -= copy_len;
2026 xd->dind = da->nvals - rem_vals; /* note remaining values */
2027 }
2028
2029 return 0;
2030 }
2031
2032 /* this must go to the xform of the latest darray struct */
2033 /* (process as 1-D array) */
append_to_xform(gxml_data * xd,const char * cdata,int len)2034 static int append_to_xform(gxml_data * xd, const char * cdata, int len)
2035 {
2036 static int mod_prev = 0;
2037 giiDataArray * da = xd->gim->darray[xd->gim->numDA-1]; /* current DA */
2038
2039 double * dptr;
2040 char * cptr;
2041 long long rem_vals;
2042 int rem_len = len, copy_len, unused, CSind;
2043 int type = gifti_str2datatype("NIFTI_TYPE_FLOAT64"); /* double */
2044
2045 if( !da || !xd->xlen || !xd->xdata || xd->dind < 0 || da->numCS <= 0) {
2046 fprintf(stderr,"** A2X: bad setup (%p,%d,%p,%lld,%d)\n",
2047 (void *)da, xd->xlen, (void *)xd->xdata, xd->dind, da->numCS);
2048 return 1;
2049 } else if( xd->verb > 4 )
2050 fprintf(stderr,"++ appending %d bytes to xform\n",len);
2051
2052 CSind = da->numCS-1;
2053 if( !da->coordsys || !da->coordsys[CSind] ) {
2054 fprintf(stderr,"** A2X: bad coordsys[%d]\n", CSind);
2055 return 1;
2056 }
2057
2058 /* if there is only whitespace, blow outta here */
2059 if( whitespace_len(cdata, len) == len ) { xd->doff = 0; return 0; }
2060
2061 /* Copy cdata to local buffer in pieces, for null termination and for
2062 storage of trailing characters that may need to be processed again
2063 (after more characters are read by the parser). */
2064 while( rem_len > 0 ) {
2065 /*--- prepare intermediate buffer ---*/
2066
2067 /* point to the current location */
2068 cptr = (char *)cdata + len - rem_len;
2069
2070 /* if we're looking at whitespace, any unused data is garbage */
2071 if( isspace(*cptr)) xd->doff = 0;
2072
2073 /* decide how many bytes to copy (avail space w/max of rem_len) */
2074 copy_len = xd->xlen - xd->doff - 1;
2075 if( copy_len > rem_len ) {
2076 unused = copy_len - rem_len; /* unused at end of buffer */
2077 copy_len = rem_len;
2078 } else unused = 0;
2079
2080 /* copy it to our buffer and null terminate */
2081 memcpy(xd->xdata+xd->doff, cptr, copy_len);
2082 xd->xdata[xd->doff+copy_len] = '\0';
2083
2084 /* note how many values remain to be computed */
2085 rem_vals = 16 - xd->dind;
2086
2087 /*--- process the ascii data ---*/
2088 if( xd->dind == 0 ) mod_prev = 0; /* nothing to modify at first */
2089 dptr = (double *)da->coordsys[CSind]->xform + (xd->dind); /* as array */
2090 xd->doff = decode_ascii(xd,
2091 xd->xdata, /* data source */
2092 xd->doff+copy_len, /* data length */
2093 type, /* data type */
2094 dptr, /* starting destination */
2095 &rem_vals, /* nvals to read */
2096 &mod_prev /* can we mod previous val */
2097 );
2098
2099 /*--- check results --- */
2100 if( xd->doff < 0 ) { xd->doff = 0; return 1; } /* error */
2101 if( xd->doff >= xd->xlen - 1 ) {
2102 if(xd->verb) fprintf(stderr,"** A2X: failed to process buffer\n");
2103 fprintf(stderr,"** rem = %d\n", xd->doff);
2104 xd->doff = 0; /* blow away the buffer and continue */
2105 }
2106
2107 /*--- adjust intermediate buffer ---*/
2108
2109 /* move any unused bytes to the beginning (last doff, before unused) */
2110 if( xd->doff > 0 ) {
2111 if( xd->verb > 5 )
2112 fprintf(stderr,"++ A2X: move %d bytes from %d (blen %d)\n",
2113 xd->doff, xd->dlen - unused - xd->doff, xd->dlen);
2114 /* (subtract unused+1, since 1 bytes is saved for null */
2115 memmove(xd->xdata, xd->xdata+xd->xlen -(unused+1) -xd->doff,
2116 xd->doff);
2117 if( xd->verb > 6 )
2118 fprintf(stderr," bytes are '%.*s'\n",xd->doff,
2119 (char *)xd->ddata);
2120 }
2121
2122 /* adjust rem_len for next time */
2123 rem_len -= copy_len;
2124 xd->dind = 16 - rem_vals; /* note remaining values */
2125 }
2126
2127 return 0;
2128 }
2129
2130 #undef GII_B64_decode4
2131 #define GII_B64_decode4(w,x,y,z,a,b,c) \
2132 ( a = (b64_decode_table[w] << 2) | (b64_decode_table[x] >> 4) , \
2133 b = (b64_decode_table[x] << 4) | (b64_decode_table[y] >> 2) , \
2134 c = (b64_decode_table[y] << 6) | b64_decode_table[z] )
2135
2136 /* given: source pointer, length, dest loc and nbytes to set,
2137 (cdata is null-terminated)
2138 modify: needed (bytes) left for output
2139 return: nbytes unprocessed, so 0-3 (< 0 on error)
2140
2141 Convert the base64 character data into binary.
2142 - read failure happens only when no characters are processed
2143 - characters are not checked for validity (maybe already done)
2144
2145 note: the base64 defaults will be applied
2146 o EOL use is not allowed
2147 o padding is expected (using '=')
2148 */
decode_b64(gxml_data * xd,char * cdata,int cdlen,char * dptr,long long * needed)2149 static int decode_b64(gxml_data * xd, char * cdata, int cdlen,
2150 char * dptr, long long * needed)
2151 {
2152 unsigned char * din = (unsigned char *)cdata;
2153 unsigned char * dout = (unsigned char *)dptr;
2154 int blocks = cdlen/4, rem = cdlen % 4;
2155 int ind, assigned;
2156
2157 if( xd->verb > 4)
2158 fprintf(stderr,"-- DB64: decode len %d, remain %lld\n", cdlen,*needed);
2159 if( *needed <= 0 ) {
2160 if( cdlen > 0 )
2161 fprintf(stderr,"** DB64: %d bytes left without a home\n", cdlen);
2162 return 0;
2163 }
2164
2165 for( ind = 0; ind < blocks && *needed >= 3; ind++, *needed -= 3 ){
2166 GII_B64_decode4(din[0],din[1],din[2],din[3], dout[0],dout[1],dout[2]);
2167
2168 din += 4;
2169 dout += 3;
2170 }
2171 assigned = 3*ind;
2172
2173 /* the first blocks-1 sets should just work */
2174 if( ind < blocks-1 || (ind < blocks && *needed == 0) ){
2175 if( xd->verb > 6 )
2176 gifti_disp_hex_data("decoded b64: 0x ", dptr, assigned, stderr);
2177 fprintf(stderr,"** decode_b64: more data than space\n");
2178 return -1;
2179 }
2180
2181 /* if we didn't finish, try to fill a partial block */
2182 if( ind < blocks ) { /* so *needed < 3 */
2183 unsigned char a, b, c;
2184 GII_B64_decode4(din[0],din[1],din[2],din[3], a, b, c);
2185 if( *needed >= 1 ) dout[0] = a;
2186 if( *needed >= 2 ) dout[1] = b;
2187 assigned += *needed;
2188 *needed = 0;
2189 }
2190
2191 if( xd->verb > 6 )
2192 gifti_disp_hex_data("decoded b64: 0x ", dptr, assigned, stderr);
2193
2194 return rem;
2195 }
2196
2197
2198 /* given: source pointer, remaining length, nvals desired, dest loc and type
2199 (cdata is null-terminated)
2200 modify: nvals left for output, mod_prev for next call
2201 return: nbytes that may still need to processed (< 0 on error)
2202
2203 read failure happens only when no characters are processed
2204 */
decode_ascii(gxml_data * xd,char * cdata,int cdlen,int type,void * dptr,long long * nvals,int * mod_prev)2205 static int decode_ascii(gxml_data * xd, char * cdata, int cdlen, int type,
2206 void * dptr, long long * nvals, int * mod_prev)
2207 {
2208 char * p1, *p2; /* for strtoX */
2209 char * prev; /* for remain */
2210 double dval; /* for strtod */
2211 long lval; /* for strtol */
2212 int remain = 0; /* use bytes remaining */
2213 int vals = 0;
2214
2215 if( xd->verb > 4)
2216 fprintf(stderr,"-- DA: type %s, len %d, nvals %lld\n",
2217 gifti_datatype2str(type),cdlen,*nvals);
2218
2219 /* if reprocessing, maybe let the user know */
2220 if( xd->doff > 0 && *mod_prev ) {
2221 if( xd->verb > 4)
2222 fprintf(stderr,"++ DA: re-proc '%.*s' from '%.*s'...\n",
2223 xd->doff, cdata, xd->doff+15, cdata);
2224 vals--; /* back up */
2225 }
2226
2227 switch( type ) {
2228 default :
2229 fprintf(stderr,"** decode_ascii cannot decode type %d\n",type);
2230 return -1;
2231 case NIFTI_TYPE_UINT8: {
2232 unsigned char * ptr = (unsigned char *)dptr;
2233 p1 = cdata;
2234 prev = p1;
2235 /* vals could be < 0, but we must care for promotion to size_t */
2236 while( (vals < 0 || vals < *nvals) && p1 ) {
2237 lval = strtol(p1, &p2, 10); /* try to read next value */
2238 if( p1 == p2 ) break; /* nothing read, terminate loop */
2239 prev = p1; /* store old success ptr */
2240 p1 = p2; /* move to next posn */
2241 ptr[vals] = lval; /* assign new value */
2242 if(xd->verb>6)fprintf(stderr," v %d (%ld)",ptr[vals],lval);
2243 vals++; /* count new value */
2244 }
2245 if(xd->verb > 6) fputc('\n', stderr);
2246 break;
2247 }
2248 case NIFTI_TYPE_INT16: {
2249 short * ptr = (short *)dptr;
2250 p1 = cdata;
2251 prev = p1;
2252 while( (vals < 0 || vals < *nvals) && p1 ) {
2253 lval = strtol(p1, &p2, 10); /* try to read next value */
2254 if( p1 == p2 ) break; /* nothing read, terminate loop */
2255 prev = p1; /* store old success ptr */
2256 p1 = p2; /* move to next posn */
2257 ptr[vals] = lval; /* assign new value */
2258 if(xd->verb>6)fprintf(stderr," v %d (%ld)",ptr[vals],lval);
2259 vals++; /* count new value */
2260 }
2261 if(xd->verb > 6) fputc('\n', stderr);
2262 break;
2263 }
2264 case NIFTI_TYPE_INT32: {
2265 int * ptr = (int *)dptr;
2266 p1 = cdata;
2267 prev = p1;
2268 while( (vals < 0 || vals < *nvals) && p1 ) {
2269 lval = strtol(p1, &p2, 10); /* try to read next value */
2270 if( p1 == p2 ) break; /* nothing read, terminate loop */
2271 prev = p1; /* store old success ptr */
2272 p1 = p2; /* move to next posn */
2273 ptr[vals] = lval; /* assign new value */
2274 if(xd->verb>6)fprintf(stderr," v %d (%ld)",ptr[vals],lval);
2275 vals++; /* count new value */
2276 }
2277 if(xd->verb > 6) fputc('\n', stderr);
2278 break;
2279 }
2280 case NIFTI_TYPE_FLOAT32: {
2281 float * ptr = (float *)dptr;
2282 p1 = cdata;
2283 prev = p1;
2284 while( (vals < 0 || vals < *nvals) && p1 ) {
2285 dval = strtod(p1, &p2); /* try to read next value */
2286 if( p1 == p2 ) break; /* nothing read, terminate loop */
2287 prev = p1; /* store old success ptr */
2288 p1 = p2; /* move to next posn */
2289 ptr[vals] = dval; /* assign new value */
2290 if(xd->verb>6)fprintf(stderr," v %f (%f)",ptr[vals],dval);
2291 vals++; /* count new value */
2292 }
2293 if(xd->verb > 6) fputc('\n', stderr);
2294 break;
2295 }
2296 case NIFTI_TYPE_COMPLEX64: {
2297 /* there are 2 pieces to each complex, so read and insert 1 at a
2298 time, and increment 'vals' only after each second piece */
2299 static int piece = 0;
2300 float * ptr = (float *)dptr;
2301 p1 = cdata;
2302 prev = p1;
2303 while( (vals < 0 || vals < *nvals) && p1 ) {
2304 dval = strtod(p1, &p2); /* try to read next value */
2305 if( p1 == p2 ) break; /* nothing read, terminate loop */
2306 prev = p1; /* store old success ptr */
2307 p1 = p2; /* move to next posn */
2308 ptr[2*vals+piece] = dval; /* assign new value */
2309 if(xd->verb>6) fprintf(stderr," v %f (%f)", ptr[2*vals],dval);
2310 if( piece == 1 ) vals++; /* have a complete data value */
2311 piece = 1-piece;
2312 }
2313 if(xd->verb > 6) fputc('\n', stderr);
2314 break;
2315 }
2316 case NIFTI_TYPE_FLOAT64: {
2317 double * ptr = (double *)dptr;
2318 p1 = cdata;
2319 prev = p1;
2320 while( (vals < 0 || vals < *nvals) && p1 ) {
2321 dval = strtod(p1, &p2); /* try to read next value */
2322 if( p1 == p2 ) break; /* nothing read, terminate loop */
2323 prev = p1; /* store old success ptr */
2324 p1 = p2; /* move to next posn */
2325 ptr[vals] = dval; /* assign new value */
2326 if(xd->verb>6)fprintf(stderr," v %f (%f)",ptr[vals],dval);
2327 vals++; /* count new value */
2328 }
2329 if(xd->verb > 6) fputc('\n', stderr);
2330 break;
2331 }
2332 case NIFTI_TYPE_RGB24: {
2333 /* there are 3 pieces to each RGB24, so read and insert 1 at a
2334 time, and increment 'vals' only after each third piece */
2335 static int piece = 0;
2336 unsigned char * ptr = (unsigned char *)dptr;
2337 p1 = cdata;
2338 prev = p1;
2339 /* vals could be < 0, but we must care for promotion to size_t */
2340 while( (vals < 0 || vals < *nvals) && p1 ) {
2341 lval = strtol(p1, &p2, 10); /* try to read next value */
2342 if( p1 == p2 ) break; /* nothing read, terminate loop */
2343 prev = p1; /* store old success ptr */
2344 p1 = p2; /* move to next posn */
2345 ptr[3*vals+piece] = lval; /* assign new value */
2346 if(xd->verb>6)
2347 fprintf(stderr," v %u (%ld)", ptr[3*vals],lval);
2348 if( piece == 2 ) vals++; /* have a complete data value */
2349 piece = (piece + 1) % 3;
2350 }
2351 if(xd->verb > 6) fputc('\n', stderr);
2352 break;
2353 }
2354 case NIFTI_TYPE_INT8: {
2355 char * ptr = (char *)dptr;
2356 p1 = cdata;
2357 prev = p1;
2358 /* vals could be < 0, but we must care for promotion to size_t */
2359 while( (vals < 0 || vals < *nvals) && p1 ) {
2360 lval = strtol(p1, &p2, 10); /* try to read next value */
2361 if( p1 == p2 ) break; /* nothing read, terminate loop */
2362 prev = p1; /* store old success ptr */
2363 p1 = p2; /* move to next posn */
2364 ptr[vals] = lval; /* assign new value */
2365 if(xd->verb>6)fprintf(stderr," v %d (%ld)",ptr[vals],lval);
2366 vals++; /* count new value */
2367 }
2368 if(xd->verb > 6) fputc('\n', stderr);
2369 break;
2370 }
2371 case NIFTI_TYPE_UINT16: {
2372 unsigned short * ptr = (unsigned short *)dptr;
2373 p1 = cdata;
2374 prev = p1;
2375 while( (vals < 0 || vals < *nvals) && p1 ) {
2376 lval = strtol(p1, &p2, 10); /* try to read next value */
2377 if( p1 == p2 ) break; /* nothing read, terminate loop */
2378 prev = p1; /* store old success ptr */
2379 p1 = p2; /* move to next posn */
2380 ptr[vals] = lval; /* assign new value */
2381 if(xd->verb>6)fprintf(stderr," v %d (%ld)",ptr[vals],lval);
2382 vals++; /* count new value */
2383 }
2384 if(xd->verb > 6) fputc('\n', stderr);
2385 break;
2386 }
2387 case NIFTI_TYPE_INT64: {
2388 long long * ptr = (long long *)dptr;
2389 long long llval;
2390 p1 = cdata;
2391 prev = p1;
2392 while( (vals < 0 || vals < *nvals) && p1 ) {
2393 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
2394 llval = strtol(p1, &p2, 10); /* There is no strtoll defined in MS VC++ */
2395 #else
2396 llval = strtoll(p1, &p2, 10); /* try to read next value */
2397 #endif
2398 if( p1 == p2 ) break; /* nothing read, terminate loop */
2399 prev = p1; /* store old success ptr */
2400 p1 = p2; /* move to next posn */
2401 ptr[vals] = llval; /* assign new value */
2402 if(xd->verb>6)fprintf(stderr," v %lld (%lld)",ptr[vals],llval);
2403 vals++; /* count new value */
2404 }
2405 if(xd->verb > 6) fputc('\n', stderr);
2406 break;
2407 }
2408 case NIFTI_TYPE_COMPLEX128: {
2409 /* there are 2 pieces to each complex, so read and insert 1 at a
2410 time, and increment 'vals' only after each second piece */
2411 static int piece = 0;
2412 double * ptr = (double *)dptr;
2413 p1 = cdata;
2414 prev = p1;
2415 while( (vals < 0 || vals < *nvals) && p1 ) {
2416 dval = strtod(p1, &p2); /* try to read next value */
2417 if( p1 == p2 ) break; /* nothing read, terminate loop */
2418 prev = p1; /* store old success ptr */
2419 p1 = p2; /* move to next posn */
2420 ptr[2*vals+piece] = dval; /* assign new value */
2421 if(xd->verb>6) fprintf(stderr," v %f (%f)", ptr[2*vals],dval);
2422 if( piece == 1 ) vals++; /* have a complete data value */
2423 piece = 1-piece;
2424 }
2425 if(xd->verb > 6) fputc('\n', stderr);
2426 break;
2427 }
2428 }
2429
2430 /* update the number of values processed */
2431 if( vals > 0 ) (*nvals) -= vals;
2432
2433 /* ponder remaining: if *p1 is space, look from there, else from prev */
2434 if( p1 ){
2435 if( isspace(*p1) ) {
2436 remain = cdlen - (p1 - cdata);
2437 *mod_prev = 0;
2438 }
2439 else if( prev ) {
2440 remain = cdlen - (prev - cdata);
2441 *mod_prev = 1; /* still looking at previous val */
2442 }
2443 }
2444
2445 /* if only whitespace left, ignore */
2446 if( whitespace_len(cdata + (cdlen-remain), remain) == remain )
2447 remain = 0;
2448
2449 if(xd->verb > 6) fprintf(stderr,"-- DA: remain = %d\n", remain);
2450
2451 return remain;
2452 }
2453
cb_instr(void * udata,const char * target,const char * data)2454 static void XMLCALL cb_instr(void *udata, const char *target, const char *data)
2455 {
2456 gxml_data * xd = (gxml_data *)udata;
2457 if( xd->verb > 3 ){
2458 show_depth(xd->depth, 1, stderr);
2459 fprintf(stderr, "instr: %s='%s'\n",target,data);
2460 }
2461 }
2462
cb_comment(void * udata,const char * str)2463 static void XMLCALL cb_comment(void *udata, const char * str)
2464 {
2465 gxml_data * xd = (gxml_data *)udata;
2466 if( xd->verb > 1 ){
2467 show_depth(xd->depth, 1, stderr);
2468 fprintf(stderr, "comment: '%s'\n",str);
2469 }
2470 }
2471
cb_cdata_start(void * udata)2472 static void XMLCALL cb_cdata_start(void *udata)
2473 {
2474 gxml_data * xd = (gxml_data *)udata;
2475
2476 if( xd->verb > 3 ){
2477 show_depth(xd->depth, 1, stderr);
2478 fprintf(stderr, "cdata_start\n");
2479 }
2480 (void)epush(xd, GXML_ETYPE_CDATA, enames[GXML_ETYPE_CDATA], NULL);
2481 }
2482
cb_cdata_end(void * udata)2483 static void XMLCALL cb_cdata_end(void *udata)
2484 {
2485 gxml_data * xd = (gxml_data *)udata;
2486 epop(xd, GXML_ETYPE_CDATA, enames[GXML_ETYPE_CDATA]);
2487 }
2488
cb_default(void * udata,const char * str,int length)2489 static void XMLCALL cb_default(void *udata, const char * str, int length)
2490 {
2491 gxml_data * xd = (gxml_data *)udata;
2492 int wlen = whitespace_len(str,length);
2493 int len = length;
2494
2495 if( len == wlen )
2496 {
2497 if( xd->verb < 4 ) return;
2498
2499 str = "whitespace"; /* just note the whitespace */
2500 len = strlen(str);
2501 }
2502
2503 if( xd->verb > 3 ){
2504 show_depth(xd->depth, 1, stderr);
2505 fprintf(stderr, "default XML element [%d]: '%.*s'\n",length,len,str);
2506 }
2507 }
2508
cb_xml_dec(void * udata,const char * ver,const char * enc,int standalone)2509 static void XMLCALL cb_xml_dec(void *udata, const char * ver,
2510 const char * enc, int standalone)
2511 {
2512 gxml_data * xd = (gxml_data *)udata;
2513 if( xd->verb > 2 ){
2514 show_depth(xd->depth, 1, stderr);
2515 fprintf(stderr, "xmldec ver = %s, enc = %s, standalone = %d\n",
2516 ver,enc,standalone);
2517 }
2518 }
2519
cb_start_doctype(void * udata,const char * doctype,const char * sysid,const char * pubid,int has_subset)2520 static void XMLCALL cb_start_doctype(void *udata, const char * doctype,
2521 const char * sysid, const char * pubid, int has_subset )
2522 {
2523 gxml_data * xd = (gxml_data *)udata;
2524 if( xd->verb > 2 ){
2525 show_depth(xd->depth, 1, stderr);
2526 /* check for NULL in optional strings 4 Mar 2010 */
2527 fprintf(stderr, "start_doctype, dt='%s', sid='%s',pid='%s', sub=%d\n",
2528 doctype, sysid?sysid:"NULL", pubid?pubid:"NULL", has_subset);
2529 }
2530 }
2531
cb_end_doctype(void * udata)2532 static void XMLCALL cb_end_doctype(void *udata)
2533 {
2534 gxml_data * xd = (gxml_data *)udata;
2535 if( xd->verb > 2 ){
2536 show_depth(xd->depth, 1, stderr);
2537 fprintf(stderr, "end_doctype\n");
2538 }
2539 }
2540
cb_elem_dec(void * udata,const char * ename,XML_Content * content)2541 static void XMLCALL cb_elem_dec(void *udata, const char * ename,
2542 XML_Content * content)
2543 {
2544 gxml_data * xd = (gxml_data *)udata;
2545 if( xd->verb > 2 ){
2546 show_depth(xd->depth, 1, stderr);
2547 fprintf(stderr,"%s: type=%d, quant=%d, name=%s, numc=%d, cp=%p\n",
2548 ename, content->type, content->quant, content->name,
2549 content->numchildren, (void *)content->children);
2550 }
2551 }
2552
init_xml_parser(void * user_data)2553 static XML_Parser init_xml_parser( void * user_data )
2554 {
2555 XML_Parser parser;
2556
2557 parser = XML_ParserCreate(NULL);
2558 XML_SetUserData(parser, user_data);
2559 XML_SetStartElementHandler(parser, cb_start_ele);
2560 XML_SetEndElementHandler(parser, cb_end_ele);
2561 XML_SetCharacterDataHandler(parser, cb_char);
2562 XML_SetProcessingInstructionHandler(parser, cb_instr);
2563 XML_SetCommentHandler(parser, cb_comment);
2564 XML_SetStartCdataSectionHandler(parser, cb_cdata_start);
2565 XML_SetEndCdataSectionHandler(parser, cb_cdata_end);
2566 XML_SetDefaultHandler(parser, cb_default);
2567 XML_SetXmlDeclHandler(parser, cb_xml_dec);
2568 XML_SetStartDoctypeDeclHandler(parser, cb_start_doctype);
2569 XML_SetEndDoctypeDeclHandler(parser, cb_end_doctype);
2570 XML_SetElementDeclHandler(parser, cb_elem_dec);
2571
2572 if( GXD.verb > 3 ) fprintf(stderr,"-- parser initialized\n");
2573
2574 return parser;
2575 }
2576
2577
show_stack(char * mesg,gxml_data * xd)2578 static int show_stack(char * mesg, gxml_data * xd)
2579 {
2580 int c;
2581 if( !xd ) return 1;
2582 if( mesg ) fputs(mesg, stderr);
2583 fprintf(stderr,"stack[%d]", xd->depth);
2584 for( c = 0; c < xd->depth; c++ )
2585 fprintf(stderr," : %s", enames[xd->stack[c]]);
2586 fputc('\n', stderr);
2587 return 0;
2588 }
2589
stack_is_valid(gxml_data * xd)2590 static int stack_is_valid(gxml_data * xd)
2591 {
2592 int valid, etype, parent, bad_parent;
2593
2594 if( xd->depth < 0 ) return 0;
2595 if( xd->depth == 0 ) return 1;
2596
2597 etype = xd->stack[xd->depth-1]; /* depth is at least 1 */
2598
2599 /* process depth 1 separately, so we can assume a parent later */
2600 if( xd->depth == 1 ) {
2601 if( etype != GXML_ETYPE_GIFTI ) {
2602 show_stack("** invalid element on ", xd);
2603 return 0;
2604 }
2605 return 1;
2606 }
2607
2608 /* verify proper parent (or invalid type) */
2609 valid = 1;
2610 bad_parent = 0;
2611 parent = xd->stack[xd->depth-2]; /* depth is at least 2 */
2612 switch( etype ) {
2613 default:
2614 case GXML_ETYPE_INVALID:
2615 case GXML_ETYPE_GIFTI: /* should only be at depth 1 */
2616 valid = 0;
2617 break;
2618 case GXML_ETYPE_META:
2619 if( parent != GXML_ETYPE_GIFTI &&
2620 parent != GXML_ETYPE_DATAARRAY ) bad_parent = 1;
2621 break;
2622 case GXML_ETYPE_MD:
2623 if( parent != GXML_ETYPE_META ) bad_parent = 1;
2624 break;
2625 case GXML_ETYPE_NAME:
2626 if( parent != GXML_ETYPE_MD ) bad_parent = 1;
2627 break;
2628 case GXML_ETYPE_VALUE:
2629 if( parent != GXML_ETYPE_MD ) bad_parent = 1;
2630 break;
2631 case GXML_ETYPE_LABELTABLE:
2632 if( parent != GXML_ETYPE_GIFTI ) bad_parent = 1;
2633 break;
2634 case GXML_ETYPE_LABEL:
2635 if( parent != GXML_ETYPE_LABELTABLE ) bad_parent = 1;
2636 break;
2637 case GXML_ETYPE_DATAARRAY:
2638 if( parent != GXML_ETYPE_GIFTI ) bad_parent = 1;
2639 break;
2640 case GXML_ETYPE_CSTM:
2641 if( parent != GXML_ETYPE_DATAARRAY ) bad_parent = 1;
2642 break;
2643 case GXML_ETYPE_DATA:
2644 if( parent != GXML_ETYPE_DATAARRAY ) bad_parent = 1;
2645 break;
2646 case GXML_ETYPE_DATASPACE:
2647 if( parent != GXML_ETYPE_CSTM ) bad_parent = 1;
2648 break;
2649 case GXML_ETYPE_XFORMSPACE:
2650 if( parent != GXML_ETYPE_CSTM ) bad_parent = 1;
2651 break;
2652 case GXML_ETYPE_MATRIXDATA:
2653 if( parent != GXML_ETYPE_CSTM ) bad_parent = 1;
2654 break;
2655 case GXML_ETYPE_CDATA:
2656 if( parent != GXML_ETYPE_NAME &&
2657 parent != GXML_ETYPE_VALUE &&
2658 parent != GXML_ETYPE_LABEL &&
2659 parent != GXML_ETYPE_DATASPACE &&
2660 parent != GXML_ETYPE_XFORMSPACE &&
2661 parent != GXML_ETYPE_MATRIXDATA ) bad_parent = 1;
2662 break;
2663 }
2664
2665 /* possibly print a message if the stack looks bad */
2666 if( bad_parent && GXD.verb )
2667 fprintf(stderr,"** %s: bad parent '%s'\n",enames[etype],enames[parent]);
2668 if( (!valid || bad_parent) && GXD.verb > 1 ) show_stack("** invalid ", xd);
2669
2670 return valid;
2671 }
2672
2673 /* if bsize is no longer correct, update it and realloc the buffer */
reset_xml_buf(gxml_data * xd,char ** buf,int * bsize)2674 static int reset_xml_buf(gxml_data * xd, char ** buf, int * bsize)
2675 {
2676 if( *bsize == xd->buf_size ) {
2677 if( xd->verb > 3 )
2678 fprintf(stderr,"-- buffer kept at %d bytes\n", *bsize);
2679 return 0;
2680 }
2681
2682 if( xd->verb > 2 )
2683 fprintf(stderr,"++ update buf, %d to %d bytes\n",*bsize,xd->buf_size);
2684
2685 *bsize = xd->buf_size;
2686 *buf = (char *)realloc(*buf, *bsize * sizeof(char));
2687
2688 if( ! *buf ) {
2689 fprintf(stderr,"** failed to alloc %d bytes of xml buf!\n", *bsize);
2690 *bsize = 0;
2691 return 1;
2692 }
2693
2694 return 0;
2695 }
2696
2697 /* decide how big a processing buffer should be
2698 (either for a small xform matrix or a Data element)
2699 */
partial_buf_size(long long nbytes)2700 static int partial_buf_size(long long nbytes)
2701 {
2702 int ibytes = (int)nbytes; /* never more than 10 MB, anyway */
2703
2704 if( ibytes <= GXML_MIN_BSIZE ) return GXML_MIN_BSIZE;
2705 if( ibytes <= 64*1024 ) return ibytes;
2706
2707 if( ibytes <= 10*1024*1024 ) /* divide by 10, but round up to a block */
2708 return (ibytes/10 + 0xfff) & ~0xfff;
2709
2710 return 1024*1024;
2711 }
2712
2713 /* update xd->buf_size, used prior to reset_xml_buf */
update_xml_buf_size(gxml_data * xd,long long bytes)2714 static int update_xml_buf_size(gxml_data * xd, long long bytes)
2715 {
2716 int new_size;
2717
2718 if( !xd || bytes < 0 ){
2719 if( xd->verb > 1 )
2720 fprintf(stderr,"** bad update_xml_buf_size with %p and %lld\n",
2721 (void *)xd,bytes);
2722 return 0;
2723 }
2724
2725 new_size = partial_buf_size(bytes);
2726 if( new_size != xd->buf_size ){
2727 if( xd->verb > 2 )
2728 fprintf(stderr,"++ update XML buf size, %d to %d (for %lld)\n",
2729 xd->buf_size, new_size, bytes);
2730 xd->buf_size = new_size;
2731 }
2732
2733 return 0;
2734 }
2735
2736
2737 /* used to update any buffer, as the pointer address is passed in */
update_partial_buffer(char ** buf,int * blen,long long bytes,int full)2738 static int update_partial_buffer(char ** buf, int * blen, long long bytes,
2739 int full)
2740 {
2741 int bsize = partial_buf_size(bytes);
2742
2743 if( full ) bsize = bytes; /* want entire buffer */
2744
2745 if( !buf || !blen || bytes <= 0 ) {
2746 fprintf(stderr,"** UPB: bad params (%p,%p,%lld)\n",
2747 (void *)buf, (void *)blen, bytes);
2748 return 1;
2749 }
2750
2751 /* just make sure we have a text buffer to work with */
2752 if( *buf || *blen != bsize ) {
2753 if( GXD.verb > 2 )
2754 fprintf(stderr,"++ UPB, alloc %d bytes (from %lld, %d) for buff\n",
2755 bsize, bytes, full);
2756 *buf = (char *)realloc(*buf, bsize * sizeof(char));
2757 if( !*buf ) {
2758 fprintf(stderr,"** UPB: cannot alloc %d bytes for buffer\n",bsize);
2759 return 1;
2760 }
2761 *blen = bsize;
2762 }
2763
2764 return 0;
2765 }
2766
gxml_write_gifti(gxml_data * xd,FILE * fp)2767 static int gxml_write_gifti(gxml_data * xd, FILE * fp)
2768 {
2769 gifti_image * gim = xd->gim;
2770
2771 int c, offset;
2772 int first = 1; /* first attr to print? */
2773
2774 if( !gim || !fp ) return 1;
2775
2776 if( xd->verb > 1 )
2777 fprintf(stderr,"++ gifti image, numDA = %d, size = %lld MB\n",
2778 gim->numDA, gifti_gim_DA_size(gim,1));
2779
2780 gxml_write_preamble(fp);
2781 fprintf(fp,"<%s",enames[GXML_ETYPE_GIFTI]);
2782 if(gim->version){ fprintf(fp," Version=\"%s\"", gim->version); first = 0; }
2783 /* add space if no version, requested by E Anderson */
2784 fprintf(fp,"%sNumberOfDataArrays=\"%d\"", first ? " " : " ", gim->numDA);
2785
2786 /* add any extra attributes */
2787 offset = strlen(enames[GXML_ETYPE_GIFTI]) + 2;
2788 ewrite_ex_atrs(xd, &gim->ex_atrs, offset, 0, fp);
2789 fputs(">\n",fp);
2790
2791 xd->depth++;
2792 ewrite_meta(xd, &gim->meta, fp);
2793 ewrite_LT(xd, &gim->labeltable, 1, fp);
2794
2795 /* write the giiDataArray */
2796 if(!gim->darray) {
2797 if( xd->verb > 0 ) fprintf(stderr,"** gifti_image, missing darray\n");
2798 } else {
2799 for( c = 0; c < gim->numDA; c++ )
2800 ewrite_darray(xd, gim->darray[c], fp);
2801 }
2802
2803 xd->depth--;
2804 fprintf(fp,"</%s>\n",enames[GXML_ETYPE_GIFTI]);
2805
2806 return 0;
2807 }
2808
ewrite_darray(gxml_data * xd,giiDataArray * da,FILE * fp)2809 static int ewrite_darray(gxml_data * xd, giiDataArray * da, FILE * fp)
2810 {
2811 int spaces = xd->indent * xd->depth;
2812 int offset, c;
2813 char dimstr[5] = "Dim0";
2814
2815 if( xd->verb > 3 ) fprintf(stderr,"++ write giiDataArray\n");
2816
2817 if( !da ) return 0;
2818
2819 offset = strlen(enames[GXML_ETYPE_DATAARRAY]) + 2 + spaces;
2820 fprintf(fp, "%*s<DataArray", spaces, "");
2821
2822 /* print attributes */
2823 ewrite_str_attr("Intent", gifti_intent_to_string(da->intent), offset,1,fp);
2824 ewrite_str_attr("DataType", gifti_datatype2str(da->datatype), offset,0,fp);
2825 ewrite_str_attr("ArrayIndexingOrder",
2826 gifti_list_index2string(gifti_index_order_list,da->ind_ord),
2827 offset,0,fp);
2828 ewrite_int_attr("Dimensionality", da->num_dim, offset, 0, fp);
2829 for( c = 0; c < da->num_dim; c++ ) {
2830 ewrite_int_attr(dimstr, da->dims[c], offset, 0, fp);
2831 dimstr[3]++; /* too devious?? iterate '0', '1', ... */
2832 }
2833 ewrite_str_attr("Encoding",
2834 gifti_list_index2string(gifti_encoding_list,da->encoding),offset,0,fp);
2835 ewrite_str_attr("Endian", /* set endian to that of this CPU */
2836 gifti_list_index2string(gifti_endian_list, gifti_get_this_endian()),
2837 offset,0,fp);
2838 ewrite_str_attr("ExternalFileName", da->ext_fname, offset, 0, fp);
2839 if( da->ext_fname && *da->ext_fname )
2840 ewrite_long_long_attr("ExternalFileOffset",da->ext_offset, offset,0,fp);
2841 else
2842 ewrite_str_attr("ExternalFileOffset", NULL, offset, 0, fp);
2843 fprintf(fp, ">\n");
2844
2845 /* write sub-elements */
2846 xd->depth++;
2847 ewrite_meta(xd, &da->meta, fp);
2848 for( c = 0; c < da->numCS; c++ )
2849 ewrite_coordsys(xd, da->coordsys[c], fp);
2850 ewrite_data(xd, da, fp);
2851 xd->depth--;
2852
2853 fprintf(fp, "%*s</DataArray>\n", spaces, "");
2854
2855 return 0;
2856 }
2857
2858
2859 /* this depends on ind_ord, how to write out lines */
ewrite_data(gxml_data * xd,giiDataArray * da,FILE * fp)2860 static int ewrite_data(gxml_data * xd, giiDataArray * da, FILE * fp)
2861 {
2862 long long c, rows, cols;
2863 int spaces = xd->indent * xd->depth;
2864 int errs = 0;
2865
2866 if( !da ) return 0; /* okay, may not exist */
2867
2868 if( xd->verb > 3 )
2869 fprintf(stderr,"++ write %s Data\n",
2870 gifti_list_index2string(gifti_encoding_list, da->encoding));
2871
2872 /* maybe there is no data to write */
2873 if( !da->data || da->nvals <= 0 || da->nbyper <= 0 ) {
2874 fprintf(fp, "%*s<%s/>\n", spaces, "", enames[GXML_ETYPE_DATA]);
2875 return 0;
2876 }
2877
2878 if (da->encoding == GIFTI_ENCODING_EXTBIN) /* then write as empty */
2879 fprintf(fp, "%*s<%s/>\n", spaces, "", enames[GXML_ETYPE_DATA]);
2880 else /* write normal Data tag */
2881 fprintf(fp, "%*s<%s>", spaces, "", enames[GXML_ETYPE_DATA]);
2882
2883 if( xd->dstore ) {
2884 if( da->encoding == GIFTI_ENCODING_ASCII ) {
2885 fprintf(fp, "\n");
2886 gifti_DA_rows_cols(da, &rows, &cols); /* product will be nvals */
2887 for(c = 0; c < rows; c++ )
2888 ewrite_data_line(da->data,da->datatype,c,cols,
2889 spaces+xd->indent,fp);
2890 fprintf(fp, "%*s", spaces, "");
2891 } else if( da->encoding == GIFTI_ENCODING_B64BIN ) {
2892 gxml_disp_b64_data(NULL, da->data, da->nvals*da->nbyper, fp);
2893 } else if( da->encoding == GIFTI_ENCODING_B64GZ ) {
2894 #ifdef HAVE_ZLIB /* for compiling, higher level test elsewhere */
2895 uLongf blen = da->nvals*da->nbyper * 1.01 + 12; /* zlib.net */
2896 int rv = 0;
2897 if( update_partial_buffer(&xd->zdata, &xd->zlen, blen, 1) )
2898 return 1;
2899
2900 rv = compress2((Bytef *)xd->zdata, &blen, da->data,
2901 da->nvals*da->nbyper, xd->zlevel);
2902 if ( xd->verb > 2 )
2903 fprintf(stderr,"-- compress buffer (%.2f%% of %lld bytes)...\n",
2904 100.0*blen/(da->nvals*da->nbyper),da->nvals*da->nbyper);
2905 if( rv != Z_OK ) {
2906 fprintf(stderr,"** zlib compression failure: ");
2907 if( rv == Z_MEM_ERROR ) fprintf(stderr,"not enough memory\n");
2908 if( rv == Z_BUF_ERROR ) fprintf(stderr,"buffer too short\n");
2909 else fprintf(stderr,"unknown error %d\n",rv);
2910 errs++;
2911 } else if ( xd->verb > 2 )
2912 fprintf(stderr,"-- compression succeeded\n");
2913
2914 gxml_disp_b64_data(NULL, xd->zdata, blen, fp);
2915 #else
2916 fprintf(stderr,"** ewrite_data: no ZLIB to compress with\n");
2917 #endif
2918 } else if (da->encoding == GIFTI_ENCODING_EXTBIN) {
2919 /* write to external file */
2920 if( gifti_write_extern_DA_data(da) ) errs = 1;
2921 } else {
2922 fprintf(stderr,"** unknown data encoding, %d\n", da->encoding);
2923 errs = 1;
2924 }
2925 }
2926
2927 if (da->encoding != GIFTI_ENCODING_EXTBIN)
2928 fprintf(fp, "</%s>\n", enames[GXML_ETYPE_DATA]);
2929
2930 return errs;
2931 }
2932
2933 #undef GII_B64_encode3
2934 #define GII_B64_encode3(a,b,c,w,x,y,z) \
2935 ( w = b64_encode_table[(a)>>2] , \
2936 x = b64_encode_table[((a & 3) << 4) | (b >> 4)] , \
2937 y = b64_encode_table[((b & 0xF) << 2) | (c >> 6)] , \
2938 z = b64_encode_table[c & 0x3F] )
gxml_disp_b64_data(const char * mesg,const void * data,int len,FILE * fp)2939 static int gxml_disp_b64_data(const char *mesg, const void *data, int len,
2940 FILE *fp)
2941 {
2942 const unsigned char * dp = (const unsigned char *)data;
2943 unsigned char w, x, y, z;
2944 FILE * stream;
2945 int c, rem = len % 3;
2946
2947 stream = fp ? fp : stdout;
2948
2949 if( !data || len < 1 ) return -1;
2950
2951 if( mesg ) fputs(mesg, stream);
2952
2953 /* first get all of the 3-byte blocks */
2954 for( c = 0; c < len/3; c++, dp += 3 ) {
2955 GII_B64_encode3(dp[0], dp[1], dp[2], w, x, y, z);
2956 fprintf(stream, "%c%c%c%c", w, x, y, z);
2957 }
2958
2959 /* finish off the last bytes */
2960 if( rem == 1 ) {
2961 GII_B64_encode3(dp[0], 0, 0, w, x, y, z);
2962 fprintf(stream, "%c%c==", w, x);
2963 } else if ( rem == 2 ) {
2964 GII_B64_encode3(dp[0], dp[1], 0, w, x, y, z);
2965 fprintf(stream, "%c%c%c=", w, x, y);
2966 }
2967 /* else we're done */
2968
2969 return 0;
2970 }
2971
2972
ewrite_coordsys(gxml_data * xd,giiCoordSystem * cs,FILE * fp)2973 static int ewrite_coordsys(gxml_data * xd, giiCoordSystem * cs, FILE * fp)
2974 {
2975 int c, spaces = xd->indent * xd->depth;
2976
2977 if( !cs ) return 0; /* okay, may not exist */
2978
2979 if( xd->verb > 3 ) fprintf(stderr,"++ write giiCoordSystem\n");
2980
2981 fprintf(fp, "%*s<%s>\n", spaces, "", enames[GXML_ETYPE_CSTM]);
2982 spaces += xd->indent;
2983
2984 ewrite_text_ele(GXML_ETYPE_DATASPACE, cs->dataspace, NULL, spaces, 1, fp);
2985 ewrite_text_ele(GXML_ETYPE_XFORMSPACE, cs->xformspace, NULL, spaces, 1, fp);
2986
2987 fprintf(fp, "%*s<MatrixData>\n", spaces, "");
2988 for(c = 0; c < 4; c++ )
2989 ewrite_double_line(cs->xform[c], 4, spaces+xd->indent, fp);
2990 fprintf(fp, "%*s</MatrixData>\n", spaces, "");
2991
2992 spaces -= xd->indent;
2993 fprintf(fp, "%*s</%s>\n", spaces, "", enames[GXML_ETYPE_CSTM]);
2994
2995 return 0;
2996 }
2997
2998
2999 /* write one 'row' ('cols' values) of data in text */
ewrite_data_line(void * data,int type,long long row,long long cols,int space,FILE * fp)3000 static int ewrite_data_line(void * data, int type, long long row,
3001 long long cols, int space, FILE * fp)
3002 {
3003 int c;
3004 if( !data || row < 0 || cols <= 0 || !fp ) return 1;
3005
3006 fprintf(fp, "%*s", space, "");
3007 switch( type ) {
3008 default :
3009 fprintf(stderr,"** write_data_line, unknown type %d\n",type);
3010 return -1;
3011 case NIFTI_TYPE_UINT8: {
3012 unsigned char * ptr = (unsigned char *)data + row * cols;
3013 for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c]);
3014 break;
3015 }
3016 case NIFTI_TYPE_INT16: {
3017 short * ptr = (short *)data + row * cols;
3018 for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c]);
3019 break;
3020 }
3021 case NIFTI_TYPE_INT32: {
3022 int * ptr = (int *)data + row * cols;
3023 for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c]);
3024 break;
3025 }
3026 case NIFTI_TYPE_FLOAT32: {
3027 float * ptr = (float *)data + row * cols;
3028 for( c = 0; c < cols; c++ ) fprintf(fp, "%f ", ptr[c]);
3029 break;
3030 }
3031 case NIFTI_TYPE_COMPLEX64: {
3032 float * ptr = (float *)data + row * 2 * cols;
3033 for(c = 0; c < 2*cols; c+=2)fprintf(fp, "%f %f ",ptr[c],ptr[c+1]);
3034 break;
3035 }
3036 case NIFTI_TYPE_FLOAT64: {
3037 double * ptr = (double *)data + row * cols;
3038 for( c = 0; c < cols; c++ ) fprintf(fp, "%f ", ptr[c]);
3039 break;
3040 }
3041 case NIFTI_TYPE_RGB24: {
3042 unsigned char * ptr = (unsigned char *)data + row * 3 * cols;
3043 for( c = 0; c < 3*cols; c+=3 )
3044 fprintf(fp, "%u %u %u ", ptr[c], ptr[c+1], ptr[c+2]);
3045 break;
3046 }
3047 case NIFTI_TYPE_INT8: {
3048 char * ptr = (char *)data + row * cols;
3049 for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c]);
3050 break;
3051 }
3052 case NIFTI_TYPE_UINT16: {
3053 unsigned short * ptr = (unsigned short *)data + row * cols;
3054 for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c]);
3055 break;
3056 }
3057 case NIFTI_TYPE_UINT32: {
3058 unsigned int * ptr = (unsigned int *)data + row * cols;
3059 for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c]);
3060 break;
3061 }
3062 case NIFTI_TYPE_INT64: {
3063 long long * ptr = (long long *)data + row * cols;
3064 for( c = 0; c < cols; c++ ) fprintf(fp, "%lld ", ptr[c]);
3065 break;
3066 }
3067 case NIFTI_TYPE_UINT64: {
3068 unsigned long long * ptr = (unsigned long long *)data + row * cols;
3069 for( c = 0; c < cols; c++ ) fprintf(fp, "%llu ", ptr[c]);
3070 break;
3071 }
3072 case NIFTI_TYPE_FLOAT128: {
3073 long double * ptr = (long double *)data + row * cols;
3074 for( c = 0; c < cols; c++ ) fprintf(fp, "%Lf ", ptr[c]);
3075 break;
3076 }
3077 case NIFTI_TYPE_COMPLEX128: {
3078 double * ptr = (double *)data + row * 2 * cols;
3079 for(c = 0; c < 2*cols; c+=2)fprintf(fp, "%f %f ",ptr[c],ptr[c+1]);
3080 break;
3081 }
3082 case NIFTI_TYPE_COMPLEX256: {
3083 long double * ptr = (long double *)data + row * 2 * cols;
3084 for(c = 0; c<2*cols; c+=2)fprintf(fp, "%Lf %Lf ",ptr[c],ptr[c+1]);
3085 break;
3086 }
3087 }
3088
3089 fputc('\n', fp);
3090
3091 return 0;
3092 }
3093
3094
ewrite_double_line(double * data,int nvals,int space,FILE * fp)3095 static int ewrite_double_line(double * data, int nvals, int space, FILE * fp)
3096 {
3097 int c;
3098 if( !data || nvals <= 0 || !fp ) return 1;
3099
3100 fprintf(fp, "%*s", space, "");
3101 for( c = 0; c < nvals; c++ ) /* duplicate trailing space for diff */
3102 fprintf(fp, "%f ", data[c]);
3103 fputc('\n', fp);
3104
3105 return 0;
3106 }
3107
3108
ewrite_text_ele(int ele,const char * cdata,const char * attr,int spaces,int in_CDATA,FILE * fp)3109 static int ewrite_text_ele(int ele, const char * cdata, const char * attr,
3110 int spaces, int in_CDATA, FILE * fp)
3111 {
3112 int index = ele;
3113
3114 if(ele < 0 || ele > GXML_MAX_ELEN) index = 0; /* be safe */
3115
3116 fprintf(fp, "%*s<%s%s>%s%s%s</%s>\n",
3117 spaces, "", enames[index],
3118 attr ? attr : "",
3119 in_CDATA ? "<![CDATA[" : "",
3120 cdata ? cdata : "",
3121 in_CDATA ? "]]>" : "",
3122 enames[index]);
3123
3124 return 0;
3125 }
3126
ewrite_LT(gxml_data * xd,giiLabelTable * lt,int in_CDATA,FILE * fp)3127 static int ewrite_LT(gxml_data *xd, giiLabelTable *lt, int in_CDATA, FILE *fp)
3128 {
3129 char attr[256] = "";
3130 float * rgba;
3131 int c, spaces = xd->indent * xd->depth;
3132
3133 if( xd->verb > 3 ) fprintf(stderr,"++ write giiLabelTable\n");
3134
3135 if( !lt || lt->length == 0 || !lt->key || !lt->label ) {
3136 fprintf(fp, "%*s<LabelTable/>\n", spaces, "");
3137 return 0;
3138 }
3139
3140 fprintf(fp, "%*s<LabelTable>\n", spaces, "");
3141 rgba = lt->rgba;
3142 for( c = 0; c < lt->length; c++ ) {
3143 if( !lt->label[c] ) {
3144 if(xd->verb > 1) fprintf(stderr,"** label[%d] unset\n", c);
3145 continue;
3146 }
3147
3148 /* store the Key and optional RGBA attributes */
3149 if( lt->rgba ) {
3150 sprintf(attr, " Key=\"%d\""
3151 " Red=\"%g\" Green=\"%g\" Blue=\"%g\" Alpha=\"%g\"",
3152 lt->key[c], rgba[0], rgba[1], rgba[2], rgba[3]);
3153 rgba += 4;
3154 } else
3155 sprintf(attr, " Key=\"%d\"", lt->key[c]);
3156
3157 ewrite_text_ele(GXML_ETYPE_LABEL, lt->label[c], attr,
3158 spaces+xd->indent, in_CDATA, fp);
3159 }
3160 fprintf(fp, "%*s</LabelTable>\n", spaces, "");
3161
3162 return 0;
3163 }
3164
3165
ewrite_meta(gxml_data * xd,giiMetaData * md,FILE * fp)3166 static int ewrite_meta(gxml_data * xd, giiMetaData * md, FILE * fp)
3167 {
3168 int c, spaces = xd->indent * xd->depth;
3169
3170 if( xd->verb > 3 ) fprintf(stderr,"++ write giiMetaData\n");
3171
3172 if( !md || md->length == 0 || !md->name || !md->value ) {
3173 fprintf(fp, "%*s<MetaData/>\n", spaces, "");
3174 return 0;
3175 }
3176
3177 if( xd->verb > 3 ) fprintf(stderr," MD length = %d\n", md->length);
3178
3179 fprintf(fp, "%*s<MetaData>\n", spaces, "");
3180 for( c = 0; c < md->length; c++ ) {
3181 if( !md->name[c] ) { /* allow empty value, but not name */
3182 if(xd->verb > 1) fprintf(stderr,"** MD[%d] unset\n", c);
3183 continue;
3184 }
3185
3186 spaces += xd->indent;
3187 fprintf(fp,"%*s<MD>\n", spaces, "");
3188
3189 spaces += xd->indent;
3190 ewrite_text_ele(GXML_ETYPE_NAME, md->name[c], NULL, spaces, 1,fp);
3191 ewrite_text_ele(GXML_ETYPE_VALUE,md->value[c],NULL, spaces, 1,fp);
3192 spaces -= xd->indent;
3193
3194 fprintf(fp,"%*s</MD>\n", spaces, "");
3195 spaces -= xd->indent;
3196 }
3197 fprintf(fp, "%*s</MetaData>\n", spaces, "");
3198
3199 return 0;
3200 }
3201
3202
3203 /* print a list of attributes, indented to the same level */
ewrite_ex_atrs(gxml_data * xd,nvpairs * nvp,int offset,int first,FILE * fp)3204 static int ewrite_ex_atrs(gxml_data * xd, nvpairs * nvp, int offset,
3205 int first, FILE * fp)
3206 {
3207 int c, spaces = xd->indent * xd->depth + offset;
3208
3209 if(xd->verb > 2) fprintf(stderr,"++ write %d ex_atr's\n", nvp->length);
3210
3211 for( c = 0; c < nvp->length; c++ ) {
3212 ewrite_str_attr(nvp->name[c], nvp->value[c], spaces, first, fp);
3213 if( first ) first = 0;
3214 }
3215
3216 return 0;
3217 }
3218
3219
ewrite_int_attr(const char * name,int value,int spaces,int first,FILE * fp)3220 static int ewrite_int_attr(const char *name, int value, int spaces,
3221 int first, FILE * fp)
3222 {
3223 fprintf(fp, "%s%*s%s=\"%d\"",
3224 (first) ? "" : "\n", /* maybe a newline */
3225 (first) ? 1 : spaces, "", /* 1 or many spaces */
3226 name, value);
3227 return 0;
3228 }
3229
3230
ewrite_long_long_attr(const char * name,long long value,int spaces,int first,FILE * fp)3231 static int ewrite_long_long_attr(const char *name, long long value, int spaces,
3232 int first, FILE * fp)
3233 {
3234 fprintf(fp, "%s%*s%s=\"%lld\"",
3235 (first) ? "" : "\n", /* maybe a newline */
3236 (first) ? 1 : spaces, "", /* 1 or many spaces */
3237 name, value);
3238 return 0;
3239 }
3240
3241
ewrite_str_attr(const char * name,const char * value,int spaces,int first,FILE * fp)3242 static int ewrite_str_attr(const char * name, const char * value, int spaces,
3243 int first, FILE * fp)
3244 {
3245 fprintf(fp, "%s%*s%s=\"%s\"",
3246 (first) ? "" : "\n", /* maybe a newline */
3247 (first) ? 1 : spaces, "", /* 1 or many spaces */
3248 name, value ? value : "");
3249 return 0;
3250 }
3251
3252
gxml_write_preamble(FILE * fp)3253 static int gxml_write_preamble(FILE * fp)
3254 {
3255 char * version = GIFTI_XML_VERSION;
3256 char * encoding = GIFTI_XML_ENCODING;
3257 char * dtd = GIFTI_XML_DTD_SOURCE;
3258
3259 fprintf(fp, "<?xml version=\"%s\" encoding=\"%s\"?>\n", version, encoding);
3260 fprintf(fp, "<!DOCTYPE GIFTI SYSTEM \"%s\">\n", dtd);
3261
3262 return 0;
3263 }
3264
disp_gxml_data(char * mesg,gxml_data * dp,int show_all)3265 static int disp_gxml_data(char * mesg, gxml_data * dp, int show_all )
3266 {
3267 if( mesg ) fputs(mesg, stderr);
3268
3269 if( !dp ) return 1;
3270
3271 fprintf(stderr,"gxml_data :\n"
3272 " verb : %d\n"
3273 " dstore : %d\n"
3274 " indent : %d\n"
3275 " buf_size : %d\n"
3276 " b64_check : %d\n"
3277 " zlevel : %d\n"
3278 " perm_by_iord: %d\n"
3279 " da_len : %d\n"
3280 , dp->verb, dp->dstore, dp->indent, dp->buf_size, dp->b64_check,
3281 dp->zlevel, dp->perm_by_iord, dp->da_len);
3282
3283 if( show_all )
3284 fprintf(stderr,
3285 " da_list : %p\n"
3286 " da_ind : %d\n"
3287 " eleDA : %d\n"
3288 " expDA : %d\n"
3289 " b64_errors : %d\n"
3290 " errors : %d\n"
3291 " skip : %d\n"
3292 " depth : %d\n"
3293 " dind : %lld\n"
3294 " clen : %d\n"
3295 " doff : %d\n"
3296 " zlen : %d\n"
3297 " cdata : %p\n"
3298 " xdata : %p\n"
3299 " ddata : %p\n"
3300 " zdata : %p\n"
3301 " gim : %p\n"
3302 , (void *)dp->da_list, dp->da_ind, dp->eleDA, dp->expDA,
3303 dp->b64_errors, dp->errors, dp->skip, dp->depth, dp->dind,
3304 dp->clen, dp->doff, dp->zlen,
3305 (void *)dp->cdata, (void *)dp->xdata, (void *)dp->ddata,
3306 (void *)dp->zdata, (void *)dp->gim);
3307
3308 return 0;
3309 }
3310