-
Notifications
You must be signed in to change notification settings - Fork 1
/
gifti_io.c
4567 lines (3829 loc) · 155 KB
/
gifti_io.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "gifti_io.h"
/*! global history and version strings, for printing */
static char * gifti_history[] =
{
"----------------------------------------------------------------------\n"
"history (of gifti library changes):\n"
"\n",
"0.0 18 July, 2007\n"
" (Rick Reynolds of the National Institutes of Health, SSCC/DIRP/NIMH)\n"
" - initial version\n"
"0.1 31 July, 2007\n",
" - changed dim0..dim5 to dims[]\n"
" - changed nvals to size_t\n"
" - added gifti_init_darray_from_attrs and some validation functions\n"
"0.2 29 October, 2007\n",
" - renamed gifti.[ch] to gifti_io.[ch]\n"
" - main data structures all start with gii (or gifti_)\n"
" - added user indenting\n"
"0.3 21 November, 2007\n",
" - added base64 encoding/decoding, via b64_en/decode_table\n"
" - added gifti_list_index2string, gifti_disp_hex_data, \n"
" gifti_check_swap, gifti_swap_Nbytes, etc.\n"
" - pop_darray: check for b64 errors and byte swapping\n"
" - dind is size_t\n",
"0.4 29 November, 2007\n"
" - added more checks and fixed nvpair value allocation\n"
"0.5 03 December, 2007: applied changes for GIFTI Format 1.0 (11/21)\n",
" - replaced Category with Intent\n"
" - replaced Location attribute with ExternalFileName/Offset\n"
" - added NumberOfDataArrays attribute to GIFTI element\n"
" - applied new index_order strings\n"
"0.6 10 December, 2007:\n",
" - can read/write Base64Binary datasets (can set compress level)\n"
" - removed datatype lists (have gifti_type_list)\n"
" - added gifti_read_da_list(), with only partial ability\n"
" - added GIFTI numDA attribute\n"
" - change size_t to long long\n"
"0.7 11 December, 2007:\n",
" - added GIFTI_B64_CHECK defines\n"
" - set b64_check default to SKIPNCOUNT\n"
" - added disp_gxml_data\n"
"0.8 12 December, 2007:\n",
" - added sub-surface selection, via dalist in gifti_read_da_list()\n"
" - added gifti_copy_DataArray, and other structures\n"
"0.9 28 December, 2007:\n",
" - made zlib optional, via -DHAVE_ZLIB in compile\n"
" (without zlib, the user will get warnings)\n"
" - now users only #include gifti_io.h, not gifti_xml, expat or zlib\n"
" - added more comments and made tables more readable\n"
" - added all user-variable access functions and reset_user_vars()\n",
" - added gifti_free_image_contents(), gifti_disp_raw_data(),\n"
" gifti_clear_float_zeros() and gifti_set_DA_atrs()\n"
" - changed gifti_gim_DA_size to long long\n"
" - added GIFTI_B64_CHECK_UNDEF as 0\n"
" - fixed 0-width indenting and accumulating base64 errors\n"
"0.10 03 January, 2008:\n",
" - added top-level gifti_create_image() interface\n"
" - must now link libniftiio\n"
" - gifti_add_empty_darray() now takes num_to_add\n"
" - if data was expected but not read, free it\n"
" (can add via gifti_alloc_DA_data())\n"
" - many minor changes\n"
"0.11 11 January, 2008:\n",
" - attribute/data setting functions are more flexible\n"
" - added gifti_disp_dtd_url, gifti_set_DA_meta, gifti_valid_int_list,\n"
" DA_data_exists, gifti_add_to_meta \n"
"0.12 16 January, 2008:\n",
" - added gifti_copy_gifti_image() and gifti_convert_to_float()\n"
" - added gifti_valid_LabelTable(), gifticlib_version(),\n"
" gifti_copy_LabelTable(), gifti_updaet_nbyper() and\n"
" gifti_valid_gifti_image()\n"
" - added control over library updates to metadata\n"
" - expanded checks in gifti_valid_dims\n"
"0.13 20 February, 2008:\n",
" - added gifti_get_meta_value() and gifti_image_has_data()\n"
"0.14 25 February, 2008:\n",
" - consider data-less metadata as valid\n"
"0.15 18 March, 2008: added comparison functions\n",
" - gifti_compare_gifti_images() is top-level function\n"
" - also added gifti_compare_gims_only(), gifti_compare_DA_pair(),\n"
" gifti_compare_nvpairs(), gifti_compare_labeltable(),\n"
" gifti_compare_coordsys()\n"
" gifti_strdiff() and gifti_compare_raw_data()\n"
"0.16 25 March, 2008\n",
" - separate data diffs in compare_gifti_images\n"
" - added gifti_compare_gifti_data() and gifti_compare_DA_data()\n"
" - NIFTI_INTENT_NONE is considered valid\n"
" - write LabelTables using CDATA\n"
"0.17 28 March, 2008 : added copy MetaData routines\n",
" - gifti_copy_gifti_meta, gifti_copy_DA_meta, gifti_copy_all_DA_meta,\n"
" - gifti_copy_DA_meta_many, gifti_copy_nvpairs\n"
"0.18 08 May, 2008 : DataArray can now contain a list of CoordSystems\n",
" - modified giiDataArray struct: new numCS, coordsys is now CS**\n"
" - added gifti_free_CS_list, gifti_add_empty_CS\n"
"\n"
"------------------------ initial release version -----------------------\n",
"1.00 13 May, 2008 : release version of gifticlib\n",
" - allowed external data\n"
" - added gifti_read/write_extern_DA_data() and\n"
" gifti_set_extern_filelist()\n"
"1.01 02 June, 2008 :\n",
" - added CMakeLists.txt and XMLCALL update from Simon Warfield\n"
" (define XMLCALL for pre-1.95.7 versions of expat)\n"
" - added LICENSE.gifti\n"
"1.02 02 October, 2008 :\n",
" - separate diffs in DAs from those in gifti_image\n"
" - decode additional data types: INT8, UINT16, INT64\n"
" - add link flags to libgiftiio_la target\n"
"1.03 17 April, 2009 : allow DA size to vary over each external file\n",
"1.04 27 October, 2009 : added support for LabelTable RGBA attributes\n"
" - valid LabelTable requires RGBA values in [0,1.0]\n"
" - compare_labeltable requires equality of RGBA values (no approx.)\n",
"1.05 08 December, 2009: ignore invalid GIFTI attrs by default\n"
"1.06 24 December, 2009: added approximate difference functions\n",
" - added gifti_approx_gifti_images, DA_pair, labeltables, diff_offset\n"
" - added gifti_triangle_diff_offset\n"
" - gifti_compare_coordsys takes comp_data param\n"
"1.07 04 March, 2010: minor changes (also see NITRC IDs 4619 and 4644)\n",
" - for integers, make default approx test to be equality\n"
" - small changes to zlib failure strings\n"
" - cast to avoid compile warning on some systems\n"
" - gifti_xml.h: made NITRC gifti.dtd link that will not change\n"
"1.08 08 March, 2010: GIfTI LabelTable format change: Index to Key\n",
" - both Index and Key work on read, Key is written out\n"
"1.09 28 June, 2010: verify that num_dim is not too big\n",
" - the most significant dimension cannot be 1 (req by N Schmansky)\n"
"1.10 19 October, 2011: \n",
" - can read/write ascii COMPLEX64, COMPLEX128, RGB24\n"
" (requested by H Breman, J Mulders, N Schmansky)\n"
"1.11 07 March, 2012: fixed sizeof in memset of gim (noted by B Cox)\n",
"1.12 15 June, 2012: make num_dim violation a warning, because of mris_convert\n",
};
static char gifti_version[] = "gifti library version 1.12, 15 June, 2012";
/* ---------------------------------------------------------------------- */
/*! global lists of XML strings */
/*! this should match GIFTI_IND_ORD_* */
char * gifti_index_order_list[] = {"Undefined", "RowMajorOrder",
"ColumnMajorOrder"};
/*! gifti_type_list is an array of gifti_type_ele structs which list, for
each type, the bytes per value, swapsize and corresponding name string
(these type values are defined in nifti1.h) */
static gifti_type_ele gifti_type_list[] = {
/* type nbyper swapsize name */
{ DT_UNKNOWN, 0, 0, "Undefined" },
{ NIFTI_TYPE_UINT8, 1, 0, "NIFTI_TYPE_UINT8" },
{ NIFTI_TYPE_INT16, 2, 2, "NIFTI_TYPE_INT16" },
{ NIFTI_TYPE_INT32, 4, 4, "NIFTI_TYPE_INT32" },
{ NIFTI_TYPE_FLOAT32, 4, 4, "NIFTI_TYPE_FLOAT32" },
{ NIFTI_TYPE_COMPLEX64, 8, 4, "NIFTI_TYPE_COMPLEX64" },
{ NIFTI_TYPE_FLOAT64, 8, 8, "NIFTI_TYPE_FLOAT64" },
{ NIFTI_TYPE_RGB24, 3, 0, "NIFTI_TYPE_RGB24" },
{ NIFTI_TYPE_INT8, 1, 0, "NIFTI_TYPE_INT8" },
{ NIFTI_TYPE_UINT16, 2, 2, "NIFTI_TYPE_UINT16" },
{ NIFTI_TYPE_UINT32, 4, 4, "NIFTI_TYPE_UINT32" },
{ NIFTI_TYPE_INT64, 8, 8, "NIFTI_TYPE_INT64" },
{ NIFTI_TYPE_UINT64, 8, 8, "NIFTI_TYPE_UINT64" },
{ NIFTI_TYPE_FLOAT128, 6, 16, "NIFTI_TYPE_FLOAT128" },
{ NIFTI_TYPE_COMPLEX128, 16, 8, "NIFTI_TYPE_COMPLEX128" },
{ NIFTI_TYPE_COMPLEX256, 32, 16, "NIFTI_TYPE_COMPLEX256" }
};
/*! this list provides a link between intent codes and their name strings */
typedef struct { int code; char * name; } gifti_intent_ele;
static gifti_intent_ele gifti_intent_list[] = {
{ NIFTI_INTENT_NONE, "NIFTI_INTENT_NONE" },
{ NIFTI_INTENT_CORREL, "NIFTI_INTENT_CORREL" },
{ NIFTI_INTENT_TTEST, "NIFTI_INTENT_TTEST" },
{ NIFTI_INTENT_FTEST, "NIFTI_INTENT_FTEST" },
{ NIFTI_INTENT_ZSCORE, "NIFTI_INTENT_ZSCORE" },
{ NIFTI_INTENT_CHISQ, "NIFTI_INTENT_CHISQ" },
{ NIFTI_INTENT_BETA, "NIFTI_INTENT_BETA" },
{ NIFTI_INTENT_BINOM, "NIFTI_INTENT_BINOM" },
{ NIFTI_INTENT_GAMMA, "NIFTI_INTENT_GAMMA" },
{ NIFTI_INTENT_POISSON, "NIFTI_INTENT_POISSON" },
{ NIFTI_INTENT_NORMAL, "NIFTI_INTENT_NORMAL" },
{ NIFTI_INTENT_FTEST_NONC, "NIFTI_INTENT_FTEST_NONC" },
{ NIFTI_INTENT_CHISQ_NONC, "NIFTI_INTENT_CHISQ_NONC" },
{ NIFTI_INTENT_LOGISTIC, "NIFTI_INTENT_LOGISTIC" },
{ NIFTI_INTENT_LAPLACE, "NIFTI_INTENT_LAPLACE" },
{ NIFTI_INTENT_UNIFORM, "NIFTI_INTENT_UNIFORM" },
{ NIFTI_INTENT_TTEST_NONC, "NIFTI_INTENT_TTEST_NONC" },
{ NIFTI_INTENT_WEIBULL, "NIFTI_INTENT_WEIBULL" },
{ NIFTI_INTENT_CHI, "NIFTI_INTENT_CHI" },
{ NIFTI_INTENT_INVGAUSS, "NIFTI_INTENT_INVGAUSS" },
{ NIFTI_INTENT_EXTVAL, "NIFTI_INTENT_EXTVAL" },
{ NIFTI_INTENT_PVAL, "NIFTI_INTENT_PVAL" },
{ NIFTI_INTENT_LOGPVAL, "NIFTI_INTENT_LOGPVAL" },
{ NIFTI_INTENT_LOG10PVAL, "NIFTI_INTENT_LOG10PVAL" },
{ NIFTI_INTENT_ESTIMATE, "NIFTI_INTENT_ESTIMATE" },
{ NIFTI_INTENT_LABEL, "NIFTI_INTENT_LABEL" },
{ NIFTI_INTENT_NEURONAME, "NIFTI_INTENT_NEURONAME" },
{ NIFTI_INTENT_GENMATRIX, "NIFTI_INTENT_GENMATRIX" },
{ NIFTI_INTENT_SYMMATRIX, "NIFTI_INTENT_SYMMATRIX" },
{ NIFTI_INTENT_DISPVECT, "NIFTI_INTENT_DISPVECT" },
{ NIFTI_INTENT_VECTOR, "NIFTI_INTENT_VECTOR" },
{ NIFTI_INTENT_POINTSET, "NIFTI_INTENT_POINTSET" },
{ NIFTI_INTENT_TRIANGLE, "NIFTI_INTENT_TRIANGLE" },
{ NIFTI_INTENT_QUATERNION, "NIFTI_INTENT_QUATERNION" },
{ NIFTI_INTENT_DIMLESS, "NIFTI_INTENT_DIMLESS" },
{ NIFTI_INTENT_TIME_SERIES, "NIFTI_INTENT_TIME_SERIES" },
{ NIFTI_INTENT_NODE_INDEX, "NIFTI_INTENT_NODE_INDEX" },
{ NIFTI_INTENT_RGB_VECTOR, "NIFTI_INTENT_RGB_VECTOR" },
{ NIFTI_INTENT_RGBA_VECTOR, "NIFTI_INTENT_RGBA_VECTOR" },
{ NIFTI_INTENT_SHAPE, "NIFTI_INTENT_SHAPE" }
};
/*! this should match GIFTI_ENCODING_* */
char * gifti_encoding_list[] = {
"Undefined", "ASCII", "Base64Binary", "GZipBase64Binary",
"ExternalFileBinary"
};
/*! this should match GIFTI_ENDIAN_* */
char * gifti_endian_list[] = {"Undefined", "BigEndian", "LittleEndian"};
/* ---------------------------------------------------------------------- */
/* local prototypes */
static int can_compare_DA_data(const giiDataArray *d1,const giiDataArray *d2,
int verb);
static int compare_labeltables(const giiLabelTable *t1, const giiLabelTable *t2,
int verb, int approx);
static int copy_data_as_float(void * dest, int dtype, void * src, int stype,
long long nvals);
static int DA_data_exists(gifti_image * gim, const int * dalist, int len);
static int str2list_index(char *list[], int max, const char *str);
/* ---------------------------------------------------------------------- */
/*! giftilib globals */
static gifti_globals G = { 1 };
/* ====================================================================== */
/* ---------------------------------------------------------------------- */
/*! user variable accessor functions - basically use gxml interface */
int gifti_get_verb( void ) { return G.verb; }
int gifti_set_verb( int level ) { G.verb = level; return 1; }
int gifti_get_indent( void ) { return gxml_get_indent(); }
int gifti_set_indent( int level ) { return gxml_set_indent(level); }
int gifti_get_b64_check( void ) { return gxml_get_b64_check(); }
int gifti_set_b64_check( int level ){ return gxml_set_b64_check(level); }
int gifti_get_update_ok( void ) { return gxml_get_update_ok(); }
int gifti_set_update_ok( int level ){ return gxml_set_update_ok(level); }
int gifti_get_zlevel( void ) { return gxml_get_zlevel(); }
int gifti_set_zlevel( int level )
{
/* note that the default currently results in 6 */
if( level != GZ_DEFAULT_COMPRESSION && (level < 0 || level > 9 ) ) {
fprintf(stderr,"** invalid zlevel, must be %d (default) or {0..9}\n",
GZ_DEFAULT_COMPRESSION);
return 1;
}
return gxml_set_zlevel(level);
}
int gifti_get_xml_buf_size(void) { return gxml_get_buf_size(); }
int gifti_set_xml_buf_size(int buf_size){ return gxml_set_buf_size(buf_size); }
/*! reset user variables to their defaults(via set to -1) */
int gifti_reset_user_vars(void)
{
gxml_set_verb(-1);
gxml_set_dstore(-1);
gxml_set_indent(-1);
gxml_set_buf_size(-1);
gxml_set_b64_check(-1);
gxml_set_update_ok(-1);
gxml_set_zlevel(-1);
return 0;
}
/* end user variable accessor functions */
/* ---------------------------------------------------------------------- */
/* ====================================================================== */
/* ---------------------------------------------------------------------- */
/* begin general library functions */
/*----------------------------------------------------------------------
*! apply the attr=value GIFTI attribute to the gifti_image
*
* return 0 on success
*//*-------------------------------------------------------------------*/
int gifti_str2attr_gifti(gifti_image * gim, const char *attr, const char *val)
{
if( !gim || !attr || !val ) {
fprintf(stderr,"** GS2AG: bad params (%p,%p,%p)\n",
(void *)gim, (void *)attr, (void *)val);
return 1;
}
if( G.verb > 2 )
fprintf(stderr,"++ setting GIFTI attr '%s' from '%s'\n", attr, val);
if( !strcmp(attr, "Version") ) {
if( gim->version ) free( gim->version ); /* lose any old copy */
gim->version = gifti_strdup(val);
} else if( !strcmp(attr, "NumberOfDataArrays") ) {
gim->numDA = atol(val);
if( gim->numDA < 0 ) {
fprintf(stderr,"** invalid NumberOfDataArrays attribute: %s\n",val);
gim->numDA = 0;
return 1;
}
} else if( !strcmp(attr, "xmlns:xsi") ||
!strcmp(attr, "xsi:noNamespaceSchemaLocation") ) {
if( G.verb > 1 )
fprintf(stderr,"-- have GIFTI attr, '%s'='%s'\n",attr,val);
return 1;
} else {
if( G.verb > 1 )
fprintf(stderr,"** unknown GIFTI attrib, '%s'='%s'\n",attr,val);
return 1;
}
return 0;
}
/*----------------------------------------------------------------------
*! This is the main dataset reading routine. Read a GIFTI dataset
* and return the corresponding gifti_image structure.
*
* Reading data is optional, via the read_data flag.
* User variables should already be set (via accessor functions).
*
* return an allocated gifti_image struct on success,
* NULL on error
*//*-------------------------------------------------------------------*/
gifti_image * gifti_read_image( const char * fname, int read_data )
{
if( !fname ) {
fprintf(stderr,"** gifti_read_image: missing filename\n");
return NULL;
}
gxml_set_verb(G.verb);
return gxml_read_image(fname, read_data, NULL, 0);
}
/*----------------------------------------------------------------------
*! Similar to gifti_read_data, this function also takes an integer list of
* DataArray indices to populate the gifti_image structure with.
*
* The indices are be zero-based, can have repeats and can be in any order.
* A simple example to read 3 DA elements (with 2 repeats) might be:
*
* gifti_image * gim;
* int ilist[5] = { 3, 0, 7, 7, 3 };
* gim = gifti_read_da_list("my_data.gii", 1, ilist, 5);
*
* return an allocated gifti_image struct on success,
* NULL on error
*//*-------------------------------------------------------------------*/
gifti_image * gifti_read_da_list( const char * fname, int read_data,
const int * dalist, int len )
{
if( !fname ) {
fprintf(stderr,"** gifti_read_da_list: missing filename\n");
return NULL;
}
gxml_set_verb(G.verb);
return gxml_read_image(fname, read_data, dalist, len);
}
/*----------------------------------------------------------------------
*! This is the main dataset writing routine.
*
* User variables should be set before this point.
*
* return 0 on success
* 1 on error
*//*-------------------------------------------------------------------*/
int gifti_write_image(gifti_image *gim, const char *fname, int write_data)
{
int errs = 0;
if( !gim ) {
fprintf(stderr,"** gifti_write_image, missing gifti_image\n");
errs++;
} else if( !fname ) {
fprintf(stderr,"** gifti_write_image: missing filename\n");
errs++;
}
if( errs ) return 1;
gxml_set_verb(G.verb);
return gxml_write_image(gim, fname, write_data);
}
/*----------------------------------------------------------------------
*! free the gifti_image struct and all its contents
*
* passing NULL (to this and any child function) should be okay
*
* the pointer is garbage after this call
*//*-------------------------------------------------------------------*/
int gifti_free_image( gifti_image * gim )
{
if( !gim ) {
if(G.verb > 2) fprintf(stderr,"** free gifti_image w/NULL pointer\n");
return 1;
}
if( G.verb > 2 ) fprintf(stderr,"-- freeing gifti_image\n");
if( gim->version ) { free(gim->version); gim->version = NULL; }
(void)gifti_free_nvpairs(&gim->meta);
(void)gifti_free_LabelTable(&gim->labeltable);
(void)gifti_free_DataArray_list(gim->darray, gim->numDA);
(void)gifti_free_nvpairs(&gim->ex_atrs);
free(gim);
return 0;
}
/*----------------------------------------------------------------------
*! free the contents of the gifti_image struct (but not the pointer)
*
* the pointer is garbage after this call
*//*-------------------------------------------------------------------*/
int gifti_free_image_contents( gifti_image * gim )
{
if( !gim ) {
if(G.verb > 2) fprintf(stderr,"** GFIC: free w/NULL gifti_image ptr\n");
return 1;
}
if( G.verb > 2 ) fprintf(stderr,"-- freeing gifti_image contents\n");
if( gim->version ) { free(gim->version); gim->version = NULL; }
(void)gifti_free_nvpairs(&gim->meta);
(void)gifti_free_LabelTable(&gim->labeltable);
(void)gifti_free_DataArray_list(gim->darray, gim->numDA);
(void)gifti_free_nvpairs(&gim->ex_atrs);
return 0;
}
/*----------------------------------------------------------------------
*! free the contents of the nvpairs struct (but not the pointer)
*
* passing NULL is okay
*//*-------------------------------------------------------------------*/
int gifti_free_nvpairs( nvpairs * p )
{
int c;
if( !p ) {
if( G.verb > 3 ) fprintf(stderr,"** free w/NULL nvpairs ptr\n");
return 1;
}
if( G.verb > 3 ) fprintf(stderr,"-- freeing %d nvpairs\n", p->length);
if( p->name && p->value ) {
for( c = 0; c < p->length; c++ ) {
if( p->name[c] ) free(p->name[c]);
if( p->value[c] ) free(p->value[c]);
}
free(p->name);
free(p->value);
p->name = NULL;
p->value = NULL;
}
p->length = 0;
return 0;
}
/*----------------------------------------------------------------------
*! free the contents of the LabelTable struct (but not the pointer)
*
* passing NULL is okay
*//*-------------------------------------------------------------------*/
int gifti_free_LabelTable( giiLabelTable * T )
{
int c;
if( !T ) {
if(G.verb > 3) fprintf(stderr,"** free w/NULL giiLabelTable ptr\n");
return 1;
}
if(G.verb > 3)
fprintf(stderr,"-- freeing %d giiLabelTable entries\n", T->length);
if( T->key && T->label ) {
for( c = 0; c < T->length; c++ )
if( T->label[c] ) free(T->label[c]);
free(T->key);
free(T->label);
T->key = NULL;
T->label = NULL;
}
if( T->rgba ) {
free(T->rgba);
T->rgba = NULL;
}
T->length = 0;
return 0;
}
/*----------------------------------------------------------------------
*! free the DataArray list (the array and all its contents)
*
* the darray list pointer is garbage after this call
*
* passing NULL is okay
*//*-------------------------------------------------------------------*/
int gifti_free_DataArray_list(giiDataArray ** darray, int numDA)
{
int c;
if( !darray ) {
if( G.verb > 3 ) fprintf(stderr,"** GFDA: free NULL darray list\n");
return 1;
}
if( G.verb > 3 ) fprintf(stderr,"-- freeing %d giiDataArrays\n", numDA);
if( numDA < 0 ) return 1;
for( c = 0; c < numDA; c++ )
if( gifti_free_DataArray(darray[c]) ) return 1;
free(darray);
return 0;
}
/*----------------------------------------------------------------------
*! free the DataArray struct and all its contents
*
* the DataArray pointer is garbage after this call
*
* passing NULL is okay
*//*-------------------------------------------------------------------*/
int gifti_free_DataArray( giiDataArray * darray )
{
if( !darray ) {
if( G.verb > 3 ) fprintf(stderr,"** tried to free NULL darray ptr\n");
return 1;
}
if( G.verb > 3 ) fprintf(stderr,"-- freeing giiDataArray\n");
if(darray->ext_fname) { free(darray->ext_fname); darray->ext_fname = NULL; }
(void)gifti_free_nvpairs(&darray->meta);
(void)gifti_free_CS_list(darray);
if( darray->data ) { free(darray->data); darray->data = NULL; }
(void)gifti_free_nvpairs(&darray->ex_atrs);
free(darray);
return 0;
}
/*----------------------------------------------------------------------
*! free the CoordSystem array from a DataArray
* passing NULL is okay
*//*-------------------------------------------------------------------*/
int gifti_free_CS_list( giiDataArray * da )
{
int c;
if( !da ) return 0;
if( G.verb > 3 ) fprintf(stderr,"-- freeing giiCoordSystem list\n");
if( da->coordsys && da->numCS > 0 ) {
for( c = 0; c < da->numCS; c++ )
gifti_free_CoordSystem(da->coordsys[c]);
free(da->coordsys);
}
da->coordsys = NULL;
da->numCS = 0;
return 0;
}
/*----------------------------------------------------------------------
*! free the CoordSystem struct and all its contents
*
* the CoordSystem pointer is garbage after this call
*
* passing NULL is okay
*//*-------------------------------------------------------------------*/
int gifti_free_CoordSystem( giiCoordSystem * cs )
{
if( !cs ) return 0;
if( G.verb > 3 ) fprintf(stderr,"-- freeing giiCoordSystem\n");
if( cs->dataspace ) { free(cs->dataspace); cs->dataspace = NULL; }
if( cs->xformspace ) { free(cs->xformspace); cs->xformspace = NULL; }
free(cs);
return 0;
}
/*----------------------------------------------------------------------
*! initialize an existing DataArray structure given a list of name=value
* attribute pairs
*
* if alen > 0, consider it the length of the attr list
* else process until attr[i] == NULL
*
* if add_to_extras, add any bad attribute pairs to ex_atrs
* else whine about any bad ones and return
*//*-------------------------------------------------------------------*/
int gifti_set_DA_atrs(giiDataArray * da, const char ** attr, int alen,
int add_to_extras )
{
int c, length = alen;
if( !da || !attr ) {
if(G.verb>1) fprintf(stderr,"** G_IDFA: bad params (%p,%p)\n",
(void *)da,(void *)attr);
return 1;
}
/* if length was not passed, compute it */
if( length <= 0 ) for( length = 0; attr[length]; length++ ) /* nada */ ;
if( G.verb > 5 )
fprintf(stderr,"++ init darray attrs, len %d, ex_atrs = %d\n",
length, add_to_extras);
/* insert attributes - if unknown, store with extras */
for(c = 0; c < length; c += 2 )
if( gifti_str2attr_darray(da, attr[c],attr[c+1]) ) {
/* a bad name=value pair, maybe add to ex_atrs */
if( add_to_extras ) {
if( gifti_add_to_nvpairs(&da->ex_atrs,attr[c],attr[c+1]) )
return 1;
}
else {
if( G.verb > 0 )
fprintf(stderr,"** set_darray_atrs, bad pair '%s'='%s'\n",
attr[c],attr[c+1]);
return 1;
}
}
/* and set computed values */
da->nvals = gifti_darray_nvals(da);
gifti_datatype_sizes(da->datatype, &da->nbyper, NULL); /* set nbyper */
return 0;
}
/*----------------------------------------------------------------------
*! determine whether the given DataArray struct seems valid
*
* if whine is set, print error messages for any failures
*
* return 1, if valid
* 0, if not
*//*-------------------------------------------------------------------*/
int gifti_valid_DataArray(const giiDataArray * da, int whine)
{
int errs = 0, nbyper;
if( !da ) {
if( whine || G.verb > 2 ) fprintf(stderr,"** invalid darray pointer\n");
return 0;
}
if( ! gifti_intent_is_valid(da->intent) ) {
if( whine || G.verb > 3 )
fprintf(stderr,"** invalid darray intent code = %d\n", da->intent);
errs++;
}
if( ! gifti_valid_datatype(da->datatype, whine) ) /* message printed */
errs++;
/* no checks for ext_fname and ext_offset (until reading) */
if( da->ind_ord<=GIFTI_IND_ORD_UNDEF || da->ind_ord>GIFTI_IND_ORD_MAX ) {
if( whine || G.verb > 3 )
fprintf(stderr,"** invalid darray ind_ord = %d\n", da->ind_ord);
errs++;
}
if( ! gifti_valid_num_dim(da->num_dim, whine) ) /* message printed */
errs++;
if( ! gifti_valid_dims(da, whine) ) /* message printed */
errs++;
if( da->encoding<=GIFTI_ENCODING_UNDEF || da->encoding>GIFTI_ENCODING_MAX ){
if( whine || G.verb > 3 )
fprintf(stderr,"** invalid darray encoding = %d\n", da->encoding);
errs++;
}
if( da->endian<=GIFTI_ENDIAN_UNDEF || da->endian>GIFTI_ENDIAN_MAX ) {
if( whine || G.verb > 3 )
fprintf(stderr,"** invalid darray endian = %d\n", da->endian);
errs++;
}
/* of sub-element, only verify giiMetaData */
if( ! gifti_valid_nvpairs(&da->meta, whine) ) /* message printed */
errs++;
if( da->nvals <= 0 ) {
if( whine || G.verb > 3 )
fprintf(stderr,"** invalid darray nvals = %u\n",
(unsigned)da->nvals );
errs++;
}
if( ! gifti_valid_nbyper(da->nbyper, whine) ) errs++;
if( ! gifti_valid_nvpairs(&da->ex_atrs, whine) ) errs++;
/* compare nbyper to what is expected for type */
errs += gifti_datatype_sizes(da->datatype, &nbyper, NULL);
if( gifti_valid_nbyper(nbyper, 0) && nbyper != da->nbyper ) {
if( whine || G.verb > 3 )
fprintf(stderr,"** nbyper %d, does not match type %s\n",
nbyper, gifti_datatype2str(da->datatype));
errs++;
}
if( errs ) return 0;
return 1;
}
/*----------------------------------------------------------------------
*! check whether pointers are valid and consistent with length
*//*-------------------------------------------------------------------*/
int gifti_valid_nvpairs(const nvpairs * nvp, int whine)
{
int c;
if( !nvp ) {
if( G.verb>3 || whine ) fprintf(stderr,"** invalid nvpairs pointer\n");
return 0;
}
if( nvp->length < 0 ) {
if( G.verb > 3 || whine )
fprintf(stderr,"** invalid nvpair length = %d\n", nvp->length);
return 0;
}
if( nvp->length == 0 ) return 1; /* quick case: valid */
if( !nvp->name || !nvp->value ){
if( G.verb > 3 || whine )
fprintf(stderr,"** invalid nvpair name, value lists = %p, %p\n",
(void *)nvp->name, (void *)nvp->value);
return 0;
}
/* quit on first error */
for( c = 0; c < nvp->length; c++ ) {
if( ! nvp->name[c] ) {
if( G.verb > 5 || whine )
fprintf(stderr,"** invalid nvpair, missing name @ %d\n", c);
return 0;
}
/* value string is not required 25 Feb 2008 */
if( ! nvp->value[c] && G.verb > 3 )
fprintf(stderr,"-- missing nvpair value[%d], name %s (is OK)\n",
c, nvp->name[c]);
}
return 1;
}
/*----------------------------------------------------------------------
*! check whether pointers are valid and consistent with length
*
* no check is done on the actual indices or labels
*//*-------------------------------------------------------------------*/
int gifti_valid_LabelTable(const giiLabelTable * T, int whine)
{
float * rgba;
int c, c2;
if( !T ) {
if(G.verb>2||whine) fprintf(stderr,"** invalid LabelTable pointer\n");
return 0;
}
if( T->length < 0 ) {
if( G.verb > 3 || whine )
fprintf(stderr,"** invalid LabelTable length = %d\n", T->length);
return 0;
}
if( T->length == 0 ) return 1; /* quick case: valid */
if( !T->key || !T->label ){
if( G.verb > 3 || whine )
fprintf(stderr,"** invalid nvpair key, label = %p, %p\n",
(void *)T->key, (void *)T->label);
return 0;
}
/* quit on first error */
rgba = T->rgba;
for( c = 0; c < T->length; c++ ) {
if( ! T->label[c] ) {
if( G.verb > 3 || whine )
fprintf(stderr,"** invalid nvpair label[%d]\n", c);
return 0;
}
if( rgba ) {
for( c2 = 0; c2 < 4; c2++ )
if( rgba[c2] < 0.0 || rgba[c2] > 1.0 ) {
if( G.verb > 3 || whine )
fprintf(stderr,"** RGBA values out of [0.0,1,0] at "
"Label[%d]\n", c);
return 0;
}
rgba += 4; /* if list exists, go to next set */
}
}
return 1;
}
/*----------------------------------------------------------------------
*! check the bounds on num_dim
*//*-------------------------------------------------------------------*/
int gifti_valid_num_dim(int num_dim, int whine)
{
if( num_dim <= 0 || num_dim > GIFTI_DARRAY_DIM_LEN ) {
if( G.verb > 3 || whine )
fprintf(stderr,"** invalid num_dim = %d\n", num_dim);
return 0;
}
return 1;
}
/*----------------------------------------------------------------------
*! check that the datatype is in the list
*//*-------------------------------------------------------------------*/
int gifti_valid_datatype(int dtype, int whine)
{
int c;
/* check for valid */
for( c = sizeof(gifti_type_list) / sizeof(gifti_type_ele) - 1; c > 0; c-- )
if( dtype == gifti_type_list[c].type ) return 1;
if( whine || G.verb > 3 )
fprintf(stderr,"** invalid datatype value %d\n", dtype);
return 0;
}
/*----------------------------------------------------------------------
*! check that nbyper is one of the values in gifti_type_list
*//*-------------------------------------------------------------------*/
int gifti_valid_nbyper(int nbyper, int whine)
{
int c;
/* check for valid */
for( c = sizeof(gifti_type_list) / sizeof(gifti_type_ele) - 1; c > 0; c-- )
if( nbyper == gifti_type_list[c].nbyper ) return 1;
if( whine || G.verb > 3 )
fprintf(stderr,"** invalid nbyper value %d\n", nbyper);
return 0;
}
/*----------------------------------------------------------------------
*! check that dimension values are consistent (and with datatype)
*
* - num_dim is in range
* - each dims[c] is postive (c < num_dim)
* - nvals is product of dims
* - datatype is valid (required to check nbyper)
* - nbyper is correct
*//*-------------------------------------------------------------------*/
int gifti_valid_dims(const giiDataArray * da, int whine)
{
long long vals = 1;
int c, nbyper;
if( !da ) {
if( G.verb > 2 ) fprintf(stderr,"** GVD: no giiDataArray\n");
return 0;
}
if( ! gifti_valid_num_dim( da->num_dim, whine ) )
return 0;
for( c = 0; c < da->num_dim; c++ ) {
if( da->dims[c] <= 0 ) {
if( G.verb > 3 || whine )
fprintf(stderr,"** invalid dims[%d] = %d\n", c, da->dims[c]);
return 0;
}
vals *= da->dims[c];
}
/* verify computed vals and nbyper against stored ones */
if( vals != da->nvals ) {
if( G.verb > 3 ) {
fprintf(stderr,"** nvals = %lld does not match %lld for dims[%d]: ",
da->nvals, vals, da->num_dim);
gifti_disp_raw_data(da->dims, DT_INT32, da->num_dim, 1, stderr);
}
return 0;
}
gifti_datatype_sizes(da->datatype, &nbyper, NULL);
if( nbyper != da->nbyper ) {
fprintf(stderr,"** nbyper %d not correct for type %s\n",
da->nbyper, gifti_datatype2str(da->datatype));
return 0;
}
/* verify that num_dim is not too big, the most significant dimension
* is not allowed to be 1
* (requested by N Schmansky) 11 Mar 2010 */
if( da->num_dim > 1 && da->dims[da->num_dim-1] < 2 && whine ) {
fprintf(stderr,"** num_dim violation: num_dim = %d, yet dim[%d] = %d\n",
da->num_dim, da->num_dim-1, da->dims[da->num_dim-1]);
/* now FS is writing these in mris_convert, grrrr... 15 Jun 2012 */
/* return 0; */
}
return 1;
}
/*----------------------------------------------------------------------
*! set the DataArray attribute, based on the name=value string pair
*
* return 0 on success
* 1 on error
*//*-------------------------------------------------------------------*/
int gifti_str2attr_darray(giiDataArray * DA, const char *attr,
const char *value)
{
if( !DA || !attr || !value ) {
if( G.verb > 0 )
fprintf(stderr,"** G_S2A_D: bad params (%p,%p,%p)\n",
(void *)DA, (void *)attr, (void *)value);
return 1;
}
if(G.verb > 3) fprintf(stderr,"++ setting DA attr '%s'='%s'\n",attr,value);
if( !strcmp(attr, "Intent") )
DA->intent = gifti_intent_from_string(value);
else if( !strcmp(attr, "DataType") )
DA->datatype = gifti_str2datatype(value);
else if( !strcmp(attr, "ArrayIndexingOrder") )
DA->ind_ord = gifti_str2ind_ord(value);
else if( !strcmp(attr, "Dimensionality") ) DA->num_dim = atoi(value);
else if( !strcmp(attr, "Dim0") ) DA->dims[0] = atoi(value);
else if( !strcmp(attr, "Dim1") ) DA->dims[1] = atoi(value);
else if( !strcmp(attr, "Dim2") ) DA->dims[2] = atoi(value);
else if( !strcmp(attr, "Dim3") ) DA->dims[3] = atoi(value);
else if( !strcmp(attr, "Dim4") ) DA->dims[4] = atoi(value);
else if( !strcmp(attr, "Dim5") ) DA->dims[5] = atoi(value);
else if( !strcmp(attr, "Encoding") )
DA->encoding = gifti_str2encoding(value);
else if( !strcmp(attr, "Endian") )
DA->endian = gifti_str2endian(value);
else if( !strcmp(attr, "ExternalFileName") )
DA->ext_fname = gifti_strdup(value);
else if( !strcmp(attr, "ExternalFileOffset") )
DA->ext_offset = atoll(value); /* assumes C99 */