1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <ctype.h>
4 #include <string.h>
5 #include "gifti_io.h"
6 
7 /*! global history and version strings, for printing */
8 static char * gifti_history[] =
9 {
10   "----------------------------------------------------------------------\n"
11   "history (of gifti library changes):\n"
12   "\n",
13   "0.0  18 July, 2007\n"
14   "     (Rick Reynolds of the National Institutes of Health, SSCC/DIRP/NIMH)\n"
15   "     - initial version\n"
16   "0.1  31 July, 2007\n",
17   "     - changed dim0..dim5 to dims[]\n"
18   "     - changed nvals to size_t\n"
19   "     - added gifti_init_darray_from_attrs and some validation functions\n"
20   "0.2  29 October, 2007\n",
21   "     - renamed gifti.[ch] to gifti_io.[ch]\n"
22   "     - main data structures all start with gii (or gifti_)\n"
23   "     - added user indenting\n"
24   "0.3  21 November, 2007\n",
25   "     - added base64 encoding/decoding, via b64_en/decode_table\n"
26   "     - added gifti_list_index2string, gifti_disp_hex_data, \n"
27   "             gifti_check_swap, gifti_swap_Nbytes, etc.\n"
28   "     - pop_darray: check for b64 errors and byte swapping\n"
29   "     - dind is size_t\n",
30   "0.4  29 November, 2007\n"
31   "     - added more checks and fixed nvpair value allocation\n"
32   "0.5  03 December, 2007: applied changes for GIFTI Format 1.0 (11/21)\n",
33   "     - replaced Category with Intent\n"
34   "     - replaced Location attribute with ExternalFileName/Offset\n"
35   "     - added NumberOfDataArrays attribute to GIFTI element\n"
36   "     - applied new index_order strings\n"
37   "0.6  10 December, 2007:\n",
38   "     - can read/write Base64Binary datasets (can set compress level)\n"
39   "     - removed datatype lists (have gifti_type_list)\n"
40   "     - added gifti_read_da_list(), with only partial ability\n"
41   "     - added GIFTI numDA attribute\n"
42   "     - change size_t to long long\n"
43   "0.7  11 December, 2007:\n",
44   "     - added GIFTI_B64_CHECK defines\n"
45   "     - set b64_check default to SKIPNCOUNT\n"
46   "     - added disp_gxml_data\n"
47   "0.8  12 December, 2007:\n",
48   "     - added sub-surface selection, via dalist in gifti_read_da_list()\n"
49   "     - added gifti_copy_DataArray, and other structures\n"
50   "0.9  28 December, 2007:\n",
51   "     - made zlib optional, via -DHAVE_ZLIB in compile\n"
52   "       (without zlib, the user will get warnings)\n"
53   "     - now users only #include gifti_io.h, not gifti_xml, expat or zlib\n"
54   "     - added more comments and made tables more readable\n"
55   "     - added all user-variable access functions and reset_user_vars()\n",
56   "     - added gifti_free_image_contents(), gifti_disp_raw_data(),\n"
57   "             gifti_clear_float_zeros() and gifti_set_DA_atrs()\n"
58   "     - changed gifti_gim_DA_size to long long\n"
59   "     - added GIFTI_B64_CHECK_UNDEF as 0\n"
60   "     - fixed 0-width indenting and accumulating base64 errors\n"
61   "0.10 03 January, 2008:\n",
62   "     - added top-level gifti_create_image() interface\n"
63   "     - must now link libniftiio\n"
64   "     - gifti_add_empty_darray() now takes num_to_add\n"
65   "     - if data was expected but not read, free it\n"
66   "         (can add via gifti_alloc_DA_data())\n"
67   "     - many minor changes\n"
68   "0.11 11 January, 2008:\n",
69   "     - attribute/data setting functions are more flexible\n"
70   "     - added gifti_disp_dtd_url, gifti_set_DA_meta, gifti_valid_int_list,\n"
71   "       DA_data_exists, gifti_add_to_meta \n"
72   "0.12 16 January, 2008:\n",
73   "     - added gifti_copy_gifti_image() and gifti_convert_to_float()\n"
74   "     - added gifti_valid_LabelTable(), gifticlib_version(),\n"
75   "             gifti_copy_LabelTable(), gifti_updaet_nbyper() and\n"
76   "             gifti_valid_gifti_image()\n"
77   "     - added control over library updates to metadata\n"
78   "     - expanded checks in gifti_valid_dims\n"
79   "0.13 20 February, 2008:\n",
80   "     - added gifti_get_meta_value() and gifti_image_has_data()\n"
81   "0.14 25 February, 2008:\n",
82   "     - consider data-less metadata as valid\n"
83   "0.15 18 March, 2008: added comparison functions\n",
84   "     - gifti_compare_gifti_images() is top-level function\n"
85   "     - also added gifti_compare_gims_only(), gifti_compare_DA_pair(),\n"
86   "                  gifti_compare_nvpairs(), gifti_compare_labeltable(),\n"
87   "                  gifti_compare_coordsys()\n"
88   "                  gifti_strdiff() and gifti_compare_raw_data()\n"
89   "0.16 25 March, 2008\n",
90   "     - separate data diffs in compare_gifti_images\n"
91   "     - added gifti_compare_gifti_data() and gifti_compare_DA_data()\n"
92   "     - NIFTI_INTENT_NONE is considered valid\n"
93   "     - write LabelTables using CDATA\n"
94   "0.17 28 March, 2008 : added copy MetaData routines\n",
95   "     - gifti_copy_gifti_meta, gifti_copy_DA_meta, gifti_copy_all_DA_meta,\n"
96   "     - gifti_copy_DA_meta_many, gifti_copy_nvpairs\n"
97   "0.18 08 May, 2008 : DataArray can now contain a list of CoordSystems\n",
98   "     - modified giiDataArray struct: new numCS, coordsys is now CS**\n"
99   "     - added gifti_free_CS_list, gifti_add_empty_CS\n"
100   "\n"
101   "------------------------ initial release version -----------------------\n",
102   "1.00 13 May, 2008 : release version of gifticlib\n",
103   "     - allowed external data\n"
104   "     - added gifti_read/write_extern_DA_data() and\n"
105   "             gifti_set_extern_filelist()\n"
106   "1.01 02 June, 2008 :\n",
107   "     - added CMakeLists.txt and XMLCALL update from Simon Warfield\n"
108   "       (define XMLCALL for pre-1.95.7 versions of expat)\n"
109   "     - added LICENSE.gifti\n"
110   "1.02 02 October, 2008 :\n",
111   "     - separate diffs in DAs from those in gifti_image\n"
112   "     - decode additional data types: INT8, UINT16, INT64\n"
113   "     - add link flags to libgiftiio_la target\n"
114   "1.03 17 April, 2009 : allow DA size to vary over each external file\n",
115   "1.04 27 October, 2009 : added support for LabelTable RGBA attributes\n"
116   "     - valid LabelTable requires RGBA values in [0,1.0]\n"
117   "     - compare_labeltable requires equality of RGBA values (no approx.)\n",
118   "1.05 08 December, 2009: ignore invalid GIFTI attrs by default\n"
119   "1.06 24 December, 2009: added approximate difference functions\n",
120   "     - added gifti_approx_gifti_images, DA_pair, labeltables, diff_offset\n"
121   "     - added gifti_triangle_diff_offset\n"
122   "     - gifti_compare_coordsys takes comp_data param\n"
123   "1.07 04 March, 2010: minor changes (also see NITRC IDs 4619 and 4644)\n",
124   "     - for integers, make default approx test to be equality\n"
125   "     - small changes to zlib failure strings\n"
126   "     - cast to avoid compile warning on some systems\n"
127   "     - gifti_xml.h: made NITRC gifti.dtd link that will not change\n"
128   "1.08 08 March, 2010: GIfTI LabelTable format change: Index to Key\n",
129   "     - both Index and Key work on read, Key is written out\n"
130   "1.09 28 June, 2010: verify that num_dim is not too big\n",
131   "     - the most significant dimension cannot be 1 (req by N Schmansky)\n"
132   "1.10 19 October, 2011: \n",
133   "     - can read/write ascii COMPLEX64, COMPLEX128, RGB24\n"
134   "       (requested by H Breman, J Mulders, N Schmansky)\n"
135   "1.11 07 March, 2012: fixed sizeof in memset of gim (noted by B Cox)\n",
136   "1.12 15 June, 2012: make num_dim violation a warning (mris_convert)\n",
137   "1.13 17 June, 2015: added gifti_read_image_buf\n"
138   "1.14 24 July, 2015: added gifti_rotate_DAs_to_front\n"
139   "1.15 01 March, 2016:\n"
140   "     - gifti_xml.c fix for Windows-style newline characters\n",
141   "     - noticed and fixed by R Vincent\n"
142   "1.16 02 May, 2017: added control over array indexing order\n"
143   "1.17 19 Feb, 2021: promote fabs() args explicitly to avoid warnings\n"
144 };
145 
146 static char gifti_version[] = "gifti library version 1.17, 19 Feb, 2021";
147 
148 /* ---------------------------------------------------------------------- */
149 /*! global lists of XML strings */
150 
151 /*! this should match GIFTI_IND_ORD_* */
152 char * gifti_index_order_list[] = {"Undefined", "RowMajorOrder",
153                                                 "ColumnMajorOrder"};
154 
155 /*! gifti_type_list is an array of gifti_type_ele structs which list, for
156     each type, the bytes per value, swapsize and corresponding name string
157     (these type values are defined in nifti1.h) */
158 static gifti_type_ele gifti_type_list[] = {
159     /* type                    nbyper  swapsize   name  */
160     { DT_UNKNOWN,                 0,      0,      "Undefined"             },
161     { NIFTI_TYPE_UINT8,           1,      0,      "NIFTI_TYPE_UINT8"      },
162     { NIFTI_TYPE_INT16,           2,      2,      "NIFTI_TYPE_INT16"      },
163     { NIFTI_TYPE_INT32,           4,      4,      "NIFTI_TYPE_INT32"      },
164     { NIFTI_TYPE_FLOAT32,         4,      4,      "NIFTI_TYPE_FLOAT32"    },
165     { NIFTI_TYPE_COMPLEX64,       8,      4,      "NIFTI_TYPE_COMPLEX64"  },
166     { NIFTI_TYPE_FLOAT64,         8,      8,      "NIFTI_TYPE_FLOAT64"    },
167     { NIFTI_TYPE_RGB24,           3,      0,      "NIFTI_TYPE_RGB24"      },
168     { NIFTI_TYPE_INT8,            1,      0,      "NIFTI_TYPE_INT8"       },
169     { NIFTI_TYPE_UINT16,          2,      2,      "NIFTI_TYPE_UINT16"     },
170     { NIFTI_TYPE_UINT32,          4,      4,      "NIFTI_TYPE_UINT32"     },
171     { NIFTI_TYPE_INT64,           8,      8,      "NIFTI_TYPE_INT64"      },
172     { NIFTI_TYPE_UINT64,          8,      8,      "NIFTI_TYPE_UINT64"     },
173     { NIFTI_TYPE_FLOAT128,        6,     16,      "NIFTI_TYPE_FLOAT128"   },
174     { NIFTI_TYPE_COMPLEX128,     16,      8,      "NIFTI_TYPE_COMPLEX128" },
175     { NIFTI_TYPE_COMPLEX256,     32,     16,      "NIFTI_TYPE_COMPLEX256" }
176 };
177 
178 /*! this list provides a link between intent codes and their name strings */
179 typedef struct { int code; char * name; } gifti_intent_ele;
180 static gifti_intent_ele gifti_intent_list[] = {
181     { NIFTI_INTENT_NONE,             "NIFTI_INTENT_NONE"        },
182     { NIFTI_INTENT_CORREL,           "NIFTI_INTENT_CORREL"      },
183     { NIFTI_INTENT_TTEST,            "NIFTI_INTENT_TTEST"       },
184     { NIFTI_INTENT_FTEST,            "NIFTI_INTENT_FTEST"       },
185     { NIFTI_INTENT_ZSCORE,           "NIFTI_INTENT_ZSCORE"      },
186     { NIFTI_INTENT_CHISQ,            "NIFTI_INTENT_CHISQ"       },
187     { NIFTI_INTENT_BETA,             "NIFTI_INTENT_BETA"        },
188     { NIFTI_INTENT_BINOM,            "NIFTI_INTENT_BINOM"       },
189     { NIFTI_INTENT_GAMMA,            "NIFTI_INTENT_GAMMA"       },
190     { NIFTI_INTENT_POISSON,          "NIFTI_INTENT_POISSON"     },
191     { NIFTI_INTENT_NORMAL,           "NIFTI_INTENT_NORMAL"      },
192     { NIFTI_INTENT_FTEST_NONC,       "NIFTI_INTENT_FTEST_NONC"  },
193     { NIFTI_INTENT_CHISQ_NONC,       "NIFTI_INTENT_CHISQ_NONC"  },
194     { NIFTI_INTENT_LOGISTIC,         "NIFTI_INTENT_LOGISTIC"    },
195     { NIFTI_INTENT_LAPLACE,          "NIFTI_INTENT_LAPLACE"     },
196     { NIFTI_INTENT_UNIFORM,          "NIFTI_INTENT_UNIFORM"     },
197     { NIFTI_INTENT_TTEST_NONC,       "NIFTI_INTENT_TTEST_NONC"  },
198     { NIFTI_INTENT_WEIBULL,          "NIFTI_INTENT_WEIBULL"     },
199     { NIFTI_INTENT_CHI,              "NIFTI_INTENT_CHI"         },
200     { NIFTI_INTENT_INVGAUSS,         "NIFTI_INTENT_INVGAUSS"    },
201     { NIFTI_INTENT_EXTVAL,           "NIFTI_INTENT_EXTVAL"      },
202     { NIFTI_INTENT_PVAL,             "NIFTI_INTENT_PVAL"        },
203     { NIFTI_INTENT_LOGPVAL,          "NIFTI_INTENT_LOGPVAL"     },
204     { NIFTI_INTENT_LOG10PVAL,        "NIFTI_INTENT_LOG10PVAL"   },
205     { NIFTI_INTENT_ESTIMATE,         "NIFTI_INTENT_ESTIMATE"    },
206     { NIFTI_INTENT_LABEL,            "NIFTI_INTENT_LABEL"       },
207     { NIFTI_INTENT_NEURONAME,        "NIFTI_INTENT_NEURONAME"   },
208     { NIFTI_INTENT_GENMATRIX,        "NIFTI_INTENT_GENMATRIX"   },
209     { NIFTI_INTENT_SYMMATRIX,        "NIFTI_INTENT_SYMMATRIX"   },
210     { NIFTI_INTENT_DISPVECT,         "NIFTI_INTENT_DISPVECT"    },
211     { NIFTI_INTENT_VECTOR,           "NIFTI_INTENT_VECTOR"      },
212     { NIFTI_INTENT_POINTSET,         "NIFTI_INTENT_POINTSET"    },
213     { NIFTI_INTENT_TRIANGLE,         "NIFTI_INTENT_TRIANGLE"    },
214     { NIFTI_INTENT_QUATERNION,       "NIFTI_INTENT_QUATERNION"  },
215     { NIFTI_INTENT_DIMLESS,          "NIFTI_INTENT_DIMLESS"     },
216     { NIFTI_INTENT_TIME_SERIES,      "NIFTI_INTENT_TIME_SERIES" },
217     { NIFTI_INTENT_NODE_INDEX,       "NIFTI_INTENT_NODE_INDEX"  },
218     { NIFTI_INTENT_RGB_VECTOR,       "NIFTI_INTENT_RGB_VECTOR"  },
219     { NIFTI_INTENT_RGBA_VECTOR,      "NIFTI_INTENT_RGBA_VECTOR" },
220     { NIFTI_INTENT_SHAPE,            "NIFTI_INTENT_SHAPE"       }
221 };
222 
223 /*! this should match GIFTI_ENCODING_* */
224 char * gifti_encoding_list[] = {
225     "Undefined", "ASCII", "Base64Binary", "GZipBase64Binary",
226     "ExternalFileBinary"
227 };
228 
229 /*! this should match GIFTI_ENDIAN_* */
230 char * gifti_endian_list[] = {"Undefined", "BigEndian", "LittleEndian"};
231 
232 /* ---------------------------------------------------------------------- */
233 /* local prototypes */
234 static int can_compare_DA_data(const giiDataArray *d1,const giiDataArray *d2,
235                                int verb);
236 static int compare_labeltables(const giiLabelTable *t1, const giiLabelTable *t2,
237                                int verb, int approx);
238 static int copy_data_as_float(void * dest, int dtype, void * src, int stype,
239                               long long nvals);
240 static int DA_data_exists(gifti_image * gim, const int * dalist, int len);
241 static int str2list_index(char *list[], int max, const char *str);
242 static int permute_by_index_order(void * dest, int new_ord, giiDataArray * da);
243 
244 /* ---------------------------------------------------------------------- */
245 /*! giftilib globals */
246 static gifti_globals G = { 1 };
247 
248 /* ====================================================================== */
249 
250 /* ---------------------------------------------------------------------- */
251 /*! user variable accessor functions - basically use gxml interface       */
252 
gifti_get_verb(void)253 int gifti_get_verb( void )          { return G.verb; }
gifti_set_verb(int level)254 int gifti_set_verb( int level )     { G.verb = level;  return 1; }
gifti_get_indent(void)255 int gifti_get_indent( void )        { return gxml_get_indent(); }
gifti_set_indent(int level)256 int gifti_set_indent( int level )   { return gxml_set_indent(level); }
gifti_get_b64_check(void)257 int gifti_get_b64_check( void )     { return gxml_get_b64_check(); }
gifti_set_b64_check(int level)258 int gifti_set_b64_check( int level ){ return gxml_set_b64_check(level); }
gifti_get_update_ok(void)259 int gifti_get_update_ok( void )     { return gxml_get_update_ok(); }
gifti_set_update_ok(int level)260 int gifti_set_update_ok( int level ){ return gxml_set_update_ok(level); }
gifti_get_zlevel(void)261 int gifti_get_zlevel( void )        { return gxml_get_zlevel(); }
gifti_set_zlevel(int level)262 int gifti_set_zlevel( int level )
263 {
264     /* note that the default currently results in 6 */
265     if( level != GZ_DEFAULT_COMPRESSION && (level < 0 || level > 9 ) ) {
266         fprintf(stderr,"** invalid zlevel, must be %d (default) or {0..9}\n",
267                 GZ_DEFAULT_COMPRESSION);
268         return 1;
269     }
270     return gxml_set_zlevel(level);
271 }
272 
gifti_get_perm_by_iord(void)273 int gifti_get_perm_by_iord(void )       { return gxml_get_perm_by_iord(); }
gifti_set_perm_by_iord(int level)274 int gifti_set_perm_by_iord(int level )  { return gxml_set_perm_by_iord(level); }
gifti_get_xml_buf_size(void)275 int gifti_get_xml_buf_size(void)        { return gxml_get_buf_size(); }
gifti_set_xml_buf_size(int buf_size)276 int gifti_set_xml_buf_size(int buf_size){ return gxml_set_buf_size(buf_size); }
277 
278 /*! reset user variables to their defaults(via set to -1) */
gifti_reset_user_vars(void)279 int gifti_reset_user_vars(void)
280 {
281     gxml_set_verb(-1);
282     gxml_set_dstore(-1);
283     gxml_set_indent(-1);
284     gxml_set_buf_size(-1);
285     gxml_set_b64_check(-1);
286     gxml_set_update_ok(-1);
287     gxml_set_zlevel(-1);
288 
289     return 0;
290 }
291 /* end user variable accessor functions                                   */
292 /* ---------------------------------------------------------------------- */
293 
294 /* ====================================================================== */
295 
296 /* ---------------------------------------------------------------------- */
297 /* begin general library functions                                        */
298 
299 /*----------------------------------------------------------------------
300  *! apply the attr=value GIFTI attribute to the gifti_image
301  *
302  *  return 0 on success
303 *//*-------------------------------------------------------------------*/
gifti_str2attr_gifti(gifti_image * gim,const char * attr,const char * val)304 int gifti_str2attr_gifti(gifti_image * gim, const char *attr, const char *val)
305 {
306     if( !gim || !attr || !val ) {
307         fprintf(stderr,"** GS2AG: bad params (%p,%p,%p)\n",
308                 (void *)gim, (void *)attr, (void *)val);
309         return 1;
310     }
311 
312     if( G.verb > 2 )
313         fprintf(stderr,"++ setting GIFTI attr '%s' from '%s'\n", attr, val);
314 
315     if( !strcmp(attr, "Version") ) {
316         if( gim->version ) free( gim->version );  /* lose any old copy */
317         gim->version = gifti_strdup(val);
318     } else if( !strcmp(attr, "NumberOfDataArrays") ) {
319         gim->numDA = atol(val);
320         if( gim->numDA < 0 ) {
321             fprintf(stderr,"** invalid NumberOfDataArrays attribute: %s\n",val);
322             gim->numDA = 0;
323             return 1;
324         }
325     } else if( !strcmp(attr, "xmlns:xsi") ||
326                !strcmp(attr, "xsi:noNamespaceSchemaLocation") ) {
327         if( G.verb > 1 )
328             fprintf(stderr,"-- have GIFTI attr, '%s'='%s'\n",attr,val);
329         return 1;
330     } else {
331         if( G.verb > 1 )
332             fprintf(stderr,"** unknown GIFTI attrib, '%s'='%s'\n",attr,val);
333         return 1;
334     }
335 
336     return 0;
337 }
338 
339 /*----------------------------------------------------------------------
340  *! This is the main dataset reading routine.  Read a GIFTI dataset
341  *  and return the corresponding gifti_image structure.
342  *
343  *  Reading data is optional, via the read_data flag.
344  *  User variables should already be set (via accessor functions).
345  *
346  *  return an allocated gifti_image struct on success,
347  *         NULL on error
348 *//*-------------------------------------------------------------------*/
gifti_read_image(const char * fname,int read_data)349 gifti_image * gifti_read_image( const char * fname, int read_data )
350 {
351     if( !fname ) {
352         fprintf(stderr,"** gifti_read_image: missing filename\n");
353         return NULL;
354     }
355 
356     gxml_set_verb(G.verb);
357 
358     return gxml_read_image(fname, read_data, NULL, 0);
359 }
360 
361 /*----------------------------------------------------------------------
362  *! Like gifti_read_image, but read from a buffer.
363  *
364  *  return an allocated gifti_image struct on success,
365  *         NULL on error
366 *//*-------------------------------------------------------------------*/
gifti_read_image_buf(const char * buf,long long bsize)367 gifti_image * gifti_read_image_buf(const char * buf, long long bsize)
368 {
369     if( !buf || bsize <= 0 ) {
370         fprintf(stderr,"** gifti_read_image: missing filename\n");
371         return NULL;
372     }
373 
374     gxml_set_verb(G.verb);
375 
376     return gxml_read_image_buf(buf, bsize, NULL, 0);
377 }
378 
379 /*----------------------------------------------------------------------
380  *! Similar to gifti_read_data, this function also takes an integer list of
381  *  DataArray indices to populate the gifti_image structure with.
382  *
383  *  The indices are be zero-based, can have repeats and can be in any order.
384  *  A simple example to read 3 DA elements (with 2 repeats) might be:
385  *
386  *    gifti_image * gim;
387  *    int           ilist[5] = { 3, 0, 7, 7, 3 };
388  *    gim = gifti_read_da_list("my_data.gii", 1, ilist, 5);
389  *
390  *  return an allocated gifti_image struct on success,
391  *         NULL on error
392 *//*-------------------------------------------------------------------*/
gifti_read_da_list(const char * fname,int read_data,const int * dalist,int len)393 gifti_image * gifti_read_da_list( const char * fname, int read_data,
394                                   const int * dalist, int len )
395 {
396     if( !fname ) {
397         fprintf(stderr,"** gifti_read_da_list: missing filename\n");
398         return NULL;
399     }
400 
401     gxml_set_verb(G.verb);
402 
403     return gxml_read_image(fname, read_data, dalist, len);
404 }
405 
406 /*----------------------------------------------------------------------
407  *! This is the main dataset writing routine.
408  *
409  *  User variables should be set before this point.
410  *
411  *  return 0 on success
412  *         1 on error
413 *//*-------------------------------------------------------------------*/
gifti_write_image(gifti_image * gim,const char * fname,int write_data)414 int gifti_write_image(gifti_image *gim, const char *fname, int write_data)
415 {
416     int errs = 0;
417 
418     if( !gim ) {
419         fprintf(stderr,"** gifti_write_image, missing gifti_image\n");
420         errs++;
421     } else if( !fname ) {
422         fprintf(stderr,"** gifti_write_image: missing filename\n");
423         errs++;
424     }
425 
426     if( errs ) return 1;
427 
428     gxml_set_verb(G.verb);
429 
430     return gxml_write_image(gim, fname, write_data);
431 }
432 
433 
434 /*----------------------------------------------------------------------
435  *! free the gifti_image struct and all its contents
436  *
437  *  passing NULL (to this and any child function) should be okay
438  *
439  *  the pointer is garbage after this call
440 *//*-------------------------------------------------------------------*/
gifti_free_image(gifti_image * gim)441 int gifti_free_image( gifti_image * gim )
442 {
443     if( !gim ) {
444         if(G.verb > 2) fprintf(stderr,"** free gifti_image w/NULL pointer\n");
445         return 1;
446     }
447 
448     if( G.verb > 2 ) fprintf(stderr,"-- freeing gifti_image\n");
449 
450     if( gim->version ) { free(gim->version);  gim->version = NULL; }
451 
452     (void)gifti_free_nvpairs(&gim->meta);
453     (void)gifti_free_LabelTable(&gim->labeltable);
454     (void)gifti_free_DataArray_list(gim->darray, gim->numDA);
455     (void)gifti_free_nvpairs(&gim->ex_atrs);
456     free(gim);
457 
458     return 0;
459 }
460 
461 /*----------------------------------------------------------------------
462  *! free the contents of the gifti_image struct (but not the pointer)
463  *
464  *  the pointer is garbage after this call
465 *//*-------------------------------------------------------------------*/
gifti_free_image_contents(gifti_image * gim)466 int gifti_free_image_contents( gifti_image * gim )
467 {
468     if( !gim ) {
469         if(G.verb > 2) fprintf(stderr,"** GFIC: free w/NULL gifti_image ptr\n");
470         return 1;
471     }
472 
473     if( G.verb > 2 ) fprintf(stderr,"-- freeing gifti_image contents\n");
474 
475     if( gim->version ) { free(gim->version);  gim->version = NULL; }
476 
477     (void)gifti_free_nvpairs(&gim->meta);
478     (void)gifti_free_LabelTable(&gim->labeltable);
479     (void)gifti_free_DataArray_list(gim->darray, gim->numDA);
480     (void)gifti_free_nvpairs(&gim->ex_atrs);
481 
482     return 0;
483 }
484 
485 /*----------------------------------------------------------------------
486  *! free the contents of the nvpairs struct (but not the pointer)
487  *
488  *  passing NULL is okay
489 *//*-------------------------------------------------------------------*/
gifti_free_nvpairs(nvpairs * p)490 int gifti_free_nvpairs( nvpairs * p )
491 {
492     int c;
493 
494     if( !p ) {
495         if( G.verb > 3 ) fprintf(stderr,"** free w/NULL nvpairs ptr\n");
496         return 1;
497     }
498 
499     if( G.verb > 3 ) fprintf(stderr,"-- freeing %d nvpairs\n", p->length);
500 
501     if( p->name && p->value ) {
502         for( c = 0; c < p->length; c++ ) {
503             if( p->name[c] ) free(p->name[c]);
504             if( p->value[c] ) free(p->value[c]);
505         }
506         free(p->name);
507         free(p->value);
508         p->name = NULL;
509         p->value = NULL;
510     }
511     p->length = 0;
512 
513     return 0;
514 }
515 
516 /*----------------------------------------------------------------------
517  *! free the contents of the LabelTable struct (but not the pointer)
518  *
519  *  passing NULL is okay
520 *//*-------------------------------------------------------------------*/
gifti_free_LabelTable(giiLabelTable * T)521 int gifti_free_LabelTable( giiLabelTable * T )
522 {
523     int c;
524 
525     if( !T ) {
526         if(G.verb > 3) fprintf(stderr,"** free w/NULL giiLabelTable ptr\n");
527         return 1;
528     }
529 
530     if(G.verb > 3)
531         fprintf(stderr,"-- freeing %d giiLabelTable entries\n", T->length);
532 
533     if( T->key && T->label ) {
534         for( c = 0; c < T->length; c++ )
535             if( T->label[c] ) free(T->label[c]);
536         free(T->key);
537         free(T->label);
538         T->key = NULL;
539         T->label = NULL;
540     }
541 
542     if( T->rgba ) {
543         free(T->rgba);
544         T->rgba = NULL;
545     }
546 
547     T->length = 0;
548 
549     return 0;
550 }
551 
552 /*----------------------------------------------------------------------
553  *! free the DataArray list (the array and all its contents)
554  *
555  *  the darray list pointer is garbage after this call
556  *
557  *  passing NULL is okay
558 *//*-------------------------------------------------------------------*/
gifti_free_DataArray_list(giiDataArray ** darray,int numDA)559 int gifti_free_DataArray_list(giiDataArray ** darray, int numDA)
560 {
561     int c;
562 
563     if( !darray ) {
564         if( G.verb > 3 ) fprintf(stderr,"** GFDA: free NULL darray list\n");
565         return 1;
566     }
567 
568     if( G.verb > 3 ) fprintf(stderr,"-- freeing %d giiDataArrays\n", numDA);
569 
570     if( numDA < 0 ) return 1;
571 
572     for( c = 0; c < numDA; c++ )
573         if( gifti_free_DataArray(darray[c]) ) return 1;
574 
575     free(darray);
576 
577     return 0;
578 }
579 
580 /*----------------------------------------------------------------------
581  *! free the DataArray struct and all its contents
582  *
583  *  the DataArray pointer is garbage after this call
584  *
585  *  passing NULL is okay
586 *//*-------------------------------------------------------------------*/
gifti_free_DataArray(giiDataArray * darray)587 int gifti_free_DataArray( giiDataArray * darray )
588 {
589     if( !darray ) {
590         if( G.verb > 3 ) fprintf(stderr,"** tried to free NULL darray ptr\n");
591         return 1;
592     }
593 
594     if( G.verb > 3 ) fprintf(stderr,"-- freeing giiDataArray\n");
595 
596     if(darray->ext_fname) { free(darray->ext_fname); darray->ext_fname = NULL; }
597 
598     (void)gifti_free_nvpairs(&darray->meta);
599     (void)gifti_free_CS_list(darray);
600     if( darray->data ) { free(darray->data); darray->data = NULL; }
601     (void)gifti_free_nvpairs(&darray->ex_atrs);
602     free(darray);
603 
604     return 0;
605 }
606 
607 /*----------------------------------------------------------------------
608  *! free the CoordSystem array from a DataArray
609  *  passing NULL is okay
610 *//*-------------------------------------------------------------------*/
gifti_free_CS_list(giiDataArray * da)611 int gifti_free_CS_list( giiDataArray * da )
612 {
613     int c;
614 
615     if( !da ) return 0;
616 
617     if( G.verb > 3 ) fprintf(stderr,"-- freeing giiCoordSystem list\n");
618 
619     if( da->coordsys && da->numCS > 0 ) {
620         for( c = 0; c < da->numCS; c++ )
621             gifti_free_CoordSystem(da->coordsys[c]);
622         free(da->coordsys);
623     }
624 
625     da->coordsys = NULL;
626     da->numCS = 0;
627 
628     return 0;
629 }
630 
631 /*----------------------------------------------------------------------
632  *! free the CoordSystem struct and all its contents
633  *
634  *  the CoordSystem pointer is garbage after this call
635  *
636  *  passing NULL is okay
637 *//*-------------------------------------------------------------------*/
gifti_free_CoordSystem(giiCoordSystem * cs)638 int gifti_free_CoordSystem( giiCoordSystem * cs )
639 {
640     if( !cs ) return 0;
641 
642     if( G.verb > 3 ) fprintf(stderr,"-- freeing giiCoordSystem\n");
643 
644     if( cs->dataspace ) { free(cs->dataspace); cs->dataspace = NULL; }
645     if( cs->xformspace ) { free(cs->xformspace); cs->xformspace = NULL; }
646 
647     free(cs);
648 
649     return 0;
650 }
651 
652 /*----------------------------------------------------------------------
653  *! initialize an existing DataArray structure given a list of name=value
654  *  attribute pairs
655  *
656  *  if alen > 0, consider it the length of the attr list
657  *  else         process until attr[i] == NULL
658  *
659  *  if add_to_extras, add any bad attribute pairs to ex_atrs
660  *  else              whine about any bad ones and return
661 *//*-------------------------------------------------------------------*/
gifti_set_DA_atrs(giiDataArray * da,const char ** attr,int alen,int add_to_extras)662 int gifti_set_DA_atrs(giiDataArray * da, const char ** attr, int alen,
663                       int add_to_extras )
664 {
665     int c, length = alen;
666 
667     if( !da || !attr ) {
668         if(G.verb>1) fprintf(stderr,"** G_IDFA: bad params (%p,%p)\n",
669                              (void *)da,(void *)attr);
670         return 1;
671     }
672 
673     /* if length was not passed, compute it */
674     if( length <= 0 ) for( length = 0; attr[length]; length++ ) /* nada */ ;
675 
676     if( G.verb > 5 )
677         fprintf(stderr,"++ init darray attrs, len %d, ex_atrs = %d\n",
678                 length, add_to_extras);
679 
680     /* insert attributes - if unknown, store with extras */
681     for(c = 0; c < length; c += 2 )
682         if( gifti_str2attr_darray(da, attr[c],attr[c+1]) ) {
683             /* a bad name=value pair, maybe add to ex_atrs */
684             if( add_to_extras ) {
685                 if( gifti_add_to_nvpairs(&da->ex_atrs,attr[c],attr[c+1]) )
686                     return 1;
687             }
688             else {
689                 if( G.verb > 0 )
690                     fprintf(stderr,"** set_darray_atrs, bad pair '%s'='%s'\n",
691                             attr[c],attr[c+1]);
692                 return 1;
693             }
694         }
695 
696     /* and set computed values */
697 
698     da->nvals = gifti_darray_nvals(da);
699     gifti_datatype_sizes(da->datatype, &da->nbyper, NULL); /* set nbyper */
700 
701     return 0;
702 }
703 
704 /*----------------------------------------------------------------------
705  *! determine whether the given DataArray struct seems valid
706  *
707  *  if whine is set, print error messages for any failures
708  *
709  *  return 1, if valid
710  *         0, if not
711 *//*-------------------------------------------------------------------*/
gifti_valid_DataArray(const giiDataArray * da,int whine)712 int gifti_valid_DataArray(const giiDataArray * da, int whine)
713 {
714     int errs = 0, nbyper;
715 
716     if( !da ) {
717         if( whine || G.verb > 2 ) fprintf(stderr,"** invalid darray pointer\n");
718         return 0;
719     }
720 
721     if( ! gifti_intent_is_valid(da->intent) ) {
722         if( whine || G.verb > 3 )
723             fprintf(stderr,"** invalid darray intent code = %d\n", da->intent);
724         errs++;
725     }
726 
727     if( ! gifti_valid_datatype(da->datatype, whine) ) /* message printed */
728         errs++;
729 
730     /* no checks for ext_fname and ext_offset (until reading) */
731 
732     if( da->ind_ord<=GIFTI_IND_ORD_UNDEF || da->ind_ord>GIFTI_IND_ORD_MAX ) {
733         if( whine || G.verb > 3 )
734             fprintf(stderr,"** invalid darray ind_ord = %d\n", da->ind_ord);
735         errs++;
736     }
737 
738     if( ! gifti_valid_num_dim(da->num_dim, whine) ) /* message printed */
739         errs++;
740 
741     if( ! gifti_valid_dims(da, whine) ) /* message printed */
742         errs++;
743 
744     if( da->encoding<=GIFTI_ENCODING_UNDEF || da->encoding>GIFTI_ENCODING_MAX ){
745         if( whine || G.verb > 3 )
746             fprintf(stderr,"** invalid darray encoding = %d\n", da->encoding);
747         errs++;
748     }
749 
750     if( da->endian<=GIFTI_ENDIAN_UNDEF || da->endian>GIFTI_ENDIAN_MAX ) {
751         if( whine || G.verb > 3 )
752             fprintf(stderr,"** invalid darray endian = %d\n", da->endian);
753         errs++;
754     }
755 
756     /* of sub-element, only verify giiMetaData */
757     if( ! gifti_valid_nvpairs(&da->meta, whine) ) /* message printed */
758         errs++;
759 
760     if( da->nvals <= 0 ) {
761         if( whine || G.verb > 3 )
762             fprintf(stderr,"** invalid darray nvals = %u\n",
763                     (unsigned)da->nvals );
764         errs++;
765     }
766 
767     if( ! gifti_valid_nbyper(da->nbyper, whine) ) errs++;
768     if( ! gifti_valid_nvpairs(&da->ex_atrs, whine) ) errs++;
769 
770     /* compare nbyper to what is expected for type */
771     errs += gifti_datatype_sizes(da->datatype, &nbyper, NULL);
772     if( gifti_valid_nbyper(nbyper, 0) && nbyper != da->nbyper ) {
773         if( whine || G.verb > 3 )
774             fprintf(stderr,"** nbyper %d, does not match type %s\n",
775                     nbyper, gifti_datatype2str(da->datatype));
776         errs++;
777     }
778 
779     if( errs ) return 0;
780 
781     return 1;
782 }
783 
784 /*----------------------------------------------------------------------
785  *! check whether pointers are valid and consistent with length
786 *//*-------------------------------------------------------------------*/
gifti_valid_nvpairs(const nvpairs * nvp,int whine)787 int gifti_valid_nvpairs(const nvpairs * nvp, int whine)
788 {
789     int c;
790 
791     if( !nvp ) {
792         if( G.verb>3 || whine ) fprintf(stderr,"** invalid nvpairs pointer\n");
793         return 0;
794     }
795 
796     if( nvp->length < 0 ) {
797         if( G.verb > 3 || whine )
798             fprintf(stderr,"** invalid nvpair length = %d\n", nvp->length);
799         return 0;
800     }
801 
802     if( nvp->length == 0 ) return 1;    /* quick case: valid */
803 
804     if( !nvp->name || !nvp->value ){
805         if( G.verb > 3 || whine )
806             fprintf(stderr,"** invalid nvpair name, value lists = %p, %p\n",
807                     (void *)nvp->name, (void *)nvp->value);
808         return 0;
809     }
810 
811     /* quit on first error */
812     for( c = 0; c < nvp->length; c++ ) {
813         if( ! nvp->name[c] ) {
814             if( G.verb > 5 || whine )
815                 fprintf(stderr,"** invalid nvpair, missing name @ %d\n", c);
816             return 0;
817         }
818 
819         /* value string is not required   25 Feb 2008 */
820         if( ! nvp->value[c] && G.verb > 3 )
821             fprintf(stderr,"-- missing nvpair value[%d], name %s (is OK)\n",
822                     c, nvp->name[c]);
823     }
824 
825     return 1;
826 }
827 
828 /*----------------------------------------------------------------------
829  *! check whether pointers are valid and consistent with length
830  *
831  *  no check is done on the actual indices or labels
832 *//*-------------------------------------------------------------------*/
gifti_valid_LabelTable(const giiLabelTable * T,int whine)833 int gifti_valid_LabelTable(const giiLabelTable * T, int whine)
834 {
835     float * rgba;
836     int     c, c2;
837 
838     if( !T ) {
839         if(G.verb>2||whine) fprintf(stderr,"** invalid LabelTable pointer\n");
840         return 0;
841     }
842 
843     if( T->length < 0 ) {
844         if( G.verb > 3 || whine )
845             fprintf(stderr,"** invalid LabelTable length = %d\n", T->length);
846         return 0;
847     }
848 
849     if( T->length == 0 ) return 1;    /* quick case: valid */
850 
851     if( !T->key || !T->label ){
852         if( G.verb > 3 || whine )
853             fprintf(stderr,"** invalid nvpair key, label = %p, %p\n",
854                     (void *)T->key, (void *)T->label);
855         return 0;
856     }
857 
858     /* quit on first error */
859     rgba = T->rgba;
860     for( c = 0; c < T->length; c++ ) {
861         if( ! T->label[c] ) {
862             if( G.verb > 3 || whine )
863                 fprintf(stderr,"** invalid nvpair label[%d]\n", c);
864             return 0;
865         }
866         if( rgba ) {
867             for( c2 = 0; c2 < 4; c2++ )
868                 if( rgba[c2] < 0.0 || rgba[c2] > 1.0 ) {
869                     if( G.verb > 3 || whine )
870                         fprintf(stderr,"** RGBA values out of [0.0,1,0] at "
871                                        "Label[%d]\n", c);
872                     return 0;
873                 }
874             rgba += 4; /* if list exists, go to next set */
875         }
876     }
877 
878     return 1;
879 }
880 
881 /*----------------------------------------------------------------------
882  *! check the bounds on num_dim
883 *//*-------------------------------------------------------------------*/
gifti_valid_num_dim(int num_dim,int whine)884 int gifti_valid_num_dim(int num_dim, int whine)
885 {
886     if( num_dim <= 0 || num_dim > GIFTI_DARRAY_DIM_LEN ) {
887         if( G.verb > 3 || whine )
888             fprintf(stderr,"** invalid num_dim = %d\n", num_dim);
889         return 0;
890     }
891     return 1;
892 }
893 
894 /*----------------------------------------------------------------------
895  *! check that the datatype is in the list
896 *//*-------------------------------------------------------------------*/
gifti_valid_datatype(int dtype,int whine)897 int gifti_valid_datatype(int dtype, int whine)
898 {
899     int c;
900 
901     /* check for valid */
902     for( c = sizeof(gifti_type_list) / sizeof(gifti_type_ele) - 1; c > 0; c-- )
903         if( dtype == gifti_type_list[c].type ) return 1;
904 
905     if( whine || G.verb > 3 )
906         fprintf(stderr,"** invalid datatype value %d\n", dtype);
907 
908     return 0;
909 }
910 
911 /*----------------------------------------------------------------------
912  *! check that nbyper is one of the values in gifti_type_list
913 *//*-------------------------------------------------------------------*/
gifti_valid_nbyper(int nbyper,int whine)914 int gifti_valid_nbyper(int nbyper, int whine)
915 {
916     int c;
917 
918     /* check for valid */
919     for( c = sizeof(gifti_type_list) / sizeof(gifti_type_ele) - 1; c > 0; c-- )
920         if( nbyper == gifti_type_list[c].nbyper ) return 1;
921 
922     if( whine || G.verb > 3 )
923         fprintf(stderr,"** invalid nbyper value %d\n", nbyper);
924 
925     return 0;
926 }
927 
928 /*----------------------------------------------------------------------
929  *! check that dimension values are consistent (and with datatype)
930  *
931  *      - num_dim is in range
932  *      - each dims[c] is postive (c < num_dim)
933  *      - nvals is product of dims
934  *      - datatype is valid (required to check nbyper)
935  *      - nbyper is correct
936 *//*-------------------------------------------------------------------*/
gifti_valid_dims(const giiDataArray * da,int whine)937 int gifti_valid_dims(const giiDataArray * da, int whine)
938 {
939     long long vals = 1;
940     int       c, nbyper;
941 
942     if( !da ) {
943         if( G.verb > 2 || whine ) fprintf(stderr,"** GVD: no giiDataArray\n");
944         return 0;
945     }
946 
947     if( ! gifti_valid_num_dim( da->num_dim, whine ) )
948         return 0;
949 
950     for( c = 0; c < da->num_dim; c++ ) {
951         if( da->dims[c] <= 0 ) {
952             if( G.verb > 3 || whine )
953                 fprintf(stderr,"** invalid dims[%d] = %d\n", c, da->dims[c]);
954             return 0;
955         }
956 
957         vals *= da->dims[c];
958     }
959 
960     /* verify computed vals and nbyper against stored ones */
961     if( vals != da->nvals ) {
962         if( G.verb > 3 ) {
963             fprintf(stderr,"** nvals = %lld does not match %lld for dims[%d]: ",
964                     da->nvals, vals, da->num_dim);
965             gifti_disp_raw_data(da->dims, DT_INT32, da->num_dim, 1, stderr);
966         }
967         return 0;
968     }
969 
970     gifti_datatype_sizes(da->datatype, &nbyper, NULL);
971     if( nbyper != da->nbyper ) {
972         fprintf(stderr,"** nbyper %d not correct for type %s\n",
973                 da->nbyper, gifti_datatype2str(da->datatype));
974         return 0;
975     }
976 
977     /* verify that num_dim is not too big, the most significant dimension
978      * is not allowed to be 1
979      * (requested by N Schmansky)                       11 Mar 2010 */
980     if( da->num_dim > 1 && da->dims[da->num_dim-1] < 2 && whine ) {
981         fprintf(stderr,"** num_dim violation: num_dim = %d, yet dim[%d] = %d\n",
982                        da->num_dim, da->num_dim-1, da->dims[da->num_dim-1]);
983         /* now FS is writing these in mris_convert, grrrr...  15 Jun 2012 */
984         /* return 0; */
985     }
986 
987     return 1;
988 }
989 
990 /*----------------------------------------------------------------------
991  *! set the DataArray attribute, based on the name=value string pair
992  *
993  *  return 0 on success
994  *         1 on error
995 *//*-------------------------------------------------------------------*/
gifti_str2attr_darray(giiDataArray * DA,const char * attr,const char * value)996 int gifti_str2attr_darray(giiDataArray * DA, const char *attr,
997                                              const char *value)
998 {
999     if( !DA || !attr || !value ) {
1000         if( G.verb > 0 )
1001             fprintf(stderr,"** G_S2A_D: bad params (%p,%p,%p)\n",
1002                     (void *)DA, (void *)attr, (void *)value);
1003         return 1;
1004     }
1005 
1006     if(G.verb > 3) fprintf(stderr,"++ setting DA attr '%s'='%s'\n",attr,value);
1007 
1008     if( !strcmp(attr, "Intent") )
1009         DA->intent = gifti_intent_from_string(value);
1010     else if( !strcmp(attr, "DataType") )
1011         DA->datatype = gifti_str2datatype(value);
1012     else if( !strcmp(attr, "ArrayIndexingOrder") )
1013         DA->ind_ord = gifti_str2ind_ord(value);
1014     else if( !strcmp(attr, "Dimensionality") ) DA->num_dim = atoi(value);
1015     else if( !strcmp(attr, "Dim0") )           DA->dims[0] = atoi(value);
1016     else if( !strcmp(attr, "Dim1") )           DA->dims[1] = atoi(value);
1017     else if( !strcmp(attr, "Dim2") )           DA->dims[2] = atoi(value);
1018     else if( !strcmp(attr, "Dim3") )           DA->dims[3] = atoi(value);
1019     else if( !strcmp(attr, "Dim4") )           DA->dims[4] = atoi(value);
1020     else if( !strcmp(attr, "Dim5") )           DA->dims[5] = atoi(value);
1021     else if( !strcmp(attr, "Encoding") )
1022         DA->encoding = gifti_str2encoding(value);
1023     else if( !strcmp(attr, "Endian") )
1024         DA->endian = gifti_str2endian(value);
1025     else if( !strcmp(attr, "ExternalFileName") )
1026         DA->ext_fname = gifti_strdup(value);
1027     else if( !strcmp(attr, "ExternalFileOffset") )
1028 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
1029         DA->ext_offset = atol(value);  /* There is no atoll defined in MS VC++ */
1030 #else
1031         DA->ext_offset = atoll(value);  /* assumes C99 */
1032 #endif
1033     else {
1034         if( G.verb > 1 )        /* might go into ex_atrs */
1035             fprintf(stderr,"** unknown giiDataArray attr, '%s'='%s'\n",
1036                     G_CHECK_NULL_STR(attr),G_CHECK_NULL_STR(value));
1037         return 1;
1038     }
1039 
1040     return 0;
1041 }
1042 
1043 /* return 0 (UNDEFINED) on failure */
str2list_index(char * list[],int max,const char * str)1044 static int str2list_index( char * list[], int max, const char *str )
1045 {
1046     int index;
1047     if( !list || !str ) {
1048         if( G.verb > 0 ) fprintf(stderr,"** str2list: bad params (%p,%p)\n",
1049                                  (void *)list, (void *)str);
1050         return 0;  /* should be *_UNDEFINED */
1051     }
1052 
1053     for( index = max; index > 0; index-- )
1054         if( !strcmp(str, list[index]) ) return index;
1055 
1056     return 0;    /* failure */
1057 }
1058 
1059 /*----------------------------------------------------------------------
1060  *! return the index for a GIFTI_IND_ORD_* string
1061 *//*-------------------------------------------------------------------*/
gifti_str2ind_ord(const char * str)1062 int gifti_str2ind_ord( const char * str )
1063 {
1064     int rv = str2list_index(gifti_index_order_list,GIFTI_IND_ORD_MAX,str);
1065     if( rv <= GIFTI_IND_ORD_UNDEF && G.verb > 1 )
1066         fprintf(stderr,"** bad index order, '%s'\n", str);
1067     return rv;
1068 }
1069 
1070 /*----------------------------------------------------------------------
1071  *! return the GIFTI_IND_ORD_* string for the given index
1072 *//*-------------------------------------------------------------------*/
gifti_ind_ord2str(int ind_ord)1073 char * gifti_ind_ord2str( int ind_ord )
1074 {
1075     return gifti_list_index2string(gifti_index_order_list, ind_ord);
1076 }
1077 
1078 
1079 /*----------------------------------------------------------------------
1080  *! return the index for a GIFTI_ENDODING_* string
1081 *//*-------------------------------------------------------------------*/
gifti_str2encoding(const char * str)1082 int gifti_str2encoding( const char * str )
1083 {
1084     int rv = str2list_index(gifti_encoding_list, GIFTI_ENCODING_MAX, str);
1085     if( rv <= GIFTI_ENCODING_UNDEF && G.verb > 1 )
1086         fprintf(stderr,"** bad data encoding, '%s'\n", str);
1087     return rv;
1088 }
1089 
1090 /*----------------------------------------------------------------------
1091  *! return the string at the given index of the given list
1092  *
1093  *  This function is meant to index into one of the gifti_*_list arrays,
1094  *  while being certain that the index is not out of range.
1095 *//*-------------------------------------------------------------------*/
gifti_list_index2string(char * list[],int index)1096 char * gifti_list_index2string(char * list[], int index)
1097 {
1098     int lsize;    /* list size cannot be computed from the passed pointer */
1099 
1100     if     ( list == gifti_index_order_list )
1101         lsize = sizeof(gifti_index_order_list)/sizeof(char *);
1102 
1103     else if( list == gifti_encoding_list )
1104         lsize = sizeof(gifti_encoding_list)/sizeof(char *);
1105 
1106     else if( list == gifti_endian_list )
1107         lsize = sizeof(gifti_endian_list)/sizeof(char *);
1108 
1109     else {
1110         fprintf(stderr,"** GLI2S: invalid list\n");
1111         return "UNKNOWN LIST";
1112     }
1113 
1114     if( index < 0 || index >= lsize ) {
1115         if( G.verb > 0)
1116             fprintf(stderr,"** GLI2S: index %d out of range {0..%d}\n",
1117                 index,lsize-1);
1118         return "INDEX OUT OF RANGE";
1119     }
1120 
1121     /* all that work, just for the expected indexing...  */
1122 
1123     return list[index];
1124 }
1125 
1126 /*----------------------------------------------------------------------
1127  *! return the NIFTI_TYPE_ value corresponding to the given string
1128 *//*-------------------------------------------------------------------*/
gifti_str2datatype(const char * str)1129 int gifti_str2datatype(const char * str)
1130 {
1131     int len = sizeof(gifti_type_list)/sizeof(gifti_type_ele);
1132     int c;
1133 
1134     for( c = len - 1; c > 0; c-- )
1135         if( !strcmp(str, gifti_type_list[c].name) )
1136             break;
1137 
1138     return gifti_type_list[c].type;
1139 }
1140 
1141 
1142 /*----------------------------------------------------------------------
1143  *! return the GIFTI_ENDIAN_ value corresponding to the given string
1144 *//*-------------------------------------------------------------------*/
gifti_str2endian(const char * str)1145 int gifti_str2endian( const char * str )
1146 {
1147     int rv = str2list_index(gifti_endian_list, GIFTI_ENDIAN_MAX, str);
1148     if( rv <= GIFTI_ENCODING_UNDEF && G.verb > 1 )
1149         fprintf(stderr,"** bad endian, '%s'\n", G_CHECK_NULL_STR(str));
1150     return rv;
1151 }
1152 
1153 
1154 /*----------------------------------------------------------------------
1155  *! return the NIFTI_TYPE_ value string corresponding to the given type
1156 *//*-------------------------------------------------------------------*/
gifti_datatype2str(int type)1157 char * gifti_datatype2str(int type)
1158 {
1159     int len = sizeof(gifti_type_list)/sizeof(gifti_type_ele);
1160     int c;
1161 
1162     for( c = len - 1; c > 0; c-- )
1163         if( type == gifti_type_list[c].type)
1164             break;
1165 
1166     return gifti_type_list[c].name;
1167 }
1168 
1169 
1170 /*----------------------------------------------------------------------
1171  *! simply set the struct contents to empty
1172 *//*-------------------------------------------------------------------*/
gifti_clear_nvpairs(nvpairs * p)1173 int gifti_clear_nvpairs(nvpairs * p)
1174 {
1175     if( !p ) return 1;
1176 
1177     p->length = 0;
1178     p->name = NULL;
1179     p->value = NULL;
1180 
1181     return 0;
1182 }
1183 
1184 /*----------------------------------------------------------------------
1185  *! simply set the struct contents to empty
1186 *//*-------------------------------------------------------------------*/
gifti_clear_LabelTable(giiLabelTable * p)1187 int gifti_clear_LabelTable(giiLabelTable * p)
1188 {
1189     if( !p ) return 1;
1190 
1191     p->length = 0;
1192     p->key = NULL;
1193     p->label = NULL;
1194     p->rgba = NULL;
1195 
1196     return 0;
1197 }
1198 
1199 /*----------------------------------------------------------------------
1200  *! simply set the struct contents to empty
1201 *//*-------------------------------------------------------------------*/
gifti_clear_CoordSystem(giiCoordSystem * p)1202 int gifti_clear_CoordSystem(giiCoordSystem * p)
1203 {
1204     if( !p ) return 1;
1205 
1206     p->dataspace = NULL;
1207     p->xformspace = NULL;
1208     memset(p->xform,0,sizeof(p->xform));
1209 
1210     return 0;
1211 }
1212 
1213 /*----------------------------------------------------------------------
1214  *! add an empty CoordSystem struct to the DataArray
1215 *//*-------------------------------------------------------------------*/
gifti_add_empty_CS(giiDataArray * da)1216 int gifti_add_empty_CS(giiDataArray * da)
1217 {
1218     if( !da ) return 1;
1219 
1220     /* be safe, if anything looks bad, start clean */
1221     if(da->numCS <= 0 || !da->coordsys) { da->numCS = 0; da->coordsys = NULL; }
1222 
1223     if(G.verb > 3 )fprintf(stderr,"++ adding empty CS[%d]\n", da->numCS);
1224 
1225     /* realloc coordsys pointer array, and add an empty structure */
1226     da->coordsys = (giiCoordSystem **)realloc(da->coordsys,
1227                         (da->numCS+1) * sizeof(giiCoordSystem *));
1228     if( !da->coordsys ) {
1229         fprintf(stderr,"** AECS: failed to alloc %d CoordSys pointers\n",
1230                        da->numCS+1);
1231         da->numCS = 0;
1232         return 1;
1233     }
1234 
1235     da->coordsys[da->numCS] = (giiCoordSystem *)malloc(sizeof(giiCoordSystem));
1236     if( !da->coordsys[da->numCS] ) {
1237         fprintf(stderr,"** push_cstm: failed to alloc new CoordSystem\n");
1238         return 1;
1239     }
1240 
1241     gifti_clear_CoordSystem(da->coordsys[da->numCS]);
1242 
1243     da->numCS++;
1244 
1245     return 0;
1246 }
1247 
1248 /*----------------------------------------------------------------------
1249  *! rotate DA list, moving from the back to the front
1250  *
1251  *  this (after add_empty) would allow one to add a new entry to the front
1252  *
1253  *  - allocate for nrot temp pointers
1254  *  - copy nrot trailing pointers to temp
1255  *  - shift numDA-nrot pointers to end
1256  *  - copy temp pointers to start
1257  *  - free temp array
1258  *
1259  *  return 0 on success
1260  *         1 on error
1261 *//*-------------------------------------------------------------------*/
gifti_rotate_DAs_to_front(gifti_image * gim,int nrot)1262 int gifti_rotate_DAs_to_front(gifti_image * gim, int nrot)
1263 {
1264     giiDataArray ** dtmp;
1265     int             ind;
1266 
1267     if( !gim || nrot < 0 || nrot >= gim->numDA) return 1;
1268 
1269     if( nrot < 1 ) return 0;
1270 
1271     if(G.verb > 3)fprintf(stderr,"++ rotate darray[%d] (%d)\n",gim->numDA,nrot);
1272 
1273     /* allocate for temporary pointers */
1274     dtmp = (giiDataArray **)malloc(nrot*sizeof(giiDataArray *));
1275     if( !dtmp ) {
1276        fprintf(stderr,"** failed to alloc %d DA pointers\n", nrot);
1277        return 1;
1278     }
1279 
1280     /* copy nrot into temp list (cleaner than memcpy?) */
1281     for( ind=0; ind < nrot; ind++ )
1282        dtmp[ind] = gim->darray[gim->numDA-nrot+ind];
1283 
1284     /* shift numDA-nrot to end (index downward over destinations) */
1285     for( ind=gim->numDA-1; ind >= nrot; ind-- )
1286        gim->darray[ind] = gim->darray[ind-nrot];
1287 
1288     /* copy nrot from temp list to start */
1289     for( ind=0; ind < nrot; ind++ )
1290        gim->darray[ind] = dtmp[ind];
1291 
1292     free(dtmp);
1293 
1294     return 0;
1295 }
1296 
1297 /*----------------------------------------------------------------------
1298  *! add an empty DataArray struct to the gim->darray list
1299  *
1300  *  this both reallocates gim->darray and allocates gim->darray[new]
1301  *
1302  *  if num_to_add > 0: add that many elements
1303  *  if defaults      : init each element with default values
1304  *
1305  *  return 0 on success
1306  *         1 on error
1307 *//*-------------------------------------------------------------------*/
gifti_add_empty_darray(gifti_image * gim,int num_to_add)1308 int gifti_add_empty_darray(gifti_image * gim, int num_to_add)
1309 {
1310     giiDataArray * dptr;
1311     int            c, ntot, nnew = num_to_add > 0 ? num_to_add : 1;
1312 
1313     if( !gim ) return 1;
1314 
1315     if(G.verb > 3)fprintf(stderr,"++ alloc darray[%d] (+%d)\n",gim->numDA,nnew);
1316 
1317     /* allocate for additional pointers */
1318     ntot = gim->numDA + nnew;
1319     gim->darray = (giiDataArray **)realloc(gim->darray,
1320                                            ntot*sizeof(giiDataArray *));
1321 
1322     if( !gim->darray ) {
1323         fprintf(stderr,"** failed realloc darray, len %d\n", ntot);
1324         gim->numDA = 0;
1325         return 1;
1326     }
1327 
1328     /* allocate the actual giiDataArray structs, inserted at the end */
1329     for( c = 0; c < nnew; c++ ) {
1330         dptr = (giiDataArray *)calloc(1, sizeof(giiDataArray));
1331         if( !dptr ) {
1332             fprintf(stderr,"** failed to alloc DA element #%d\n",gim->numDA);
1333             return 1;   /* leave allocated list as is */
1334         }
1335         gim->darray[gim->numDA] = dptr;
1336         gim->numDA++;
1337 
1338         /* clear any non-value attributes/elements */
1339         gifti_clear_DataArray(dptr);
1340     }
1341 
1342     return 0;
1343 }
1344 
1345 /*----------------------------------------------------------------------
1346  *! add the given name=value pair to the nvpairs struct
1347  *
1348  *  this allocates memory for the p->name and p->value arrays, along
1349  *  with duplicating the passed name/value strings
1350 *//*-------------------------------------------------------------------*/
gifti_add_to_nvpairs(nvpairs * p,const char * name,const char * value)1351 int gifti_add_to_nvpairs(nvpairs * p, const char * name, const char * value)
1352 {
1353     int index;
1354 
1355     if( !p || !name || !value ) {
1356         if(G.verb > 1) fprintf(stderr,"** GATN: bad params(%p,%p,%p)\n",
1357                                (void *)p, (void *)name, (void *)value);
1358         return 1;
1359     }
1360 
1361     p->length++;
1362     p->name = (char **)realloc(p->name, p->length * sizeof(char *));
1363     p->value = (char **)realloc(p->value, p->length * sizeof(char *));
1364 
1365     if( !p->name || !p->value ) {
1366         fprintf(stderr,"** GATN: failed to realloc %d pointers\n",p->length);
1367         return 1;
1368     } else if ( G.verb > 3 )
1369         fprintf(stderr,"++ add_nvp [%d]: '%s', '%s'\n", p->length,
1370                 name ? name : "NULL", value ? value : "NULL");
1371 
1372     index = p->length - 1;
1373     p->name[index] = gifti_strdup(name);
1374     p->value[index] = gifti_strdup(value);
1375 
1376     if( !p->name[index] || !p->value[index] ) {
1377         fprintf(stderr,"** GATN: failed to copy pair '%s'='%s'\n",name,value);
1378         return 1;
1379     }
1380 
1381     return 0;
1382 }
1383 
1384 /*----------------------------------------------------------------------
1385  *! display the contents of the nvpairs struct
1386 *//*-------------------------------------------------------------------*/
gifti_disp_nvpairs(const char * mesg,const nvpairs * p)1387 int gifti_disp_nvpairs(const char * mesg, const nvpairs * p)
1388 {
1389     int c;
1390 
1391     if( mesg ) { fputs(mesg, stderr); fputc(' ', stderr); }
1392 
1393     if( !p ){ fputs("disp: nvpairs = NULL\n", stderr); return 1; }
1394 
1395     fprintf(stderr,"nvpairs struct, len = %d :\n", p->length);
1396 
1397     for(c = 0; c < p->length; c++ )
1398         fprintf(stderr,"    nvpair: '%s' = '%s'\n",
1399                 G_CHECK_NULL_STR(p->name[c]), G_CHECK_NULL_STR(p->value[c]));
1400     if( p->length > 0 ) fputc('\n', stderr);
1401 
1402     return 0;
1403 }
1404 
1405 /*----------------------------------------------------------------------
1406  *! display the contents of the LabelTable struct
1407 *//*-------------------------------------------------------------------*/
gifti_disp_LabelTable(const char * mesg,const giiLabelTable * p)1408 int gifti_disp_LabelTable(const char * mesg, const giiLabelTable * p)
1409 {
1410     float * rgba;
1411     int     c;
1412 
1413     if( mesg ) { fputs(mesg, stderr); fputc(' ', stderr); }
1414 
1415     if( !p ){ fputs("disp: giiLabelTable = NULL\n", stderr); return 1; }
1416 
1417     fprintf(stderr,"giiLabelTable struct, len = %d :\n", p->length);
1418 
1419     rgba = p->rgba;
1420     for(c = 0; c < p->length; c++ ) {
1421         fprintf(stderr,"    key %d, ", p->key[c]);
1422         if( rgba ) {
1423             fprintf(stderr,"rgba (%5.3f, %5.3f, %5.3f, %5.3f), ",
1424                     rgba[0], rgba[1], rgba[2], rgba[3]);
1425             rgba += 4;
1426         }
1427         fprintf(stderr,"label '%s'\n", G_CHECK_NULL_STR(p->label[c]));
1428     }
1429 
1430     if( p->length > 0 ) fputc('\n', stderr);
1431 
1432     return 0;
1433 }
1434 
1435 /*----------------------------------------------------------------------
1436  *! display the contents of the CoordSystem struct
1437 *//*-------------------------------------------------------------------*/
gifti_disp_CoordSystem(const char * mesg,const giiCoordSystem * p)1438 int gifti_disp_CoordSystem(const char * mesg, const giiCoordSystem * p)
1439 {
1440     int c1, c2;
1441 
1442     if( mesg ) { fputs(mesg, stderr); fputc(' ', stderr); }
1443 
1444     if( !p ){ fputs("disp: giiCoordSystem = NULL\n", stderr); return 1; }
1445 
1446     fprintf(stderr,"giiCoordSystem struct\n"
1447                    "    dataspace  = %s\n"
1448                    "    xformspace = %s\n",
1449                    G_CHECK_NULL_STR(p->dataspace),
1450                    G_CHECK_NULL_STR(p->xformspace));
1451     for( c1 = 0; c1 < 4; c1++ )
1452     {
1453         fprintf(stderr,"    xform[%d] :", c1);
1454         for( c2 = 0; c2 < 4; c2++ )
1455             fprintf(stderr,"  %f", p->xform[c1][c2]);
1456         fputc('\n', stderr);
1457     }
1458 
1459     return 0;
1460 }
1461 
1462 /*----------------------------------------------------------------------
1463  *! display the contents of the DataArray struct
1464  *
1465  *  if 'subs' is set, display the contents of the sub-structures
1466 *//*-------------------------------------------------------------------*/
gifti_disp_DataArray(const char * mesg,const giiDataArray * p,int subs)1467 int gifti_disp_DataArray(const char * mesg, const giiDataArray * p, int subs)
1468 {
1469     int c;
1470     fprintf(stderr,"--------------------------------------------------\n");
1471 
1472     if( mesg ) { fputs(mesg, stderr); fputc(' ', stderr); }
1473 
1474     if( !p ){ fputs("disp: giiDataArray = NULL\n", stderr); return 1; }
1475 
1476     fprintf(stderr,"giiDataArray struct\n"
1477                    "    intent   %4d = %s\n"
1478                    "    datatype   %2d = %s\n"
1479                    "    ind_ord    %2d = %s\n"
1480                    "    num_dim       = %d\n"
1481                    "    dims          = %d, %d, %d, %d, %d, %d\n"
1482                    "    encoding   %2d = %s\n"
1483                    "    endian     %2d = %s\n"
1484                    "    ext_fname     = %s\n"
1485                    "    ext_offset    = %lld\n"
1486                 , p->intent,
1487                 gifti_intent_to_string(p->intent),
1488                 p->datatype, gifti_datatype2str(p->datatype),
1489                 p->ind_ord,
1490                 gifti_list_index2string(gifti_index_order_list, p->ind_ord),
1491                 p->num_dim,
1492                 p->dims[0], p->dims[1], p->dims[2],
1493                 p->dims[3], p->dims[4], p->dims[5],
1494                 p->encoding,
1495                 gifti_list_index2string(gifti_encoding_list, p->encoding),
1496                 p->endian,
1497                 gifti_list_index2string(gifti_endian_list, p->endian),
1498                 G_CHECK_NULL_STR(p->ext_fname), p->ext_offset
1499            );
1500 
1501     if( subs ) gifti_disp_nvpairs("darray->meta", &p->meta);
1502     if( subs ) for( c = 0; c < p->numCS; c++ )
1503                    gifti_disp_CoordSystem("darray->coordsys", p->coordsys[c]);
1504 
1505     fprintf(stderr,"    data       = %s\n"
1506                    "    nvals      = %u\n"
1507                    "    nbyper     = %d\n"
1508                    "    numCS      = %d\n",
1509                 p->data ? "<set>" : "NULL", (unsigned)p->nvals,
1510                 p->nbyper, p->numCS);
1511 
1512     if( subs ) gifti_disp_nvpairs("darray->ex_atrs", &p->ex_atrs);
1513     fprintf(stderr,"--------------------------------------------------\n");
1514 
1515     return 0;
1516 }
1517 
1518 /*----------------------------------------------------------------------
1519  *! display the contents of the gifti_image struct
1520  *
1521  *  if 'subs' is set, display the contents of the sub-structures, such
1522  *  as all of the DataArray elements
1523 *//*-------------------------------------------------------------------*/
gifti_disp_gifti_image(const char * mesg,const gifti_image * p,int subs)1524 int gifti_disp_gifti_image(const char * mesg, const gifti_image * p, int subs)
1525 {
1526     fprintf(stderr,"==================================================\n");
1527 
1528     if( mesg ) { fputs(mesg, stderr); fputc(' ', stderr); }
1529 
1530     if( !p ){ fputs("disp: gifti_image = NULL\n", stderr); return 1; }
1531 
1532     fprintf(stderr,"gifti_image struct\n"
1533                    "    version    = %s\n"
1534                    "    numDA      = %d\n",
1535                    G_CHECK_NULL_STR(p->version), p->numDA);
1536 
1537     if( subs ) {
1538         char buf[32];
1539         int  c;
1540 
1541         gifti_disp_nvpairs("gim->meta", &p->meta);
1542         gifti_disp_LabelTable("gim->labeltable", &p->labeltable);
1543         for( c = 0; c < p->numDA; c++ ) {
1544             sprintf(buf, "gim->darray[%d]", c);
1545             gifti_disp_DataArray(buf, p->darray[c], subs);
1546         }
1547     }
1548 
1549     fprintf(stderr,"gifti_image struct\n"
1550                    "    swapped    = %d\n"
1551                    "    compressed = %d\n", p->swapped, p->compressed);
1552 
1553     fprintf(stderr," -- darray totals: %lld MB\n",gifti_gim_DA_size(p,1));
1554     if( subs ) gifti_disp_nvpairs("gim->ex_atrs" , &p->ex_atrs);
1555 
1556     fprintf(stderr,"==================================================\n");
1557 
1558     return 0;
1559 }
1560 
1561 /*----------------------------------------------------------------------
1562  *! compute the number of bytes summed over all DataArray elements
1563  *
1564  *  if in_mb is set, return the (rounded) number of megabytes
1565  *  (i.e. 17 is 17 MB)
1566 *//*-------------------------------------------------------------------*/
gifti_gim_DA_size(const gifti_image * p,int in_mb)1567 long long gifti_gim_DA_size(const gifti_image * p, int in_mb)
1568 {
1569     long long bytes = 0;
1570     int       c;
1571 
1572     if( !p ) return -1;
1573     if( !p->darray || p->numDA <= 0 ) return 0;
1574 
1575     for( c = 0; c < p->numDA; c++ ) {
1576         if( ! p->darray[c]->data ) continue;  /* skip anything without data */
1577         if( p->darray[c]->nvals <= 0 || p->darray[c]->nbyper <= 0 ) {
1578             fprintf(stderr,"** have data[%d], but nvals = %lld, nbyper = %d\n",
1579                     c, p->darray[c]->nvals, p->darray[c]->nbyper);
1580             return 0;
1581         }
1582         bytes += p->darray[c]->nvals * p->darray[c]->nbyper;
1583     }
1584 
1585     if( bytes <= 0LL ) return 0;
1586 
1587     if( in_mb ) bytes = (bytes + (1<<19) ) >> 20;  /* round to nearest MB */
1588 
1589     return bytes;
1590 }
1591 
1592 /*----------------------------------------------------------------------
1593  *! given a datatype, return the corresponding bytes per value and swapsize
1594  *
1595  *  nbyper and swapsize are filled only if the pointers are set
1596 *//*-------------------------------------------------------------------*/
gifti_datatype_sizes(int datatype,int * nbyper,int * swapsize)1597 int gifti_datatype_sizes(int datatype, int *nbyper, int *swapsize)
1598 {
1599     int c;
1600 
1601     for( c = sizeof(gifti_type_list) / sizeof(gifti_type_ele) - 1; c > 0; c-- )
1602         if( datatype == gifti_type_list[c].type ) {
1603             if( nbyper ) *nbyper = gifti_type_list[c].nbyper;
1604             if( swapsize ) *swapsize = gifti_type_list[c].swapsize;
1605             return 0;
1606         }
1607 
1608     if( G.verb > 0 ) fprintf(stderr,"** GDS with bad datatype %d\n", datatype);
1609     if( nbyper ) *nbyper = 0;
1610     if( swapsize ) *swapsize = 0;
1611 
1612     return 1;
1613 }
1614 
1615 /*----------------------------------------------------------------------
1616  *! compute the total number of data values in a DataArray element
1617 *//*-------------------------------------------------------------------*/
gifti_darray_nvals(const giiDataArray * da)1618 long long gifti_darray_nvals(const giiDataArray * da)
1619 {
1620     long long ndim = 1;
1621     int       c;
1622 
1623     if(!da){ fprintf(stderr,"** GDND, no ptr\n"); return 0; }
1624 
1625     if( ! gifti_valid_num_dim(da->num_dim, 0) ) {
1626         fprintf(stderr,"** giiDataArray has illegal num_dim = %d\n",
1627                 da->num_dim);
1628         return 0;
1629     }
1630 
1631     for( c = 0; c < da->num_dim; c++ ) ndim *= da->dims[c];
1632 
1633     if( ndim <= 0 ) {
1634         gifti_disp_DataArray("** bad Dim list in ", da, 0);
1635         return 0;
1636     }
1637 
1638     return ndim;
1639 }
1640 
1641 /*----------------------------------------------------------------------
1642  *! find giiDataArray element #index of the given intent
1643 *//*-------------------------------------------------------------------*/
gifti_find_DA(gifti_image * gim,int intent,int index)1644 giiDataArray * gifti_find_DA(gifti_image * gim, int intent, int index)
1645 {
1646     int c, nfound;
1647 
1648     if( !gim || !gifti_intent_is_valid(intent) || index < 0 ) {
1649         fprintf(stderr,"** find_DA: bad inputs (%p, %d, %d)\n",
1650                 (void*)gim, intent, index);
1651         return NULL;
1652     }
1653 
1654     if ( !gim-> darray ) return NULL;
1655 
1656     for( c = 0, nfound = 0; c < gim->numDA; c++ )
1657         if( gim->darray[c] && gim->darray[c]->intent == intent ) {
1658             if( nfound == index )
1659                 return gim->darray[c];  /* success */
1660             nfound++;   /* else, increment counter and keep looking */
1661         }
1662 
1663     return NULL;
1664 }
1665 
1666 /*----------------------------------------------------------------------
1667  *! return an allocated list of giiDataArray pointers of the given intent
1668  *
1669  *  'list' should be freed or taken
1670 *//*-------------------------------------------------------------------*/
gifti_find_DA_list(gifti_image * gim,int intent,giiDataArray *** list,int * len)1671 int gifti_find_DA_list(gifti_image * gim, int intent,
1672                        giiDataArray *** list, int * len)
1673 {
1674     int c, nfound;
1675 
1676     if( !gim || !gifti_intent_is_valid(intent) || !list || !len ) {
1677         fprintf(stderr,"** find_DA: bad inputs (%p, %d, %p, %p)\n",
1678                 (void *)gim, intent, (void *)list, (void *)len);
1679         return 1;
1680     }
1681 
1682     if ( !gim->darray ) return 1;
1683 
1684     /* create one big enough to hold everything */
1685     *len = gim->numDA;
1686     *list = (giiDataArray **)calloc(*len, sizeof(giiDataArray *));
1687     if( !*list ) {
1688         fprintf(stderr,"** find_DA_list: failed to alloc %d ptrs\n",*len);
1689         *len = 0;
1690         return 1;
1691     }
1692 
1693     for( c = 0, nfound = 0; c < gim->numDA; c++ )
1694         if( gim->darray[c] && gim->darray[c]->intent == intent )
1695             (*list)[nfound++] = gim->darray[c];
1696 
1697     /* if we didn't find any, nuke list, but do not return an error */
1698     if( nfound == 0 ) { free(*list); *list = NULL; *len = 0; return 0; }
1699 
1700     /* otherwise, reallocate a smaller list */
1701     if( nfound < *len ) {
1702         *len  = nfound;
1703         *list = (giiDataArray**)realloc(*list,*len*sizeof(giiDataArray*));
1704         if( !*list ) {
1705             fprintf(stderr,"** find_DA_list: failed realloc of %d ptrs\n",*len);
1706             *len = 0;
1707             return 1;
1708         }
1709     }
1710 
1711     return 0;
1712 }
1713 
1714 /*----------------------------------------------------------------------
1715  *! given metadata name, return the corresponding value (or NULL)
1716  *
1717  *  no allocation is done here
1718 *//*-------------------------------------------------------------------*/
gifti_get_meta_value(const nvpairs * nvp,const char * name)1719 char * gifti_get_meta_value(const nvpairs * nvp, const char * name)
1720 {
1721     int c;
1722 
1723     if( !nvp || !name ) {
1724         if( G.verb > 3 )
1725           fprintf(stderr,"** get_meta_value: NULL input (%p, %p)\n",
1726                 (void*)nvp, name);
1727         return NULL;
1728     }
1729 
1730     if( G.verb > 5 )
1731         fprintf(stderr,"-- G_get_meta_value: looking for name = '%s'\n", name);
1732 
1733     if ( !nvp->name || !nvp->value || nvp->length <= 0 ) {
1734         if( G.verb > 3 )
1735             fprintf(stderr,"-- G_get_meta_value: no name/value array\n");
1736         return NULL;
1737     }
1738 
1739     for( c = 0; c < nvp->length; c++ )
1740         if( !strcmp(nvp->name[c], name) )
1741             break;  /* found */
1742 
1743     if( c >= nvp->length ) return NULL;
1744 
1745     if( G.verb > 3 )
1746         fprintf(stderr,"++ found meta '%s'='%s'\n",nvp->name[c],nvp->value[c]);
1747 
1748     return nvp->value[c];
1749 }
1750 
1751 /*----------------------------------------------------------------------
1752  *! return the number of 'rows' and 'columns' of a DataArray element
1753  *
1754  *  define rows to be along the first dimension, and collapse the
1755  *  remaining dimensions as cols
1756 *//*-------------------------------------------------------------------*/
gifti_DA_rows_cols(giiDataArray * da,long long * rows,long long * cols)1757 int gifti_DA_rows_cols(giiDataArray * da, long long * rows, long long * cols)
1758 {
1759     *rows = da->dims[0];  /* init */
1760     *cols = 1;
1761 
1762     if( da->num_dim == 1 ) return 0;          /* use default */
1763 
1764     /* ROW_MAJOR does not matter here    25 Apr 2017 [rickr] */
1765     /* treat Dim[0] as nodes (they change most slowly)       */
1766     *rows = da->dims[0];
1767     *cols = (*rows) ? da->nvals / *rows : 1;      /* be safe */
1768 
1769 #if 0
1770         /* old COL_MAJOR case... */
1771         *rows = da->dims[da->num_dim-1];  /* take highest index */
1772         *cols = (*rows > 0) ? da->nvals / *rows : 1;
1773 #endif
1774 
1775     return 0;
1776 }
1777 
1778 /*----------------------------------------------------------------------
1779  *! print the gifti library history string
1780 *//*-------------------------------------------------------------------*/
gifti_disp_lib_hist(void)1781 void gifti_disp_lib_hist(void)
1782 {
1783    int c, len = sizeof(gifti_history)/sizeof(char *);
1784    for( c = 0; c < len; c++ )
1785        fputs(gifti_history[c], stdout);
1786 }
1787 
1788 /*----------------------------------------------------------------------
1789  *! print the gifti library version string
1790 *//*-------------------------------------------------------------------*/
gifti_disp_lib_version(void)1791 void gifti_disp_lib_version(void)
1792 {
1793     printf("%s, compiled %s\n", gifti_version, __DATE__);
1794 }
1795 
1796 /*----------------------------------------------------------------------
1797  *! return the gifti library version string
1798 *//*-------------------------------------------------------------------*/
gifticlib_version(void)1799 char * gifticlib_version(void)
1800 {
1801     return gifti_version;
1802 }
1803 
1804 /*----------------------------------------------------------------------
1805  *! print the gifti DTD URL
1806 *//*-------------------------------------------------------------------*/
gifti_disp_dtd_url(void)1807 void gifti_disp_dtd_url(void)
1808 {
1809     printf("The GIFTI Document Type Definition (DTD) is at:\n    %s\n",
1810            GIFTI_XML_DTD_SOURCE);
1811 }
1812 
1813 /*----------------------------------------------------------------------
1814  *! display data in hexidecimal, on one line
1815  *
1816  *  if mesg is set, print the message first
1817  *  if fp is not set, print to stdout
1818 *//*-------------------------------------------------------------------*/
gifti_disp_hex_data(const char * mesg,const void * data,int len,FILE * fp)1819 int gifti_disp_hex_data(const char *mesg, const void *data, int len, FILE *fp)
1820 {
1821     const char * dp = (const char *)data;
1822     FILE       * stream;
1823     int          c;
1824 
1825     stream = fp ? fp : stdout;
1826 
1827     if( !data || len < 1 ) return -1;
1828 
1829     if( mesg ) fputs(mesg, stream);
1830 
1831     for( c = 0; c < len; c++ )
1832         fprintf(stream, " %02x", dp[c]);
1833 
1834     return 0;
1835 }
1836 
1837 /*----------------------------------------------------------------------
1838  *! swap sets of 2-byte values
1839 *//*-------------------------------------------------------------------*/
gifti_swap_2bytes(void * data,long long nsets)1840 int gifti_swap_2bytes(void * data, long long nsets)
1841 {
1842     char    * cp1 = (char *)data, * cp2;
1843     char      tval;
1844     long long c;
1845 
1846     for( c = 0; c < nsets; c++ ) {
1847         cp2 = cp1 + 1;
1848         tval = *cp1;  *cp1 = *cp2;  *cp2 = tval;
1849         cp1 += 2;
1850     }
1851 
1852     return 0;
1853 }
1854 
1855 /*----------------------------------------------------------------------
1856  *! swap sets of 4-byte values
1857 *//*-------------------------------------------------------------------*/
gifti_swap_4bytes(void * data,long long nsets)1858 int gifti_swap_4bytes(void * data, long long nsets)
1859 {
1860     char    * cp0 = (char *)data, * cp1, * cp2;
1861     char      tval;
1862     long long c;
1863 
1864     for( c = 0; c < nsets; c++ ) {
1865         cp1 = cp0;
1866         cp2 = cp0 + 3;
1867         tval = *cp1;  *cp1 = *cp2;  *cp2 = tval;
1868         cp1++;  cp2--;
1869         tval = *cp1;  *cp1 = *cp2;  *cp2 = tval;
1870         cp0 += 4;
1871     }
1872 
1873     return 0;
1874 }
1875 
1876 /*----------------------------------------------------------------------
1877  *! swap sets of N-byte values
1878  *
1879  *  if N < 2         : just return
1880  *  if N = 2 or N = 4: call explicit function for that size (speed)
1881  *  else             : swap in a loop
1882 *//*-------------------------------------------------------------------*/
gifti_swap_Nbytes(void * data,long long nsets,int swapsize)1883 int gifti_swap_Nbytes(void * data, long long nsets, int swapsize)
1884 {
1885     char    * cp0, * cp1, * cp2;
1886     char      tval;
1887     long long c;
1888     int       offset;      /* swapsize - 1, for speed */
1889 
1890     if( ! data || nsets < 0 || swapsize < 0 ) {
1891         fprintf(stderr,"** swap_Nbytes: bad params (%p,%lld,%d)\n",
1892                 (void *)data, nsets, swapsize);
1893         return 1;
1894     }
1895 
1896     if     ( swapsize  < 2 ) return 0;  /* nothing to do */
1897     else if( swapsize == 2 ) return gifti_swap_2bytes(data, nsets);
1898     else if( swapsize == 4 ) return gifti_swap_4bytes(data, nsets);
1899 
1900     /* peform a swap */
1901     cp0 = (char *)data;
1902     offset = swapsize-1;  /* just for speed */
1903 
1904     for( c = 0; c < nsets; c++ ) {
1905         cp1 = cp0;
1906         cp2 = cp0 + offset;
1907         while( cp2 > cp1 ) {
1908             tval = *cp1;  *cp1 = *cp2;  *cp2 = tval;
1909             cp1++;  cp2--;
1910         }
1911         cp0 += swapsize;
1912     }
1913 
1914     return 0;
1915 }
1916 
1917 /*----------------------------------------------------------------------
1918  *! return the current CPU endian: GIFTI_ENDIAN_BIG or _LITTLE
1919 *//*-------------------------------------------------------------------*/
gifti_get_this_endian(void)1920 int gifti_get_this_endian(void)
1921 {
1922    int    one = 1;
1923    char * cp = (char *)&one;
1924 
1925    if( *cp ) return GIFTI_ENDIAN_LITTLE;
1926 
1927    return GIFTI_ENDIAN_BIG;
1928 }
1929 
1930 /*----------------------------------------------------------------------
1931  *! if endian does not match that of this CPU, swap the data bytes
1932  *
1933  *  return whether bytes were swapped
1934 *//*-------------------------------------------------------------------*/
gifti_check_swap(void * data,int endian,long long nsets,int swapsize)1935 int gifti_check_swap(void * data, int endian, long long nsets, int swapsize)
1936 {
1937     if( !data || nsets < 0 || swapsize < 0 ) {
1938         fprintf(stderr,"** check_swap: bad params (%p,%lld, %d)\n",
1939                 (void *)data, nsets, swapsize);
1940         return 0;
1941     } else if ( endian <= GIFTI_ENDIAN_UNDEF || endian > GIFTI_ENDIAN_MAX ) {
1942         fprintf(stderr, "** check_swap: invalid endian %d\n", endian);
1943         return 0;
1944     }
1945 
1946     /* if endian is the same as this one, just return */
1947     if( endian == gifti_get_this_endian() ) {
1948         if( G.verb > 2 )
1949             fprintf(stderr,"-- darray no swap needed : %lld sets of %d bytes\n",
1950                     nsets, swapsize);
1951         return 0;
1952     }
1953 
1954     if( G.verb > 2 )
1955         fprintf(stderr,"++ darray swap: %lld sets of %d bytes\n",
1956                 nsets, swapsize);
1957 
1958     /* do the swap */
1959     (void)gifti_swap_Nbytes(data, nsets, swapsize);
1960 
1961     return 1;
1962 }
1963 
1964 #ifdef GIFTI_BAD_SIZEOF
1965 #undef GIFTI_BAD_SIZEOF
1966 #endif
1967 #define GIFTI_BAD_SIZEOF(mesg, type, size)                      \
1968    ((sizeof(type) == size) ? 0 :                                \
1969     (fprintf(stderr,"%s : sizeof(#type) != %d\n", mesg, size), 1))
1970 
1971 /*---------------------------------------------------------------------*/
1972 /*! Convert the ArrayIndexingOrder of the gifti_image DA elements to
1973  *  the given order.                             28 Apr 2017 [rickr]
1974  *
1975  *  This is not just a tranpose, but a more general permutation of
1976  *  the data in memory, so allocate a new data pointer.
1977  *
1978  *  Terminate on first DA failure.
1979  *
1980  *  return 1 if convertion occurred, 0 if not, -1 on error
1981 *//*-------------------------------------------------------------------*/
gifti_convert_ind_ord(gifti_image * gim,int new_ord)1982 int gifti_convert_ind_ord(gifti_image * gim, int new_ord)
1983 {
1984    int dind, rv, perm=0;
1985 
1986    if ( ! gim ) {
1987       fprintf(stderr,"** gifti_convert_ind_ord: no gifti_image\n");
1988       return 1;
1989    }
1990 
1991    for( dind = 0; dind < gim->numDA; dind++ ) {
1992       rv = gifti_convert_DA_ind_ord(gim->darray[dind], new_ord);
1993       if( rv < 0 ) return rv;   /* fail on any error */
1994       if( rv > 0 ) perm = 1;    /* note that it happened */
1995    }
1996 
1997    return perm;
1998 }
1999 
2000 /*---------------------------------------------------------------------*/
2001 /*! Convert the ArrayIndexingOrder of the DataArry element to the
2002  *  specified order.                          27 Apr 2017 [rickr]
2003  *
2004  *  This is not just a tranpose, but a more general permutation of
2005  *  the data in memory, so allocate a new data pointer.
2006  *
2007  *  return 1 if converted, 0 of not, -1 on error
2008 *//*-------------------------------------------------------------------*/
gifti_convert_DA_ind_ord(giiDataArray * da,int new_ord)2009 int gifti_convert_DA_ind_ord(giiDataArray * da, int new_ord)
2010 {
2011    char * fname = "convert_ind_ord";
2012    void * newdata = NULL;
2013 
2014    if ( !gifti_valid_dims(da, 1) ) /* will whine */
2015       return -1;
2016 
2017    if( new_ord <= GIFTI_IND_ORD_UNDEF || new_ord > GIFTI_IND_ORD_MAX ) {
2018       if( G.verb )
2019          fprintf(stderr,"** %s: invalid order %d\n", fname, new_ord);
2020       return -1;
2021    }
2022 
2023    if( da->ind_ord == new_ord ) {
2024       if( G.verb > 4 )
2025          fprintf(stderr,"-- %s: order already %d = %s\n", fname, new_ord,
2026                  gifti_list_index2string(gifti_index_order_list, new_ord));
2027       return 0;
2028    }
2029 
2030    if( da->nvals == 0 ) return 0;
2031 
2032    /*--- have something to do ---*/
2033 
2034    if( G.verb > 3 )
2035       fprintf(stderr,"-- changing ind_ord from %d (%s) to %d (%s)...\n",
2036               da->ind_ord,
2037               gifti_list_index2string(gifti_index_order_list, da->ind_ord),
2038               new_ord,
2039               gifti_list_index2string(gifti_index_order_list, new_ord));
2040 
2041    /* have something to do, but is it trivial? */
2042    if( da->num_dim == 1 ) {
2043       if( G.verb > 3 )
2044          fprintf(stderr,"-- %s: num_dim == 1, so simply change field\n",fname);
2045       da->ind_ord = new_ord;
2046       return 0;
2047    }
2048 
2049    /*------ have something real to do, either RM->CM or the reverse ------*/
2050 
2051    /* allocate output data array (or could overwrite input not to change it? */
2052    newdata = malloc(da->nvals * da->nbyper);
2053    if( ! newdata ) {
2054       fprintf(stderr,"** %s: failed to alloc %lld bytes for DA\n",
2055               fname, da->nvals*da->nbyper);
2056       return -1;
2057    }
2058 
2059    /* actually permute the data */
2060    if( permute_by_index_order(newdata, new_ord, da) ) {
2061       free(newdata);
2062       return -1;
2063    }
2064 
2065    /* insert result and clean up */
2066    free(da->data);
2067    da->data = newdata;
2068    da->ind_ord = new_ord;
2069 
2070    return 1;  /* change happened */
2071 }
2072 
2073 /*===========================================================================
2074  * row major/column major index order permutation macros
2075  *===========================================================================*/
2076 
2077 /* column major to row major conversion */
2078 #define GIFTI_PBIO_C2R_2(type, din, dout)                       \
2079    do {                                                         \
2080       type * dinp = (type *)din, * doutp = (type *)dout;        \
2081       for( i0 = 0; i0 < m0; i0++ )                              \
2082          for( i1 = 0; i1 < m1; i1++ )                           \
2083             *doutp++ = dinp[i0 + m0 * i1];                      \
2084    } while(0)
2085 
2086 
2087 #define GIFTI_PBIO_C2R_3(type, din, dout)                       \
2088    do {                                                         \
2089       type * dinp = (type *)din, * doutp = (type *)dout;        \
2090       type * bp0, * bp1, * bp2;                                 \
2091       for( i0 = 0; i0 < m0; i0++ ) {                            \
2092          bp0 = dinp + i0;                                       \
2093          for( i1 = 0; i1 < m1; i1++ ) {                         \
2094             bp1 = bp0 + i1 * m0;                                \
2095             for( i2 = 0; i2 < m2; i2++ ) {                      \
2096                bp2 = bp1 + i2 * m0*m1;                          \
2097                *doutp++ = *bp2;                                 \
2098             } } }                                               \
2099    } while(0)
2100 
2101 #define GIFTI_PBIO_C2R_4(type, din, dout)                       \
2102    do {                                                         \
2103       type * dinp = (type *)din, * doutp = (type *)dout;        \
2104       type * bp0, * bp1, * bp2, * bp3;                          \
2105       for( i0 = 0; i0 < m0; i0++ ) {                            \
2106          bp0 = dinp + i0;                                       \
2107          for( i1 = 0; i1 < m1; i1++ ) {                         \
2108             bp1 = bp0 + i1 * m0;                                \
2109             for( i2 = 0; i2 < m2; i2++ ) {                      \
2110                bp2 = bp1 + i2 * m0*m1;                          \
2111                for( i3 = 0; i3 < m3; i3++ ) {                   \
2112                   bp3 = bp2 + i3 * m0*m1*m2;                    \
2113                   *doutp++ = *bp3;                              \
2114                } } } }                                          \
2115    } while(0)
2116 
2117 #define GIFTI_PBIO_C2R_5(type, din, dout)                       \
2118    do {                                                         \
2119       type * dinp = (type *)din, * doutp = (type *)dout;        \
2120       type * bp0, * bp1, * bp2, * bp3, * bp4;                   \
2121       for( i0 = 0; i0 < m0; i0++ ) {                            \
2122          bp0 = dinp + i0;                                       \
2123          for( i1 = 0; i1 < m1; i1++ ) {                         \
2124             bp1 = bp0 + i1 * m0;                                \
2125             for( i2 = 0; i2 < m2; i2++ ) {                      \
2126                bp2 = bp1 + i2 * m0*m1;                          \
2127                for( i3 = 0; i3 < m3; i3++ ) {                   \
2128                   bp3 = bp2 + i3 * m0*m1*m2;                    \
2129                   for( i4 = 0; i4 < m4; i4++ ) {                \
2130                      bp4 = bp3 + i4 * m0*m1*m2*m3;              \
2131                      *doutp++ = *bp4;                           \
2132                   } } } } }                                     \
2133    } while(0)
2134 
2135 #define GIFTI_PBIO_C2R_6(type, din, dout)                       \
2136    do {                                                         \
2137       type * dinp = (type *)din, * doutp = (type *)dout;        \
2138       type * bp0, * bp1, * bp2, * bp3, * bp4, * bp5;            \
2139       for( i0 = 0; i0 < m0; i0++ ) {                            \
2140          bp0 = dinp + i0;                                       \
2141          for( i1 = 0; i1 < m1; i1++ ) {                         \
2142             bp1 = bp0 + i1 * m0;                                \
2143             for( i2 = 0; i2 < m2; i2++ ) {                      \
2144                bp2 = bp1 + i2 * m0*m1;                          \
2145                for( i3 = 0; i3 < m3; i3++ ) {                   \
2146                   bp3 = bp2 + i3 * m0*m1*m2;                    \
2147                   for( i4 = 0; i4 < m4; i4++ ) {                \
2148                      bp4 = bp3 + i4 * m0*m1*m2*m3;              \
2149                      for( i5 = 0; i5 < m5; i5++ ) {             \
2150                         bp5 = bp4 + i5 * m0*m1*m2*m3*m4;        \
2151                         *doutp++ = *bp5;                        \
2152                      } } } } } }                                \
2153    } while(0)
2154 
2155 
2156 /* row major to column major conversions */
2157 /* same indexing, but switch application between in and out pointers */
2158 #define GIFTI_PBIO_R2C_2(type, din, dout)                       \
2159    do {                                                         \
2160       type * dinp = (type *)din, * doutp = (type *)dout;        \
2161       for( i0 = 0; i0 < m0; i0++ )                              \
2162          for( i1 = 0; i1 < m1; i1++ )                           \
2163             doutp[i0 + m0 * i1] = *dinp++;                      \
2164    } while(0)
2165 
2166 
2167 #define GIFTI_PBIO_R2C_3(type, din, dout)                       \
2168    do {                                                         \
2169       type * dinp = (type *)din, * doutp = (type *)dout;        \
2170       type * bp0, * bp1, * bp2;                                 \
2171       for( i0 = 0; i0 < m0; i0++ ) {                            \
2172          bp0 = doutp + i0;                                      \
2173          for( i1 = 0; i1 < m1; i1++ ) {                         \
2174             bp1 = bp0 + i1 * m0;                                \
2175             for( i2 = 0; i2 < m2; i2++ ) {                      \
2176                bp2 = bp1 + i2 * m0*m1;                          \
2177                *bp2 = *dinp++;                                  \
2178             } } }                                               \
2179    } while(0)
2180 
2181 #define GIFTI_PBIO_R2C_4(type, din, dout)                       \
2182    do {                                                         \
2183       type * dinp = (type *)din, * doutp = (type *)dout;        \
2184       type * bp0, * bp1, * bp2, * bp3;                          \
2185       for( i0 = 0; i0 < m0; i0++ ) {                            \
2186          bp0 = doutp + i0;                                      \
2187          for( i1 = 0; i1 < m1; i1++ ) {                         \
2188             bp1 = bp0 + i1 * m0;                                \
2189             for( i2 = 0; i2 < m2; i2++ ) {                      \
2190                bp2 = bp1 + i2 * m0*m1;                          \
2191                for( i3 = 0; i3 < m3; i3++ ) {                   \
2192                   bp3 = bp2 + i3 * m0*m1*m2;                    \
2193                   *bp3 = *dinp++;                               \
2194                } } } }                                          \
2195    } while(0)
2196 
2197 #define GIFTI_PBIO_R2C_5(type, din, dout)                       \
2198    do {                                                         \
2199       type * dinp = (type *)din, * doutp = (type *)dout;        \
2200       type * bp0, * bp1, * bp2, * bp3, * bp4;                   \
2201       for( i0 = 0; i0 < m0; i0++ ) {                            \
2202          bp0 = doutp + i0;                                      \
2203          for( i1 = 0; i1 < m1; i1++ ) {                         \
2204             bp1 = bp0 + i1 * m0;                                \
2205             for( i2 = 0; i2 < m2; i2++ ) {                      \
2206                bp2 = bp1 + i2 * m0*m1;                          \
2207                for( i3 = 0; i3 < m3; i3++ ) {                   \
2208                   bp3 = bp2 + i3 * m0*m1*m2;                    \
2209                   for( i4 = 0; i4 < m4; i4++ ) {                \
2210                      bp4 = bp3 + i4 * m0*m1*m2*m3;              \
2211                      *bp4 = *dinp++;                            \
2212                   } } } } }                                     \
2213    } while(0)
2214 
2215 #define GIFTI_PBIO_R2C_6(type, din, dout)                       \
2216    do {                                                         \
2217       type * dinp = (type *)din, * doutp = (type *)dout;        \
2218       type * bp0, * bp1, * bp2, * bp3, * bp4, * bp5;            \
2219       for( i0 = 0; i0 < m0; i0++ ) {                            \
2220          bp0 = doutp + i0;                                      \
2221          for( i1 = 0; i1 < m1; i1++ ) {                         \
2222             bp1 = bp0 + i1 * m0;                                \
2223             for( i2 = 0; i2 < m2; i2++ ) {                      \
2224                bp2 = bp1 + i2 * m0*m1;                          \
2225                for( i3 = 0; i3 < m3; i3++ ) {                   \
2226                   bp3 = bp2 + i3 * m0*m1*m2;                    \
2227                   for( i4 = 0; i4 < m4; i4++ ) {                \
2228                      bp4 = bp3 + i4 * m0*m1*m2*m3;              \
2229                      for( i5 = 0; i5 < m5; i5++ ) {             \
2230                         bp5 = bp4 + i5 * m0*m1*m2*m3*m4;        \
2231                         *bp5 = *dinp++;                         \
2232                      } } } } } }                                \
2233    } while(0)
2234 
2235 
2236 /*===========================================================================*/
2237 
2238 /* decisions... slow and steady or fast and dangerous?
2239  * let's change to slow and steady, since this should be uncommon
2240  *
2241  * return 0 on success
2242  */
permute_by_index_order(void * dest,int new_ord,giiDataArray * da)2243 static int permute_by_index_order(void * dest, int new_ord, giiDataArray * da)
2244 {
2245    long long m0, m1, m2, m3, m4, m5;
2246    long long i0, i1, i2, i3, i4, i5;
2247    char    * mesg = "permute index order";
2248 
2249    /* avoid repetitive indexing (for speed) */
2250    m0 = da->dims[0]; m1 = da->dims[1]; m2 = da->dims[2];
2251    m3 = da->dims[3]; m4 = da->dims[4]; m5 = da->dims[5];
2252 
2253    /* we checked before, but hey... */
2254    if( new_ord != GIFTI_IND_ORD_ROW_MAJOR &&
2255        new_ord != GIFTI_IND_ORD_COL_MAJOR ) {
2256       fprintf(stderr,"** PBIO: invalid index order %d\n", new_ord);
2257       return 1;
2258    }
2259 
2260    if( G.verb > 3 ) {
2261       fprintf(stderr,"-- permute order: %d to %d, nbyper %d\n   dims: ",
2262               da->ind_ord, new_ord, da->nbyper);
2263       gifti_disp_raw_data(da->dims, DT_INT32, da->num_dim, 1, stderr);
2264    }
2265 
2266    switch( da->nbyper ) {
2267       default: {
2268          /* don't need to fail after malloc, but this should be rare,
2269             and this is a good place for a failure check */
2270          fprintf(stderr,"** %s: not prepared for nbyper = %d\n",
2271                  mesg, da->nbyper);
2272          return 1;
2273       }
2274       case 1: { /* process as char (signed int8) */
2275          if( GIFTI_BAD_SIZEOF(mesg, char, 1) ) return 1;
2276 
2277          if( new_ord == GIFTI_IND_ORD_ROW_MAJOR ) {
2278             switch( da->num_dim ) {
2279                default: break; /* do nothing for 1 or unknown */
2280                case 2: GIFTI_PBIO_C2R_2(char, da->data, dest); break;
2281                case 3: GIFTI_PBIO_C2R_3(char, da->data, dest); break;
2282                case 4: GIFTI_PBIO_C2R_4(char, da->data, dest); break;
2283                case 5: GIFTI_PBIO_C2R_5(char, da->data, dest); break;
2284                case 6: GIFTI_PBIO_C2R_6(char, da->data, dest); break;
2285             }
2286          } else { /* to GIFTI_IND_ORD_COL_MAJOR */
2287             switch( da->num_dim ) {
2288                default: break; /* do nothing for 1 or unknown */
2289                case 2: GIFTI_PBIO_R2C_2(char, da->data, dest); break;
2290                case 3: GIFTI_PBIO_R2C_3(char, da->data, dest); break;
2291                case 4: GIFTI_PBIO_R2C_4(char, da->data, dest); break;
2292                case 5: GIFTI_PBIO_R2C_5(char, da->data, dest); break;
2293                case 6: GIFTI_PBIO_R2C_6(char, da->data, dest); break;
2294             }
2295          }
2296          break;
2297       }
2298       case 2: { /* process as short (signed int16) */
2299          if( GIFTI_BAD_SIZEOF(mesg, short, 2) ) return 1;
2300 
2301          if( new_ord == GIFTI_IND_ORD_ROW_MAJOR ) {
2302             switch( da->num_dim ) {
2303                default: break; /* do nothing for 1 or unknown */
2304                case 2: GIFTI_PBIO_C2R_2(short, da->data, dest); break;
2305                case 3: GIFTI_PBIO_C2R_3(short, da->data, dest); break;
2306                case 4: GIFTI_PBIO_C2R_4(short, da->data, dest); break;
2307                case 5: GIFTI_PBIO_C2R_5(short, da->data, dest); break;
2308                case 6: GIFTI_PBIO_C2R_6(short, da->data, dest); break;
2309             }
2310          } else { /* to GIFTI_IND_ORD_COL_MAJOR */
2311             switch( da->num_dim ) {
2312                default: break; /* do nothing for 1 or unknown */
2313                case 2: GIFTI_PBIO_R2C_2(short, da->data, dest); break;
2314                case 3: GIFTI_PBIO_R2C_3(short, da->data, dest); break;
2315                case 4: GIFTI_PBIO_R2C_4(short, da->data, dest); break;
2316                case 5: GIFTI_PBIO_R2C_5(short, da->data, dest); break;
2317                case 6: GIFTI_PBIO_R2C_6(short, da->data, dest); break;
2318             }
2319          }
2320          break;
2321       }
2322       case 4: { /* process as int (signed int32) */
2323          if( GIFTI_BAD_SIZEOF(mesg, int,   4) ) return 1;
2324 
2325          if( new_ord == GIFTI_IND_ORD_ROW_MAJOR ) {
2326             switch( da->num_dim ) {
2327                default: break; /* do nothing for 1 or unknown */
2328                case 2: GIFTI_PBIO_C2R_2(int, da->data, dest); break;
2329                case 3: GIFTI_PBIO_C2R_3(int, da->data, dest); break;
2330                case 4: GIFTI_PBIO_C2R_4(int, da->data, dest); break;
2331                case 5: GIFTI_PBIO_C2R_5(int, da->data, dest); break;
2332                case 6: GIFTI_PBIO_C2R_6(int, da->data, dest); break;
2333             }
2334          } else { /* to GIFTI_IND_ORD_COL_MAJOR */
2335             switch( da->num_dim ) {
2336                default: break; /* do nothing for 1 or unknown */
2337                case 2: GIFTI_PBIO_R2C_2(int, da->data, dest); break;
2338                case 3: GIFTI_PBIO_R2C_3(int, da->data, dest); break;
2339                case 4: GIFTI_PBIO_R2C_4(int, da->data, dest); break;
2340                case 5: GIFTI_PBIO_R2C_5(int, da->data, dest); break;
2341                case 6: GIFTI_PBIO_R2C_6(int, da->data, dest); break;
2342             }
2343          }
2344          break;
2345       }
2346       case 8: { /* process as long long (signed int64) */
2347          if( GIFTI_BAD_SIZEOF(mesg, long long, 8) ) return 1;
2348 
2349          if( new_ord == GIFTI_IND_ORD_ROW_MAJOR ) {
2350             switch( da->num_dim ) {
2351                default: break; /* do nothing for 1 or unknown */
2352                case 2: GIFTI_PBIO_C2R_2(long long, da->data, dest); break;
2353                case 3: GIFTI_PBIO_C2R_3(long long, da->data, dest); break;
2354                case 4: GIFTI_PBIO_C2R_4(long long, da->data, dest); break;
2355                case 5: GIFTI_PBIO_C2R_5(long long, da->data, dest); break;
2356                case 6: GIFTI_PBIO_C2R_6(long long, da->data, dest); break;
2357             }
2358          } else { /* to GIFTI_IND_ORD_COL_MAJOR */
2359             switch( da->num_dim ) {
2360                default: break; /* do nothing for 1 or unknown */
2361                case 2: GIFTI_PBIO_R2C_2(long long, da->data, dest); break;
2362                case 3: GIFTI_PBIO_R2C_3(long long, da->data, dest); break;
2363                case 4: GIFTI_PBIO_R2C_4(long long, da->data, dest); break;
2364                case 5: GIFTI_PBIO_R2C_5(long long, da->data, dest); break;
2365                case 6: GIFTI_PBIO_R2C_6(long long, da->data, dest); break;
2366             }
2367          }
2368          break;
2369       }
2370    }
2371 
2372    return 0;
2373 }
2374 
2375 /*---------------------------------------------------------------------*/
2376 /*! Allocate and fill the data array with data read from the given
2377  *  external file.
2378  *
2379  *  return 0 on success
2380 *//*-------------------------------------------------------------------*/
gifti_read_extern_DA_data(giiDataArray * da)2381 int gifti_read_extern_DA_data(giiDataArray * da)
2382 {
2383     FILE      * fp;
2384     long long   nbytes, nread;
2385 
2386     if( !da || !da->ext_fname || !*da->ext_fname ) return 0;
2387 
2388     if(G.verb > 4) fprintf(stderr,"-- external read of '%s'\n",da->ext_fname);
2389 
2390     if( da->ext_offset < 0 ) {
2391         fprintf(stderr,"** want external DA data with bad offset %lld\n",
2392                 da->ext_offset);
2393         return 1;
2394     } else if( da->data ) {
2395         fprintf(stderr,"** want external DA data but data already allocated\n");
2396         return 1;
2397     } else if ( !gifti_valid_dims(da, 1) ) {
2398         fprintf(stderr,"** cannot read external DA data with bad dims...\n");
2399         return 1;
2400     }
2401 
2402     /* allocate data */
2403     nbytes = da->nvals * da->nbyper;
2404     da->data = calloc(da->nvals, da->nbyper); /* zero in case of read failure */
2405     if( !da->data ) {
2406         fprintf(stderr,"** failed to alloc %lld bytes for external read\n",
2407                 nbytes);
2408         return 1;
2409     }
2410 
2411     /* open file, jump to offset and read */
2412     fp = fopen(da->ext_fname, "r");
2413     if( !fp ) {
2414         fprintf(stderr,"** ext read: failed to open '%s'\n",da->ext_fname);
2415         return 1;
2416     }
2417 
2418     if( fseek(fp, da->ext_offset, SEEK_SET) ) {
2419         fprintf(stderr,"** ext read: failed to seek to %lld in '%s'\n",
2420                 da->ext_offset, da->ext_fname);
2421         fclose(fp); return 1;
2422     }
2423 
2424     nread = fread(da->data, sizeof(char), nbytes, fp);
2425     fclose(fp);  /* close now in any case */
2426 
2427     if( nread != nbytes ) {
2428         fprintf(stderr,"** ext_read: read only %lld of %lld bytes from %s\n",
2429                 nread, nbytes, da->ext_fname);
2430         return 1;
2431     }
2432 
2433     if(G.verb > 2)
2434         fprintf(stderr,"-- read %lld bytes from external '%s' @ %lld\n",
2435                        nbytes, da->ext_fname, da->ext_offset);
2436 
2437     return 0;
2438 }
2439 
2440 /*---------------------------------------------------------------------*/
2441 /*! Write DA data to the given external file.
2442  *
2443  *  Note: the given ext_offset _must_ refer to the current end of file.
2444  *
2445  *  return 0 on success
2446 *//*-------------------------------------------------------------------*/
gifti_write_extern_DA_data(giiDataArray * da)2447 int gifti_write_extern_DA_data(giiDataArray * da)
2448 {
2449     FILE      * fp;
2450     long long   nbytes, nwritten, posn;
2451 
2452     if( !da || !da->ext_fname || !*da->ext_fname ) return 0;
2453 
2454     if(G.verb > 4) fprintf(stderr,"-- external write to '%s'\n",da->ext_fname);
2455 
2456     if( da->ext_offset < 0 ) {
2457         fprintf(stderr,"** bad offset for external DA data write, %lld\n",
2458                 da->ext_offset);
2459         return 1;
2460     } else if( !da->data ) {
2461         fprintf(stderr,"** no data for external DA data write\n");
2462         return 1;
2463     } else if ( !gifti_valid_dims(da, 1) ) {
2464         fprintf(stderr,"** cannot write external DA data with bad dims...\n");
2465         return 1;
2466     }
2467 
2468     nbytes = da->nvals * da->nbyper;
2469 
2470     /* open file for append and verify that the file offset matches this one */
2471     fp = fopen(da->ext_fname, "a+");
2472     if( !fp ) {
2473         fprintf(stderr,"** ext write: failed to open '%s' for append\n",
2474                 da->ext_fname);
2475         return 1;
2476     }
2477 
2478     /* we should be at the end of the file, which measn posn da->ext_offset */
2479     fseek(fp, 0, SEEK_END);  /* append should write to the end, but be sure */
2480     posn = ftell(fp);
2481     if( posn != da->ext_offset ) {
2482         fprintf(stderr,"** ext write: cur posn (%lld) not ext_offset (%lld)"
2483                        " in file %s\n", posn, da->ext_offset, da->ext_fname);
2484         fclose(fp); return 1;
2485     }
2486 
2487     nwritten = fwrite(da->data, sizeof(char), nbytes, fp);
2488 
2489     fclose(fp);         /* close now in any case */
2490 
2491     if( nwritten != nbytes ) {
2492         fprintf(stderr,"** ext_write: appended only %lld of %lld bytes to %s\n",
2493                 nwritten, nbytes, da->ext_fname);
2494         return 1;
2495     }
2496 
2497     if(G.verb > 2)
2498         fprintf(stderr,"-- appended %lld bytes to external '%s' @ %lld\n",
2499                        nbytes, da->ext_fname, da->ext_offset);
2500 
2501     return 0;
2502 }
2503 
2504 /*---------------------------------------------------------------------*/
2505 /*! Apply the file list as external files.
2506  *
2507  *  The files are assumed to be partitioned by DataArray entries.  So
2508  *  the list length must divide numDA evenly.
2509  *
2510  *  External files are not checked for her, as this is independent of any
2511  *  read or write operation.
2512  *
2513  *  return 0 on success
2514 *//*-------------------------------------------------------------------*/
gifti_set_extern_filelist(gifti_image * gim,int nfiles,char ** files)2515 int gifti_set_extern_filelist(gifti_image * gim, int nfiles, char ** files)
2516 {
2517     giiDataArray * da;
2518     long long      nbytes, offset;
2519     int            nper;
2520     int            daindex, findex, oindex;
2521 
2522     if(!gim || gim->numDA <= 0 || nfiles <= 0 || !files) {
2523         if(G.verb>1) fprintf(stderr,"-- set_extern_filelist: nothing to do\n");
2524         return 1;
2525     }
2526 
2527     nper = gim->numDA / nfiles;
2528 
2529     if(G.verb>4) fprintf(stderr,"-- set_extern_flist for %d files (nper=%d)\n",
2530                          nfiles, nper);
2531 
2532     if( nfiles * nper != gim->numDA ) { /* be sure division is integral */
2533         fprintf(stderr,"** Cannot evenly divide %d DataArrays by %d"
2534                        " external files\n", gim->numDA, nfiles);
2535         return 1;
2536     }
2537 
2538     daindex = 0;  /* DataArray index */
2539     for( findex = 0; findex < nfiles; findex++ ) {
2540         if( !files[findex] || !*files[findex] ) {
2541             fprintf(stderr,"** set_extern_flist: missing filename %d\n",findex);
2542             return 1;
2543         }
2544 
2545         /* note and check nbytes */
2546         nbytes = gim->darray[daindex]->nvals * gim->darray[daindex]->nbyper;
2547         if( nbytes <= 0 ) {
2548             fprintf(stderr,"** gifti_set_extern_filelist: bad nbytes\n");
2549             return 1;
2550         }
2551 
2552         /* within this file, offset will be multiples of nbytes */
2553         for( oindex=0, offset=0; oindex < nper; oindex++, offset += nbytes ) {
2554             da = gim->darray[daindex];
2555 
2556             if( nbytes != da->nvals * da->nbyper ) {
2557               fprintf(stderr,"** set_extern_flist: nbytes mismatch at DA[%d]\n"
2558                              "   (expected %lld, found %lld)\n",
2559                              daindex, nbytes, da->nvals * da->nbyper);
2560               return 1;
2561             }
2562 
2563             /* set encoding and external file fields */
2564             da->encoding   = GIFTI_ENCODING_EXTBIN;
2565             da->ext_fname  = gifti_strdup(files[findex]);
2566             da->ext_offset = offset;
2567 
2568             daindex++;  /* increment DataArray index every time */
2569         }
2570     }
2571 
2572     if(G.verb > 2)
2573         fprintf(stderr,"++ set extern file list, %d files, %d DAs per file",
2574                 nfiles, nper);
2575 
2576     return 0;
2577 }
2578 
2579 /*---------------------------------------------------------------------*/
2580 /*! Given a NIFTI_INTENT string, such as "NIFTI_INTENT_NODE_INDEX",
2581  *  return the corresponding integral intent code.  The intent code is
2582  *  the macro value defined in nifti1.h.
2583  *
2584  *  return 0 on failure (NIFTI_INTENT_NONE)
2585 *//*-------------------------------------------------------------------*/
gifti_intent_from_string(const char * name)2586 int gifti_intent_from_string( const char * name )
2587 {
2588     int tablen = sizeof(gifti_intent_list)/sizeof(gifti_intent_ele);
2589     int c;
2590 
2591     if( !name ) return 0;
2592 
2593     for( c = tablen-1; c > 0; c-- )
2594         if( !strcmp(name, gifti_intent_list[c].name) )
2595             break;
2596 
2597     return gifti_intent_list[c].code;
2598 }
2599 
2600 
2601 /*---------------------------------------------------------------------*/
2602 /*! Given a NIFTI_TYPE value, such as NIFTI_TYPE_INT16, return the
2603  *  corresponding macro label as a string.  The dtype code is the
2604  *  macro value defined in nifti1.h.
2605 *//*-------------------------------------------------------------------*/
gifti_intent_to_string(int code)2606 char * gifti_intent_to_string( int code )
2607 {
2608     int tablen = sizeof(gifti_intent_list)/sizeof(gifti_intent_ele);
2609     int c;
2610 
2611     for( c = tablen-1; c > 0; c-- )
2612         if( gifti_intent_list[c].code == code )
2613             break;
2614 
2615     return gifti_intent_list[c].name;
2616 }
2617 
2618 
2619 /*---------------------------------------------------------------------*/
2620 /*! Return whether the given code is a valid NIFTI_INTENT code.
2621 *//*-------------------------------------------------------------------*/
gifti_intent_is_valid(int code)2622 int gifti_intent_is_valid( int code )
2623 {
2624     int tablen = sizeof(gifti_intent_list)/sizeof(gifti_intent_ele);
2625     int c;
2626 
2627     for( c = tablen-1; c > 0; c-- )
2628         if( gifti_intent_list[c].code == code )
2629             break;
2630 
2631     return( c >= 0 );
2632 }
2633 
2634 
2635 /*---------------------------------------------------------------------*/
2636 /*! duplicate the given string
2637 *//*-------------------------------------------------------------------*/
gifti_strdup(const char * src)2638 char * gifti_strdup( const char * src )
2639 {
2640     char * newstr;
2641     int    len;
2642 
2643     if( !src ) return NULL;  /* easy case */
2644 
2645     len = strlen(src) + 1;
2646 
2647     newstr = (char *)malloc(len * sizeof(char));
2648     if( !newstr ) {
2649         fprintf(stderr,"** failed gifti_strdup, len = %d\n", len);
2650         return NULL;
2651     }
2652 
2653     strcpy(newstr, src);
2654 
2655     return newstr;
2656 }
2657 
2658 /*---------------------------------------------------------------------*/
2659 /*! duplicate the given giiDataArray struct, optionally including data
2660  *
2661  *  Allocate for a new struct, and fill it so that the contents are
2662  *  identical (sans pointers) to orig.  Sub-structure arrays will need
2663  *  to be allocated, also.
2664  *
2665  *  If get_data is not set, gnew->data will be left as NULL.
2666  *
2667  *  return the address of the newly allocated structure
2668 *//*-------------------------------------------------------------------*/
gifti_copy_DataArray(const giiDataArray * orig,int get_data)2669 giiDataArray * gifti_copy_DataArray(const giiDataArray * orig, int get_data)
2670 {
2671     giiDataArray * gnew;
2672     int            c;
2673 
2674     if( ! orig ){ fprintf(stderr,"** copy_DA: input is NULL\n"); return NULL; }
2675 
2676     if(G.verb > 5) fprintf(stderr,"++ copying giiDataArray...\n");
2677 
2678     gnew = (giiDataArray *)calloc(1, sizeof(giiDataArray));
2679     if(!gnew){fprintf(stderr,"** copy_DA, failed to alloc DA\n"); return NULL;}
2680 
2681     /* cheat - start by copying the entire struct contents */
2682     *gnew = *orig;
2683 
2684     /* copy any pointer data or structures */
2685     gnew->ext_fname = gifti_strdup(orig->ext_fname);
2686     gifti_copy_nvpairs(&gnew->meta, &orig->meta);
2687     if( orig->numCS > 0 && orig->coordsys ) {
2688         gnew->coordsys = (giiCoordSystem **)malloc(gnew->numCS *
2689                                 sizeof(giiCoordSystem *));
2690         if(!gnew->coordsys) {
2691             fprintf(stderr,"** copy_DA: failed to alloc %d CS pointers\n",
2692                     gnew->numCS);
2693             gnew->numCS = 0;
2694         } else
2695             for( c = 0; c < gnew->numCS; c++ )
2696                 gnew->coordsys[c] = gifti_copy_CoordSystem(orig->coordsys[c]);
2697     }
2698 
2699     /* maybe the needy user wants data, too */
2700     if(orig->data && get_data) {
2701         if(G.verb > 5) fprintf(stderr,"++ copy_DA, adding data\n");
2702         gnew->data = malloc(gnew->nvals * gnew->nbyper);
2703         if(!gnew->data)       /* continue? */
2704             fprintf(stderr,"** copy DA, failed to alloc %lld bytes for data\n",
2705                     gnew->nvals * gnew->nbyper);
2706         memcpy(gnew->data, orig->data, gnew->nvals * gnew->nbyper);
2707     } else
2708         gnew->data = NULL;
2709 
2710     /* last and certainly least, ex_atrs */
2711     gifti_copy_nvpairs(&gnew->ex_atrs, &orig->ex_atrs);
2712 
2713     return gnew;
2714 }
2715 
2716 /*---------------------------------------------------------------------*/
2717 /*! dupliate the giiCoordSystem struct (passing NULL is okay)
2718 *//*-------------------------------------------------------------------*/
gifti_copy_CoordSystem(const giiCoordSystem * src)2719 giiCoordSystem * gifti_copy_CoordSystem(const giiCoordSystem * src)
2720 {
2721     giiCoordSystem * csnew;
2722     int              r, c;
2723 
2724     if( !src ) return NULL;     /* this may be okay */
2725 
2726     if( G.verb > 6 ) fprintf(stderr,"++ copy_CS\n");
2727 
2728     csnew = (giiCoordSystem *)malloc(sizeof(giiCoordSystem));
2729     if( !csnew ){ fprintf(stderr,"** copy_CS: failed alloc\n"); return NULL; }
2730 
2731     csnew->dataspace  = gifti_strdup(src->dataspace);
2732     csnew->xformspace = gifti_strdup(src->xformspace);
2733 
2734     for( r = 0; r < 4; r++ )
2735         for( c = 0; c < 4; c++ )
2736             csnew->xform[r][c] = src->xform[r][c];
2737 
2738     return csnew;
2739 }
2740 
2741 /*---------------------------------------------------------------------*/
2742 /*! dupliate the contents of the giiLabelTable struct
2743 *//*-------------------------------------------------------------------*/
gifti_copy_LabelTable(giiLabelTable * dest,const giiLabelTable * src)2744 int gifti_copy_LabelTable(giiLabelTable * dest, const giiLabelTable * src)
2745 {
2746     int c;
2747 
2748     if( !src || !dest ) {
2749         fprintf(stderr,"** copy_LabelTable: bad params (%p,%p)\n",
2750                 (void *)src, (void *)dest);
2751         return 1;
2752     }
2753 
2754     if( G.verb > 6 ) fprintf(stderr,"++ copy_LT\n");
2755 
2756     /* quick case: empty table */
2757     if( src->length <= 0 ) return gifti_clear_LabelTable(dest);
2758 
2759     /* otherwise, allocate and copy lists */
2760     dest->length = src->length;
2761 
2762     dest->key = (int *)malloc(dest->length * sizeof(int));
2763     dest->label = (char **)malloc(dest->length * sizeof(char *));
2764     if( src->rgba )
2765         dest->rgba = (float *)malloc(dest->length * 4 * sizeof(float));
2766 
2767     /* check for failure */
2768     if( !dest->key || !dest->label || (src->rgba && !dest->rgba) ) {
2769         fprintf(stderr,"** failed to dup label arrays of length %d\n",
2770                 dest->length);
2771         gifti_free_LabelTable(dest);
2772         return 1;
2773     }
2774 
2775     /* copy any rgba list */
2776     if( dest->rgba )
2777         memcpy(dest->rgba, src->rgba, dest->length * 4 * sizeof(float));
2778 
2779     /* copy indices */
2780     for( c = 0; c < dest->length; c++ )
2781         dest->key[c] = src->key[c];
2782 
2783     /* copy labels */
2784     for( c = 0; c < dest->length; c++ )
2785         dest->label[c] = gifti_strdup(src->label[c]);
2786 
2787     return 0;
2788 }
2789 
2790 /*---------------------------------------------------------------------*/
2791 /*! dupliate the contents of one nvpairs structure into an empty one
2792  *
2793  *  return 0 on success
2794 *//*-------------------------------------------------------------------*/
gifti_copy_nvpairs(nvpairs * dest,const nvpairs * src)2795 int gifti_copy_nvpairs(nvpairs * dest, const nvpairs * src)
2796 {
2797     if( !dest || !src ){
2798         fprintf(stderr,"** copy_NVP, bad params (%p,%p)\n",
2799                 (void*)dest,(void*)src);
2800         return 1;
2801     }
2802 
2803     if( G.verb > 6 ) fprintf(stderr,"++ copy_nvp, length %d\n", src->length);
2804 
2805     /* check for a simple case */
2806     if( src->length <= 0 || !src->name || !src->value ) {
2807         dest->length = 0;
2808         dest->name = dest->value = NULL;
2809         return 0;
2810     }
2811 
2812     /* else, copy the lists */
2813     dest->length = src->length;
2814     dest->name   = gifti_copy_char_list(src->name, src->length);
2815     dest->value  = gifti_copy_char_list(src->value, src->length);
2816 
2817     return 0;
2818 }
2819 
2820 /*---------------------------------------------------------------------*/
2821 /*! dupliate the list of strings
2822 *//*-------------------------------------------------------------------*/
gifti_copy_char_list(char ** list,int len)2823 char ** gifti_copy_char_list(char ** list, int len)
2824 {
2825     char ** newlist = NULL;
2826     int     c;
2827 
2828     if( !list || len <= 0 ) return NULL;
2829 
2830     newlist = (char **)malloc(len * sizeof(char *));
2831     if( !newlist ) {
2832         fprintf(stderr,"** copy_char_list fails for %d pointers\n", len);
2833         return NULL;
2834     }
2835 
2836     for( c = 0; c < len; c++)                   /* big finish */
2837         newlist[c] = gifti_strdup(list[c]);
2838 
2839     return newlist;
2840 }
2841 
2842 /*---------------------------------------------------------------------*/
2843 /*! copy any GIFTI MetaData named 'name' from dest to src (replace old)
2844  *
2845  *  return 0 on success, 1 on failure to find, -1 on error
2846 *//*-------------------------------------------------------------------*/
gifti_copy_gifti_meta(gifti_image * dest,gifti_image * src,const char * name)2847 int gifti_copy_gifti_meta(gifti_image * dest, gifti_image * src,
2848                           const char * name)
2849 {
2850     char * value;
2851 
2852     if( !dest || !src || !name ) {
2853         if( G.verb > 0 )
2854             fprintf(stderr,"** copy_gifti_meta: bad params(%p,%p,%p)\n",
2855                     (void *)dest, (void *)src, name);
2856         return -1;
2857     }
2858 
2859     value = gifti_get_meta_value(&src->meta, name);
2860     if( !value ) {
2861         if( G.verb > 4 )
2862             fprintf(stderr,"-- GCGM: did not find meta name '%s'\n", name);
2863         return 1;
2864     }
2865 
2866     return gifti_add_to_meta(&dest->meta, name, value, 1);
2867 }
2868 
2869 /*---------------------------------------------------------------------*/
2870 /*! copy any DataArray MetaData named 'name' from dest to src (replace old)
2871  *  (apply to list of DAs, or to all)
2872  *
2873  *  return 0 on success, 1 on failure to find, -1 on error
2874 *//*-------------------------------------------------------------------*/
gifti_copy_DA_meta_many(gifti_image * dest,gifti_image * src,const char * name,const int * dalist,int len)2875 int gifti_copy_DA_meta_many(gifti_image * dest, gifti_image * src,
2876                             const char * name, const int * dalist, int len)
2877 {
2878     int c, index, use_list, numDA, rv = 0;
2879 
2880     if( !dest || !dest->darray || !src || !src->darray || !name ) {
2881         if( G.verb > 1 ) fprintf(stderr,"** GCDAMM: bad params\n");
2882         return -1;
2883     }
2884 
2885     /* if they are not equal, it is probably a user mistake to be here */
2886     if( dest->numDA != src->numDA ) {
2887         if(G.verb>0) fprintf(stderr,"-- cannot copy DA meta, numDA %d != %d\n",
2888                              src->numDA, dest->numDA);
2889         return -1;
2890     }
2891 
2892     /* the empty case is probably not an error */
2893     if( dest->numDA <= 0 || src->numDA <= 0 ) {
2894         if( G.verb > 4 ) fprintf(stderr,"-- GCDAMM: numDA %d, %d\n",
2895                                  src->numDA, dest->numDA);
2896         return 0;
2897     }
2898 
2899     /* decide whether to use dalist or all DAs */
2900     use_list = gifti_valid_int_list(dalist, len, 0, src->numDA-1, G.verb);
2901 
2902     if( use_list && G.verb > 2 )
2903         fprintf(stderr,"++ copy_DA_meta_many, %s (list length %d)\n",
2904                 use_list ? "DA in list" : "all DAs", len);
2905 
2906     /* finally, get to work */
2907     numDA = use_list ? len : src->numDA;
2908     for( c = 0; c < numDA; c++ ) {
2909         index = use_list ? dalist[c] : c;  /* choose appropriate DA index */
2910 
2911         /* note any failures */
2912         rv |= gifti_copy_DA_meta(dest->darray[index], src->darray[index], name);
2913     }
2914 
2915     return rv;
2916 }
2917 
2918 /*---------------------------------------------------------------------*/
2919 /*! copy any DataArray MetaData named 'name' from dest to src (replace old)
2920  *
2921  *  return 0 on success, 1 on failure to find, -1 on error
2922 *//*-------------------------------------------------------------------*/
gifti_copy_DA_meta(giiDataArray * dest,giiDataArray * src,const char * name)2923 int gifti_copy_DA_meta(giiDataArray *dest, giiDataArray *src, const char *name)
2924 {
2925     char * value;
2926 
2927     if( !dest || !src || !name ) {
2928         if( G.verb > 0 )
2929             fprintf(stderr,"** copy_DA_meta: bad params(%p,%p,%p)\n",
2930                     (void *)dest, (void *)src, name);
2931         return -1;
2932     }
2933 
2934     value = gifti_get_meta_value(&src->meta, name);
2935     if( !value ) {
2936         if( G.verb > 4 )
2937             fprintf(stderr,"-- GCDAM: did not find meta name '%s'\n", name);
2938         return 1;
2939     }
2940 
2941     return gifti_add_to_meta(&dest->meta, name, value, 1);
2942 }
2943 
2944 /*---------------------------------------------------------------------*/
2945 /*! copy ALL DataArray MetaData from dest to src (replace old)
2946  *
2947  *  return 0 on success, 1 on failure to find, -1 on error
2948 *//*-------------------------------------------------------------------*/
gifti_copy_all_DA_meta(giiDataArray * dest,giiDataArray * src)2949 int gifti_copy_all_DA_meta(giiDataArray *dest, giiDataArray *src)
2950 {
2951     int c, rv = 0;
2952 
2953     if( !dest || !src ) {
2954         if( G.verb > 0 )
2955             fprintf(stderr,"** copy_all_DA_meta: bad params(%p,%p)\n",
2956                     (void *)dest, (void *)src);
2957         return -1;
2958     }
2959 
2960     for( c = 0; c < src->meta.length; c++ )
2961         rv |= gifti_copy_DA_meta(dest, src, src->meta.name[c]);
2962 
2963     return rv;
2964 }
2965 
2966 /*---------------------------------------------------------------------*/
2967 /*! find any differences between the two images
2968  *
2969  *  verb  0-3 = quiet, state diff, state per DA, state all diffs
2970  *
2971  *  return 0 if they are the same, 1 if they differ
2972 *//*-------------------------------------------------------------------*/
gifti_compare_gifti_images(const gifti_image * g1,const gifti_image * g2,int comp_data,int verb)2973 int gifti_compare_gifti_images(const gifti_image * g1, const gifti_image * g2,
2974                                int comp_data, int verb)
2975 {
2976     int diffs = 0, data_diffs = 0, gdiffs = 0, c, rv, numDA;
2977     int lverb = verb;           /* possibly override passed 'verb' */
2978 
2979     if( G.verb > lverb ) lverb = G.verb;
2980 
2981     if( !g1 || !g2 ) {
2982         if( !g1 && !g2 ) return 0;  /* both NULL means equal */
2983 
2984         if(lverb) printf("-- gifti_images differ (exactly one is NULL)\n");
2985         return 1;
2986     }
2987 
2988     /* check main structs */
2989     if( gifti_compare_gims_only(g1, g2, lverb) ) {
2990         if( lverb > 0 ) printf("++ gifti_images differ\n");
2991         if( lverb < 2 ) return 1;        /* all we need to know */
2992         gdiffs++;
2993     }
2994 
2995     /* get min numDA, just to be safe */
2996     numDA = g1->numDA < g2->numDA ? g1->numDA : g2->numDA;
2997     for( c = 0; c < numDA; c++ ) {
2998         rv = gifti_compare_DA_pair(g1->darray[c],g2->darray[c],comp_data,lverb);
2999         if( rv ) {
3000             diffs++;
3001             if( rv & 2 ) data_diffs++;
3002             if( lverb < 2 ) break;
3003             printf("++ DataArray[%d] - difference (data %s)\n",
3004                    c, ! comp_data  ? "untested" :
3005                         data_diffs ? "differs"  : "identical");
3006         }
3007     }
3008 
3009     if( diffs && lverb > 0 )
3010         printf("-- differences found in %d of %d DAs\n", diffs, numDA);
3011 
3012     /* state data diffs separately */
3013     if( lverb > 2 && comp_data ) {
3014         if( ! data_diffs ) printf("-- no data differences found\n");
3015         else printf("-- data differences found in %d of %d DAs\n",
3016                     data_diffs, numDA);
3017     }
3018 
3019     if( diffs || gdiffs ) return 1;
3020     return 0;
3021 }
3022 
3023 /*---------------------------------------------------------------------*/
3024 /*! find any differences between the two sets of image data
3025  *
3026  *  verb  0-2+ = quiet, state diff, state per DA
3027  *
3028  *  return 0 if they are the same, 1 if they differ
3029 *//*-------------------------------------------------------------------*/
gifti_compare_gifti_data(const gifti_image * g1,const gifti_image * g2,int verb)3030 int gifti_compare_gifti_data(const gifti_image * g1, const gifti_image * g2,
3031                              int verb)
3032 {
3033     int lverb = verb, c, diffs = 0, numDA;
3034 
3035     if( G.verb > lverb ) lverb = G.verb;
3036 
3037     if( !g1 || !g2 ) {
3038         if( !g1 && !g2 ) return 0;  /* both NULL means equal */
3039         if(lverb) printf("-- gim data difference (exactly one gim is NULL)\n");
3040         return 1;
3041     }
3042 
3043     /* if numDA does not match, they differ */
3044     if( g1->numDA != g2->numDA ) {
3045         if( lverb > 0 )
3046             printf("-- gim data differs: numDA differs, %d vs. %d\n",
3047                    g1->numDA, g2->numDA);
3048         if( lverb < 2 ) return 1;
3049     }
3050 
3051     /* even if they differ, we may want to continue, so use minimum */
3052     numDA = g1->numDA < g2->numDA ? g1->numDA : g2->numDA;
3053     for( c = 0; c < numDA; c++ ) {
3054         if( gifti_compare_DA_data(g1->darray[c],g2->darray[c],lverb) ) {
3055             diffs++;
3056             if( lverb > 0 ) printf("++ data difference at DataArray[%d]\n", c);
3057             if( lverb < 2 ) return 1;
3058         }
3059     }
3060 
3061     if( diffs ) {  /* verb must be 2, so print */
3062         printf("-- found data diffs in %d DataArrays\n", diffs);
3063         return 1;
3064     }
3065 
3066     if( G.verb > 1 ) fprintf(stderr,"-- no data diffs found\n");
3067 
3068     return 0;
3069 }
3070 
gifti_compare_DA_data(const giiDataArray * d1,const giiDataArray * d2,int verb)3071 int gifti_compare_DA_data(const giiDataArray * d1, const giiDataArray * d2,
3072                           int verb)
3073 {
3074     long long nbytes, offset;
3075 
3076     if( !d1 || !d2 ) {
3077         if( !d1 && !d2 ) return 0;  /* both NULL means equal */
3078         if(verb>1) printf("-- DA data difference (exactly one DA is NULL)\n");
3079         return 1;
3080     }
3081 
3082     if( ! gifti_valid_dims(d1,verb>1) || ! gifti_valid_dims(d2,verb>1) ) {
3083         if(verb>1) printf("-- DA data diff: dims are not valid\n");
3084         return 1;
3085     }
3086 
3087     nbytes = d1->nvals * d1->nbyper;
3088     if( nbytes != (d2->nvals * d2->nbyper) ) {
3089         if(verb>1) printf("-- DA data diff: nbytes differs, %lld vs. %lld\n",
3090                           nbytes, d2->nvals * d2->nbyper);
3091         return 1;
3092     }
3093 
3094     /* okay, let's test the data */
3095     offset = gifti_compare_raw_data(d1->data,d2->data,nbytes);
3096 
3097     if ( offset >= 0 ) {  /* difference in data */
3098         if(verb > 1) printf("-- diff in DA data at posn %lld\n",
3099                             offset/d1->nbyper);
3100         return 1;
3101     }
3102 
3103     return 0;
3104 }
3105 
3106 /* compare everything but darray
3107  * (for diffs, only print if verb > 1)
3108  */
gifti_compare_gims_only(const gifti_image * g1,const gifti_image * g2,int verb)3109 int gifti_compare_gims_only(const gifti_image * g1, const gifti_image * g2,
3110                             int verb)
3111 {
3112     int diffs = 0;
3113     int lverb = verb;           /* possibly override passed 'verb' */
3114 
3115     if( G.verb > lverb ) lverb = G.verb;
3116 
3117     if( !g1 || !g2 ) {
3118         if( !g1 && !g2 ) return 0;   /* equal */
3119         if( lverb > 1 )
3120             printf("-- comp gifti ims: have NULL %p, %p\n",(void*)g1,(void*)g2);
3121         return 1;   /* not equal */
3122     }
3123 
3124     if( g1->numDA != g2->numDA ) {
3125         diffs++;
3126         if( lverb > 1 )
3127             fprintf(stderr,"-- diff in GIFTI numDA: %d vs %d\n",
3128                            g1->numDA, g2->numDA);
3129         if( lverb <= 1 ) return 1;
3130     }
3131 
3132     if( !g1->version || !g2->version ) {  /* handle at least one NULL */
3133         if( g1->version || g2->version ) {
3134             diffs++;
3135             if( lverb > 1 )
3136                 fprintf(stderr,"-- diff in GIFTI version: one is NULL\n");
3137             if( lverb <= 1 ) return 1;
3138         }
3139         /* else both NULL, which means equal */
3140     } else if ( strcmp(g1->version, g2->version) ) {
3141         diffs++;
3142         if( lverb > 1 )
3143             fprintf(stderr,"-- diff in GIFTI version: %s vs. %s\n",
3144                     g1->version, g2->version);
3145         if( lverb <= 1 ) return 1;
3146     }
3147 
3148     if( gifti_compare_labeltable(&g1->labeltable, &g2->labeltable, verb) ) {
3149         diffs++;
3150         if( lverb > 1 ) printf("-- diff in gifti labeltable\n");
3151         if( lverb <= 1 ) return 1;
3152     }
3153 
3154     if( gifti_compare_nvpairs(&g1->meta, &g2->meta, verb) ) {
3155         diffs++;
3156         if( lverb > 1 ) printf("-- diff in gifti meta\n");
3157         if( lverb <= 1 ) return 1;
3158     }
3159 
3160 
3161     if( g1->swapped != g2->swapped ) {
3162         diffs++;
3163         if( lverb > 1 )
3164             fprintf(stderr,"-- difference in GIM->swapped: %d vs %d\n",
3165                            g1->swapped, g2->swapped);
3166         if( lverb <= 1 ) return 1;
3167     }
3168 
3169     if( g1->compressed != g2->compressed ) {
3170         diffs++;
3171         if( lverb > 1 )
3172             fprintf(stderr,"-- difference in GIM->compressed: %d vs %d\n",
3173                            g1->compressed, g2->compressed);
3174         if( lverb <= 1 ) return 1;
3175     }
3176 
3177     if( gifti_compare_nvpairs(&g1->ex_atrs, &g2->ex_atrs, verb) ) {
3178         diffs++;
3179         if( lverb > 1 ) printf("-- diff in gifti ex_atrs\n");
3180         if( lverb <= 1 ) return 1;
3181     }
3182 
3183     return diffs;
3184 }
3185 
3186 /*! return 0 if equal, 1 if diffs, 2 if data diffs (and 3 if both diffs) */
gifti_compare_DA_pair(const giiDataArray * d1,const giiDataArray * d2,int comp_data,int verb)3187 int gifti_compare_DA_pair(const giiDataArray * d1, const giiDataArray * d2,
3188                           int comp_data, int verb)
3189 {
3190     long long offset;
3191     int       c, top, diffs = 0, data_diffs = 0;
3192     int       lverb = verb;           /* possibly override passed 'verb' */
3193 
3194     if( G.verb > lverb ) lverb = G.verb;
3195 
3196     if( !d1 || !d2 ) {
3197         if( !d1 && !d2 ) return 0;   /* equal */
3198         if(lverb>2)
3199             printf("-- comp DA: have NULL: %p, %p\n", (void*)d1,(void*)d2);
3200         return 3;   /* not equal */
3201     }
3202 
3203     if( d1->intent != d2->intent ) {
3204         diffs = 1;
3205         if( lverb > 1 )
3206             printf("-- diff in DA intent: %d (%s) vs. %d (%s)\n",
3207                    d1->intent, gifti_intent_to_string(d1->intent),
3208                    d2->intent, gifti_intent_to_string(d2->intent));
3209         if( lverb < 3 ) return 1;
3210     }
3211 
3212     if( d1->datatype != d2->datatype ) {
3213         diffs = 1;
3214         if( lverb > 1 )
3215             printf("-- diff in DA datatype: %d (%s) vs. %d (%s)\n",
3216                    d1->datatype, gifti_datatype2str(d1->datatype),
3217                    d2->datatype, gifti_datatype2str(d2->datatype));
3218         if( lverb < 3 ) return 1;
3219     }
3220 
3221     if( d1->ind_ord != d2->ind_ord ) {
3222         diffs = 1;
3223         if( lverb > 1 )
3224             printf("-- diff in DA ind_ord: %d (%s) vs. %d (%s)\n",
3225                d1->ind_ord,
3226                gifti_list_index2string(gifti_index_order_list, d1->ind_ord),
3227                d2->ind_ord,
3228                gifti_list_index2string(gifti_index_order_list, d2->ind_ord));
3229         if( lverb < 3 ) return 1;
3230     }
3231 
3232     if( d1->num_dim != d2->num_dim ) {
3233         diffs = 1;
3234         data_diffs = 1;
3235         if( lverb > 1 )
3236             printf("-- diff in DA num_dim: %d vs. %d\n",
3237                    d1->num_dim, d2->num_dim );
3238         if( lverb < 3 ) return 3;
3239     }
3240 
3241     /* get minimum num_dim */
3242     top = d1->num_dim < d2->num_dim ? d1->num_dim : d2->num_dim;
3243     for( c = 0; c < top; c++ ) if( d1->dims[c] != d2->dims[c] ) break;
3244     if( c < top ) {
3245         diffs = 1;
3246         data_diffs = 1;
3247         if( lverb > 1 ) {
3248             printf("-- diff in DA dims (length %d)\n   ", top);
3249             gifti_disp_raw_data(d1->dims, NIFTI_TYPE_INT32, top, 0, stdout);
3250             printf("  vs  ");
3251             gifti_disp_raw_data(d2->dims, NIFTI_TYPE_INT32, top, 1, stdout);
3252         }
3253         if( lverb < 3 ) return 3;
3254     }
3255 
3256     if( d1->encoding != d2->encoding ) {
3257         diffs = 1;
3258         if( lverb > 1 )
3259             printf("-- diff in DA encoding: %d (%s) vs. %d (%s)\n",
3260                d1->encoding,
3261                gifti_list_index2string(gifti_encoding_list, d1->encoding),
3262                d2->encoding,
3263                gifti_list_index2string(gifti_encoding_list, d2->encoding));
3264         if( lverb < 3 ) return 1;
3265     }
3266 
3267     if( d1->endian != d2->endian ) {
3268         diffs = 1;
3269         if( lverb > 1 )
3270             printf("-- diff in DA endian: %d (%s) vs. %d (%s)\n",
3271                d1->endian,
3272                gifti_list_index2string(gifti_endian_list, d1->endian),
3273                d2->endian,
3274                gifti_list_index2string(gifti_endian_list, d2->endian));
3275         if( lverb < 3 ) return 1;
3276     }
3277 
3278     if( d1->ext_fname || d2->ext_fname ) {
3279         if( ! d1->ext_fname || !d2->ext_fname ||
3280               strcmp(d1->ext_fname, d2->ext_fname) ) {
3281             diffs = 1;
3282             if( lverb > 1 )
3283                 printf("-- diff in DA ext_fname: %s vs. %s\n",
3284                    G_CHECK_NULL_STR(d1->ext_fname),
3285                    G_CHECK_NULL_STR(d2->ext_fname));
3286             if( lverb < 3 ) return 1;
3287         }
3288     }
3289 
3290     if( d1->ext_offset != d2->ext_offset ) {
3291         diffs = 1;
3292         if( lverb > 1 )
3293             printf("-- diff in DA ext_offset: %lld vs. %lld\n",
3294                d1->ext_offset, d2->ext_offset);
3295         if( lverb < 3 ) return 1;
3296     }
3297 
3298     if( gifti_compare_nvpairs(&d1->meta, &d2->meta, verb) ) {
3299         diffs = 1;
3300         if( lverb > 1 ) printf("-- diff in DA meta\n");
3301         if( lverb < 3 ) return 1;
3302     }
3303 
3304     if( d1->numCS != d2->numCS ) {
3305         diffs = 1;
3306         if( lverb > 1 ) printf("-- diff in DA numCS\n");
3307         if( lverb < 3 ) return 1;
3308     }
3309 
3310     /* compare each of the CoordSystem structs */
3311     top = d1->numCS < d2->numCS ? d1->numCS : d2->numCS;
3312     for( c = 0; c < top; c++ )
3313         if( gifti_compare_coordsys(d1->coordsys[c], d2->coordsys[c],1,verb) ) {
3314             diffs = 1;
3315             if( lverb > 1 ) printf("-- diff in DA coordsys[%d]\n", c);
3316             if( lverb < 3 ) return 1;
3317         }
3318 
3319     if( d1->nvals != d2->nvals ) {
3320         diffs = 1;
3321         data_diffs = 1;
3322         if( lverb > 1 )
3323             printf("-- diff in DA nvals: %lld vs. %lld\n",
3324                d1->nvals, d2->nvals);
3325         if( lverb < 3 ) return 3;
3326     }
3327 
3328     if( d1->nbyper != d2->nbyper ) {
3329         diffs = 1;
3330         data_diffs = 1;
3331         if( lverb > 1 )
3332             printf("-- diff in DA nbyper: %d vs. %d\n", d1->nbyper, d2->nbyper);
3333         if( lverb < 3 ) return 3;
3334     }
3335 
3336     if( gifti_compare_nvpairs(&d1->ex_atrs, &d2->ex_atrs, verb) ) {
3337         diffs = 1;
3338         if( lverb > 1 ) printf("-- diff in DA ex_atrs\n");
3339         if( lverb < 3 ) return 1;
3340     }
3341 
3342     /* check data last, and only if no data diffs and dims are valid */
3343     /* (set the 2^1 bit for a data diff)                             */
3344     if( comp_data && !data_diffs && gifti_valid_dims(d1, 0) ) {
3345         offset = gifti_compare_raw_data(d1->data,d2->data,d1->nvals*d1->nbyper);
3346         if ( offset >= 0 ) {
3347             diffs |= 2;
3348             if(lverb>1) printf("-- diff in DA data at position %lld\n",
3349                                offset/d1->nbyper);
3350             if(lverb<3) return 3;
3351         }
3352     }
3353 
3354     return diffs;
3355 }
3356 
3357 /*---------------------------------------------------------------------*/
3358 /*! return 1 if gifti_images are approximately equal (from a data standpoint)
3359  *           note: return value is opposite from gifti_compare_gifti_images
3360  *
3361  *  verb  0-3 = quiet, state diff, state per DA, state all diffs
3362  *
3363  *  compare information close to the data:
3364  *      - numDA
3365  *      - labeltable
3366  *      - darray elements (pairwise)
3367  *  ignore version, meta, swapped, encoding, endian, ext_*, ex_atrs, etc.
3368  *
3369  *  return 1 if they are approximately the same, 0 if otherwise
3370 *//*-------------------------------------------------------------------*/
gifti_approx_gifti_images(const gifti_image * g1,const gifti_image * g2,int comp_data,int verb)3371 int gifti_approx_gifti_images(const gifti_image * g1, const gifti_image * g2,
3372                               int comp_data, int verb)
3373 {
3374     int diffs = 0, c, numDA;
3375     int lverb = verb;           /* possibly override passed 'verb' */
3376 
3377     if( G.verb > lverb ) lverb = G.verb;
3378 
3379     if( !g1 || !g2 ) {
3380         if( !g1 && !g2 ) return 1;  /* both NULL means equal */
3381 
3382         if(lverb) printf("-- gifti_images not approx (exactly one is NULL)\n");
3383         return 0;
3384     }
3385 
3386     if( g1->numDA != g2->numDA ) {
3387         if( lverb ) printf("-- gifti_images differ in numDA\n");
3388         if( lverb < 2 ) return 0;
3389         diffs++;
3390     }
3391 
3392     if( ! gifti_approx_labeltables(&g1->labeltable, &g2->labeltable, lverb) ) {
3393         if( lverb ) printf("-- gifti labeltables not approx. equal\n");
3394         if( lverb < 2 ) return 0;
3395         diffs++;
3396     }
3397 
3398     /* get min numDA, just to be safe */
3399     numDA = g1->numDA < g2->numDA ? g1->numDA : g2->numDA;
3400     for( c = 0; c < numDA; c++ ) {
3401         if( !gifti_approx_DA_pair(g1->darray[c],g2->darray[c],comp_data,lverb)){
3402             diffs++;
3403             if(lverb) printf("++ DataArrays[%d] - not approximately equal\n",c);
3404             if( lverb < 2 ) break;
3405         }
3406     }
3407 
3408     if( diffs && lverb > 0 ) printf("-- GIFTI: approx diffs found\n");
3409 
3410     return ! diffs;
3411 }
3412 
3413 /* ------------------------------------------------------------------------- */
3414 /*! return 1 if DAs are approximately equal (opposite of compare functions)
3415  *
3416  * test for difference in:
3417  *
3418  *      transformation matrices : 16 values each (approx)
3419  *      coordinates             : 3 values per node (approx)
3420  *      triangles               : exact (starting node can be any of the 3)
3421  *      data                    : approx
3422  *
3423  * lverb = 0    : no print (no print anywhere)
3424  *         1    : no print (print at higher level)
3425  *         2    : print DA level diff
3426  *         3    : print all diffs
3427  *
3428  */
gifti_approx_DA_pair(const giiDataArray * d1,const giiDataArray * d2,int comp_data,int verb)3429 int gifti_approx_DA_pair(const giiDataArray * d1, const giiDataArray * d2,
3430                           int comp_data, int verb)
3431 {
3432     int c, top, can_comp, offset, diffs = 0;
3433     int lverb = verb;           /* possibly override passed 'verb' */
3434 
3435     if( G.verb > lverb ) lverb = G.verb;
3436 
3437     /* deal with any NULLs for starter */
3438     if( !d1 && !d2 ) {
3439         if(lverb>2) printf("-- approx DA: have NULL\n");
3440         return 1;       /* yes, these are equal */
3441     } else if( !d1 || !d2 ) {
3442         if(lverb>2) printf("-- approx DA: have one NULL\n");
3443         return 0;       /* not approximately equal */
3444     }
3445 
3446     /* do early, to put higher level whining first */
3447     can_comp = can_compare_DA_data(d1, d2, verb);
3448 
3449     if( d1->numCS != d2->numCS ) {
3450         diffs = 1;
3451         if( lverb > 1 ) printf("-- approx DA: diff in numCS\n");
3452         if( lverb < 3 ) return 0;
3453     }
3454 
3455     /* compare each of the CoordSystem structs */
3456     top = d1->numCS < d2->numCS ? d1->numCS : d2->numCS;
3457     for( c = 0; c < top; c++ ) {
3458         /* first compare without checking the data */
3459         if( gifti_compare_coordsys(d1->coordsys[c], d2->coordsys[c],1,verb) ) {
3460             diffs = 1;
3461             if( lverb > 1 ) printf("-- diff in DA coordsys[%d]\n", c);
3462             if( lverb < 3 ) return 0;
3463         }
3464     }
3465 
3466     /* if we cannot or do not want to compare the data, return */
3467     if( ! comp_data || ! can_comp ) return !diffs;
3468 
3469     /* if data is coordinates, compare percent diff
3470      * if trianges, compare exactly, but with any starting index
3471      * else, compare percent diff */
3472     if( d1->intent == d2->intent && d1->intent==NIFTI_INTENT_TRIANGLE ) {
3473         /* verify that these look like triangles */
3474         if( d1->num_dim < 2 || d1->dims[1] != 3 ) {
3475             if( lverb > 1 ) printf("-- approx DA: bad dims for TRIANGLEs: "
3476                        "num_dim=%d, dims[1]=%d\n", d1->num_dim, d1->dims[1]);
3477             return 0;
3478         }
3479 
3480         offset = gifti_triangle_diff_offset(d1->data, d2->data, d1->dims[0],
3481                                             d1->datatype);
3482         if( offset >= 0 ) {
3483             diffs |= 2;
3484             if(lverb > 1) printf("-- approx DA: triange diff at offset %d\n",
3485                                  offset);
3486             if(lverb < 3) return 0;
3487         }
3488     } else {
3489         offset = gifti_approx_diff_offset(d1->data, d2->data, d1->nvals,
3490                                           d1->datatype, 1.0);
3491         if( offset >= 0 ) {
3492             diffs |= 2;
3493             if(lverb>1) printf("-- approx DA: data diff at offset %d\n",offset);
3494             if(lverb<3) return 0;
3495         }
3496     }
3497 
3498     return !diffs;
3499 }
3500 
3501 
3502 /* return whether the DA elements match so as to compare the data
3503  *
3504  * apply the same verb as above
3505  */
can_compare_DA_data(const giiDataArray * d1,const giiDataArray * d2,int verb)3506 static int can_compare_DA_data(const giiDataArray *d1,const giiDataArray *d2,
3507                                int verb)
3508 {
3509     int c, top, rv = 1;
3510     int lverb = verb;   /* possibly override passed 'verb' */
3511 
3512     if( G.verb > lverb ) lverb = G.verb;
3513 
3514     if( !d1 || !d2 ) {
3515         if(lverb>1) printf("-- comp DAs: have NULL DA(s) (%p, %p)\n",
3516                            (void*)d1,(void*)d2);
3517         return 0;   /* not equal */
3518     }
3519 
3520     if( d1->datatype != d2->datatype ) {
3521         rv = 0;
3522         if( lverb > 1 )
3523             printf("-- comp DAs: DA datatype diff: %d (%s) vs. %d (%s)\n",
3524                    d1->datatype, gifti_datatype2str(d1->datatype),
3525                    d2->datatype, gifti_datatype2str(d2->datatype));
3526         if( lverb < 3 ) return 0;
3527     }
3528 
3529     if( d1->ind_ord != d2->ind_ord ) {
3530         rv = 0;
3531         if( lverb > 1 )
3532             printf("-- comp DAs: ind_ord diff: %d (%s) vs. %d (%s)\n",
3533                d1->ind_ord,
3534                gifti_list_index2string(gifti_index_order_list, d1->ind_ord),
3535                d2->ind_ord,
3536                gifti_list_index2string(gifti_index_order_list, d2->ind_ord));
3537         if( lverb < 3 ) return 0;
3538     }
3539 
3540     if( d1->num_dim != d2->num_dim ) {
3541         rv = 0;
3542         if( lverb > 1 ) printf("-- comp DAs: num_dim diff: %d vs. %d\n",
3543                                d1->num_dim, d2->num_dim );
3544         if( lverb < 3 ) return 0;
3545     }
3546 
3547     /* get minimum num_dim */
3548     top = d1->num_dim < d2->num_dim ? d1->num_dim : d2->num_dim;
3549     for( c = 0; c < top; c++ ) if( d1->dims[c] != d2->dims[c] ) break;
3550     if( c < top ) {
3551         rv = 0;
3552         if( lverb > 1 ) {
3553             printf("-- comp DAs: DA dims diff (length %d)\n   ", top);
3554             gifti_disp_raw_data(d1->dims, NIFTI_TYPE_INT32, top, 0, stdout);
3555             printf("  vs  ");
3556             gifti_disp_raw_data(d2->dims, NIFTI_TYPE_INT32, top, 1, stdout);
3557         }
3558         if( lverb < 3 ) return 0;
3559     }
3560 
3561     if( d1->nvals != d2->nvals ) {
3562         rv = 0;
3563         if( lverb > 1 ) printf("-- comp DAs: nvals diff: %lld vs. %lld\n",
3564                                d1->nvals, d2->nvals);
3565         if( lverb < 3 ) return 0;
3566     }
3567 
3568     if( d1->nbyper != d2->nbyper ) {
3569         rv = 0;
3570         if( lverb > 1 ) printf("-- comp DAs: nbyper diff: %d vs. %d\n",
3571                                d1->nbyper, d2->nbyper);
3572         if( lverb < 3 ) return 0;
3573     }
3574 
3575     /* as a last test, make sure dims are valid, not just the same */
3576     if( ! gifti_valid_dims(d1, 0) ) {
3577         rv = 0;
3578         if( lverb > 1 ) printf("-- comp DAs: dims not valid\n");
3579     }
3580 
3581     return rv;
3582 }
3583 
3584 /*---------------------------------------------------------------------*/
3585 /*! check pointers, compare lengths, then check the Names in each list,
3586  *  and see if there is a matching Name=Value pari
3587  *
3588  *  only state diffs in the verb=3 case
3589 *//*-------------------------------------------------------------------*/
gifti_compare_nvpairs(const nvpairs * p1,const nvpairs * p2,int verb)3590 int gifti_compare_nvpairs(const nvpairs * p1, const nvpairs * p2, int verb)
3591 {
3592     char * value;
3593     int    lverb = verb;        /* possibly override passed verb */
3594     int    c, diffs = 0;
3595 
3596     if( G.verb > lverb ) lverb = G.verb;
3597 
3598     if( !p1 || !p2 ) {
3599         if(!p1 && !p2) return 0;   /* equal */
3600         if(lverb>2)
3601             printf("-- comp nvpairs: have NULL: %p, %p\n",(void*)p1,(void*)p2);
3602         return 1;   /* not equal */
3603     }
3604 
3605     /* they must be valid to proceed */
3606     if( ! gifti_valid_nvpairs(p1, 0) || ! gifti_valid_nvpairs(p2, 0) ) {
3607         if( lverb > 2 ) printf("-- cannot compare invalid nvpairs\n");
3608         return 1;
3609     }
3610 
3611     if( p1->length != p2->length ) {
3612         if( lverb > 2 ) printf("-- nvp list lengths differ: %d vs %d\n",
3613                                p1->length, p2->length);
3614         if( lverb < 3 ) return 1;
3615     }
3616 
3617     /* search for mis-matches or non-existence from list 1 into list 2  */
3618     /* assume Names are unique (each that is not will show a mis-match) */
3619     for( c = 0; c < p1->length; c++ ) {
3620         if( ! p1->value[c] ) continue;  /* skip anything that doesn't exist */
3621         value = gifti_get_meta_value(p2, p1->name[c]);
3622         if( !value ) {
3623             if( lverb > 2 )
3624                 printf("-- nvp list 2 missing Name: '%s'\n",p1->name[c]);
3625             diffs++;
3626         }
3627         else if( strcmp(value, p1->value[c]) ) {
3628             if( lverb > 2 )
3629                 printf("-- nvp diff for Name '%s':\n   '%s' vs. '%s'\n",
3630                        p1->name[c], p1->value[c], value);
3631             diffs++;
3632         }
3633         if( diffs && lverb < 3 ) return 1;
3634     }
3635 
3636     /* now just search for non-existence (mis-matches have been found) */
3637     for( c = 0; c < p2->length; c++ ) {
3638         if( ! p2->value[c] ) continue;  /* skip anything that doesn't exist */
3639         value = gifti_get_meta_value(p1, p2->name[c]);
3640         if( !value ) {
3641             if( lverb > 2 )
3642                 printf("-- nvp list 1 missing Name: '%s'\n",p2->name[c]);
3643             if( lverb < 3 ) return 1;
3644             diffs++;
3645         }
3646     }
3647 
3648     return diffs;
3649 }
3650 
3651 /*---------------------------------------------------------------------*/
3652 /*! check pointers, lengths and contents
3653  *
3654  *  return 0 if equal
3655  *
3656  *  only state diffs in the verb=3 case
3657 *//*-------------------------------------------------------------------*/
gifti_compare_labeltable(const giiLabelTable * t1,const giiLabelTable * t2,int verb)3658 int gifti_compare_labeltable(const giiLabelTable *t1, const giiLabelTable *t2,
3659                              int verb)
3660 {
3661     return compare_labeltables(t1, t2, verb, 0);
3662 }
3663 
3664 /*---------------------------------------------------------------------*/
3665 /*! return 1 if tables are approximately equal (opposite of compare function)
3666  *
3667  *  RGBA data is compared approximately
3668  *
3669  *  only state diffs in the verb=3 case
3670 *//*-------------------------------------------------------------------*/
gifti_approx_labeltables(const giiLabelTable * t1,const giiLabelTable * t2,int verb)3671 int gifti_approx_labeltables(const giiLabelTable *t1, const giiLabelTable *t2,
3672                              int verb)
3673 {
3674     return( ! compare_labeltables(t1, t2, verb, 1));
3675 }
3676 
3677 /*---------------------------------------------------------------------*/
3678 /*! check pointers, lengths and contents
3679  *
3680  *  only state diffs in the verb=3 case
3681  *
3682  *  if approx, compare RBGA approximately
3683 *//*-------------------------------------------------------------------*/
compare_labeltables(const giiLabelTable * t1,const giiLabelTable * t2,int verb,int approx)3684 static int compare_labeltables(const giiLabelTable *t1, const giiLabelTable *t2,
3685                                int verb, int approx)
3686 {
3687     int lverb = verb;        /* possibly override passed verb */
3688     int c, offset, diffs = 0;
3689 
3690     if( G.verb > lverb ) lverb = G.verb;
3691 
3692     if( !t1 || !t2 ) {
3693         if(!t1 && !t2) return 0;   /* equal */
3694         if(lverb>2)
3695             printf("-- Comp LabTab: have NULL: %p, %p\n",(void*)t1,(void*)t2);
3696         return 1;   /* not   */
3697     }
3698 
3699     /* if empty, return 0 */
3700     if( t1->length <= 0 && t2->length <= 0 ) return 0;
3701 
3702     if( t1->length != t2->length ) {
3703         if(lverb>2)printf("-- labeltable lengths diff: %d vs. %d\n",
3704                           t1->length, t2->length);
3705         return 1;  /* cannot compare without equal lengths */
3706     }
3707 
3708     /* exactly 1 RGBA list is a difference */
3709     if( (t1->rgba && !t2->rgba) || (!t1->rgba && t2->rgba) ) {
3710         if(lverb>2)printf("-- only 1 labeltable has RGBA list\n");
3711         if(lverb<3) return 1;
3712     }
3713 
3714     /* so lengths are positive and equal, compare index list and labels */
3715 
3716     /* set limit to 0.0 to compare indicies exactly */
3717     offset = (int)gifti_approx_diff_offset(t1->key, t2->key,
3718                        t1->length, NIFTI_TYPE_INT32, approx?1.0:0.0);
3719     if( offset >= 0 ) {
3720         if(lverb>2)printf("-- labeltable Key diff at index %d\n", offset);
3721         if(lverb<3) return 1;
3722         diffs++;
3723     }
3724 
3725     /* walk through list to compare labels */
3726     for( c = 0; c < t1->length; c++ ) {
3727         if( gifti_strdiff(t1->label[c], t2->label[c]) ) {
3728             if(lverb>2)printf("-- labeltable Label diff at index %d\n", c);
3729             if(lverb<3) return 1;
3730             diffs++;
3731             break;      /* stop at first difference */
3732         }
3733     }
3734 
3735     if( t1->rgba && t2->rgba ) {
3736         /* if not approx, set limit to 0.0 to compare exactly */
3737         offset = (int)gifti_approx_diff_offset(t1->rgba, t2->rgba,
3738                            4*t1->length, NIFTI_TYPE_FLOAT32, approx?1.0:0.0);
3739         if( offset >= 0 ) {
3740             offset /= 4;  /* convert from float index to RGBA index */
3741             if(lverb>2)printf("-- labeltable RGBA diff at index %d\n", offset);
3742             if(lverb<3) return 1;
3743             diffs++;
3744         }
3745     }
3746 
3747     return diffs;
3748 }
3749 
3750 /*---------------------------------------------------------------------*/
3751 /*! like strcmp, but also return:
3752  *      0: if both pointers are NULL
3753  *      1: if exactly one is NULL
3754 *//*-------------------------------------------------------------------*/
gifti_strdiff(const char * s1,const char * s2)3755 int gifti_strdiff(const char * s1, const char * s2)
3756 {
3757     if( !s1 || !s2 ) {
3758         if( s1 || s2 ) return 1;        /* one NULL means different */
3759         else           return 0;        /* both NULL mean equal */
3760     }
3761 
3762     return strcmp(s1,s2);       /* fall through to normal case */
3763 }
3764 
3765 /*---------------------------------------------------------------------*/
3766 /*! check pointers, compare names and xforms
3767  *
3768  *  only state diffs in the verb=3 case
3769 *//*-------------------------------------------------------------------*/
gifti_compare_coordsys(const giiCoordSystem * s1,const giiCoordSystem * s2,int comp_data,int verb)3770 int gifti_compare_coordsys(const giiCoordSystem *s1, const giiCoordSystem *s2,
3771                            int comp_data, int verb)
3772 {
3773     long long offset;
3774     int       lverb = verb;        /* possibly override passed verb */
3775     int       diffs = 0;
3776 
3777     if( G.verb > lverb ) lverb = G.verb;
3778 
3779     if( !s1 || !s2 ) {
3780         if(!s1 && !s2) return 0;   /* equal */
3781         if(lverb>2)
3782             printf("-- Comp CoordSys: have NULL: %p, %p\n",(void*)s1,(void*)s2);
3783         return 1;
3784     }
3785 
3786     if( !s1->dataspace || !s2->dataspace ) {
3787         if( s1->dataspace || s2->dataspace ) {
3788             if(lverb>2)printf("-- coordsys dspace diff: exactly one is NULL\n");
3789             if(lverb<3) return 1;
3790             diffs++;
3791         }
3792     } else if( strcmp(s1->dataspace, s2->dataspace) ) {
3793         if(lverb>2) printf("-- coordsys dspace diff: %s vs. %s\n",
3794                            s1->dataspace, s2->dataspace);
3795         if( lverb < 3 ) return 1;
3796         diffs++;
3797     }
3798 
3799     if( !s1->xformspace || !s2->xformspace ) {
3800         if( s1->xformspace || s2->xformspace ) {
3801             if(lverb>2)
3802                 printf("-- coordsys xformspace diff: exactly one is NULL\n");
3803             if(lverb<3) return 1;
3804             diffs++;
3805         }
3806     } else if( strcmp(s1->xformspace, s2->xformspace) ) {
3807         if(lverb>2) printf("-- coordsys xformspace diff: %s vs. %s\n",
3808                            s1->xformspace, s2->xformspace);
3809         if( lverb < 3 ) return 1;
3810         diffs++;
3811     }
3812 
3813     if( ! comp_data ) return diffs;     /* maybe we are done */
3814 
3815     offset = gifti_compare_raw_data(s1->xform, s2->xform, sizeof(s1->xform));
3816     if( offset >= 0 ) {
3817         /* convert to index (to avoid printf warning)  2 Mar 2010 */
3818         offset /= (long long)sizeof(double);
3819         if(lverb>2) printf("-- coordsys xform diff at offset %lld\n", offset);
3820         if( lverb < 3 ) return 1;
3821         diffs++;
3822     }
3823 
3824     return diffs;
3825 }
3826 
3827 /*---------------------------------------------------------------------*/
3828 /*! compare raw data, returing the first location difference
3829  *
3830  * return byte position of difference, so that < 0 means no difference
3831 *//*-------------------------------------------------------------------*/
gifti_compare_raw_data(const void * p1,const void * p2,long long length)3832 long long gifti_compare_raw_data(const void * p1, const void * p2,
3833                                  long long length)
3834 {
3835     long long   posn;
3836     char      * d1 = (char *)p1, * d2 = (char *)p2;
3837 
3838     if( !p1 || !p2 ) {
3839         if( !p1 && !p2 ) return -1; /* both NULL -> same */
3840         if( G.verb > 3 ) fprintf(stderr,"-- raw_data pointer diff\n");
3841         return 0;  /* set difference */
3842     }
3843 
3844     /* scan data until done or a difference is found */
3845     for( d1 = (char *)p1, d2 = (char *)p2, posn = 0;
3846          posn < length && *d1 == *d2;
3847          posn++, d1++, d2++ )
3848         ;
3849 
3850     if( posn < length ) return posn;    /* differ at posn */
3851 
3852     return -1;  /* equal */
3853 }
3854 
3855 
3856 /* make a local definition for this symmetric fractional difference */
3857 #undef GIFTI_SFD
3858 #define GIFTI_SFD(a,b) (fabs((double)(a)-(double)(b)) \
3859                              / (fabs((double)(a))+fabs((double)(b))))
3860 
3861 /*---------------------------------------------------------------------*/
3862 /*! approximate comparison of raw data, returing the first location difference
3863  *  (>= 0 means difference, -1 means "approximately equal")
3864  *
3865  * Compute a symmetric fractional difference:
3866  *
3867  *      SFD = abs(a-b)/(abs(a)+abs(b))
3868  *
3869  * length       - number of contiguous elements to test
3870  * ni_type      - NIFTI_TYPE_*, denoting the type of data to compare
3871  * limit        - maximum SFD to be considered approximately equal
3872  *
3873  *              * if limit = 0.0, check is faster
3874  *
3875  *              * if limit >= 1.0, apply a default requiring almost all
3876  *                significant bits
3877  *
3878  *              * for integers, all bits are considered significant
3879  *              * for real numbers, mantissa bits are considered significant
3880  *
3881  * return offset index, so that < 0 (-1)  means no difference
3882  *
3883  * (return -1 if the pointers differ in whether they are set)
3884 *//*-------------------------------------------------------------------*/
gifti_approx_diff_offset(const void * p1,const void * p2,long long length,int ni_type,double limit)3885 long long gifti_approx_diff_offset(const void * p1, const void * p2,
3886                                    long long length, int ni_type, double limit)
3887 {
3888     long long posn;
3889     double    llim = limit; /* local limit (passed limit or default) */
3890 
3891     if( !p1 || !p2 ) {
3892         if( !p1 && !p2 ) return -1; /* same */
3893         return 0;                   /* different */
3894     }
3895 
3896     switch( ni_type ) {
3897         default:
3898             fprintf(stderr,"** cannot test approx data with type %d (%s)\n",
3899                     ni_type, nifti_datatype_to_string(ni_type));
3900             return 0;
3901 
3902         case NIFTI_TYPE_INT8: {
3903             char * d1 = (char *)p1, * d2 = (char *)p2;
3904             if( llim >= 1.0 ) llim = 0.0;       /* require equality for ints */
3905             for( posn = 0; posn < length; posn++, d1++, d2++ ) {
3906                 if( *d1 == *d2 ) continue;      /* fast check for equality */
3907                 if( llim == 0.0 ) break;        /* fast check for inequality */
3908                 if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */
3909             }
3910             break;
3911         }
3912         case NIFTI_TYPE_INT16: {
3913             short * d1 = (short *)p1, * d2 = (short *)p2;
3914             if( llim >= 1.0 ) llim = 0.0;       /* require equality for ints */
3915             for( posn = 0; posn < length; posn++, d1++, d2++ ) {
3916                 if( *d1 == *d2 ) continue;      /* fast check for equality */
3917                 if( llim == 0.0 ) break;        /* fast check for inequality */
3918                 if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */
3919             }
3920             break;
3921         }
3922         case NIFTI_TYPE_INT32: {
3923             int * d1 = (int *)p1, * d2 = (int *)p2;
3924             if( llim >= 1.0 ) llim = 0.0;       /* require equality for ints */
3925             for( posn = 0; posn < length; posn++, d1++, d2++ ) {
3926                 if( *d1 == *d2 ) continue;      /* fast check for equality */
3927                 if( llim == 0.0 ) break;        /* fast check for inequality */
3928                 if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */
3929             }
3930             break;
3931         }
3932         case NIFTI_TYPE_INT64: {
3933             long long * d1 = (long long *)p1, * d2 = (long long *)p2;
3934             if( llim >= 1.0 ) llim = 0.0;       /* require equality for ints */
3935             for( posn = 0; posn < length; posn++, d1++, d2++ ) {
3936                 if( *d1 == *d2 ) continue;      /* fast check for equality */
3937                 if( llim == 0.0 ) break;        /* fast check for inequality */
3938                 if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */
3939             }
3940             break;
3941         }
3942         case NIFTI_TYPE_UINT8: {
3943             unsigned char *d1 = (unsigned char *)p1, *d2 = (unsigned char *)p2;
3944             if( llim >= 1.0 ) llim = 0.0;       /* require equality for ints */
3945             for( posn = 0; posn < length; posn++, d1++, d2++ ) {
3946                 if( *d1 == *d2 ) continue;      /* fast check for equality */
3947                 if( llim == 0.0 ) break;        /* fast check for inequality */
3948                 if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */
3949             }
3950             break;
3951         }
3952         case NIFTI_TYPE_UINT16: {
3953             unsigned short *d1=(unsigned short *)p1, *d2=(unsigned short *)p2;
3954             if( llim >= 1.0 ) llim = 0.0;       /* require equality for ints */
3955             for( posn = 0; posn < length; posn++, d1++, d2++ ) {
3956                 if( *d1 == *d2 ) continue;      /* fast check for equality */
3957                 if( llim == 0.0 ) break;        /* fast check for inequality */
3958                 if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */
3959             }
3960             break;
3961         }
3962         case NIFTI_TYPE_UINT32: {
3963             unsigned int * d1 = (unsigned int *)p1, * d2 = (unsigned int *)p2;
3964             if( llim >= 1.0 ) llim = 0.0;       /* require equality for ints */
3965             for( posn = 0; posn < length; posn++, d1++, d2++ ) {
3966                 if( *d1 == *d2 ) continue;      /* fast check for equality */
3967                 if( llim == 0.0 ) break;        /* fast check for inequality */
3968                 if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */
3969             }
3970             break;
3971         }
3972         case NIFTI_TYPE_UINT64: {
3973             unsigned long long * d1 = (unsigned long long *)p1;
3974             unsigned long long * d2 = (unsigned long long *)p2;
3975             if( llim >= 1.0 ) llim = 0.0;       /* require equality for ints */
3976             for( posn = 0; posn < length; posn++, d1++, d2++ ) {
3977                 if( *d1 == *d2 ) continue;      /* fast check for equality */
3978                 if( llim == 0.0 ) break;        /* fast check for inequality */
3979                 if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */
3980             }
3981             break;
3982         }
3983         case NIFTI_TYPE_FLOAT32: {
3984             float * d1 = (float *)p1, * d2 = (float *)p2;
3985             if( llim >= 1.0 ) llim = 1e-5;
3986             for( posn = 0; posn < length; posn++, d1++, d2++ ) {
3987                 if( *d1 == *d2 ) continue;      /* fast check for equality */
3988                 if( llim == 0.0 ) break;        /* fast check for inequality */
3989                 if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */
3990             }
3991             break;
3992         }
3993         case NIFTI_TYPE_FLOAT64: {
3994             double * d1 = (double *)p1, * d2 = (double *)p2;
3995             if( llim >= 1.0 ) llim = 1e-12;
3996             for( posn = 0; posn < length; posn++, d1++, d2++ ) {
3997                 if( *d1 == *d2 ) continue;      /* fast check for equality */
3998                 if( llim == 0.0 ) break;        /* fast check for inequality */
3999                 if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */
4000             }
4001             break;
4002         }
4003     }
4004 
4005     if( posn < length ) return posn;    /* differ at 1-based posn */
4006 
4007     return -1;  /* approximately equal */
4008 }
4009 
4010 /*---------------------------------------------------------------------*/
4011 /*! compare triangles - return triangle index of first difference
4012  *                    - so -1 means no difference
4013  *
4014  *  require the type to be 1, 2 or 4-byte integers
4015  *  could cheat and compare as unsigned...
4016  *
4017  *  require consistent wrapping, but allow for varying first vertex
4018 *//*-------------------------------------------------------------------*/
gifti_triangle_diff_offset(const void * p1,const void * p2,int ntri,int ni_type)4019 int gifti_triangle_diff_offset(const void *p1, const void *p2, int ntri,
4020                                int ni_type)
4021 {
4022     int posn = -1;
4023 
4024     /* if either pointer is not set, we're out of here */
4025     if( !p1 || !p2 ) {
4026         if( !p1 && !p2 ) return -1; /* same */
4027         return 0;                   /* different */
4028     }
4029 
4030     if( ntri <= 0 ) return -1;
4031 
4032     switch( ni_type ) {
4033         case NIFTI_TYPE_INT8: {
4034             char * d1 = (char *)p1, * d2 = (char *)p2;
4035             for( posn = 0; posn < ntri; posn++, d1+=3, d2+=3 ) {
4036                 if( *d1 == *d2 ) {              /* same first index */
4037                     if( d1[1] != d2[1] || d1[2] != d2[2] ) break;
4038                 } else if ( d1[0] == d2[1] ) {  /* index off by 1   */
4039                     if( d1[1] != d2[2] || d1[2] != d2[0] ) break;
4040                 } else if ( d1[0] == d2[2] ) {  /* index off by 2   */
4041                     if( d1[1] != d2[0] || d1[2] != d2[1] ) break;
4042                 }
4043             }
4044             break;
4045         }
4046         case NIFTI_TYPE_INT16: {
4047             short * d1 = (short *)p1, * d2 = (short *)p2;
4048             for( posn = 0; posn < ntri; posn++, d1+=3, d2+=3 ) {
4049                 if( *d1 == *d2 ) {              /* same first index */
4050                     if( d1[1] != d2[1] || d1[2] != d2[2] ) break;
4051                 } else if ( d1[0] == d2[1] ) {  /* index off by 1   */
4052                     if( d1[1] != d2[2] || d1[2] != d2[0] ) break;
4053                 } else if ( d1[0] == d2[2] ) {  /* index off by 2   */
4054                     if( d1[1] != d2[0] || d1[2] != d2[1] ) break;
4055                 }
4056             }
4057             break;
4058         }
4059         case NIFTI_TYPE_INT32: {
4060             int * d1 = (int *)p1, * d2 = (int *)p2;
4061             for( posn = 0; posn < ntri; posn++, d1+=3, d2+=3 ) {
4062                 if( *d1 == *d2 ) {              /* same first index */
4063                     if( d1[1] != d2[1] || d1[2] != d2[2] ) break;
4064                 } else if ( d1[0] == d2[1] ) {  /* index off by 1   */
4065                     if( d1[1] != d2[2] || d1[2] != d2[0] ) break;
4066                 } else if ( d1[0] == d2[2] ) {  /* index off by 2   */
4067                     if( d1[1] != d2[0] || d1[2] != d2[1] ) break;
4068                 }
4069             }
4070             break;
4071         }
4072         case NIFTI_TYPE_UINT8: {
4073             unsigned char *d1 = (unsigned char *)p1, *d2 = (unsigned char *)p2;
4074             for( posn = 0; posn < ntri; posn++, d1+=3, d2+=3 ) {
4075                 if( *d1 == *d2 ) {              /* same first index */
4076                     if( d1[1] != d2[1] || d1[2] != d2[2] ) break;
4077                 } else if ( d1[0] == d2[1] ) {  /* index off by 1   */
4078                     if( d1[1] != d2[2] || d1[2] != d2[0] ) break;
4079                 } else if ( d1[0] == d2[2] ) {  /* index off by 2   */
4080                     if( d1[1] != d2[0] || d1[2] != d2[1] ) break;
4081                 }
4082             }
4083             break;
4084         }
4085         case NIFTI_TYPE_UINT16: {
4086             unsigned short *d1=(unsigned short *)p1, *d2=(unsigned short *)p2;
4087             for( posn = 0; posn < ntri; posn++, d1+=3, d2+=3 ) {
4088                 if( *d1 == *d2 ) {              /* same first index */
4089                     if( d1[1] != d2[1] || d1[2] != d2[2] ) break;
4090                 } else if ( d1[0] == d2[1] ) {  /* index off by 1   */
4091                     if( d1[1] != d2[2] || d1[2] != d2[0] ) break;
4092                 } else if ( d1[0] == d2[2] ) {  /* index off by 2   */
4093                     if( d1[1] != d2[0] || d1[2] != d2[1] ) break;
4094                 }
4095             }
4096             break;
4097         }
4098         case NIFTI_TYPE_UINT32: {
4099             unsigned int * d1 = (unsigned int *)p1, * d2 = (unsigned int *)p2;
4100             for( posn = 0; posn < ntri; posn++, d1+=3, d2+=3 ) {
4101                 if( *d1 == *d2 ) {              /* same first index */
4102                     if( d1[1] != d2[1] || d1[2] != d2[2] ) break;
4103                 } else if ( d1[0] == d2[1] ) {  /* index off by 1   */
4104                     if( d1[1] != d2[2] || d1[2] != d2[0] ) break;
4105                 } else if ( d1[0] == d2[2] ) {  /* index off by 2   */
4106                     if( d1[1] != d2[0] || d1[2] != d2[1] ) break;
4107                 }
4108             }
4109             break;
4110         }
4111         default: {
4112             fprintf(stderr,"** gifti_tri_diff: invalid type %d\n", ni_type);
4113             return 1;
4114         }
4115     }
4116 
4117     if( posn < ntri ) return posn;   /* difference offset */
4118 
4119     return -1;  /* no difference */
4120 }
4121 
4122 /*-----------------------------------------------------------------*/
4123 /*! print raw data (nvals of type 'type') to the given file stream
4124  *
4125  *  possibly write a trailing newline
4126 *//*-------------------------------------------------------------------*/
gifti_disp_raw_data(const void * data,int type,int nvals,int newline,FILE * stream)4127 int gifti_disp_raw_data(const void * data, int type, int nvals, int newline,
4128                         FILE * stream)
4129 {
4130     FILE * fp = stream ? stream : stdout;
4131     char * dp, fbuf[64];
4132     int    c, size;
4133 
4134     gifti_datatype_sizes(type, &size, NULL);   /* get nbyper */
4135     if( size == 0 ) {
4136         fprintf(stderr,"** GDRD: cannot print with size 0, type %d\n", type);
4137         return 1;
4138     }
4139 
4140     for( c = 0, dp = (char *)data; c < nvals; c++, dp += size ) {
4141         switch( type ) {
4142             case NIFTI_TYPE_INT8:
4143                 fprintf(fp, "%d", *(char *)dp);
4144                 break;
4145             case NIFTI_TYPE_INT16:
4146                 fprintf(fp, "%d", *(short *)dp);
4147                 break;
4148             case NIFTI_TYPE_INT32:
4149                 fprintf(fp, "%d", *(int *)dp);
4150                 break;
4151             case NIFTI_TYPE_INT64:
4152                 fprintf(fp, "%lld", *(long long *)dp);
4153                 break;
4154             case NIFTI_TYPE_UINT8:
4155                 fprintf(fp, "%u", *(unsigned char *)dp);
4156                 break;
4157             case NIFTI_TYPE_UINT16:
4158                 fprintf(fp, "%u", *(unsigned short *)dp);
4159                 break;
4160             case NIFTI_TYPE_UINT32:
4161                 fprintf(fp, "%u", *(unsigned int *)dp);
4162                 break;
4163             case NIFTI_TYPE_UINT64:
4164                 fprintf(fp, "%llu", *(unsigned long long *)dp);
4165                 break;
4166             case NIFTI_TYPE_FLOAT32:
4167                 sprintf(fbuf,"%f", *(float *)dp);
4168                 gifti_clear_float_zeros(fbuf);
4169                 fprintf(fp, "%s", fbuf);
4170                 break;
4171             case NIFTI_TYPE_FLOAT64:
4172                 sprintf(fbuf,"%f", *(double *)dp);
4173                 gifti_clear_float_zeros(fbuf);
4174                 fprintf(fp, "%s", fbuf);
4175                 break;
4176             default:
4177                 fprintf(stderr,"** Gdisp_raw_data: invalid type %d\n", type);
4178                 return 1;
4179         }
4180         if( c < nvals - 1 ) fputc(' ', fp);
4181     }
4182 
4183     if ( newline ) fputc('\n', fp);
4184 
4185     return 0;
4186 }
4187 
4188 /*----------------------------------------------------------------------
4189  *! remove trailing zeros from string of printed float
4190  *  return  1 if something was cleared
4191  *          0 if not
4192 *//*-------------------------------------------------------------------*/
gifti_clear_float_zeros(char * str)4193 int gifti_clear_float_zeros( char * str )
4194 {
4195    char * dp, * valp;
4196    int    len;
4197 
4198    if( !str || !*str ) return 0;  /* that was easy    */
4199 
4200    dp  = strchr(str, '.');        /* find '.'         */
4201    if( !dp ) return 0;            /* no '.', easy too */
4202 
4203    len = strlen(dp);
4204 
4205    /* never clear what is just to the right of '.' */
4206    for( valp = dp+len-1; (valp > dp+1) && (*valp==' ' || *valp=='0'); valp-- )
4207        *valp = '\0';     /* clear, so we don't worry about break conditions */
4208 
4209    if( valp < dp + len - 1 ) return 1;
4210 
4211    return 0;
4212 }
4213 
4214 /*----------------------------------------------------------------------
4215  *! set all DataArray attributes of the given name to the given value
4216 *//*-------------------------------------------------------------------*/
gifti_set_atr_in_DAs(gifti_image * gim,const char * name,const char * value,const int * dalist,int len)4217 int gifti_set_atr_in_DAs(gifti_image *gim, const char *name, const char *value,
4218                          const int * dalist, int len)
4219 {
4220     int c, ind;
4221 
4222     if( !gim || !name || !value ) {
4223         fprintf(stderr,"** set_DA_atrs: bad params (%p,%p,%p)\n",
4224                 (void *)gim, (void *)name, (void *)value);
4225         return 1;
4226     }
4227 
4228     if( !gim->darray ) return 0;    /* just leave */
4229 
4230     if( dalist && len > 0 ) {       /* set atrs for those DA in dalist */
4231         if( ! gifti_valid_int_list(dalist, len, 0, gim->numDA-1, 1) )
4232             return 1;
4233 
4234         /* good to go */
4235         for( c = 0; c < len; c++ ) {
4236             ind = dalist[c];    /* for clarity */
4237             if( ! gim->darray[ind] ) continue;  /* trioanoid */
4238             if( gifti_str2attr_darray(gim->darray[ind], name, value) ) {
4239                 if( G.verb > 1 )
4240                     fprintf(stderr,"** bad DA attr '%s'='%s'\n",name,value);
4241                 return 1;
4242             }
4243         }
4244 
4245         if( G.verb > 2 )
4246             fprintf(stderr,"++ set atrs in %d DAs, '%s'='%s'\n",len,name,value);
4247 
4248         return 0;
4249     }
4250 
4251     /* else continue, do all of them */
4252 
4253     for( c = 0; c < gim->numDA; c++ ) {
4254         if( ! gim->darray[c] ) continue;  /* trioanoid */
4255         if( gifti_str2attr_darray(gim->darray[c], name, value) ) {
4256             if(G.verb>1)fprintf(stderr,"** bad DA attr '%s'='%s'\n",name,value);
4257             return 1;
4258         }
4259     }
4260 
4261     if( G.verb > 4 )
4262         fprintf(stderr,"++ set attr in all DAs, '%s'='%s'\n", name, value);
4263 
4264     return 0;
4265 }
4266 
4267 /*----------------------------------------------------------------------
4268  *! set MetaData name/value pairs in all DAs in list (or all in gim)
4269 *//*-------------------------------------------------------------------*/
gifti_set_DA_meta(gifti_image * gim,const char * name,const char * value,const int * dalist,int len,int replace)4270 int gifti_set_DA_meta( gifti_image *gim, const char *name, const char *value,
4271                        const int * dalist, int len, int replace )
4272 {
4273     int c, ind;
4274 
4275     if( !gim || !name || !value ) {
4276         fprintf(stderr,"** set_DA_meta: bad params (%p,%p,%p)\n",
4277                 (void *)gim, (void *)name, (void *)value);
4278         return 1;
4279     }
4280 
4281     if( !gim->darray ) return 0;    /* just leave */
4282 
4283     if( dalist && len > 0 ) {       /* set meta for those DA in dalist */
4284         if( ! gifti_valid_int_list(dalist, len, 0, gim->numDA-1, 1) )
4285             return 1;
4286 
4287         /* good to go */
4288         for( c = 0; c < len; c++ ) {
4289             ind = dalist[c];    /* for clarity */
4290             if( ! gim->darray[ind] ) continue;  /* trioanoid */
4291             if( gifti_add_to_meta(&gim->darray[ind]->meta,name,value,replace) )
4292                 return 1;
4293         }
4294 
4295         if( G.verb > 2 )
4296             fprintf(stderr,"++ set meta in %d DAs, '%s'='%s'\n",len,name,value);
4297 
4298         return 0;
4299     }
4300 
4301     /* else continue, do all of them */
4302 
4303     for( c = 0; c < gim->numDA; c++ ) {
4304         if( ! gim->darray[c] ) continue;  /* trioanoid */
4305         if( gifti_add_to_meta(&gim->darray[c]->meta,name,value,replace) )
4306             return 1;
4307     }
4308 
4309     if( G.verb > 4 )
4310         fprintf(stderr,"++ set MetaData in all DAs, '%s'='%s'\n", name, value);
4311 
4312     return 0;
4313 }
4314 
4315 /*----------------------------------------------------------------------
4316  *! allocate and return a newly created gifti_image_struct
4317  *
4318  *  if numDA > 0, allocate and initialize gim->darray
4319  *  if intent is a valid NIFTI_INTENT code, set it in all DataArray elements
4320  *  if dtype is a valid NIFTI_TYPE, set it in all DA elements
4321  *  if dims is set (MUST be of length 6), set the dims in all DA elements
4322  *  if alloc_data, allocate zero-filled data in each DA element
4323  *
4324  *  note that if numDA <= 0, the function returns an empty gifti_image
4325 *//*-------------------------------------------------------------------*/
gifti_create_image(int numDA,int intent,int dtype,int ndim,const int * dims,int alloc_data)4326 gifti_image * gifti_create_image( int numDA, int intent, int dtype, int ndim,
4327                                   const int * dims, int alloc_data )
4328 {
4329     gifti_image * gim;
4330     int           c, errs = 0;
4331 
4332     if( G.verb > 1 ) {  /* maybe start with some chit-chat */
4333         fprintf(stderr,"++ creating gifti_image with %d DA elements\n", numDA);
4334         if( G.verb > 2 ) {
4335             fprintf(stderr,"     intent[%d] = %s, dtype[%d] = %s,\n"
4336                            "     alloc_data = %d, ndim = %d, dims: ",
4337                     intent, gifti_intent_to_string(intent),
4338                     dtype,  gifti_datatype2str(dtype), alloc_data, ndim);
4339             if( !dims ) fprintf(stderr,"<empty>\n");
4340             else gifti_disp_raw_data(dims, DT_INT32, GIFTI_DARRAY_DIM_LEN,
4341                                      1, stderr);
4342         }
4343     }
4344 
4345     /* basic step - create empty image (with a version string) */
4346     gim = (gifti_image *)calloc(1, sizeof(gifti_image));
4347     if(!gim){ fprintf(stderr,"** failed to alloc gifti_image\n"); return NULL; }
4348 
4349     gifti_clear_gifti_image(gim);
4350     gim->version = gifti_strdup(GIFTI_XML_VERSION);
4351 
4352     if( numDA <= 0 ) return gim;        /* done */
4353 
4354     /* apply numDA, which is incremented in add_empty_darray() */
4355     gim->numDA = 0;
4356     if( gifti_add_empty_darray(gim, numDA) ) {  /* then cannot continue */
4357         gifti_free_image(gim);
4358         return NULL;
4359     }
4360 
4361     /* init all to defaults */
4362     for( c = 0; c < gim->numDA; c++ )
4363         errs += gifti_set_DA_defaults(gim->darray[c]);
4364 
4365     /* and fill in any other pieces */
4366 
4367     if( gifti_intent_is_valid(intent) )
4368         errs += gifti_set_atr_in_DAs(gim,"Intent",
4369                                      gifti_intent_to_string(intent), NULL, 0);
4370 
4371     if( gifti_valid_datatype(dtype, 1) ) {
4372         errs += gifti_set_atr_in_DAs(gim,"DataType", gifti_datatype2str(dtype),
4373                                      NULL, 0);
4374         errs += gifti_update_nbyper(gim);
4375     }
4376 
4377     if( dims && ndim >= 0 ) errs += gifti_set_dims_all_DA(gim, ndim, dims);
4378 
4379     /* don't try this if there are errors */
4380     if( !errs && alloc_data ) errs += gifti_alloc_DA_data(gim, NULL, 0);
4381 
4382     if( errs ) {  /* then fail out */
4383         gifti_free_image(gim);
4384         return NULL;
4385     }
4386 
4387     return gim;
4388 }
4389 
4390 /*----------------------------------------------------------------------
4391  *! allocate nvals*nbyper bytes of (zero-filled) data in each DataArray
4392  *  (in dalist or simply in gim)
4393  *
4394  *  return 0 on success
4395  *         1 on error
4396 *//*-------------------------------------------------------------------*/
gifti_alloc_DA_data(gifti_image * gim,const int * dalist,int len)4397 int gifti_alloc_DA_data(gifti_image * gim, const int * dalist, int len)
4398 {
4399     giiDataArray * da;
4400     long long      nbytes, ntot = 0;
4401     int            c, index, nset = 0, use_list, numDA;
4402 
4403     if( !gim || !gim->darray || gim->numDA <= 0 ) return 0;
4404 
4405     /* decide whether to use dalist or allocate all data */
4406     use_list = gifti_valid_int_list(dalist, len, 0, gim->numDA-1, 0);
4407 
4408     if( use_list && G.verb > 2 )
4409         fprintf(stderr,"++ allocating data for %s\n",
4410                 use_list ? "DA in list" : "all DAs");
4411 
4412     if( use_list && DA_data_exists(gim, dalist, len) ) {
4413         fprintf(stderr,"** data already exists for some DAs in list\n");
4414         return 1;
4415     }
4416 
4417     numDA = use_list ? len : gim->numDA;
4418     for( c = 0; c < numDA; c++ ) {
4419         index = use_list ? dalist[c] : c;  /* choose appropriate DA index */
4420         da = gim->darray[index];           /* set convenient pointer */
4421 
4422         if( ! da ) continue;
4423 
4424         /* if dimensions do not make sense, fail out */
4425         if( ! gifti_valid_dims(da, G.verb > 0) ) return 1;
4426 
4427         if( da->nvals < 0 || da->nbyper < 0 ) {
4428             fprintf(stderr,"** bad nvals, nbyper in DA[%d]\n",index);
4429             return 1;
4430         }
4431         nbytes = da->nvals * da->nbyper;
4432         if( nbytes <= 0 ) continue;  /* skip empty data */
4433 
4434         ntot += nbytes;          /* compute total bytes */
4435         nset++;
4436 
4437         da->data = calloc(nbytes, sizeof(char));
4438         if( !da->data ) {
4439             fprintf(stderr,"** gifti_alloc_DA_data: failed on DA %d of %d\n"
4440                            "     %lld bytes (%lld total)\n",
4441                            index, numDA, nbytes, ntot);
4442             return 1;
4443         }
4444     }
4445 
4446     if( G.verb > 3)
4447         fprintf(stderr,"++ alloc'd %lld bytes in %d DA elements\n", ntot, nset);
4448 
4449     return 0;
4450 }
4451 
4452 /*----------------------------------------------------------------------
4453  *! set num_dims, dims and nvals in every DataArray element
4454  *
4455  *  return 0 on success
4456  *         1 on error
4457 *//*-------------------------------------------------------------------*/
gifti_set_dims_all_DA(gifti_image * gim,int ndim,const int * dims)4458 int gifti_set_dims_all_DA(gifti_image * gim, int ndim, const int * dims)
4459 {
4460     long long nvals;
4461     int       c, d, nset = 0;
4462 
4463     if(!gim || ndim < 0 || ndim > GIFTI_DARRAY_DIM_LEN || !dims) {
4464         fprintf(stderr,"** SDA_DA: bad params (%p, %d, %p)\n",
4465                 (void *)gim, ndim, (void *)dims);
4466         return 1;
4467     }
4468 
4469     if( !gim->darray || gim->numDA == 0 ) return 0;
4470 
4471     /* first compute nvals */
4472     for( d = 0, nvals = 1; d < ndim; d++) nvals *= dims[d];
4473     if( nvals <= 0 ) {
4474         fprintf(stderr,"** GSDA_DA: malformed dims[%d]: ", ndim);
4475         gifti_disp_raw_data(dims, DT_INT32, GIFTI_DARRAY_DIM_LEN, 1, stderr);
4476         return 1;
4477     }
4478     if( ndim == 0 ) nvals = 0;
4479 
4480     /* insert num_dim and fill dims (pad with 0s) */
4481     for( c = 0; c < gim->numDA; c++ ) {
4482         if( !gim->darray[c] ) continue;  /* paranoid */
4483         gim->darray[c]->num_dim = ndim;
4484         for( d = 0; d < ndim; d++ )
4485             gim->darray[c]->dims[d] = dims[d];
4486         for( /* continue */ ; d < GIFTI_DARRAY_DIM_LEN; d++ )
4487             gim->darray[c]->dims[d] = 0;
4488         gim->darray[c]->nvals = nvals;
4489         nset++;
4490     }
4491 
4492     if(G.verb > 3) {
4493         fprintf(stderr,"++ set dims in %d of %d DA elements to: ",
4494                 nset, gim->numDA);
4495         gifti_disp_raw_data(dims, DT_INT32, GIFTI_DARRAY_DIM_LEN, 1, stderr);
4496     }
4497 
4498     return 0;
4499 }
4500 
4501 /*----------------------------------------------------------------------
4502  *! update nbyper/swapsize for all DataArray elements
4503  *
4504  *  return 0 on success
4505  *         1 on error
4506 *//*-------------------------------------------------------------------*/
gifti_update_nbyper(gifti_image * gim)4507 int gifti_update_nbyper(gifti_image * gim)
4508 {
4509     giiDataArray * da;
4510     int            c, errs = 0;
4511 
4512     if( !gim ) return 1;
4513 
4514     if( !gim->darray || gim->numDA == 0 ) return 0;
4515 
4516     for( c = 0; c < gim->numDA; c++ ){
4517         da = gim->darray[c];    /* just to look cleaner */
4518         if( !da ) continue;
4519         errs += gifti_datatype_sizes(da->datatype, &da->nbyper, NULL);
4520     }
4521 
4522     return errs;
4523 }
4524 
4525 /*----------------------------------------------------------------------
4526  *! fill DataArray element with default values
4527  *
4528  *  return 0 on success
4529  *         1 on error
4530 *//*-------------------------------------------------------------------*/
gifti_set_DA_defaults(giiDataArray * da)4531 int gifti_set_DA_defaults(giiDataArray * da)
4532 {
4533     int c;
4534 
4535     if(!da) { fprintf(stderr,"** NULL in set_DA_defaults\n"); return 1; }
4536 
4537     if( G.verb > 6 ) fprintf(stderr,"-- setting DA defaults\n");
4538 
4539     gifti_clear_DataArray(da);                  /* start with empty struct */
4540 
4541     /* and fill with any non-NULL, non-zero values */
4542 
4543     da->intent = NIFTI_INTENT_NONE;
4544     da->datatype = NIFTI_TYPE_FLOAT32;
4545     da->ind_ord = GIFTI_IND_ORD_ROW_MAJOR;
4546     da->num_dim = 1;                            /* one value per node */
4547 
4548     for( c = 0; c < GIFTI_DARRAY_DIM_LEN; c++ ) da->dims[c] = 0;
4549 
4550     da->encoding = GIFTI_ENCODING_B64BIN;       /* zlib may not be available */
4551     da->endian = gifti_get_this_endian();
4552     da->ext_offset = 0;
4553 
4554     da->nvals = 0;
4555     da->nbyper = 0;
4556     gifti_datatype_sizes(da->datatype, &da->nbyper, NULL);
4557 
4558     return 0;
4559 }
4560 
4561 /*----------------------------------------------------------------------
4562  *! clear the DataArray element
4563 *//*-------------------------------------------------------------------*/
gifti_clear_DataArray(giiDataArray * da)4564 int gifti_clear_DataArray(giiDataArray * da)
4565 {
4566     if(!da) { fprintf(stderr,"** NULL in clear_DataArray\n"); return 1; }
4567 
4568     if( G.verb > 5 ) fprintf(stderr,"-- clearing DataArray\n");
4569 
4570     memset(da, 0, sizeof(giiDataArray));
4571 
4572     da->ext_fname = NULL;
4573     gifti_clear_nvpairs(&da->meta);
4574     da->coordsys = NULL;
4575     da->data = NULL;
4576     gifti_clear_nvpairs(&da->ex_atrs);
4577 
4578     return 0;
4579 }
4580 
4581 /*----------------------------------------------------------------------
4582  *! simply clear all contents of the passed gifti_image
4583  *  (being explicit with pointers)
4584  *
4585  *  return 0 on success
4586  *         1 on error
4587 *//*-------------------------------------------------------------------*/
gifti_clear_gifti_image(gifti_image * gim)4588 int gifti_clear_gifti_image(gifti_image * gim)
4589 {
4590     if(!gim) { fprintf(stderr,"** NULL in clear_gifti_image\n"); return 1; }
4591 
4592     if( G.verb > 5 ) fprintf(stderr,"-- clearing gifti_image\n");
4593 
4594     /* set the version and clear all pointers */
4595     memset(gim, 0, sizeof(*gim));
4596 
4597     gim->version = NULL;
4598     gifti_clear_nvpairs(&gim->meta);
4599     gifti_clear_LabelTable(&gim->labeltable);
4600     gim->darray = NULL;
4601     gifti_clear_nvpairs(&gim->ex_atrs);
4602 
4603     return 0;
4604 }
4605 
4606 /*----------------------------------------------------------------------
4607  *! read a dataset, just for numDA
4608  *
4609  *  may write faster gxml function for this, if it seems important
4610 *//*-------------------------------------------------------------------*/
gifti_read_dset_numDA(const char * fname)4611 int gifti_read_dset_numDA(const char * fname)
4612 {
4613     gifti_image * gim;
4614     int           numDA;
4615 
4616     if( !fname ) {
4617         fprintf(stderr,"** NULL to gifti_read_dset_numDA\n");
4618         return -1;
4619     }
4620 
4621     if( G.verb > 2 ) fprintf(stderr,"++ read dset numDA, file '%s'\n",fname);
4622 
4623     gim = gifti_read_da_list(fname, 0, NULL, 0);
4624 
4625     if( !gim ) return -1;       /* errors already printed */
4626 
4627     numDA = gim->numDA;
4628 
4629     if(G.verb > 1)
4630         fprintf(stderr,"++ read dset numDA, file '%s', numDA = %d\n",
4631                 fname, numDA);
4632 
4633     gifti_free_image(gim);      /* lose dataset and return */
4634 
4635     return numDA;
4636 }
4637 
4638 /*----------------------------------------------------------------------
4639  *! return whether the list values are from min to max
4640 *//*-------------------------------------------------------------------*/
gifti_valid_int_list(const int * list,int len,int min,int max,int whine)4641 int gifti_valid_int_list(const int *list, int len, int min, int max, int whine)
4642 {
4643     int c;
4644 
4645     if( !list || len <= 0 ) return 0;
4646 
4647     for( c = 0; c < len; c++ )
4648         if( list[c] < min || list[c] > max ) {
4649             if( whine )
4650                 fprintf(stderr,"** bad list index [%d] = %d, not in [%d,%d]\n",
4651                     c, list[c], min, max);
4652             return 0;
4653         }
4654 
4655     return 1;
4656 }
4657 
4658 /* return whether any DAs in list have data */
DA_data_exists(gifti_image * gim,const int * dalist,int len)4659 static int DA_data_exists(gifti_image * gim, const int * dalist, int len)
4660 {
4661     int length, uselist = 0;
4662     int c, ind;
4663 
4664     if( !dalist || len <= 0 ) { /* then scan all DA elements */
4665         length = gim->numDA;
4666         if( length <= 0 ) return 0;
4667     } else if( !gifti_valid_int_list(dalist, len, 0, gim->numDA-1, 1) ) {
4668         return 0;
4669     } else {
4670         uselist = 1;
4671         length = len;
4672     }
4673 
4674     for( c = 0; c < length; c++ ) {
4675         ind = uselist ? dalist[c] : c;
4676         if( gim->darray[ind] && gim->darray[ind]->data )
4677             return 1;
4678     }
4679 
4680     return 0;
4681 }
4682 
4683 /*----------------------------------------------------------------------
4684  *! add the name=value pair to the MetaData lists
4685  *
4686  *  if the name already exists, fail, unless 'replace' is set
4687  *
4688  *  return 0 on success, 1 on error
4689 *//*-------------------------------------------------------------------*/
gifti_add_to_meta(giiMetaData * md,const char * name,const char * value,int replace)4690 int gifti_add_to_meta( giiMetaData * md, const char * name, const char * value,
4691                        int replace )
4692 {
4693     int c;
4694 
4695     if( !md || !name || !value ) return 1;
4696 
4697     if( G.verb > 5 )
4698         fprintf(stderr,"++ GA2M: name '%s', value '%s', replace = %d\n",
4699                        name, value, replace);
4700 
4701     /* see if 'name' is already here */
4702     for( c = 0; c < md->length; c++ )
4703     {
4704         if( !md->name[c] && G.verb > 2 ) {
4705             fprintf(stderr,"** G MD[%d]: no name to check for replacement\n",c);
4706             continue;
4707         }
4708 
4709         if( !strcmp(md->name[c], name) ) {      /* a match, apply and return */
4710             if( !md->value[c] && G.verb > 2 ) {
4711                 fprintf(stderr,"** G MD[%d]: no value to replace\n",c);
4712                 md->value[c] = gifti_strdup(value);
4713                 return 0;
4714             }
4715 
4716             if( replace ) {
4717                 if( G.verb > 5 ) fprintf(stderr,"   (add via REPLACE)\n");
4718                 if( md->value[c] ) free(md->value[c]);
4719                 md->value[c] = gifti_strdup(value);
4720                 return 0;
4721             } else {
4722                 fprintf(stderr,"** G_add_to_meta: name '%s', already exists\n",
4723                                name);
4724                 return 1;
4725             }
4726         }
4727     }
4728 
4729     /* name is new, so just add it */
4730 
4731     if( G.verb > 5 ) fprintf(stderr,"   (adding new entry)\n");
4732 
4733     md->length++;
4734     md->name = (char **)realloc(md->name, md->length * sizeof(char *));
4735     md->value = (char **)realloc(md->value, md->length * sizeof(char *));
4736 
4737     if( !md->name || !md->value ) {
4738         fprintf(stderr,"** GA2M:failed to realloc %d MD pointers\n",md->length);
4739         md->length = 0;
4740         return 1;
4741     }
4742 
4743     md->name[md->length-1] = gifti_strdup(name);
4744     md->value[md->length-1] = gifti_strdup(value);
4745 
4746     if( ! md->name[md->length-1] || ! md->value[md->length-1] )
4747         return 1;
4748 
4749     return 0;
4750 }
4751 
4752 /*----------------------------------------------------------------------
4753  *! check for validity of the gifti_image (including sub-structures)
4754  *
4755  *  if whine is set, complain about any errors
4756  *
4757  *  return 1 if valid, 0 otherwise
4758 *//*-------------------------------------------------------------------*/
gifti_valid_gifti_image(gifti_image * gim,int whine)4759 int gifti_valid_gifti_image( gifti_image * gim, int whine )
4760 {
4761     int c, errs = 0;
4762 
4763     if( !gim ) {
4764         if(whine) fprintf(stderr,"** invalid: gifti_image ptr is NULL\n");
4765         return 0;
4766     }
4767 
4768     if( G.verb > 3 ) fprintf(stderr,"-- checking for valid gifti_image...\n");
4769 
4770     if( gim->numDA < 0 ) {
4771         if(whine) fprintf(stderr,"** invalid: numDA = %d\n", gim->numDA);
4772         errs ++;
4773     }
4774 
4775     if( !gim->version || strcmp(gim->version, GIFTI_XML_VERSION) ) {
4776         if(whine) fprintf(stderr, "** invalid: gim version = %s\n",
4777                           G_CHECK_NULL_STR(gim->version));
4778         errs++;
4779     }
4780 
4781     if( ! gifti_valid_nvpairs(&gim->meta, whine) ) errs ++;
4782 
4783     if( ! gifti_valid_LabelTable(&gim->labeltable, whine) ) errs ++;
4784 
4785     for( c = 0; c < gim->numDA; c++ ) {
4786         if( G.verb > 5 ) fprintf(stderr,"-- checking DA[%d]\n", c);
4787         if( ! gifti_valid_DataArray(gim->darray[c], whine) ) {
4788             if( G.verb > 3 ) fprintf(stderr,"-- DA[%d] has errors\n",c);
4789             errs++;
4790         } else if( G.verb > 4 )
4791             fprintf(stderr,"-- DA[%d] is VALID\n",c);
4792     }
4793 
4794     /* no check on swapped or compressed */
4795 
4796     if( ! gifti_valid_nvpairs(&gim->ex_atrs, whine) ) errs ++;
4797 
4798     if( G.verb > 2 ) {
4799         fprintf(stderr,"-- gifti_image: errors = %d", errs);
4800         if( errs ) fprintf(stderr," (INVALID)\n");
4801         else       fprintf(stderr," (VALID)\n");
4802     }
4803 
4804     if( errs ) return 0;
4805     else       return 1;
4806 }
4807 
4808 /*---------------------------------------------------------------------*/
4809 /*! return whether data exists
4810  *
4811  *  - darray, each darray[i] and darray[i]->data must be set
4812  *
4813  *  return 1 if true, 0 otherwise
4814 *//*-------------------------------------------------------------------*/
gifti_image_has_data(const gifti_image * gim)4815 int gifti_image_has_data(const gifti_image * gim)
4816 {
4817     int c;
4818 
4819     if( !gim || !gim->darray || gim->numDA <= 0 ) return 0;
4820 
4821     for( c = 0; c < gim->numDA; c++ )
4822         if( !gim->darray[c] ) {
4823             if(G.verb > 3) fprintf(stderr,"** gim missing data at ind %d\n",c);
4824             return 0;
4825         }
4826 
4827     return 1;
4828 }
4829 
4830 /*---------------------------------------------------------------------*/
4831 /*! duplicate the given gifti_image struct, optionally including data
4832  *
4833  *  Allocate and copy all contents of the gifti_image structure and
4834  *  sub-structures.  If copy_data is not set, all data pointers within
4835  *  DataArray elements will be left as NULL.
4836  *
4837  *  return a pointer to the newly allocated structure
4838 *//*-------------------------------------------------------------------*/
gifti_copy_gifti_image(const gifti_image * gold,int copy_data)4839 gifti_image * gifti_copy_gifti_image(const gifti_image * gold, int copy_data)
4840 {
4841     gifti_image * gnew;
4842     int           c, errs = 0;   /* check for errors at each step */
4843 
4844     if( !gold ){ fprintf(stderr,"** copy_gim: input is NULL\n"); return NULL; }
4845 
4846     if(G.verb > 3) fprintf(stderr,"++ copying gifti_image (%s data)...\n",
4847                            copy_data ? "with" : "without" );
4848 
4849     gnew = (gifti_image *)calloc(1, sizeof(gifti_image));
4850     if(!gnew){fprintf(stderr,"** copy_gim, failed alloc\n"); return NULL;}
4851 
4852     /* copy one piece at a time */
4853     gnew->numDA = gold->numDA;
4854     gnew->version = gifti_strdup(gold->version);
4855 
4856     errs = gifti_copy_nvpairs(&gnew->meta, &gold->meta);
4857     if(!errs) errs=gifti_copy_LabelTable(&gnew->labeltable, &gold->labeltable);
4858 
4859     /* if needed, create and copy the DataArray list */
4860     if( !errs && gold->darray && gold->numDA > 0 ) {
4861         gnew->darray=(giiDataArray**)malloc(gold->numDA*sizeof(giiDataArray*));
4862         if( !gnew->darray ) {
4863             fprintf(stderr,"** copy_gim: failed to alloc darray of len %d\n",
4864                     gold->numDA);
4865             errs = 1;
4866         }
4867 
4868         for( c = 0; !errs && c < gold->numDA; c++ ) {
4869             gnew->darray[c] = gifti_copy_DataArray(gold->darray[c], copy_data);
4870             if( !gnew->darray[c]) errs++;
4871         }
4872     }
4873 
4874     /* and copy the extras */
4875     if( !errs ) {
4876         gnew->swapped = gold->swapped;
4877         gnew->compressed = gold->compressed;
4878         errs = gifti_copy_nvpairs(&gnew->ex_atrs, &gold->ex_atrs);
4879     }
4880 
4881     /* on failure, blow everything away */
4882     if( errs ) { gifti_free_image(gnew); return NULL; }
4883 
4884     return gnew;
4885 }
4886 
4887 /*---------------------------------------------------------------------*/
4888 /*! convert all data to NIFTI_TYPE_FLOAT32
4889  *
4890  *  for each DataArray
4891  *      if data exists, convert it (free old, allocate new)
4892  *      else, leave as NULL
4893 *//*-------------------------------------------------------------------*/
gifti_convert_to_float(gifti_image * gim)4894 int gifti_convert_to_float(gifti_image * gim)
4895 {
4896     giiDataArray * da;
4897     void         * olddata;
4898     int            oldtype, newtype = NIFTI_TYPE_FLOAT32; /* for future? */
4899     int            c, nbyper, oldnbyper;
4900 
4901     if( !gim ) return 1;
4902 
4903     if( !gim->darray || gim->numDA <= 0 ) {
4904         if( G.verb > 1 ) fprintf(stderr,"-- no darray to convert to float\n");
4905         return 0;
4906     }
4907 
4908     if( G.verb > 1 ) fprintf(stderr,"++ converting gifti_image to float\n");
4909 
4910     /* first, check for problems in any DA */
4911     for( c = 0; c < gim->numDA; c++ ) {
4912         da = gim->darray[c];
4913         if( !da ) continue;
4914 
4915         /* if the data has an unknown type, panic into error */
4916         if( da->data && !gifti_valid_datatype(da->datatype, 0) ) {
4917             fprintf(stderr,"** unknown dtype %d, cannot convert to floats\n",
4918                     da->datatype);
4919             return 1;
4920         }
4921 
4922         /* dimension information must be consistent */
4923         if( !gifti_valid_dims(da, 1) ) return 1;
4924     }
4925 
4926     /* will update nbyper in each DA, below */
4927     gifti_datatype_sizes(newtype, &nbyper, NULL);
4928 
4929     /* all is well, update all DA elements */
4930     for( c = 0; c < gim->numDA; c++ ) {
4931         da = gim->darray[c];
4932         if( !da ) continue;
4933 
4934         oldtype = da->datatype;
4935         oldnbyper = da->nbyper;
4936 
4937         if( oldtype == newtype ) {
4938             if(G.verb > 3) fprintf(stderr,"++ convert DA[%d] already type %s\n",
4939                                    c, gifti_datatype2str(newtype));
4940             continue; /* no change needed */
4941         }
4942 
4943         if(G.verb > 3)
4944             fprintf(stderr,"++ convert DA[%d] from %s to %s\n", c,
4945                     gifti_datatype2str(oldtype), gifti_datatype2str(newtype));
4946 
4947         if( oldtype == newtype ) continue; /* no change needed */
4948 
4949         /* start trashing DataArray: adjust datatype and nbyper */
4950         da->datatype = newtype;
4951         da->nbyper = nbyper;
4952 
4953         /* if there is no data, we are done with this DA */
4954         if( !da->data ) {
4955             if( G.verb > 4 ) fprintf(stderr,"-- no data to convert\n");
4956             continue;
4957         }
4958 
4959         /* store old data pointer, and allocate new data space */
4960         olddata = da->data;
4961         da->data = NULL;    /* so alloc_DA_data doesn't whine */
4962         if( gifti_alloc_DA_data(gim, &c, 1) ) return 1;
4963 
4964         /* copy the data, and nuke the old stuff */
4965         if( copy_data_as_float(da->data,newtype,olddata,oldtype,da->nvals) ) {
4966             /* undo this copy and return */
4967             free(da->data);
4968             da->data = olddata; da->datatype = oldtype; da->nbyper = oldnbyper;
4969             return 1;
4970         }
4971 
4972         free(olddata);  /* done with this, data has been copied */
4973     }
4974 
4975     return 0;
4976 }
4977 
4978 /* copy old data to float array */
copy_data_as_float(void * dest,int dtype,void * src,int stype,long long nvals)4979 static int copy_data_as_float(void * dest, int dtype, void * src, int stype,
4980                               long long nvals)
4981 {
4982     float     * dptr = (float *)dest;
4983     long long   c;
4984 
4985     if( !dest || !src ) {
4986         fprintf(stderr,"** copy_data_as_float: missing pointers\n");
4987         return 1;
4988     }
4989 
4990     if( dtype != NIFTI_TYPE_FLOAT32 ) {
4991         fprintf(stderr,"** can't copy to float with dest type %d\n", dtype);
4992         return 1;
4993     }
4994 
4995     switch( stype ) {
4996         default: {
4997             fprintf(stderr,"** copy2float: can't handle src type %d\n",stype);
4998             return 1;
4999         }
5000 
5001         case NIFTI_TYPE_INT8: {
5002             char * sptr = (char *)src;
5003             for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c];
5004             break;
5005         }
5006 
5007         case NIFTI_TYPE_INT16: {
5008             short * sptr = (short *)src;
5009             for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c];
5010             break;
5011         }
5012 
5013         case NIFTI_TYPE_INT32: {
5014             int * sptr = (int *)src;
5015             for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c];
5016             break;
5017         }
5018 
5019         case NIFTI_TYPE_INT64: {
5020             long long * sptr = (long long *)src;
5021             for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c];
5022             break;
5023         }
5024 
5025         case NIFTI_TYPE_UINT8: {
5026             unsigned char * sptr = (unsigned char *)src;
5027             for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c];
5028             break;
5029         }
5030 
5031         case NIFTI_TYPE_UINT16: {
5032             unsigned short * sptr = (unsigned short *)src;
5033             for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c];
5034             break;
5035         }
5036 
5037         case NIFTI_TYPE_UINT32: {
5038             unsigned int * sptr = (unsigned int *)src;
5039             for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c];
5040             break;
5041         }
5042 
5043         case NIFTI_TYPE_UINT64: {
5044             unsigned long long * sptr = (unsigned long long *)src;
5045             for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c];
5046             break;
5047         }
5048 
5049         case NIFTI_TYPE_FLOAT32: {
5050             float * sptr = (float *)src;
5051             for( c = 0; c < nvals; c++ ) dptr[c] = sptr[c];
5052             break;
5053         }
5054 
5055         case NIFTI_TYPE_FLOAT64: {
5056             double * sptr = (double *)src;
5057             for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c];
5058             break;
5059         }
5060     }
5061 
5062     return 0;
5063 }
5064