gifticlib-1.0.9/0000755007023700001440000000000011412212735012512 5ustar rickrusersgifticlib-1.0.9/gifti.test.io0000755007023700001440000000345211012356763015140 0ustar rickrusers#!/bin/tcsh # either include the names of the gifti files on the command line, # or be sitting in the directory with them set skip_ts = 0 set prog = gifti_tool # was gifti_test # if the user specifies -nots, skip the time series dataset set narg = $#argv set base = 1 set gt_comp = 0 if ( $narg >= 1 ) then if ( "$argv[1]" == "-help" ) then echo "usage: gifti.test.io [-nots] [-gt_compare] [files...]" echo "" echo "option:" echo " -nots : do not process *time_series*.gii" echo "" echo "examples:" echo " gifti.test.io" echo " gifti.test.io *.gii" echo " gifti.test.io -nots" echo " gifti.test.io -nots *.gii" exit else if ( "$argv[1]" == "-gt_compare" ) then @ narg -- @ base ++ set gt_comp = 1 else if ( "$argv[1]" == "-nots" ) then @ narg -- @ base ++ set skip_ts = 1 endif endif echo using `which $prog` ... if ( $narg >= 1 ) then set files = ( $argv[$base-] ) else echo applying default gifti files... set files = ( gifti.*.gii ) endif echo "" foreach file ( $files ) echo -n "$file : " if ( $skip_ts && "$file" =~ *time_series*.gii ) then echo "skipping ..." continue endif $prog -infile $file -no_updates -write_gifti new.gii if( $status ) then echo "** FAILURE : $prog -infile $file -no_updates -write_gifti new.gii" else if ( $gt_comp ) then gifti_tool -compare_gifti -compare_data -infiles $file new.gii \ >& /dev/null set result = $status if ( $result ) echo '** differs **' else cmp $file new.gii set result = $status endif if( ! $result ) echo okay endif end gifticlib-1.0.9/CMakeLists.txt0000644007023700001440000000565611412211052015255 0ustar rickrusers# This project is designed to be built outside the source tree. # File generated by Simon K. Warfield simon.warfield@childrens.harvard.edu # with support from NIH grant RR021885. PROJECT(gifticlib) cmake_minimum_required(VERSION 2.6) # install destinations SET(GIFTI_INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin") SET(GIFTI_INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") SET(GIFTI_INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include/gifti") FIND_PACKAGE(ITK) IF(ITK_FOUND) # ITK provides expat and zlib. INCLUDE(${ITK_USE_FILE}) SET(EXPAT_LIBRARIES ITKEXPAT) SET(ZLIB_LIBRARIES ITKznz) SET(NIFTI_LIBRARIES ITKniftiio) ELSE(ITK_FOUND) # Otherwise, get it from elsewhere. FIND_PACKAGE(EXPAT) FIND_PACKAGE(ZLIB) FIND_LIBRARY(NIFTI_LIBRARY NAMES niftiio PATH /usr/local/nifti/lib ) SET(NIFTI_LIBRARIES ${NIFTI_LIBRARY} znz m) FIND_PATH(NIFTI_INCLUDE_DIR nifti1.h /usr/local/nifti/include/nifti /usr/include/nifti) GET_FILENAME_COMPONENT(GIFTI_LINK_DIRECTORIES ${NIFTI_LIBRARY} PATH) LINK_DIRECTORIES(${GIFTI_LINK_DIRECTORIES}) INCLUDE_DIRECTORIES(${NIFTI_INCLUDE_DIR}) ENDIF(ITK_FOUND) # shared library API versioning -- NOT the same as the release version SET(GIFTI_SHAREDLIB_VERSION "0.0.0") STRING( REGEX MATCH "^[0-9]+" GIFTI_SHAREDLIB_SOVERSION ${GIFTI_SHAREDLIB_VERSION}) SET(GIFTI_LIBRARY_PROPERTIES VERSION ${GIFTI_SHAREDLIB_VERSION} SOVERSION ${GIFTI_SHAREDLIB_SOVERSION}) IF(ZLIB_FOUND) ADD_DEFINITIONS(-DHAVE_ZLIB) ENDIF(ZLIB_FOUND) INCLUDE_DIRECTORIES( ${CRKIT_SOURCE_DIR}/External ${gifticlib_SOURCE_DIR} ${gifticlib_BINARY_DIR} ) SET(GIFTIIO_SRC gifti_io.c gifti_xml.c) # shared version ADD_LIBRARY(giftiio SHARED ${GIFTIIO_SRC}) # Set library version when building shared libs. SET_TARGET_PROPERTIES(giftiio PROPERTIES ${GIFTI_LIBRARY_PROPERTIES}) TARGET_LINK_LIBRARIES(giftiio ${EXPAT_LIBRARIES} ${NIFTI_LIBRARIES}) IF(ZLIB_FOUND) TARGET_LINK_LIBRARIES(giftiio ${ZLIB_LIBRARIES}) ENDIF(ZLIB_FOUND) # static version ADD_LIBRARY(giftiio_static STATIC ${GIFTIIO_SRC}) #The library target "via_static" has a default OUTPUT_NAME of "via_static", can be changed with SET_TARGET_PROPERTIES(giftiio_static PROPERTIES ${GIFTI_LIBRARY_PROPERTIES} OUTPUT_NAME "giftiio") LINK_DIRECTORIES(${gifticlib_BINARY_DIR}) ADD_EXECUTABLE(gifti_tool gifti_tool.c) TARGET_LINK_LIBRARIES(gifti_tool giftiio ${EXPAT_LIBRARIES} ${ZLIB_LIBRARIES} ${NIFTI_LIBRARIES}) ADD_EXECUTABLE(gifti_test gifti_test.c) TARGET_LINK_LIBRARIES(gifti_test giftiio ${EXPAT_LIBRARIES} ${ZLIB_LIBRARIES} ${NIFTI_LIBRARIES}) # binaries INSTALL(TARGETS giftiio giftiio_static gifti_tool gifti_test RUNTIME DESTINATION ${GIFTI_INSTALL_BIN_DIR} COMPONENT RuntimeLibraries LIBRARY DESTINATION ${GIFTI_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${GIFTI_INSTALL_LIB_DIR} COMPONENT Development) # headers INSTALL(FILES gifti_io.h gifti_xml.h DESTINATION ${GIFTI_INSTALL_INCLUDE_DIR} COMPONENT Development) gifticlib-1.0.9/gifti_tool.c0000644007023700001440000023225311314734712015031 0ustar rickrusers #include #include #include #include "gifti_io.h" #include "gifti_tool.h" static char * g_history[] = { "----------------------------------------------------------------------\n" "history (of gifti_tool):\n" "\n", "0.0 28 Dec, 2007\n" " (Rick Reynolds of the National Institutes of Health, SSCC/DIRP/NIMH)\n" " - initial version\n" "0.1 03 Jan, 2008: changed structure of program\n", " - can do one of display, write or test (more to come)\n" " - added dset creation ability and options, via -new_dset or MAKE_IM\n" " (options -new_*, for numDA, intent, dtype, ndim, dims, data)\n" " - added AFNI-style DA selection, for input datasets\n" "0.2 11 Jan, 2008: added modification functionality\n", " - added option -gifti_dtd_url\n" " - added options -mod_DAs and -read_DAs (replaced -dalist)\n" " - added options -mod_add_data, -mod_DA_atr, -mod_DA_meta,\n" " -mod_gim_atr, -mod_gim_meta\n" " (modification takes place at dataset read time)\n" " - reformatted help output\n" "0.3 16 Jan, 2008:\n", " - added options -gifti_zlib, -gifti_test, -mod_to_float, -no_updates\n" "0.4 18 Mar, 2008: added comparison options\n", " - added -compare_gifti, -compare_data, -compare_verb\n" "0.5 24 Mar, 2008: -compare_data is now separate from -compare_gifti\n", "0.6 28 Mar, 2008: added copy meta options:\n", " - added -copy_gifti_meta, -copy_DA_meta\n" "1.0 13 May, 2008: based on release library version 1.0\n", " - added -set_extern_filelist\n" "1.1 02 Oct, 2008: mention NITRC web site in help\n" "1.2 17 Apr, 2009: added -set_extern_filelist help and more examples\n", "1.3 24 Dec, 2009: added -approx_gifti option\n" }; static char g_version[] = "gifti_tool version 1.3, 24 December 2009"; /* globals: verbosity, for now */ typedef struct { int verb; } gt_globs; gt_globs G = { 1 }; /* local prototypes */ static int add_to_int_list(gt_int_list * ilist, int val); static int add_to_str_list(gt_str_list * slist, char * str); static int disp_gt_opts(char * mesg, gt_opts * opts, FILE * stream); static int free_gt_opts(gt_opts * opts); static int init_opts(gt_opts * opts); static int show_help(void); static int show_hist(void); static int show_str_list(const char * mesg, gt_str_list * list, FILE * fp); static int process_opts(int argc, char *argv[], gt_opts * opts); static int show_version(void); /* the main event */ int main( int argc, char * argv[] ) { gt_opts opts; int rv = 0; init_opts(&opts); rv = process_opts(argc, argv, &opts); if ( rv < 0 ) return 1; /* non-zero means terminate */ else if ( rv > 0 ) return 0; /* choose top-level operation to perform */ if ( opts.gt_display ) rv = gt_display(&opts); else if( opts.gt_compare ) rv = gt_compare(&opts); else if( opts.gt_copy ) rv = gt_copy(&opts); else if( opts.gt_write ) rv = gt_write(&opts); else rv = gt_test(&opts); free_gt_opts(&opts); return rv; } /* process the user options * * return 1 : success, but exit program * 0 : success, continue * -1 : failure, terminate */ static int process_opts(int argc, char *argv[], gt_opts * opts) { int ac, c; if( argc <= 1 ) { show_help(); return 1; } for( ac = 1; ac < argc; ac++ ) { /* terminal options, verbose, then alphabetical */ if( !strcmp(argv[ac], "-help") ) { show_help(); return 1; } else if( !strcmp(argv[ac], "-hist") ) { show_hist(); return 1; } else if( !strcmp(argv[ac], "-ver") ) { show_version(); return 1; } else if( !strcmp(argv[ac], "-gifti_dtd_url") ) { gifti_disp_dtd_url(); return 1; } else if( !strcmp(argv[ac], "-gifti_hist") ) { gifti_disp_lib_hist(); return 1; } else if( !strcmp(argv[ac], "-gifti_ver") ) { gifti_disp_lib_version(); return 1; } else if( !strcmp(argv[ac], "-gifti_zlib") ) { printf("library compiled %s ZLIB\n", GIFTI_COMP_WITH_ZLIB ? "with" : "without"); return 1; } /* do this early, in case it is wanted for other options */ else if( !strcmp(argv[ac], "-verb") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-verb"); opts->verb = atoi(argv[ac]); G.verb = opts->verb; } /* now alphabetical */ else if( !strcmp(argv[ac], "-approx_gifti") ) { opts->approx_gifti = 1; opts->gt_compare = 1; } else if( !strcmp(argv[ac], "-b64_check") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-b64_check"); if ( !strcmp(argv[ac], "NONE" ) ) opts->b64_check = GIFTI_B64_CHECK_NONE; else if( !strcmp(argv[ac], "DETECT") ) opts->b64_check = GIFTI_B64_CHECK_DETECT; else if( !strcmp(argv[ac], "COUNT") ) opts->b64_check = GIFTI_B64_CHECK_COUNT; else if( !strcmp(argv[ac], "SKIP" ) ) opts->b64_check = GIFTI_B64_CHECK_SKIP; else if( !strcmp(argv[ac], "SKIPnCOUNT" ) ) opts->b64_check = GIFTI_B64_CHECK_SKIPNCOUNT; else { fprintf(stderr,"** invalid parm to -b64_check: %s\n",argv[ac]); return -1; } } else if( !strcmp(argv[ac], "-buf_size") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-buf_size"); opts->buf_size = atoi(argv[ac]); /* compare options */ } else if( !strcmp(argv[ac], "-compare_data") ) { opts->comp_data = 1; opts->gt_compare = 1; } else if( !strcmp(argv[ac], "-compare_gifti") ) { opts->comp_gifti = 1; opts->gt_compare = 1; } else if( !strcmp(argv[ac], "-compare_verb") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-compare_verb"); opts->comp_verb = atoi(argv[ac]); /* copy options */ } else if( !strcmp(argv[ac], "-copy_gifti_meta") ) { opts->copy_gim_meta = 1; ac++; CHECK_NEXT_OPT(ac, argc, "-copy_gifti_meta"); if( add_to_str_list(&opts->gim_meta, argv[ac] ) ) return -1; } else if( !strcmp(argv[ac], "-copy_DA_meta") ) { opts->copy_DA_meta = 1; ac++; CHECK_NEXT_OPT(ac, argc, "-copy_DA_meta"); if( add_to_str_list(&opts->DA_meta, argv[ac] ) ) return -1; } else if( !strcmp(argv[ac], "-DA_index_list") ) { ac++; for( c = 0; (ac < argc) && (argv[ac][0] != '-'); ac++, c++ ) if( add_to_int_list(&opts->DAlist, atoi(argv[ac])) ) return -1; if( G.verb > 1 ) fprintf(stderr,"+d have %d DA indices\n", c); if( opts->DAlist.len == 0 ) { fprintf(stderr,"** no DA indices with -DA_index_list'\n"); return -1; } /* and back up if we've looked too far */ if( ac < argc && argv[ac][0] == '-') ac--; } else if( !strcmp(argv[ac], "-encoding") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-encoding"); if ( !strcmp(argv[ac], "ASCII" ) ) opts->encoding = GIFTI_ENCODING_ASCII; else if( !strcmp(argv[ac], "BASE64") ) opts->encoding = GIFTI_ENCODING_B64BIN; else if( !strcmp(argv[ac], "BASE64GZIP") ) opts->encoding = GIFTI_ENCODING_B64GZ; else { fprintf(stderr,"** invalid parm to -encoding: %s\n",argv[ac]); return -1; } } else if( !strcmp(argv[ac], "-gifti_test") ) { opts->gt_test = 1; } else if( !strcmp(argv[ac], "-indent") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-indent"); opts->indent = atoi(argv[ac]); } else if( !strncmp(argv[ac], "-infile", 7) ) { /* maybe infiles... */ ac++; for( c = 0; (ac < argc) && (argv[ac][0] != '-'); ac++, c++ ) if( add_to_str_list(&opts->infiles, argv[ac]) ) return -1; if( G.verb > 1 ) fprintf(stderr,"+d have %d infile names\n", c); if( opts->infiles.len == 0 ) { fprintf(stderr,"** no filenames with '-infiles'\n"); return -1; } /* and back up if we've looked too far */ if( ac < argc && argv[ac][0] == '-') ac--; } else if( !strcmp(argv[ac], "-mod_add_data") ) { opts->mod_add_data = 1; } else if( !strcmp(argv[ac], "-mod_DA_atr") ) { opts->mod_DA_atr = 1; ac++; if( ac > argc-2 || argv[ac][0] == '-' || argv[ac+1][0] == '-' ) { fprintf(stderr,"** option -mod_DA_atr requires 2 arguments\n"); return -1; } if( add_to_str_list(&opts->DA_atrs, argv[ac] ) || add_to_str_list(&opts->DA_atrs, argv[ac+1] ) ) return -1; ac++; /* and consume last arg */ } else if( !strcmp(argv[ac], "-mod_DA_meta") ) { opts->mod_DA_meta = 1; ac++; if( ac > argc-2 || argv[ac][0] == '-' || argv[ac+1][0] == '-' ) { fprintf(stderr,"** option -mod_DA_meta requires 2 arguments\n"); return -1; } if( add_to_str_list(&opts->DA_meta, argv[ac] ) || add_to_str_list(&opts->DA_meta, argv[ac+1] ) ) return -1; ac++; /* and consume last arg */ } else if( !strcmp(argv[ac], "-mod_DAs") ) { ac++; for( c = 0; (ac < argc) && (argv[ac][0] != '-'); ac++, c++ ) if(add_to_int_list(&opts->DAmodlist, atoi(argv[ac]))) return -1; if( G.verb > 1 ) fprintf(stderr,"+d have %d DA mod indices\n", c); if( opts->DAmodlist.len == 0 ) { fprintf(stderr,"** no DA indices with '-mod_DAs'\n"); return -1; } /* and back up if we've looked too far */ if( ac < argc && argv[ac][0] == '-') ac--; } else if( !strcmp(argv[ac], "-mod_gim_atr") ) { opts->mod_gim_atr = 1; ac++; if( ac > argc-2 || argv[ac][0] == '-' || argv[ac+1][0] == '-' ) { fprintf(stderr,"** option -mod_gim_atr requires 2 args\n"); return -1; } if( add_to_str_list(&opts->gim_atrs, argv[ac] ) || add_to_str_list(&opts->gim_atrs, argv[ac+1] ) ) return -1; ac++; /* and consume last arg */ } else if( !strcmp(argv[ac], "-mod_gim_meta") ) { opts->mod_gim_meta = 1; ac++; if( ac > argc-2 || argv[ac][0] == '-' || argv[ac+1][0] == '-' ) { fprintf(stderr,"** option -mod_gim_meta requires 2 args\n"); return -1; } if( add_to_str_list(&opts->gim_meta, argv[ac] ) || add_to_str_list(&opts->gim_meta, argv[ac+1] ) ) return -1; ac++; /* and consume last arg */ } else if( !strcmp(argv[ac], "-mod_to_float") ) { opts->mod_to_float = 1; } else if( !strcmp(argv[ac], "-new_dset") ) { if( add_to_str_list(&opts->infiles, "MAKE_IM") ) return -1; } else if( !strcmp(argv[ac], "-new_numDA") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-new_numDA"); opts->new_numDA = atol(argv[ac]); } else if( !strcmp(argv[ac], "-new_intent") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-new_intent"); opts->new_intent = gifti_intent_from_string(argv[ac]); if( !gifti_intent_is_valid(opts->new_intent) ) { fprintf(stderr,"** invalid intent '%s'\n",argv[ac]); return -1; } } else if( !strcmp(argv[ac], "-new_dtype") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-new_dtype"); opts->new_dtype = gifti_str2datatype(argv[ac]); if( opts->new_dtype == DT_UNKNOWN ) { fprintf(stderr,"** invalid datatype '%s'\n",argv[ac]); return -1; } } else if( !strcmp(argv[ac], "-new_ndim") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-new_ndim"); opts->new_ndim = atol(argv[ac]); } else if( !strcmp(argv[ac], "-new_dims") ) { ac++; for( c = 0; ac < argc && c < GIFTI_DARRAY_DIM_LEN && argv[ac][0] != '-'; ac++, c++ ) opts->new_dims[c] = atol(argv[ac]); if( c < GIFTI_DARRAY_DIM_LEN ) { fprintf(stderr, "** -new_dims have only %d of %d dims\n", c, GIFTI_DARRAY_DIM_LEN); return -1; } ac--; /* You've gone too far, go to your room! */ } else if( !strcmp(argv[ac], "-new_data") ) { opts->new_data = 1; } else if( !strcmp(argv[ac], "-no_data") ) { opts->dstore = 0; } else if( !strcmp(argv[ac], "-no_updates") ) { opts->update_ok = 0; } else if( !strcmp(argv[ac], "-read_DAs") ) { ac++; for( c = 0; (ac < argc) && (argv[ac][0] != '-'); ac++, c++ ) if( add_to_int_list(&opts->DAlistr, atoi(argv[ac])) ) return -1; if( G.verb > 1 ) fprintf(stderr,"+d have %d DA indices names\n", c); if( opts->DAlistr.len == 0 ) { fprintf(stderr,"** no DA indices with -read_DAs'\n"); return -1; } /* and back up if we've looked too far */ if( ac < argc && argv[ac][0] == '-') ac--; } else if( !strcmp(argv[ac], "-set_extern_filelist") ) { opts->set_extern = 1; ac++; for( c = 0; (ac < argc) && (argv[ac][0] != '-'); ac++, c++ ) if( add_to_str_list(&opts->ext_files, argv[ac]) ) return -1; if( G.verb > 1 ) fprintf(stderr,"+d have %d external files\n", c); if( opts->ext_files.len == 0 ) { fprintf(stderr, "** no external files with -set_extern_filelist\n"); return -1; } /* and back up if we've looked too far */ if( ac < argc && argv[ac][0] == '-') ac--; } else if( !strcmp(argv[ac], "-show_gifti") ) { opts->gt_display = 1; opts->show_gifti = 1; } else if( !strcmp(argv[ac], "-write_1D") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-write_1D"); opts->ofile_1D = argv[ac]; } else if( !strcmp(argv[ac], "-write_asc") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-write_asc"); opts->ofile_asc = argv[ac]; } else if( !strcmp(argv[ac], "-write_gifti") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-write_gifti"); opts->ofile_gifti = argv[ac]; } else if( !strcmp(argv[ac], "-zlevel") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-zlevel"); opts->zlevel = atoi(argv[ac]); } else { fprintf(stderr,"** unknown option: '%s'\n",argv[ac]); return 1; } } /* flat whether we are modifying input data */ opts->gt_modify = opts->mod_add_data || opts->mod_gim_atr || opts->mod_gim_meta || opts->mod_DA_atr || opts->mod_DA_meta || opts->mod_to_float; /* flag whether we have a copying operation */ opts->gt_copy = opts->copy_gim_meta || opts->copy_DA_meta; /* flag whether we have a general write operation (only if not copying) */ if( !opts->gt_copy ) opts->gt_write = opts->ofile_1D || opts->ofile_asc || opts->ofile_gifti; if( G.verb > 3 ) disp_gt_opts("options read: ", opts, stderr); /* be sure we have something to read */ if( opts->infiles.len <= 0 ) { fprintf(stderr,"** missing option: -infiles\n"); return 1; } /* only allow one major operation per program execution */ c = opts->gt_compare + opts->gt_copy + opts->gt_display + opts->gt_write; if( c == 0 ) opts->gt_test = 1; else if( c > 1 ) { fprintf(stderr,"** only 1 major operation allowed, have %d\n", c); return 1; } if( opts->gt_copy && opts->gt_modify ) { fprintf(stderr,"** cannot mix copy and modify options\n"); return 1; } /* apply any XML user options * (non-zero defaults: verb, zlevel -1) */ if( opts->verb != 1 ) gifti_set_verb(opts->verb); if( opts->indent != -1 ) gifti_set_indent(opts->indent); if( opts->buf_size ) gifti_set_xml_buf_size(opts->buf_size); if( opts->b64_check ) gifti_set_b64_check(opts->b64_check); if( opts->update_ok != -1 ) gifti_set_update_ok(opts->update_ok); if( opts->zlevel != -1 ) gifti_set_zlevel(opts->zlevel); return 0; } static int free_gt_opts(gt_opts * opts) { if( opts->DAlist.len > 0 && opts->DAlist.list ) free(opts->DAlist.list); if( opts->DAlistr.len > 0 && opts->DAlistr.list ) free(opts->DAlistr.list); if( opts->DAmodlist.len>0&&opts->DAmodlist.list) free(opts->DAmodlist.list); if( opts->gim_atrs.len>0 && opts->gim_atrs.list ) free(opts->gim_atrs.list); if( opts->gim_meta.len>0 && opts->gim_meta.list ) free(opts->gim_meta.list); if( opts->DA_atrs.len > 0 && opts->DA_atrs.list ) free(opts->DA_atrs.list); if( opts->DA_meta.len > 0 && opts->DA_meta.list ) free(opts->DA_meta.list); if( opts->infiles.len > 0 && opts->infiles.list ) free(opts->infiles.list); opts->DAlist.len = 0; opts->DAlist.list = NULL; opts->DAlistr.len = 0; opts->DAlistr.list = NULL; opts->DAmodlist.len = 0; opts->DAmodlist.list = NULL; opts->gim_atrs.len = 0; opts->gim_atrs.list = NULL; opts->gim_meta.len = 0; opts->gim_meta.list = NULL; opts->DA_atrs.len = 0; opts->DA_atrs.list = NULL; opts->DA_meta.len = 0; opts->DA_meta.list = NULL; opts->infiles.len = 0; opts->infiles.list = NULL; return 0; } int gt_display(gt_opts * opts) { gifti_image * gim; int c, rv = 0; if( opts->infiles.len < 1 ) { fprintf(stderr,"** no datasets to display\n"); return 1; } /* just display any dataset for now */ opts->show_gifti = 1; for( c = 0; c < opts->infiles.len; c++ ) { gim = gt_read_dataset(opts, opts->infiles.list[c]); if( !gim ) { fprintf(stderr,"** gt_display: failed to read '%s'\n", opts->infiles.list[c]); rv = 1; } else gifti_free_image(gim); } return rv; } /* compare gifti structures and/or included data */ int gt_compare(gt_opts * opts) { gifti_image * gimA; gifti_image * gimB; int rv0 = 0, rv1 = 0; if( opts->infiles.len != 2 ) { fprintf(stderr,"** must have exactly 2 gifti_images files to test\n"); return 1; } gimA = gt_read_dataset(opts, opts->infiles.list[0]); gimB = gt_read_dataset(opts, opts->infiles.list[1]); if( !gimA || !gimB ) { /* if failure, make no comparison */ gifti_free_image(gimA); gifti_free_image(gimB); return -1; } if( opts->comp_gifti || opts->comp_data ) { if( opts->comp_gifti ) { rv0 = gifti_compare_gifti_images(gimA, gimB, 0, opts->comp_verb); if( !rv0 && opts->comp_verb > 0 ) printf("++ no differences between gifti_images\n"); } if( opts->comp_data ) { rv1 = gifti_compare_gifti_data(gimA, gimB, opts->comp_verb); if( !rv1 && opts->comp_verb > 0 ) printf("++ no data differences between gifti_images\n"); } rv0 |= rv1; } if( opts->approx_gifti ) { /* return value of approx is opposite that of compare */ rv0 = gifti_approx_gifti_images(gimA, gimB, 1, opts->comp_verb); if( rv0 && opts->comp_verb > 0 ) printf("++ gifti_images are approximately equal\n"); rv0 = !rv0; /* invert return value for exit status */ } gifti_free_image(gimA); gifti_free_image(gimB); return rv0; } /* copy MetaData between GIFTI elements or some DataArray elements */ int gt_copy(gt_opts * opts) { gifti_image * src; gifti_image * dest; char ** names; int c, rv = 0; if( opts->infiles.len != 2 ) { fprintf(stderr,"** copy operation requires exactly 2 gifti_images\n"); return 1; } if( !opts->ofile_gifti ) { fprintf(stderr,"** missing output filename for copy operation\n"); return 1; } src = gt_read_dataset(opts, opts->infiles.list[0]); dest = gt_read_dataset(opts, opts->infiles.list[1]); /* if we fail to read or the metadata is not valid, bail */ if( !src || !dest || !gifti_valid_nvpairs(&src->meta, 1) || !gifti_valid_nvpairs(&dest->meta, 1) ) { gifti_free_image(src); gifti_free_image(dest); return -1; } /* first go for GIFTI meta */ if(opts->copy_gim_meta) { /* if ALL, copy everything, else get what's in the list */ if(opts->gim_meta.len==1 && !strcmp(opts->gim_meta.list[0],"ALL")) { names = src->meta.name; for( c = 0; c < src->meta.length; c++ ) rv |= gifti_copy_gifti_meta(dest, src, names[c]); } else { names = opts->gim_meta.list; for( c = 0; c < opts->gim_meta.len; c++ ) rv |= gifti_copy_gifti_meta(dest,src,names[c]); } } if(opts->copy_DA_meta) { /* if ALL, copy everything, else get what's in the list */ if(opts->DA_meta.len==1 && !strcmp(opts->DA_meta.list[0],"ALL")) { if(src->numDA != dest->numDA || src->numDA <= 0) { fprintf(stderr,"** bad numDA for DA MD copy, %d, %d\n", src->numDA, dest->numDA); rv = 1; } else if(!src->darray || !dest->darray) { fprintf(stderr,"** invalid darray pointers for copy\n"); rv = 1; } else { /* all seems well, copy all meta from src to dest */ for( c = 0; c < src->numDA; c++ ) rv |= gifti_copy_all_DA_meta(dest->darray[c], src->darray[c]); } } else { names = opts->DA_meta.list; for( c = 0; c < opts->DA_meta.len; c++ ) rv |= gifti_copy_DA_meta_many(dest, src, names[c], opts->DAlist.list, opts->DAlist.len); } } gt_write_dataset(opts, dest); gifti_free_image(src); gifti_free_image(dest); return rv; } int gt_test(gt_opts * opts) { gifti_image * gim; int c, rv = 0; if( opts->infiles.len < 1 ) { fprintf(stderr,"** no datasets to test\n"); return 1; } /* add more test later, now we just try to read */ for( c = 0; c < opts->infiles.len; c++ ) { gim = gt_read_dataset(opts, opts->infiles.list[c]); if( !gim ) { fprintf(stderr,"** gt_test: failed to read '%s'\n", opts->infiles.list[c]); rv = 1; } else gifti_free_image(gim); } return rv; } /* output is desired, one of: * * - GIFTI dataset * - 1D file as text data * - .asc file, as a FreeSurfer style geometry dataset * * input: there can be only one (immortal? Sean Connery?) */ int gt_write(gt_opts * opts) { gifti_image * gim; int rv; if( opts->infiles.len > 1 ) { fprintf(stderr,"** when writing, only one input dataset is allowed\n"); return 1; } /* actually read the dataset */ gim = gt_read_dataset(opts, opts->infiles.list[0]); if( !gim ){ fprintf(stderr,"** failed gifti_read_da_list()\n"); return 1; } rv = gt_write_dataset(opts, gim); /* clean up */ gifti_free_image(gim); gim = NULL; return rv; } /* apply encoding, and allow other formats */ int gt_write_dataset(gt_opts * opts, gifti_image * gim) { int c; if(!gim) { if(opts->verb) fprintf(stderr,"** trying to write NULL dataset\n"); return 1; } if(opts->verb > 1) fprintf(stderr,"++ gt_write_dataset: gim %s, 1D %s, asc %s\n", G_CHECK_NULL_STR(opts->ofile_gifti), G_CHECK_NULL_STR(opts->ofile_1D), G_CHECK_NULL_STR(opts->ofile_asc)); /* possibly adjust encoding */ if(opts->encoding > GIFTI_ENCODING_UNDEF && opts->encoding <= GIFTI_ENCODING_MAX) for( c = 0; c < gim->numDA; c++ ) { /* when modifying enconding, if we are changing _from_ external, then clear the external filename and offset */ if(gim->darray[c]->encoding == GIFTI_ENCODING_EXTBIN && opts->encoding != GIFTI_ENCODING_EXTBIN) { if(gim->darray[c]->ext_fname) { if(opts->verb>2) fprintf(stderr,"-- deleting ext_fname\n"); free(gim->darray[c]->ext_fname); gim->darray[c]->ext_fname = NULL; } gim->darray[c]->ext_offset = 0; } /* actually make the user-requested change */ if( gim->darray[c]->encoding ) gim->darray[c]->encoding = opts->encoding; } if(opts->ofile_gifti) { /* maybe user wants to point to external files */ if(opts->set_extern) { if(opts->ext_files.len <= 0 || !opts->ext_files.list) { fprintf(stderr,"** no file list to set as external\n"); return 1; } if(gifti_set_extern_filelist(gim, opts->ext_files.len, opts->ext_files.list)) return 1; } gifti_write_image(gim,opts->ofile_gifti,opts->dstore); } if(opts->ofile_1D) write_1D_file(gim->darray,gim->numDA,opts->ofile_1D,1); if(opts->ofile_asc) write_as_asc(gim, opts->ofile_asc); return 0; } /* read one GIFTI dataset * * The default is to just call gifti_read_da_list(), but... * if name == MAKE_IM : create a new dataset * else if we have name : read one dataset * * Note that name may have the form dset[int list], where the integer * list is used to create the DataArray list. * * e.g. dset.gii[5..12(3),0,$] * * this would select DA elements 5,8,11,0,numDA-1 * * Note that the DA list selection requires reading the dataset twice, * first to compute the number of DA elements. */ gifti_image * gt_read_dataset(gt_opts * opts, char * fname) { gifti_image * gim; char * fcopy = NULL, * iptr, * infile = fname; int * dalist = NULL, numDA = -1; if( !fname || !*fname ) { fprintf(stderr,"** gt_read_dataset: no filename to read\n"); return NULL; } /* first case, create a new image (fname == MAKE_IM) */ if( !strcmp(fname, "MAKE_IM") ) { if( opts->verb > 1 ) fprintf(stderr,"++ creating new GIFTI dataset\n"); gim = gifti_create_image(opts->new_numDA, opts->new_intent, opts->new_dtype, opts->new_ndim, opts->new_dims, opts->new_data); if( opts->gt_modify && gt_modify_dset(opts, gim) ) { if( opts->verb > 1 ) fprintf(stderr,"** bad modification to new dset, failing...\n"); gifti_free_image(gim); return NULL; } if( opts->show_gifti ) gifti_disp_gifti_image("dset MAKE_IM :",gim,1); return gim; } /* otherwise, see if there is an int list, before using gifti_read */ if( strchr(fname, '[') ) { /* then create an int list */ fcopy = gifti_strdup(fname); infile = fcopy; /* store for later */ iptr = strchr(fcopy, '['); if(opts->verb>2) fprintf(stderr,"-- getting DA list from %s\n",iptr); *iptr = '\0'; /* don't need the char, but want terminated filename */ /* read dataset just for numDA */ numDA = gifti_read_dset_numDA(fcopy); if( numDA < 0 ) { fprintf(stderr, "** GT_RD: failed to get numDA from '%s'\n", fcopy); free(fcopy); return NULL; } dalist = nifti_get_intlist(numDA, iptr+1); if( !dalist ) { fprintf(stderr,"** GT_RD: bad int list from '%s'\n", iptr+1); free(fcopy); return NULL; } if( opts->verb > 2 ) { fprintf(stderr,"++ have DA list: "); gifti_disp_raw_data(dalist, NIFTI_TYPE_INT32, numDA, 1, stderr); } } /* pass either dalist or from opts */ if( dalist && numDA > 0 ) gim = gifti_read_da_list(infile, opts->dstore, dalist+1, dalist[0]); else gim = gifti_read_da_list(infile, opts->dstore, opts->DAlistr.list, opts->DAlistr.len); /* possibly make modifications */ if( opts->gt_modify ) gt_modify_dset(opts, gim); /* regardless of success, check to free data and return */ if( dalist ) free(dalist); if( fcopy ) free(fcopy); if( opts->show_gifti ) { fcopy = (char *)malloc((strlen(fname)+32) * sizeof(char)); if( !fcopy ) return gim; /* forget it */ sprintf(fcopy, "dset '%s' :", fname); gifti_disp_gifti_image(fcopy, gim, 1 ); free(fcopy); } if( opts->gt_test ) { if( gifti_valid_gifti_image(gim, opts->verb > 0) ) printf("++ gifti_image '%s' is VALID\n", fname); else printf("++ gifti_image '%s' is INVALID\n", fname); } return gim; } /* init any options that should not default to 0 (so 0 means something, * or the default is non-zero) */ static int init_opts(gt_opts * opts) { memset(opts, 0, sizeof(gt_opts)); /* gt_* should init to 0 */ /* new flags can be set to something useful (1 DA, no data, ...) */ opts->new_numDA = 1; opts->new_intent = NIFTI_INTENT_NONE; opts->new_dtype = NIFTI_TYPE_FLOAT32; opts->new_ndim = 0; /* opts->new_dims left with zeros */ opts->new_data = 0; opts->comp_verb = 1; opts->verb = 1; opts->indent = -1; opts->dstore = 1; opts->update_ok = -1; opts->zlevel = -1; return 0; } static int disp_gt_opts(char * mesg, gt_opts * opts, FILE * stream) { FILE * fp = stream ? stream : stdout; if( mesg ) fputs(mesg, fp); fprintf(fp, "gt_opts struct:\n" " gt_compare : %d\n" " gt_display : %d\n" " gt_write : %d\n" " gt_modify : %d\n" " gt_test : %d\n" "\n" " new_numDA : %d\n" " new_intent : %d\n" " new_dtype : %d\n" " new_ndim : %d\n" " new_dims [%d] : ", opts->gt_compare, opts->gt_display, opts->gt_write, opts->gt_modify, opts->gt_test, opts->new_numDA, opts->new_intent, opts->new_dtype, opts->new_ndim, GIFTI_DARRAY_DIM_LEN ); gifti_disp_raw_data(opts->new_dims, NIFTI_TYPE_INT32, GIFTI_DARRAY_DIM_LEN, 1, fp); fprintf(fp, " new_data : %d\n" "\n" " mod_add_data : %d\n" " mod_gim_atr : %d\n" " mod_gim_meta : %d\n" " mod_DA_atr : %d\n" " mod_DA_meta : %d\n" " mod_to_float : %d\n" "\n" " comp_data : %d\n" " comp_verb : %d\n" "\n" " verb : %d\n" " indent : %d\n" " buf_size : %d\n" " b64_check : %d\n" " update_ok : %d\n" " zlevel : %d\n" "\n" " dstore : %d\n" " encoding : %d\n" " show_gifti : %d\n" " ofile_1D : %s\n" " ofile_asc : %s\n" " ofile_gifti : %s\n\n", opts->new_data, opts->mod_add_data, opts->mod_gim_atr, opts->mod_gim_meta, opts->mod_DA_atr, opts->mod_DA_meta, opts->mod_to_float, opts->comp_data, opts->comp_verb, opts->verb, opts->indent, opts->buf_size, opts->b64_check, opts->update_ok, opts->zlevel, opts->dstore, opts->encoding, opts->show_gifti, G_CHECK_NULL_STR(opts->ofile_1D), G_CHECK_NULL_STR(opts->ofile_asc), G_CHECK_NULL_STR(opts->ofile_gifti)); /* DataArray index list */ fprintf(fp, " DAlist[%d] : ", opts->DAlist.len); if( opts->DAlist.len <= 0 || !opts->DAlist.list ) fprintf(fp, "\n"); else gifti_disp_raw_data(opts->DAlist.list, NIFTI_TYPE_INT32, opts->DAlist.len, 1, fp); /* DataArray index list */ fprintf(fp, " DAlistr[%d] : ", opts->DAlistr.len); if( opts->DAlistr.len <= 0 || !opts->DAlistr.list ) fprintf(fp, "\n"); else gifti_disp_raw_data(opts->DAlistr.list, NIFTI_TYPE_INT32, opts->DAlistr.len, 1, fp); /* DataArray modification list */ fprintf(fp, " DAmodlist[%d] : ", opts->DAmodlist.len); if( opts->DAmodlist.len <= 0 || !opts->DAmodlist.list ) fprintf(fp, "\n"); else gifti_disp_raw_data(opts->DAmodlist.list, NIFTI_TYPE_INT32, opts->DAmodlist.len, 1, fp); show_str_list(" gim_atrs ", &opts->gim_atrs, fp); show_str_list(" gim_meta ", &opts->gim_meta, fp); show_str_list(" DA_atrs ", &opts->DA_atrs, fp); show_str_list(" DA_meta ", &opts->DA_meta, fp); show_str_list(" ext_files ", &opts->ext_files, fp); show_str_list(" infiles ", &opts->infiles, fp); return 0; } static int show_str_list( const char * mesg, gt_str_list * list, FILE * fp ) { FILE * stream = fp ? fp : stdout; int c; if( mesg ) fprintf(stream, "%-14s", mesg); else fputs("list",stream); if( ! list || !list->list || list->len <= 0 ) { fprintf(stream, "[0] : \n"); return 0; } fprintf(stream, "[%d] : ", list->len); for( c = 0; c < list->len; c++ ) fprintf(stream, "%s ", list->list[c]); fputc('\n', stream); return 0; } static int show_hist(void) { int c, len = sizeof(g_history)/sizeof(char *); for( c = 0; c < len; c++) fputs(g_history[c], stdout); putchar('\n'); return 0; } static int show_version(void) { puts(g_version); return 0; } static int show_help() { printf( "------------------------------------------------------------\n" "gifti_tool - create, display, modify or compare GIFTI datasets\n" "\n" " general examples:\n" "\n" " 1. read in a GIFTI dataset (set verbose level? show GIFTI dataset?)\n" "\n" " gifti_tool -infile dset.gii\n" " gifti_tool -infile dset.gii -verb 3\n" " gifti_tool -infile dset.gii -show_gifti\n" "\n" " 2. copy a GIFTI dataset\n" "\n" " a. create a simple copy, and check for differences\n" "\n" " gifti_tool -infile dset.gii -write_gifti copy.gii\n" " diff dset.gii copy.gii\n" "\n" " b. copy only 3 DataArray indices: 4, 0, 5\n" "\n" " gifti_tool -infile time_series.gii -write_gifti ts3.gii \\\n" " -read_DAs 4 0 5\n" " OR\n" "\n" " gifti_tool -infile time_series.gii'[4,0,5]' \\\n" " -write_gifti ts3.gii\n" "\n" " 3. write datasets in other formats\n" "\n" " a. FreeSurfer-style .asc surface dataset\n" "\n" " gifti_tool -infile pial.gii -write_asc pial.asc\n" "\n" " b. .1D time series surface dataset\n" "\n" " gifti_tool -infile time_series.gii -write_1D ts.1D\n" "\n" ); printf ( " 4. create a new gifti dataset from nothing, where\n" "\n" " a. - the dataset has 3 DataArray elements\n" " - the data will be of type 'short' (NIFTI_TYPE_INT16)\n" " - the intent codes will reflect a t-test\n" " - the data will be 2-dimensional (per DataArray), 5 by 2 shorts\n" " - memory will be allocated for the data (a modification option)\n" " - the result will be written to created.gii\n" "\n" " gifti_tool -new_dset \\\n" " -new_numDA 3 -new_dtype NIFTI_TYPE_INT16 \\\n" " -new_intent NIFTI_INTENT_TTEST \\\n" " -new_ndim 2 -new_dims 5 2 0 0 0 0 \\\n" " -mod_add_data -write_gifti created.gii\n" "\n" " b. - the dataset has 12 DataArray elements (40 floats each)\n" " - the data is partitioned over 2 files (so 6*40 floats in each)\n" "\n" " ** Note: since dataset creation does not add data (without\n" " -mod_add_data), this operation will not create or\n" " try to overwrite the external datafiles.\n" "\n" " gifti_tool -new_dset -new_numDA 12 \\\n" " -new_ndim 1 -new_dims 40 0 0 0 0 0 \\\n" " -set_extern_filelist ext1.bin ext2.bin \\\n" " -write_gifti points_to_extern.gii\n" "\n"); printf( " 5. modify a gifti dataset\n" "\n" " a. apply various modifications at the GIFTI level and to all DAs\n" "\n" " - set the Version attribute at the GIFTI level\n" " - set 'Date' as GIFTI MetaData, with value of today's date\n" " - set 'Description' as GIFTI MetaData, with some value\n" " - set all DA Intent attributes to be an F-test\n" " - set 'Name' as an attribute of all DAs, with some value\n" " - read created.gii, and write to first_mod.gii\n" "\n" " gifti_tool -mod_gim_atr Version 1.0 \\\n" " -mod_gim_meta Date \"`date`\" \\\n" " -mod_gim_meta Description 'modified surface' \\\n" " -mod_DA_atr Intent NIFTI_INTENT_FTEST \\\n" " -mod_DA_meta Name 'same name for all DAs' \\\n" " -infile created.gii -write_gifti first_mod.gii\n" "\n" " b. modify the 'Name' attribute is DA index #42 only\n" "\n" " gifti_tool -mod_DA_meta Name 'data from pickle #42' \\\n" " -mod_DAs 42 \\\n" " -infile stats.gii -write_gifti mod_stats.gii\n" "\n" " c. set the data to point to a single external data file, without\n" " overwriting the external file on write (so use -no_data), \n" " and where the DataArrays will point to sequential partitions\n" " of the file\n" "\n" " gifti_tool -infiles created.gii -no_data \\\n" " -set_extern_filelist ex_data.bin \\\n" " -write_gifti extern.gii\n" "\n" ); printf ( " d. convert a POINTSET/TRIANGLE Base64 format dataset to one where\n" " to one where the data is external (raw binary):\n" "\n" " gifti_tool -infiles inflated.gii \\\n" " -set_extern_filelist points.data tri.data \\\n" " -write_gifti inflated.external.gii\n" "\n" " e. convert a 5 run time series dataset from internal Base64 format\n" " to one where the data is external (raw binary):\n" "\n" " as one external file:\n" "\n" " gifti_tool -infiles epi.5runs.gii \\\n" " -set_extern_filelist data.5runs.bin \\\n" " -write_gifti epi.ext.5runs.gii\n" "\n" " as 5 external files (1 per run):\n" "\n" " gifti_tool -infiles epi.5runs.gii \\\n" " -set_extern_filelist data.5runs.r{1,2,3,4,5}.bin \\\n" " -write_gifti epi.ext.5runs.gii\n" "\n" " f. convert the previous external dataset back to internal form\n" " (i.e. it should be the same as epi.5runs.gii)\n" "\n" " gifti_tool -infiles epi.ext.5runs.gii \\\n" " -encoding BASE64 \\\n" " -write_gifti epi.int.5runs.gii\n" "\n" ); printf ( " 6. compare 2 gifti datasets\n" "\n" " a. compare GIFTI structures, compare data, and report all diffs\n" "\n" " gifti_tool -compare_gifti -compare_data -compare_verb 3 \\\n" " -infiles created.gii first_mod.gii\n" "\n" " b. report approximate comparison: focusing on data, but allowing\n" " for small, fractional differences varying per datatype\n" "\n" " gifti_tool -approx_gifti -compare_verb 3 \\\n" " -infiles created.gii first_mod.gii\n" "\n" " 7. copy MetaData from one dataset to another\n" " (any old Value will be replaced if the Name already exists)\n" "\n" " - copy every (ALL) MetaData element at the GIFTI level\n" " - copy MetaData named 'Label' per DataArray element\n" " - only apply DataArray copies to indices 0, 3 and 6\n" " - first input file is the source, second is the destination\n" " - write the modified 'destination.gii' dataset to meta_copy.gii\n" "\n" " gifti_tool -copy_gifti_meta ALL \\\n" " -copy_DA_meta Label \\\n" " -DA_index_list 0 3 6 \\\n" " -infiles source.gii destination.gii \\\n" " -write_gifti meta_copy.gii\n" "\n" "----------------------------------------------------------------------\n" ); printf ( "\n" " (all warranties are void in Montana, and after 4 pm on Tuesdays)\n" "\n" "----------------------------------------------------------------------\n" " informational options:\n" "\n" " -help : display this help\n" " -hist : display the modification history of gifti_tool\n" " -ver : display the gifti_tool version\n" " -gifti_hist : display thd modification history of gifticlib\n" " -gifti_ver : display gifticlib version\n" " -gifti_dtd_url : display the gifti DTD URL\n" " -gifti_zlib : display whether the zlib is linked in library\n" "\n" ); printf ( " ----------------------------------------\n" " general/input options\n" "\n" " -b64_check TYPE : set method for checking base64 errors\n" "\n" " e.g. -b64_check COUNT\n" "\n" " This option sets the preference for how to deal with errors\n" " in Base64 encoded data (whether compressed or not). The\n" " default is SKIPnCOUNT, which skips any illegal characters,\n" " and reports a count of the number found.\n" "\n" " TYPE = NONE : no checks - assume all is well\n" " TYPE = DETECT : report whether errors were found\n" " TYPE = COUNT : count the number of bad chars\n" " TYPE = SKIP : ignore any bad characters\n" " TYPE = SKIPnCOUNT : ignore but count bad characters\n" "\n" " This default adds perhaps 10%% to the reading time.\n" "\n" " -buf_size SIZE : set the buffer size (given to expat library)\n" "\n" " e.g. -buf_size 1024\n" "\n" " -DA_index_list I0 I1 ... : specify a list of DataArray indices\n" "\n" " e.g. -DA_index_list 0\n" " e.g. -DA_index_list 0 17 19\n" "\n" " This option is used to specify a list of DataArray indices\n" " for use via some other option (such as -copy_DA_meta).\n" "\n" " Each DataArray element corresponding to one of the given\n" " indices will have the appropriate action applied, such as\n" " copying a given MetaData element from the source dataset\n" " to the destination dataset.\n" "\n" " Note that this differs from -read_DAs, which specifies which\n" " DataArray elements to even read in. Both options could be\n" " used in the same command, such as if one wanted to copy the\n" " 'Name' MetaData from index 17 of a source dataset into the\n" " MetaData of the first DataArray in a dataset with only two\n" " DataArray elements.\n" "\n" " e.g. gifti_tool -infiles source.gii dest.gii \\\n" " -write_gifti new_dest.gii \\\n" " -copy_DA_meta Name \\\n" " -read_DAs 17 17 \\\n" " -DA_index_list 0\n" "\n" " Note that DA_index_list applies to the indices _after_ the\n" " datasets are read in.\n" "\n" ); printf ( " -gifti_test : test whether each gifti dataset is valid\n" "\n" " This performs a consistency check on each input GIFTI\n" " dataset. Lists and dimensions must be consistent.\n" "\n" " -infile INPUT : specify one or more GIFTI datasets as input\n" "\n" " e.g. -input pial.gii\n" " e.g. -input run1.gii run2.gii\n" " e.g. -input MAKE_IM (create a new image)\n" " e.g. -input run1.gii'[3,4,5]' (read DAs 3,4,5 )\n" " e.g. -input run1.gii'[0..16(2)]' (read evens from 0 to 16)\n" " e.g. -input run1.gii'[4..$]' (read all but 0..3)\n" "\n" " There are 2 special ways to specify input. One is via the\n" " name 'MAKE_IM'. That 'input' filename tell gifti_tool to\n" " create a new dataset, applying any '-new_*' options to it.\n" "\n" " (refer to options: -new_*)\n" "\n" " The other special way is to specify which DataArray elements\n" " should be read in, using AFNI-style syntax within '[]'. The\n" " quotes prevent the shell from interpreting the brackets.\n" "\n" " DataArray indices are zero-based.\n" "\n" " The list of DAs can be comma-delimited, and can use '..' or\n" " '-' to specify a range, and a value in parentheses to be used\n" " as a step. The '$' character means the last index (numDA-1).\n" "\n" ); printf ( " -no_data : do not read in data\n" "\n" " This option means not to read in the Data element in any\n" " DataArray, akin to reading only the header.\n" "\n" " -no_updates : do not allow the library to modify metadata\n" "\n" " By default, the library may update some metadata fields, such\n" " as 'gifticlib-version'. The -no_updates option will prevent\n" " that operation.\n" "\n" " -read_DAs s0 ... : read DataArray list indices s0,... from input\n" "\n" " e.g. -read_DAs 0 4 3 3 8\n" " e.g. -input run1.gii -read_DAs 0 2 4 6 8\n" " e.g. -input run1.gii'[0..8(2)]' (same effect)\n" "\n" " Specify a list of DataArray indices to read. This is a\n" " simplified form of using brackets '[]' with -input names.\n" "\n" " -show_gifti : show final gifti image\n" "\n" " Display all of the dataset information on the screen (sans\n" " data). This includes meta data and all DataArray elements.\n" "\n" " -verb VERB : set verbose level (default: 1)\n" "\n" " e.g. -verb 2\n" "\n" " Print extra information to the screen. The VERB level can\n" " be from 0 to 8, currently.\n" "\n" " Level 0 is considered 'quiet' mode, and should only report\n" " serious errors. Level 1 is the default.\n" "\n" ); printf ( " ----------------------------------------\n" " output options\n" "\n" " -encoding TYPE : set the data encoding for any output file\n" "\n" " e.g. -encoding BASE64GZIP\n" "\n" " TYPE = ASCII : ASCII encoding\n" " TYPE = BASE64 : base64 binary\n" " TYPE = BASE64GZIP : base64 compressed binary\n" "\n" " This operation can also be performed via -mod_DA_atr:\n" " e.g. -mod_DA_atr Encoding BASE64GZIP\n" "\n" " -set_extern_filelist F1 F2 ... : store data in external files\n" "\n" " e.g. -set_extern_filelist run.1.data run.2.data run.3.data\n" " e.g. -set_extern_filelist runs.all.data\n" " e.g. -set_extern_filelist points.data triangles.data\n" "\n" " Data is normally stored within the XML file as numerical\n" " text or Base64 encoded raw or compressed data.\n" "\n" " With use of this option, users can set to have data stored in\n" " external binary files (neither encoded nor compressed) upon a\n" " write operation.\n" "\n" " External file storage is subject to a couple of restrictions:\n" "\n" " - GIFTI requires that they are in the same directory\n" "\n" " - the library allows multiple DataArrays per file, but each\n" " DataArray within the same file must have the same size\n" " (this is a gifticlib limit, not a GIFTI limit)\n" "\n" " OK : equal data in 1 file\n" " OK : equal data in k files, numDA is multiple of k\n" " BAD: equal data in k files, numDA is NOT multiple of k\n" " OK : points/triangles in 2 files\n" " BAD: points/triangles in 1 file (sizes differ)\n" "\n" " The most basic use of this option is to convert data from\n" " internal to external. See examples 5d and 5e.\n" "\n" " Note that one can also create a GIFTI dataset out of nothing\n" " and use this option to point to existing external data files.\n" " This would help conversion from other dataset formats. See\n" " example 5c.\n" "\n" " Note that one can convert from an external data format to\n" " internal just by modifying the -encoding. See example 5f.\n" "\n" ); printf ( " -write_1D DSET : write out data to AFNI style 1D file\n" "\n" " e.g. -write_1D stats.1D\n" "\n" " Currently, all DAs need to be of the same datatype. This\n" " restriction could be lifted if there is interest.\n" "\n" " -write_asc DSET : write out geometry to FreeSurfer style ASC file\n" "\n" " e.g. -write_asc pial.asc\n" "\n" " To write a surface file in FreeSurfer asc format, it must\n" " contain DataArray elements of intent NIFTI_INTENT_POINTSET\n" " and NIFTI_INTENT_TRIANGLE. The POINTSET data is written as\n" " node coordinates and the TRIANGLE data as triangles (node\n" " index triplets).\n" "\n" " -write_gifti DSET : write out dataset as gifti image\n" "\n" " e.g. -write_gifti new.pial.gii\n" "\n" " -zlevel LEVEL : set compression level (-1 or 0..9)\n" "\n" " This option sets the compression level used by zlib. Some\n" " LEVEL values are noteworthy:\n" "\n" " -1 : specify to use the default of zlib (currently 6)\n" " 0 : no compression (but still needs a few extra bytes)\n" " 1 : fastest but weakest compression\n" " 6 : default (good speed/compression trade-off)\n" " 9 : slowest but strongest compression\n" "\n" ); printf ( " ----------------------------------------\n" " modification options\n" "\n" " These modification options will affect every DataArray element\n" " specified by the -mod_DAs option. If the option is not used,\n" " then ALL DataArray elements will be affected.\n" "\n" " -mod_add_data : add data to empty DataArray elements\n" "\n" " Allocate data in every DataArray element. Datasets can be\n" " created without any stored data. This will allocate data\n" " and fill it with zeros of the given type.\n" "\n" " -mod_DA_atr NAME VALUE : set the NAME=VALUE attribute pair\n" "\n" " e.g. -mod_DA_atr Intent NIFTI_INTENT_ZSCORE\n" "\n" " This option will set the DataArray attribute corresponding\n" " to NAME to the value, VALUE. Attribute name=value pairs are\n" " specified in the gifti DTD (see -gifti_dtd_url).\n" "\n" " One NAME=VALUE pair can be specified per -mod_DA_atr\n" " option. Multiple -mod_DA_atr options can be used.\n" "\n" " -mod_DA_meta NAME VALUE : set the NAME=VALUE pair in DA's MetaData\n" "\n" " e.g. -mod_DA_meta Description 'the best dataset, ever'\n" "\n" " Add a MetaData entry to each DataArray element for this\n" " NAME and VALUE. If 'NAME' already exists, the old value\n" " is replaced by VALUE.\n" "\n" " -mod_DAs i0 i1 ... : specify the set of DataArrays to modify\n" "\n" " e.g. -mod_DAs 0 4 5\n" "\n" " Specify the list of DataArray elements to modify. All the\n" " -mod_* options apply to this list of DataArray indices. If\n" " no -mod_DAs option is used, the operations apply to ALL\n" " DataArray elements.\n" "\n" " Note that the indices are zero-based, 0 .. numDA-1.\n" "\n" " -mod_gim_atr NAME VALUE : set the GIFTI NAME=VALUE attribute pair\n" "\n" " e.g. -mod_gim_atr Version 3.141592\n" "\n" " Set the GIFTI element attribute corresponding to NAME to the\n" " value, VALUE.\n" "\n" " Given that numDA is computed and version will rarely change,\n" " this option will probably not feel much love.\n" "\n" " -mod_gim_meta NAME VALUE : add this pair to the GIFTI MetaData\n" "\n" " e.g. -mod_gim_meta date \"`date`\"\n" "\n" " Add a MetaData entry to each DataArray element for this\n" " NAME and VALUE pair. If NAME exists, VALUE will replace\n" " the old value.\n" "\n" " -mod_to_float : change all DataArray data to float\n" "\n" " Convert all DataArray elements of all datasets to datatype\n" " NIFTI_TYPE_FLOAT32 (4-byte floats). If the data does not\n" " actually exist, only the attribute will be set. Otherwise\n" " all of the data will be converted. There are some types\n" " for which this operation may not be appropriate.\n" "\n" ); printf ( " ----------------------------------------\n" "\n" " creation (new dataset) options\n" "\n" " -new_dset : create a new GIFTI dataset\n" " -new_numDA NUMDA : new dataset will have NUMDA DataArray elements\n" " e.g. -new_numDA 3\n" " -new_intent INTENT: DA elements will have intent INTENT\n" " e.g. -new_intent NIFTI_INTENT_FTEST\n" " -new_dtype TYPE : set datatype to TYPE\n" " e.g. -new_dtype NIFTI_TYPE_FLOAT32\n" " -new_ndim NUMDIMS : set Dimensionality to NUMDIMS (see -new_dims)\n" " -new_dims D0...D5 : set dims[] to these 6 values\n" " e.g. -new_ndim 2 -new_dims 7 2 0 0 0 0\n" " -new_data : allocate space for data in created dataset\n" "\n" ); printf ( " ----------------------------------------\n" " comparison options\n" "\n" " -approx_gifti : approximate comparison of GIFTI dsets\n" "\n" " This compares all data elements of the two GIFTI structures.\n" " The attributes, MetaData, etc. are ignored if they do not\n" " pertain directly to the data.\n" "\n" " The comparisons allow for small, fractional differences,\n" " which depend on the datatype.\n" "\n" " -compare_gifti : specifies to compare two GIFTI datasets\n" "\n" " This compares all elements of the two GIFTI structures.\n" " The attributes, LabelTabels, MetaData are compared, and then\n" " each of the included DataArray elements. All sub-structures\n" " of the DataArrays are compared, except for the actual 'data',\n" " which requires the '-compare_data' flag.\n" "\n" " There must be exactly 2 input datasets to use this option.\n" " See example #7 for sample usage.\n" "\n" " -compare_data : flag to request comparison of the data\n" "\n" " Data comparison is done per DataArray element.\n" "\n" " Comparing data is a separate operation from comparing GIFTI.\n" " Neither implies the other.\n" "\n" " -compare_verb LEVEL : set the verbose level of comparisons\n" "\n" " Data comparison is done per DataArray element. Setting the\n" " verb level will have the following effect:\n" "\n" " 0 : quiet, only return whether there was a difference\n" " 1 : show whether there was a difference\n" " 2 : show whether there was a difference per DataArray\n" " 3 : show all differences\n" "\n" ); printf ( " ----------------------------------------\n" " MetaData copy options\n" "\n" " -copy_gifti_meta MD_NAME : copy MetaData with name MD_NAME\n" "\n" " e.g. -copy_gifti_meta AFNI_History\n" "\n" " Copy the MetaData with the given name from the first input\n" " dataset to the second (last). This applies to MetaData at\n" " the GIFTI level (not in the DataArray elements).\n" "\n" " -copy_DA_meta MD_NAME : copy MetaData with name MD_NAME\n" "\n" " e.g. -copy_DA_meta intent_p1\n" "\n" " Copy the MetaData with the given name from the first input\n" " dataset to the second (last). This applies to MetaData at\n" " DataArray level.\n" "\n" " This will apply to all DataArray elements, unless the\n" " -DA_index_list option is used to specify a zero-based\n" " index list.\n" "\n" " see also -DA_index_list\n" "\n" ); printf ( "------------------------------------------------------------\n" "see the GIfTI community web site at:\n" "\n" " http://www.nitrc.org/projects/gifti\n" "\n" "R Reynolds, National Institutes of Health\n" "------------------------------------------------------------\n" ); return 0; } int write_as_asc(gifti_image * gim, char * prefix) { giiDataArray * dac; /* coords */ giiDataArray * dat; /* triangles */ fprintf(stderr,"-- trying to write data with prefix '%s'\n", prefix); /* write surface file, *.1D */ if( (dac = gifti_find_DA(gim, NIFTI_INTENT_POINTSET, 0)) && (dat = gifti_find_DA(gim, NIFTI_INTENT_TRIANGLE, 0)) ) (void) write_surf_file(dac, dat, prefix, 1); else { fprintf(stderr,"** failed to find coordinate/triangle structs\n"); return 1; } return 0; } /* if dlist contains 1 element, write out as 2-D list, else each DA must have only 1 dimension */ int write_1D_file(giiDataArray ** dlist, int len, char * prefix, int add_suf) { giiDataArray * da; FILE * fp; char * name = prefix; char * nbuf = NULL; long long rows, cols, c; if( add_suf && !strstr(prefix, ".1D")) { /* create a new name */ nbuf = (char *)malloc(strlen(prefix) + strlen(".1D") + 1); strcpy(nbuf, prefix); strcat(nbuf, ".1D"); name = nbuf; } if( len == 1 ){ /* write out as 2D list */ /* note the number of rows and columns */ fprintf(stderr,"++ writing 1D '%s' from single DA\n", name); da = dlist[0]; if( gifti_DA_rows_cols(da, &rows, &cols) ) { fprintf(stderr,"** bad return from rows_cols, failing...\n"); if( nbuf ) free(nbuf); return 1; } if( !(fp = fopen(name, "w")) ) { fprintf(stderr,"** failed to open '%s' for 'w'\n",name); if( nbuf ) free(nbuf); return 1; } fprintf(stderr,"++ 1D write, RxC = %lld x %lld\n", rows, cols); if( da->ind_ord == GIFTI_IND_ORD_COL_MAJOR ) { fprintf(stderr,"-- writing data rows in reverse order\n"); for(c = rows-1; c >= 0; c-- ) ewrite_data_line(da->data, da->datatype, c, cols, 0, 0, fp); } else { fprintf(stderr,"-- writing data rows in normal order\n"); for(c = 0; c < rows; c++ ) ewrite_data_line(da->data, da->datatype, c, cols, 0, 0, fp); } } else { /* write da->nvals lines of 'num values */ void ** vlist = (void **)malloc(len * sizeof(void *)); int fail = 0; fprintf(stderr,"++ writing 1D '%s' from DA list (%d)\n", name, len); /* set data pointers */ for( c = 0; c < len; c++ ) { vlist[c] = dlist[c]->data; if( !vlist[c] ) { fprintf(stderr,"** DA[%lld] has no data, bailing...\n", c); fail = 1; } else if( dlist[c]->nvals != dlist[0]->nvals ) { fprintf(stderr,"** d[%lld] has %lld vals, but d[0] has %lld\n", c, dlist[c]->nvals, dlist[0]->nvals); fail = 1; } else if (dlist[c]->datatype != dlist[0]->datatype) { fprintf(stderr,"** d[%lld] has type %d, but d[0] has %d\n", c, dlist[c]->datatype, dlist[0]->datatype); fail = 1; } if( fail ) { free(vlist); if( nbuf ) free(nbuf); return 1; } } /* good to go */ if( !(fp = fopen(name, "w")) ) { fprintf(stderr,"** failed to open '%s' for 'w'\n",name); if( nbuf ) free(nbuf); return 1; } if(G.verb > 1) fprintf(stderr,"++ 1D write many, RxC = %lld x %d\n", dlist[0]->nvals, len); ewrite_many_lines(vlist, dlist[0]->datatype,len, dlist[0]->nvals, 0,fp); free(vlist); } if( G.verb > 1 ) fprintf(stderr,"++ 1D write, apparent success\n"); if( nbuf ) free(nbuf); fclose(fp); return 0; } int write_surf_file(giiDataArray * dc, giiDataArray * dt, char * prefix, int add_suf) { giiDataArray * da; FILE * fp; char * name = prefix; char * nbuf = NULL; long long crows, ccols, trows, tcols, rows, cols, c; if( add_suf && !strstr(prefix, ".asc") ) { /* maybe create a new name */ nbuf = (char *)malloc(strlen(prefix) + strlen(".asc") + 1); strcpy(nbuf, prefix); strcat(nbuf, ".asc"); name = nbuf; } if( !(fp = fopen(name, "w")) ) { fprintf(stderr,"** failed to open '%s' for 'w'\n",name); if( nbuf ) free(nbuf); return 1; } /* note the number of rows and columns */ if( gifti_DA_rows_cols(dc, &crows, &ccols) ) { fclose(fp); if( nbuf ) free(nbuf); return 1; } else if( gifti_DA_rows_cols(dt, &trows, &tcols) ) { fclose(fp); if( nbuf ) free(nbuf); return 1; } fprintf(fp, "#!ascii version of surface\n" "%lld %lld\n", crows, trows); /* write out the coordinates */ da = dc; rows = crows; cols = ccols; if( da->ind_ord == GIFTI_IND_ORD_COL_MAJOR ) { fprintf(stderr,"-- writing coord rows in reverse order\n"); for(c = rows-1; c >= 0; c-- ) ewrite_data_line(da->data, da->datatype, c, cols, 0, 1, fp); } else { fprintf(stderr,"-- writing coord rows in normal order\n"); for(c = 0; c < rows; c++ ) ewrite_data_line(da->data, da->datatype, c, cols, 0, 1, fp); } /* write out the triangles */ da = dt; rows = trows; cols = tcols; if( da->ind_ord == GIFTI_IND_ORD_COL_MAJOR ) { fprintf(stderr,"-- writing triangle rows in reverse order\n"); for(c = rows-1; c >= 0; c-- ) ewrite_data_line(da->data, da->datatype, c, cols, 0, 1, fp); } else { fprintf(stderr,"-- writing triangle rows in normal order\n"); for(c = 0; c < rows; c++ ) ewrite_data_line(da->data, da->datatype, c, cols, 0, 1, fp); } fclose(fp); return 0; } int ewrite_data_line(void * data, int type, int row, int cols, int spaces, int trail0, FILE * fp) { int c; if( !data || row < 0 || cols <= 0 || !fp ) { static int show = 1; if(show){ fprintf(stderr,"** write data line: bad inputs (%p,%d,%d,%p)\n", data, row, cols, (void *)fp); show=0; } return 1; } fprintf(fp, "%*s", spaces, ""); switch( type ) { default : fprintf(stderr,"** write_data_line, unknown type %d\n",type); return -1; case NIFTI_TYPE_UINT8: { unsigned char * ptr = (unsigned char *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c]); break; } case NIFTI_TYPE_INT16: { short * ptr = (short *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c]); break; } case NIFTI_TYPE_INT32: { int * ptr = (int *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c]); break; } case NIFTI_TYPE_FLOAT32: { float * ptr = (float *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%f ", ptr[c]); break; } case NIFTI_TYPE_COMPLEX64: { float * ptr = (float *)data + row * cols; for(c = 0; c < 2*cols; c+=2)fprintf(fp, "%f %f ",ptr[c],ptr[c+1]); break; } case NIFTI_TYPE_FLOAT64: { double * ptr = (double *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%f ", ptr[c]); break; } case NIFTI_TYPE_RGB24: { unsigned char * ptr = (unsigned char *)data + row * cols; for( c = 0; c < 3*cols; c+=3 ) fprintf(fp, "%u %u %u ", ptr[c], ptr[c+1], ptr[c+2]); break; } case NIFTI_TYPE_INT8: { char * ptr = (char *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c]); break; } case NIFTI_TYPE_UINT16: { unsigned short * ptr = (unsigned short *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c]); break; } case NIFTI_TYPE_UINT32: { /* NIFTI_TYPE_UINT32 */ unsigned int * ptr = (unsigned int *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c]); break; } case NIFTI_TYPE_INT64: { long long * ptr = (long long *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%lld ", ptr[c]); break; } case NIFTI_TYPE_UINT64: { unsigned long long * ptr = (unsigned long long *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%llu ", ptr[c]); break; } case NIFTI_TYPE_FLOAT128: { fprintf(stderr,"** ewrite_data_line, won't write %s\n", gifti_datatype2str(type)); break; } case NIFTI_TYPE_COMPLEX128: { double * ptr = (double *)data + row * cols; for(c = 0; c < 2*cols; c+=2)fprintf(fp, "%f %f ",ptr[c],ptr[c+1]); break; } case NIFTI_TYPE_COMPLEX256: { fprintf(stderr,"** ewrite_data_line, won't write %s\n", gifti_datatype2str(type)); break; } } if( trail0 ) fputs(" 0", fp); /* maybe write trailing zero */ fputc('\n', fp); return 0; } /* write out as cols by rows (else we'd use ewrite_data_line) */ int ewrite_many_lines(void ** data, int type, long long cols, long long rows, int spaces, FILE * fp) { long long r, c; if( !data || rows == 0 || cols == 0 || !fp ) return 1; fprintf(fp, "%*s", spaces, ""); switch( type ) { default : fprintf(stderr,"** write_data_line, unknown type %d\n",type); return -1; case NIFTI_TYPE_UINT8: { unsigned char ** ptr = (unsigned char **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c][r]); fputc('\n', fp); } break; } case NIFTI_TYPE_INT16: { short ** ptr = (short **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c][r]); fputc('\n', fp); } break; } case NIFTI_TYPE_INT32: { int ** ptr = (int **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c][r]); fputc('\n', fp); } break; } case NIFTI_TYPE_FLOAT32: { float ** ptr = (float **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%f ", ptr[c][r]); fputc('\n', fp); } break; } case NIFTI_TYPE_COMPLEX64: { /* process as float32 pairs */ float ** ptr = (float **)data; for( r = 0; r < 2*rows; r+=2 ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%f %f ", ptr[c][r], ptr[c][r+1]); fputc('\n', fp); } break; } case NIFTI_TYPE_FLOAT64: { double ** ptr = (double **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%f ", ptr[c][r]); fputc('\n', fp); } break; } case NIFTI_TYPE_RGB24: { /* process as char triplets */ char ** ptr = (char **)data; for( r = 0; r < 3*rows; r+=3 ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%u %u %u ",ptr[c][r],ptr[c][r+1],ptr[c][r+2]); fputc('\n', fp); } break; } case NIFTI_TYPE_INT8: { char ** ptr = (char **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c][r]); fputc('\n', fp); } break; } case NIFTI_TYPE_UINT16: { unsigned short ** ptr = (unsigned short **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c][r]); fputc('\n', fp); } break; } case NIFTI_TYPE_UINT32: { unsigned int ** ptr = (unsigned int **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c][r]); fputc('\n', fp); } break; } case NIFTI_TYPE_INT64: { long long ** ptr = (long long **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%lld ", ptr[c][r]); fputc('\n', fp); } break; } case NIFTI_TYPE_UINT64: { unsigned long long ** ptr = (unsigned long long **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%llu ", ptr[c][r]); fputc('\n', fp); } break; } /* just forget these ... case NIFTI_TYPE_FLOAT128: { break; } case NIFTI_TYPE_COMPLEX128: { break; } case NIFTI_TYPE_COMPLEX256: { break; } */ } return 0; } /*---------------------------------------------------------------------- * - only bother to alloc one pointer at a time (don't need efficiency here) * - return 0 on success *----------------------------------------------------------------------*/ static int add_to_int_list(gt_int_list * ilist, int val) { if( ilist->len == 0 ) ilist->list = NULL; /* just to be safe */ ilist->len++; ilist->list = (int *)realloc(ilist->list,ilist->len*sizeof(int)); if( ! ilist->list ){ fprintf(stderr,"** A2IL: failed to alloc %d (int) elements\n",ilist->len); return -1; } ilist->list[ilist->len-1] = val; return 0; } /*---------------------------------------------------------------------- * - do not duplicate the string * - only bother to alloc one pointer at a time (don't need efficiency here) * - return 0 on success *----------------------------------------------------------------------*/ static int add_to_str_list(gt_str_list * slist, char * str) { if( slist->len == 0 ) slist->list = NULL; /* just to be safe */ slist->len++; slist->list = (char **)realloc(slist->list,slist->len*sizeof(char *)); if( ! slist->list ){ fprintf(stderr,"** A2SL: failed to alloc %d (char *) elements\n", slist->len); return -1; } slist->list[slist->len-1] = str; return 0; } int gt_modify_dset(gt_opts * opts, gifti_image * gim) { gt_int_list * ilist; int c, errs = 0; if( !gim ) return 0; if( opts->verb > 2 ) fprintf(stderr,"-- starting modifications\n"); /* modify GIFTI attributes */ if( opts->mod_gim_atr ) for( c = 0; c < opts->gim_atrs.len-1; c+=2 ) /* grab in pairs */ errs += gifti_str2attr_gifti(gim, opts->gim_atrs.list[c], opts->gim_atrs.list[c+1]); /* modify GIFTI MetaData (replacing any 'name' matches) */ if( opts->mod_gim_meta ) for( c = 0; c < opts->gim_meta.len-1; c+=2 ) /* grab in pairs */ errs += gifti_add_to_meta(&gim->meta, opts->gim_meta.list[c], opts->gim_meta.list[c+1], 1); /* modify DataArray attributes */ if( opts->mod_DA_atr ) { ilist = &opts->DAmodlist; if( ilist->list && ilist->len > 0 ) { if(!gifti_valid_int_list(ilist->list,ilist->len,0,gim->numDA-1,1)){ fprintf(stderr,"** invalid DAmodlist\n"); return 1; } /* apply to list */ for( c = 0; c < opts->DAmodlist.len; c++ ) errs += gifti_set_DA_atrs(gim->darray[ilist->list[c]], (const char **)opts->DA_atrs.list,opts->DA_atrs.len,0); } else /* apply to all DA elements */ for( c = 0; c < gim->numDA; c++ ) errs += gifti_set_DA_atrs(gim->darray[c], (const char **)opts->DA_atrs.list,opts->DA_atrs.len, 0); } /* modify DataArray MetaData (replacing any 'name' matches) */ if( opts->mod_DA_meta ) for( c = 0; c < opts->DA_meta.len-1; c+=2 ) /* grab in pairs */ errs += gifti_set_DA_meta(gim, opts->DA_meta.list[c], opts->DA_meta.list[c+1], opts->DAmodlist.list, opts->DAmodlist.len, 1); /* for data manipulation functions, do not proceed if there there errors */ /* if desired, convert any existing data to float */ if( !errs && opts->mod_to_float ) errs += gifti_convert_to_float(gim); /* do this last, in case data related attributes were modified */ if( !errs && opts->mod_add_data ) if(gifti_alloc_DA_data(gim, opts->DAmodlist.list, opts->DAmodlist.len)) errs++; if(opts->verb>2) fprintf(stderr,"-- modifications done, %d errors\n",errs); return errs; } gifticlib-1.0.9/README.gifti0000644007023700001440000000364411314732367014513 0ustar rickrusersThese notes are with respect to the AFNI GIFTI C API. - This API is built on top of expat, and is released into the public domain. - The main functions are: gifti_read_image, gifti_write_image, gifti_free_image - The exported functions in gifti_io.h are intended for users of this API, particularly those prototypes listed first. - The gifti_xml functions are not intended for external use. - Taking pointers from the gifti_image structure should be okay (providing they are then set to NULL), but it may be less confusing to copy data out. - To save memory, it is suggested to steal the darray[k]->data pointers, and set them to NULL. ---------------------------------------------------------------------- Speeds: (last checked in version 0.7) Since I/O speed was a question when deciding whether to use XML for GIFTI, read times (in seconds) from a mac G5 are provided. (no b64 error checking) (with b64 error counting and skipping) ascii base64 base64gz base64 base64gz surface name ----- ------ -------- ------ -------- ------------ 0.05 0.00 0.00 0.01 0.00 aoantonym 0.37 0.08 0.12 0.10 0.13 pial 7.20 0.95 0.75 1.14 0.79 time_series ---------------------------------------------------------------------- todo: - on alloc failure, propogate error up and return NULL - accessor functions - indexed reading - test doxygen comments - #ifdef __cplusplus - select node list - display all valid attributes? DTD? valid attribute values given the name? known metadata? - gifti_remove_gim_metadata() - gifti_remove_DA_metadata() - gifti_remove_all_metadata() - gifti_MD_delete(name) - post XML read: validate gifti structure - check for UNKNOWN attributes - done?? "invalid darray XX" - check that MD names are unique gifticlib-1.0.9/gifti_xml.c0000644007023700001440000032416211345215135014652 0ustar rickrusers#include #include #include #include "gifti_io.h" #define GXML_MIN_BSIZE 2048 #define GXML_DEF_BSIZE 32768 /* local prototypes */ static int append_to_cdata (gxml_data *, const char *, int); static int append_to_data (gxml_data *, const char *, int); static int append_to_data_ascii(gxml_data *, const char *, int); static int append_to_data_b64 (gxml_data *, char*,long long,const char*, int); /* static int append_to_data_b64gz(gxml_data *, const char *, int); */ static int add_label_rgba (gxml_data *, giiLabelTable *, float *); static int append_to_xform (gxml_data *, const char *, int); static int apply_da_list_order (gxml_data *, const int *, int); static int int_compare (const void * v0, const void * v1); static int copy_b64_data (gxml_data *, const char *, char *, int, int*); static int decode_ascii (gxml_data*,char*,int,int,void*,long long*,int*); static int decode_b64 (gxml_data*, char*, int, char *, long long *); static int disp_gxml_data (char *, gxml_data *, int); static int ename2type (const char *); static int epush (gxml_data *, int, const char *, const char **); static int epop (gxml_data *, int, const char *); static int free_xd_data (gxml_data *); static int get_label_attrs (gxml_data *, const char **, int *, float *); static int init_gxml_data (gxml_data *, int, const int *, int); static int partial_buf_size (long long); static int push_gifti (gxml_data *, const char **); static int push_meta (gxml_data *); static int push_md (gxml_data *); static int push_name (gxml_data *); static int push_value (gxml_data *); static int push_LT (gxml_data *); static int push_label (gxml_data *, const char **); static int push_darray (gxml_data *, const char **); static int push_cstm (gxml_data *); static int push_data (gxml_data *); static int push_dspace (gxml_data *); static int push_xspace (gxml_data *); static int push_xform (gxml_data *); static int reset_xml_buf (gxml_data *, char **, int *); static void show_attrs (gxml_data *,int,const char **); static void show_depth (int, int, FILE *); static void show_enames (FILE *); static int show_stack (char *, gxml_data *); static int short_sorted_da_list(gxml_data *dp, const int * dalist, int len); static int stack_is_valid (gxml_data *); static int whitespace_len (const char *, int); static int update_xml_buf_size (gxml_data *, long long); static int update_partial_buffer(char **, int *, long long, int); static int count_bad_b64_chars (const char *, int); static int show_bad_b64_chars (const char *, int); static giiMetaData * find_current_MetaData(gxml_data *, int); #ifndef XMLCALL /* XMLCALL was added to expat in version 1.95.7 to define a calling convention, * as cdecl */ #if defined(XML_USE_MSC_EXTENSIONS) #define XMLCALL __cdecl #elif defined(__GNUC__) && defined(__i386) #define XMLCALL __attribute__((cdecl)) #else #define XMLCALL #endif #endif /* not defined XMLCALL */ #ifndef XML_STATUS_ERROR #define XML_STATUS_ERROR 0 #endif #ifndef XML_STATUS_OK #define XML_STATUS_OK 1 #endif static void XMLCALL cb_start_ele (void *, const char *, const char **); static void XMLCALL cb_end_ele (void *, const char *); static void XMLCALL cb_char (void *, const char *, int); static void XMLCALL cb_instr (void *, const char *, const char *); static void XMLCALL cb_comment (void *, const char *); static void XMLCALL cb_cdata_start (void *); static void XMLCALL cb_cdata_end (void *); static void XMLCALL cb_default (void *, const char *, int); static void XMLCALL cb_xml_dec (void *, const char *, const char * , int); static void XMLCALL cb_start_doctype(void *, const char *, const char *, const char *, int); static void XMLCALL cb_end_doctype (void *); static void XMLCALL cb_elem_dec (void *, const char *, XML_Content *); static XML_Parser init_xml_parser (void *); /* writing functions */ static int gxml_write_gifti (gxml_data *, FILE *); static int gxml_write_preamble (FILE *); static int ewrite_text_ele (int, const char *, const char *, int, int, FILE *); static int ewrite_coordsys (gxml_data *, giiCoordSystem *, FILE *); static int ewrite_data (gxml_data *, giiDataArray *, FILE *); static int ewrite_data_line (void *, int, long long, long long, int, FILE *); static int ewrite_double_line (double *, int, int, FILE *); static int ewrite_int_attr (const char *, int, int, int, FILE *); static int ewrite_long_long_attr (const char *, long long, int, int, FILE *); static int ewrite_str_attr (const char*, const char*, int, int, FILE*); static int ewrite_darray (gxml_data *, giiDataArray *, FILE *); static int ewrite_ex_atrs (gxml_data *, nvpairs *, int, int, FILE *); static int ewrite_LT (gxml_data*, giiLabelTable*, int, FILE*); static int ewrite_meta (gxml_data *, giiMetaData *, FILE *); static int gxml_disp_b64_data (const char *, const void *, int, FILE *); /* these should match GXML_ETYPE_* defines */ static char * enames[GXML_MAX_ELEN] = { "Invalid", "GIFTI", "MetaData", "MD", "Name", "Value", "LabelTable", "Label", "DataArray", "CoordinateSystemTransformMatrix", "Data", "DataSpace", "TransformedSpace", "MatrixData", "CDATA" }; /* ---------------------------------------------------------------------- */ /* GIFTI XML global struct and access functions */ static gxml_data GXD = { 1, /* verb, default to 1 (0 means quiet) */ 1, /* dstore, flag whether to store data */ 3, /* indent, spaces per indent level */ GXML_DEF_BSIZE, /* buf_size, allocated for XML parsing */ GIFTI_B64_CHECK_SKIPNCOUNT, /* b64_check, for b64 errors */ 1, /* assume it is okay to update metadata */ GZ_DEFAULT_COMPRESSION, /* zlevel, compress level, -1..9 */ NULL, /* da_list, list of DA indices to store */ 0, /* da_len, length of da_list */ 0, /* da_ind, current index into da_list */ 0, /* eleDA, number of DA elements found */ 0, /* expDA, number of DA elements expected */ 0, /* b64_errors, number of errors found */ 0, /* errors, number of encountered errors */ 0, /* skip depth (at positive depth, 0 is clear) */ 0, /* depth, current stack depth */ {0}, /* stack, ints, max depth GXML_MAX_DEPTH */ 0, /* dind, index into decoded data array */ 0, /* clen, length of current CDATA string */ 0, /* xlen, length of current xform buffer */ 0, /* dlen, length of current Data buffer */ 0, /* doff, offset into current data buffer */ 0, /* zlen, length of compression buffer */ NULL, /* cdata, CDATA char pointer */ NULL, /* xdata, xform buffer pointer */ NULL, /* ddata, Data buffer pointer */ NULL, /* zdata, compression buffer pointer */ NULL /* gim, gifti_image *, for results */ }; #ifndef HAVE_ZLIB /* so we can print a callback message once per file */ static int g_first_zlib_err_msg = 1; #endif /*--- Base64 binary encoding and decoding tables ---*/ /* encoding: converting values 0-63 to characters */ static unsigned char b64_encode_table[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 26 upper case */ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', /* 26 lower case */ 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', /* 10 digits */ '+', '/' }; /* decoding: converting characters A-Z, a-z, 0-9, +, /, to integers 0-63 * (other characters are considered invalid, though '=' is mapped to 0, * to account for the end of input (didn't Arnold make a movie about that?)) */ static unsigned char b64_decode_table[256] = { 128, 128, 128, 128, 128, 128, 128, 128, /* 0 - 7 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 8 - 15 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 16 - 23 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 24 - 31 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 32 - 39 */ /* d['+'] = d[43] = 62, d['/'] = d[47] = 63 */ 128, 128, 128, 62, 128, 128, 128, 63, /* 40 - 47 */ /* d['0'] = d[48] = 52, ... d['9'] = 61, d['='] = 0 */ 52, 53, 54, 55, 56, 57, 58, 59, /* 48 - 55 */ 60, 61, 128, 128, 128, 0, 128, 128, /* 56 - 63 */ /* d['A'] = d[65] = 0, ... d['Z'] = 25 */ 128, 0, 1, 2, 3, 4, 5, 6, /* 64 - 71 */ 7, 8, 9, 10, 11, 12, 13, 14, /* 72 - 79 */ 15, 16, 17, 18, 19, 20, 21, 22, /* 80 - 87 */ 23, 24, 25, 128, 128, 128, 128, 128, /* 88 - 95 */ /* d['a'] = d[97] = 26, ... d['a'] = 51 */ 128, 26, 27, 28, 29, 30, 31, 32, /* 96 - 103 */ 33, 34, 35, 36, 37, 38, 39, 40, /* 104 - 111 */ 41, 42, 43, 44, 45, 46, 47, 48, /* 112 - 119 */ 49, 50, 51, 128, 128, 128, 128, 128, /* 120 - 127 */ /* ... and the rest, are heeere in deecode liiiiiist! poor Mary Ann :( */ 128, 128, 128, 128, 128, 128, 128, 128, /* 128 - 135 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 136 - 143 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 144 - 151 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 152 - 159 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 160 - 167 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 168 - 175 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 176 - 183 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 184 - 191 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 192 - 199 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 200 - 207 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 208 - 215 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 216 - 223 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 224 - 231 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 232 - 239 */ 128, 128, 128, 128, 128, 128, 128, 128, /* 240 - 247 */ 128, 128, 128, 128, 128, 128, 128, 128 /* 248 - 255 */ }; /* note: the buffer needs to be large enough to contain any contiguous piece of (CDATA?) text, o.w. it will require parsing in pieces */ gifti_image * gxml_read_image(const char * fname, int read_data, const int * dalist, int dalen) { gxml_data * xd = &GXD; /* point to global struct */ XML_Parser parser; unsigned blen; FILE * fp; char * buf = NULL; int bsize; /* be sure it doesn't change at some point */ int done = 0, pcount = 1; if( init_gxml_data(xd, 0, dalist, dalen) ) /* reset non-user variables */ return NULL; xd->dstore = read_data; /* store for global access */ if( !fname ) { fprintf(stderr,"** gxml_read_image: missing filename\n"); return NULL; } fp = fopen(fname, "r"); if( !fp ) { fprintf(stderr,"** failed to open GIFTI XML file '%s'\n", fname); return NULL; } /* create a new buffer */ bsize = 0; if( reset_xml_buf(xd, &buf, &bsize) ) { fclose(fp); return NULL; } if(xd->verb > 1) { fprintf(stderr,"-- reading gifti image '%s'\n", fname); if(xd->da_list) fprintf(stderr," (length %d DA list)\n", xd->da_len); fprintf(stderr,"-- using %d byte XML buffer\n",bsize); if(xd->verb > 4) show_enames(stderr); } /* allocate return structure */ xd->gim = (gifti_image *)calloc(1,sizeof(gifti_image)); if( !xd->gim ) { fprintf(stderr,"** failed to alloc initial gifti_image\n"); free(buf); return NULL; } /* create parser, init handlers */ parser = init_xml_parser((void *)xd); while( !done ) { if( reset_xml_buf(xd, &buf, &bsize) ) /* fail out */ { gifti_free_image(xd->gim); xd->gim = NULL; break; } blen = fread(buf, 1, bsize, fp); done = blen < sizeof(buf); if(xd->verb > 3) fprintf(stderr,"-- XML_Parse # %d\n", pcount); pcount++; if( XML_Parse(parser, buf, blen, done) == XML_STATUS_ERROR) { fprintf(stderr,"** %s at line %u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser)); gifti_free_image(xd->gim); xd->gim = NULL; break; } } if(xd->verb > 1) { if(xd->gim) fprintf(stderr,"-- have gifti image '%s', " "(%d DA elements = %lld MB)\n", fname, xd->gim->numDA, gifti_gim_DA_size(xd->gim,1)); else fprintf(stderr,"** gifti image '%s', failure\n", fname); } fclose(fp); if( buf ) free(buf); /* parser buffer */ XML_ParserFree(parser); if( dalist && xd->da_list ) if( apply_da_list_order(xd, dalist, dalen) ) { fprintf(stderr,"** failed apply_da_list_order\n"); gifti_free_image(xd->gim); xd->gim = NULL; } free_xd_data(xd); /* free data buffers */ return xd->gim; } /* free da_list and buffers */ static int free_xd_data(gxml_data * xd) { if( xd->da_list ){ free(xd->da_list); xd->da_list = NULL; } if( xd->xdata ){ free(xd->xdata); xd->xdata = NULL; } /* xform matrix */ if( xd->zdata) { free(xd->zdata); xd->zdata = NULL; } /* compress buff */ if( xd->ddata ){ free(xd->ddata); xd->ddata = NULL; } /* Data buffer */ return 0; } /* verify that the current lengths match * create a new list of NULL DA pointers * create a 'taken' list, matching xd->da_len (but unset) * for each index, if it is not set, find one and copy */ static int apply_da_list_order(gxml_data * xd, const int * orig, int len) { giiDataArray ** newlist; int * taken; /* whether xd->da_list[i] was used */ int newc, oldc, errors = 0, nDA; if( !xd || !xd->gim || !orig || len <= 0 || !xd->da_list || xd->da_len<=0 ) return 0; /* do nothing, or start small, diversionary fire, hmmm... */ nDA = xd->gim->numDA; /* this may replace da_len */ if( nDA <= 0 ) return 0; /* create new DA list */ newlist = (giiDataArray **)malloc(len * sizeof(giiDataArray *)); if(!newlist){ fprintf(stderr,"** ADLO: no alloc for DAlist\n"); return 1; } /* create taken list (of all 0) */ taken = (int *)calloc(nDA, sizeof(int)); if(!taken){ fprintf(stderr,"** ADLO: no alloc for taken\n"); return 1; } /* insert pointers to current or copied DA */ for( newc = 0; newc < len; newc++ ) { newlist[newc] = NULL; /* in case there are failures */ /* find old index in da_list */ for( oldc = 0; oldc < nDA; oldc++ ) if( xd->da_list[oldc] == orig[newc] ) break; if( oldc >= nDA ) { /* should never happen */ fprintf(stderr,"** ADLO: failed to find index %d in da_list\n", orig[newc]); errors++; continue; } else if ( xd->verb > 3 ) fprintf(stderr,"++ found orig index %d at sorted list %d\n", orig[newc], oldc); /* either steal the pointer or copy the DA */ if( !taken[oldc] ) { taken[oldc] = 1; /* mark it as taken */ newlist[newc] = xd->gim->darray[oldc]; } else { /* we must make a new copy */ newlist[newc] = gifti_copy_DataArray( xd->gim->darray[oldc], 1); if( ! newlist[newc] ) errors++; } } /* at this point, we should be good, but check... */ /* if anything has not been taken, free them and fail */ for( oldc = 0; oldc < nDA; oldc++ ) { if( !taken[oldc] ) { fprintf(stderr,"** ADLO: taken list is not all set\n"); errors++; free(xd->gim->darray[oldc]); } } free(taken); /* we're done with that */ /* free old DA list, since all the pointers are free'd or taken */ free(xd->gim->darray); xd->gim->darray = newlist; xd->gim->numDA = len; /* last check for errors, is the current darray filled? */ for( newc = 0; newc < len; newc++ ) if( ! xd->gim->darray[newc] ) { fprintf(stderr,"** ADLO: copied darray not full\n"); errors++; } return errors; /* we just need to free gim on return */ } /* return 0 on success */ int gxml_write_image(gifti_image * gim, const char * fname, int write_data) { gxml_data * xd = &GXD; /* point to global struct */ FILE * fp; if( !gim ) { fprintf(stderr,"** GXML write: no gifti_image\n"); return 1; } else if ( !fname ) { fprintf(stderr,"** GXML write: no filename\n"); return 1; } if(GXD.verb > 1) { fprintf(stderr,"++ writing gifti image (%s data) to '%s'", write_data?"with":"no", fname); if( write_data ) fprintf(stderr," (%d DA elements = %lld MB)", gim->numDA, gifti_gim_DA_size(gim,1)); fputc('\n', stderr); } #ifndef HAVE_ZLIB /* if the data is to be compressed, fail */ if( gim->darray && gim->darray[0] && gim->darray[0]->encoding == GIFTI_ENCODING_B64GZ ) { fprintf(stderr,"** no ZLIB for compression...\n"); gifti_set_atr_in_DAs(gim, "Encoding", "Base64Binary", NULL, 0); } #endif init_gxml_data(xd, 0, NULL, 0); /* reset non-user variables */ xd->dstore = write_data; /* store for global access */ xd->gim = gim; /* note the library version */ if( xd->update_ok ) { if( xd->verb > 2 ) fprintf(stderr,"++ setting GIFTI MD: gifticlib-version to %s\n", gifticlib_version()); gifti_add_to_meta(&gim->meta,"gifticlib-version",gifticlib_version(),1); } fp = fopen(fname, "w"); if( !fp ) { fprintf(stderr,"** failed to open '%s' for gifti write\n", fname); return 1; } (void)gxml_write_gifti(xd, fp); if( xd->xdata ){ free(xd->xdata); xd->xdata = NULL; } if( xd->zdata) { free(xd->zdata); xd->zdata = NULL; } fclose(fp); return 0; } /*---------- accessor functions for user-controllable variables ----------*/ /*---------- (one can pass -1 to set the default value) ----------*/ /*! verb is the vebose level, with 0 meaning "only report errors" (up to 7) */ int gxml_get_verb( void ){ return GXD.verb; } int gxml_set_verb( int val ) { if ( val == -1 ) GXD.verb = 1; else if( val >= 0 ) GXD.verb = val; return 0; } /*! the dstore flag controls whether data is read from a GIFTI file */ int gxml_get_dstore( void ){ return GXD.dstore; } int gxml_set_dstore( int val ) { if( val ) GXD.dstore = 1; /* includes -1 as applying the default */ else GXD.dstore = 0; return 0; } /*! indent is the number of spaces per indent level written to a GIFTI file */ int gxml_get_indent( void ){ return GXD.indent; } int gxml_set_indent( int val ) { if ( val == -1 ) GXD.indent = 3; else if ( val >= 0 ) GXD.indent = val; else return 1; /* failure - no action */ return 0; } /*! buf_size is the size of the XML I/O buffer given to expat */ int gxml_get_buf_size( void ){ return GXD.buf_size; } int gxml_set_buf_size( int val ) { if ( val == -1 ) GXD.buf_size = GXML_DEF_BSIZE; else if ( val > 0 ) GXD.buf_size = val; else return 1; /* failure - no action */ return 0; } /*! b64_check is the checking level for base64 binary data (see gifti_io.h) */ int gxml_get_b64_check( void ){ return GXD.b64_check; } int gxml_set_b64_check( int val ) /* -1 means apply default */ { if( val == -1 ) GXD.b64_check = GIFTI_B64_CHECK_SKIPNCOUNT; else if ( val > GIFTI_B64_CHECK_UNDEF && val <= GIFTI_B64_CHECK_MAX ) GXD.b64_check = val; else return 1; /* failure - no action */ return 0; } /*! update_ok tells the library whether it is allowed to modify metadata */ int gxml_get_update_ok( void ){ return GXD.update_ok; } int gxml_set_update_ok( int val ) { if ( val == -1 ) GXD.update_ok = 1; /* default is yes */ else if ( val >= 0 ) GXD.update_ok = val; else return 1; /* failure - no action */ return 0; } /*! zlevel is the zlib compression level, with -1 implying the default (of 6, I believe) and value levels being in {0..9} (with 0 meaning no compression) */ int gxml_get_zlevel( void ){ return GXD.zlevel; } int gxml_set_zlevel( int val ) { if( val == -1 ) GXD.zlevel = GZ_DEFAULT_COMPRESSION; else if ( val >= 0 && val <= 9 ) GXD.zlevel = val; else return 1; /* failure - no action */ return 0; } /*----------------------- END accessor functions -----------------------*/ static int init_gxml_data(gxml_data *dp, int doall, const int *dalist, int len) { int errs = 0; if( doall ) { /* user modifiable - init all to defaults */ dp->verb = 1; dp->dstore = 1; dp->indent = 3; dp->buf_size = GXML_DEF_BSIZE; dp->b64_check = GIFTI_B64_CHECK_SKIPNCOUNT; dp->update_ok = 1; dp->zlevel = GZ_DEFAULT_COMPRESSION; } if( dalist && len > 0 ) { if( short_sorted_da_list(dp, dalist, len) ) errs++; /* continue */ } else { dp->da_list = NULL; dp->da_len = 0; } dp->da_ind = 0; /* maybe show the user */ if( dp->verb > 2 ) disp_gxml_data("-- user opts: ", dp, dp->verb > 3); dp->eleDA = 0; dp->expDA = 0; dp->b64_errors = 0; dp->errors = 0; dp->skip = 0; dp->depth = 0; memset(dp->stack, 0, sizeof(dp->stack)); dp->dind = 0; dp->clen = 0; dp->xlen = 0; dp->dlen = 0; dp->doff = 0; dp->zlen = 0; dp->cdata = NULL; dp->xdata = NULL; dp->ddata = NULL; dp->zdata = NULL; dp->gim = NULL; #ifndef HAVE_ZLIB /* if we don't have this (and need it), print warnings */ g_first_zlib_err_msg = 1; #endif return errs; } static int short_sorted_da_list(gxml_data *dp, const int * dalist, int len) { int * da_copy, c, cind; /* first, duplicate list */ da_copy = (int *)malloc(len*sizeof(int)); if( !da_copy ) { fprintf(stderr,"** cannot duplicate da_list of %d elements\n", len); return 1; } for( c = 0; c < len; c++ ) da_copy[c] = dalist[c]; /* now sort */ qsort(da_copy, len, sizeof(int), int_compare); /* remove duplicates */ for( c = 1, cind = 0; c < len; c++ ) { if( da_copy[c] != da_copy[cind] ) { cind++; if( cind < c ) da_copy[cind] = da_copy[c]; } } dp->da_list = da_copy; dp->da_len = cind+1; if( dp->verb > 1 ) { fprintf(stderr,"-- original da_list:"); for(c = 0; c < len; c++ ) fprintf(stderr," %d", dalist[c]); fputc('\n', stderr); fprintf(stderr,"++ unique, sorted da_list:"); for(c = 0; c < dp->da_len; c++ ) fprintf(stderr," %d", dp->da_list[c]); fputc('\n', stderr); } return 0; } /* for qsort */ static int int_compare(const void * v0, const void * v1) { int * i0 = (int *)v0; int * i1 = (int *)v1; if( *i0 < *i1 ) return -1; if( *i0 == *i1 ) return 0; return 1; } /* ---------------------------------------------------------------------- */ static void show_depth( int depth, int show, FILE * fp ) { if( show ) fprintf(fp, "%*s %02d ", 3*depth, "", depth); else fprintf(fp, "%*s ", 3*depth, ""); } static void show_enames( FILE * fp ) { int c; fprintf(fp, "-------------------------------\n" "++ ename list :\n"); for( c = 0; c <= GXML_ETYPE_LAST; c++ ) fprintf(fp," %02d : %s\n", c, enames[c]); fprintf(fp, "-------------------------------\n"); } static int ename2type( const char * name ) { int etype; for( etype = GXML_ETYPE_LAST; etype > GXML_ETYPE_INVALID; etype-- ) if( !strcmp(name, enames[etype]) ) break; return etype; } /* name should be null terminated */ static int epush( gxml_data * xd, int etype, const char * ename, const char ** attr ) { if( xd->depth < 0 || xd->depth > GXML_MAX_DEPTH ) { fprintf(stderr,"** push: stack depth %d out of [0,%d] range\n", xd->depth, GXML_MAX_DEPTH); xd->errors++; return 1; } if( xd->verb > 4 ) { /* maybe we want to print something */ show_depth(xd->depth, 1, stderr); fprintf(stderr,"++ push %02d: '%s'\n", etype, enames[etype]); } xd->stack[xd->depth] = etype; xd->depth++; /* if we are in a skip block, do nothing but monitor stack */ if( xd->skip ) { if( xd->verb > 2 ) fprintf(stderr,"-- skip=%d, depth=%d, skipping element '%s'\n", xd->skip, xd->depth, ename); return 0; } /* determine whether we should enter a skip block */ if( etype == GXML_ETYPE_INVALID ) { if(xd->verb > 0) fprintf(stderr,"** pushed invalid element, '%s', skip depth %d\n", ename, xd->depth); xd->skip = xd->depth; return 1; } if ( xd->verb > 5 ) show_stack("++ ", xd); if( !stack_is_valid(xd) ) return 1; /* call appropriate XML processing function */ switch( etype ) { case GXML_ETYPE_GIFTI : return push_gifti (xd, attr); case GXML_ETYPE_META : return push_meta (xd); case GXML_ETYPE_MD : return push_md (xd); case GXML_ETYPE_NAME : return push_name (xd); case GXML_ETYPE_VALUE : return push_value (xd); case GXML_ETYPE_LABELTABLE : return push_LT (xd); case GXML_ETYPE_LABEL : return push_label (xd, attr); case GXML_ETYPE_DATAARRAY : return push_darray(xd, attr); case GXML_ETYPE_CSTM : return push_cstm (xd); case GXML_ETYPE_DATA : return push_data (xd); case GXML_ETYPE_DATASPACE : return push_dspace(xd); case GXML_ETYPE_XFORMSPACE : return push_xspace(xd); case GXML_ETYPE_MATRIXDATA : return push_xform (xd); case GXML_ETYPE_CDATA : return 0; /* do nothing */ default: fprintf(stderr,"** epush, unknow type '%s'\n",enames[etype]); break; } return 1; } /* initialize the gifti_element and set attributes */ static int push_gifti(gxml_data * xd, const char ** attr ) { gifti_image * gim; int c; if( !xd ) return 1; /* be explicit with pointers (struct should be clear) */ gim = xd->gim; gifti_clear_gifti_image(gim); if( !attr ) return 0; for(c = 0; attr[c]; c+= 2 ) if( gifti_str2attr_gifti(gim, attr[c], attr[c+1]) ) if( gifti_add_to_nvpairs(&gim->ex_atrs,attr[c],attr[c+1]) ) return 1; if( xd->verb > 1 ) fprintf(stderr,"++ set %d GIFTI attr(s)\n",c/2); if( xd->verb > 3 ) gifti_disp_gifti_image("push:", gim, 0); /* now store any gim->numDA, and use gim to count as they are added */ if( gim->numDA >= 0 ) { xd->expDA = gim->numDA; gim->numDA = 0; /* clear for counting */ if( xd->verb > 1 ) fprintf(stderr,"-- expecting %d DA elements\n", xd->expDA); } return 0; } /* simply verify that we have not been here before */ static int push_meta(gxml_data * xd) { giiMetaData * md = find_current_MetaData(xd, 0); if( md->length != 0 || md->name || md->value ) { fprintf(stderr,"** push meta: already initialized??\n"); return 1; } return 0; } /* find the parent struct, and return its meta field */ static giiMetaData * find_current_MetaData(gxml_data * xd, int cdepth) { giiDataArray * da; giiMetaData * md; int da_ind, parent; if( !xd || cdepth < 0 || xd->depth < (2+cdepth) ) { fprintf(stderr,"FMeta: bad params (%p,%d)\n",(void *)xd,cdepth); return NULL; } /* find the appropriate parent struct */ parent = xd->stack[xd->depth-2-cdepth]; if( parent == GXML_ETYPE_GIFTI ) md = &xd->gim->meta; else if( parent == GXML_ETYPE_DATAARRAY ) { if( !xd->gim->darray ) { fprintf(stderr,"** FMeta: gim->darry not initialized\n"); return NULL; } da_ind = xd->gim->numDA-1; da = xd->gim->darray[da_ind]; if( !da ) { fprintf(stderr,"** FMeta: gim->darry[%d] not initialized\n",da_ind); return NULL; } md = &da->meta; } else { fprintf(stderr,"** FMeta: child of invalid parent '%s'\n", enames[parent]); return NULL; } return md; } /* we will add a pair, so update length and allocate pointers */ static int push_md(gxml_data * xd) { giiMetaData * md = find_current_MetaData(xd, 1); /* MD is 1 below */ if( !md ) return 1; /* error were printed */ md->length++; md->name = (char **)realloc(md->name, md->length * sizeof(char *)); md->value = (char **)realloc(md->value, md->length * sizeof(char *)); if( !md->name || !md->value ) { fprintf(stderr,"** failed to realloc %d MD pointers\n",md->length); md->length = 0; return 1; } /* and clear the new pointers */ md->name[md->length-1] = NULL; md->value[md->length-1] = NULL; return 0; } /* set cdata to the current meta->name address, and clear it */ static int push_name(gxml_data * xd) { giiMetaData * md = find_current_MetaData(xd, 2); /* name is 2 below */ if( !md ) return 1; xd->cdata = &md->name[md->length-1]; /* use cdata to fill */ *xd->cdata = NULL; /* init to empty */ xd->clen = 0; return 0; } /* set cdata to the current meta->value address, and clear it */ static int push_value(gxml_data * xd) { giiMetaData * md = find_current_MetaData(xd, 2); /* value is 2 below */ if( !md ) return 1; xd->cdata = &md->value[md->length-1]; /* use cdata to fill */ *xd->cdata = NULL; /* init to empty */ xd->clen = 0; return 0; } /* check that LT is currently empty */ static int push_LT(gxml_data * xd) { giiLabelTable * lt = &xd->gim->labeltable; if( lt->length || lt->key || lt->label ) { fprintf(stderr,"** multiple giiLabelTables?\n"); } return 0; } /* increase LabelTable length by 1, and fill new entries * (note that the Key (or Index) attribute is required) * * 'Index' attribute has been replaced by 'Key' 7 Mar 2010 */ static int push_label(gxml_data * xd, const char ** attr) { giiLabelTable * lt = &xd->gim->labeltable; float rgba[4]={0.0, 0.0, 0.0, 0.0}; int key=0, rv; lt->length++; lt->key = (int *)realloc(lt->key, lt->length * sizeof(int)); lt->label = (char **)realloc(lt->label, lt->length * sizeof(char *)); if( !lt->key || !lt->label ) { fprintf(stderr,"** gifti alloc failure for label %d\n",lt->length); return 1; } /* set key from the attributes */ if( !attr ) { fprintf(stderr,"** Label %d missing attributes\n", lt->length-1); lt->key[lt->length-1] = 0; } else { /* get any known attributes */ rv = get_label_attrs(xd, attr, &key, rgba); if ( rv == 1 ) { lt->key[lt->length-1] = key; } else if ( rv == 2 ) { lt->key[lt->length-1] = key; (void) add_label_rgba(xd, lt, rgba); } /* else error already printed */ } xd->cdata = lt->label + (lt->length-1); /* addr of newest (char *) */ *xd->cdata = NULL; /* init to empty */ xd->clen = 0; return 0; } /* add the rgba entries to the LabelTable, length is already updated */ static int add_label_rgba(gxml_data * xd, giiLabelTable * lt, float * rgba) { if( !xd || !lt || !rgba ) { fprintf(stderr,"** add_label_rgba, bad params\n"); return 1; } if( lt->length > 1 && !lt->rgba ) { fprintf(stderr,"** first RGBA at Label %d, so table is incomplete\n", lt->length-1); return 1; } lt->rgba = (float *)realloc(lt->rgba, lt->length * 4 * sizeof(float)); if( !lt->rgba ) { fprintf(stderr,"** failed to malloc rgba of length %d\n", lt->length); return 1; } memcpy(lt->rgba + 4*(lt->length-1), rgba, 4*sizeof(float)); if(xd->verb > 4) fprintf(stderr,"-- adding Label RGBA %g %g %g %g\n", lt->rgba[0], lt->rgba[1], lt->rgba[2], lt->rgba[3]); return 0; } /* get key and RGBA attributes, if they exist * return 1 if key, 2 if key+rgba, 0 if neither, -1 on error */ static int get_label_attrs(gxml_data * xd, const char ** attr, int * key, float * rgba) { giiLabelTable * lt = &xd->gim->labeltable; const char ** aptr; char * endp; /* for verifying float read */ int found, lind; if( !xd || !key || !rgba ) { fprintf(stderr,"** GLA: missing params\n"); return -1; } if( !attr || !*attr ) return 0; /* note label index */ lind = lt->length - 1; found = 0; /* bitmask, key,R,G,B,A (in 0..31, should end as 1 or 31) */ for( aptr = attr; *aptr ; aptr += 2 ) { if( !aptr[1] ) { fprintf(stderr,"** label %d, attr %s, missing value\n",lind,*aptr); return -1; } if( !strcmp(*aptr, "Key") ) { *key = atoi(aptr[1]); found |= (1<<0); } else if( !strcmp(*aptr, "Index") ) { /* old form of Key */ *key = atoi(aptr[1]); found |= (1<<0); } else if( !strcmp(*aptr, "Red") ) { rgba[0] = strtod(aptr[1], &endp); if( endp <= aptr[1] ) { fprintf(stderr,"** bad GIFTI label %d Red attr\n", lind); show_attrs(xd, GXML_ETYPE_LABEL, attr); return -1; } found |= (1<<1); } else if( !strcmp(*aptr, "Green") ) { rgba[1] = strtod(aptr[1], &endp); if( endp <= aptr[1] ) { fprintf(stderr,"** bad GIFTI label %d Green attr\n", lind); show_attrs(xd, GXML_ETYPE_LABEL, attr); return -1; } found |= (1<<2); } else if( !strcmp(*aptr, "Blue") ) { rgba[2] = strtod(aptr[1], &endp); if( endp <= aptr[1] ) { fprintf(stderr,"** bad GIFTI label %d Blue attr\n", lind); show_attrs(xd, GXML_ETYPE_LABEL, attr); return -1; } found |= (1<<3); } else if( !strcmp(*aptr, "Alpha") ) { rgba[3] = strtod(aptr[1], &endp); if( endp <= aptr[1] ) { fprintf(stderr,"** bad GIFTI label %d Alpha attr\n", lind); show_attrs(xd, GXML_ETYPE_LABEL, attr); return -1; } found |= (1<<4); } else { fprintf(stderr,"** unknown GIFTI label %d attr\n", lind); show_attrs(xd, GXML_ETYPE_LABEL, attr); return -1; } } if( found == 0 ) { fprintf(stderr,"** GIFTI label %d, missing 'Key' attr\n", lind); return 0; } else if( found != 1 && found != 31 ) { fprintf(stderr,"** GIFTI label %d, partial attributes\n", lind); show_attrs(xd, GXML_ETYPE_LABEL, attr); return -1; } if(xd->verb > 2) { if( found == 1 ) fprintf(stderr,"-- have Label Key %d\n", *key); else fprintf(stderr,"-- have Label Key %d, RGBA %g %g %g %g\n", *key, rgba[0], rgba[1], rgba[2], rgba[3]); } if( found == 1 ) return 1; return 2; } /* initialize the gifti_element and set attributes */ static int push_darray(gxml_data * xd, const char ** attr) { giiDataArray * da; /* maintain a count of the number seen */ xd->eleDA++; if( xd->da_list ) { if( (xd->da_ind < xd->da_len) && (xd->da_list[xd->da_ind] == xd->eleDA-1) ) /* keeper */ { if(xd->verb > 1) fprintf(stderr,"++ keeping DA[%d]\n",xd->eleDA-1); xd->da_ind++; } else { if(xd->verb > 1) fprintf(stderr,"++ skipping DA[%d]\n",xd->eleDA-1); xd->skip = xd->depth; return 1; /* return and skip this element */ } } if( gifti_add_empty_darray(xd->gim, 1) ) return 1; da = xd->gim->darray[xd->gim->numDA-1]; /* get new pointer */ /* fill the struct from the attributes (store ex_atrs) */ if( gifti_set_DA_atrs(da, attr, 0, 1) ) return 1; (void)gifti_valid_DataArray(da, xd->verb > 1); /* make a request to potentially update the XML buffer size */ if( da->nvals>0 && da->nbyper>0 ) update_xml_buf_size(xd, da->nvals*da->nbyper); if( xd->verb > 4 ) gifti_disp_DataArray("push:", da, 0); return 0; } /* check for base64 errors, needed uncompression, and byte swapping */ static int pop_darray(gxml_data * xd) { giiDataArray * da = xd->gim->darray[xd->gim->numDA-1]; /* current DA */ if( !da ) return 1; /* check for and clear any b64 errors */ if( xd->b64_errors > 0 ) { if( xd->b64_check == GIFTI_B64_CHECK_DETECT ) fprintf(stderr,"** bad base64 chars found in DataArray[%d]\n", xd->gim->numDA-1); else if( xd->b64_check == GIFTI_B64_CHECK_COUNT || xd->b64_check == GIFTI_B64_CHECK_SKIPNCOUNT ) fprintf(stderr,"** %d bad base64 chars found in DataArray[%d]\n", xd->b64_errors, xd->gim->numDA-1); xd->b64_errors = 0; } if( da->encoding == GIFTI_ENCODING_B64GZ && da->data ) { #ifdef HAVE_ZLIB /* for compiling, higher level test elsewhere */ long long olen; /* to avoid warnings printing outlen */ uLongf outlen = da->nvals*da->nbyper; int rv = 0; /* unzip zdata to da->data */ if( xd->verb > 2 ) fprintf(stderr,"-- uncompressing %lld bytes into %lld\n", xd->dind, (long long)outlen); rv = uncompress(da->data, &outlen, (Bytef*)xd->zdata, xd->dind); olen = outlen; if( rv != Z_OK ) { fprintf(stderr,"** uncompress fails for DA[%d]\n",xd->gim->numDA-1); if( rv == Z_MEM_ERROR ) fprintf(stderr," (zlib failure, not enough memory)\n"); else if ( rv == Z_BUF_ERROR ) fprintf(stderr," (zlib failure, output buffer too short)\n"); else if ( rv == Z_DATA_ERROR ) fprintf(stderr," (zlib failure, corrupted data)\n"); else if ( rv != Z_OK ) fprintf(stderr," (zlib failure, unknown error %d)\n", rv); } else if ( xd->verb > 2 || (xd->verb > 1 && xd->gim->numDA == 1 )) fprintf(stderr,"-- uncompressed buffer (%.2f%% of %lld bytes)\n", 100.0*xd->dind/olen, olen); if( olen != da->nvals*da->nbyper ) { fprintf(stderr,"** uncompressed buf is %lld bytes, expected %lld\n", olen, da->nvals*da->nbyper); } #endif xd->gim->compressed = 1; /* flag whether some data was compressed */ } /* possibly read data from an external file */ if( da->ext_fname && *da->ext_fname ) (void)gifti_read_extern_DA_data(da); /* nothing to do on failure */ /* possibly perform byte-swapping on data */ if( da->data && da->encoding != GIFTI_ENCODING_ASCII ) { long long nvals; int swapsize; gifti_datatype_sizes(da->datatype, NULL, &swapsize); if( swapsize <= 0 ) { fprintf(stderr,"** bad swapsize %d for dtype %d\n", swapsize, da->datatype); return 1; } nvals = da->nvals * da->nbyper / swapsize; if( gifti_check_swap(da->data, da->endian, nvals, swapsize) ) xd->gim->swapped = 1; /* flag that it happened */ } return 0; } /* make space for a new CS structure in the current DataArray */ static int push_cstm(gxml_data * xd) { giiDataArray * da = xd->gim->darray[xd->gim->numDA-1]; /* current DA */ if( da->intent != NIFTI_INTENT_POINTSET && xd->verb > 0 ) fprintf(stderr,"** DA[%d] has coordsys with intent %s (should be %s)\n", xd->gim->numDA-1, gifti_intent_to_string(da->intent), gifti_intent_to_string(NIFTI_INTENT_POINTSET)); if( gifti_add_empty_CS(da) ) return 1; return 0; } /* verify the processing buffer space, alloc data space */ static int push_data(gxml_data * xd) { giiDataArray * da = xd->gim->darray[xd->gim->numDA-1]; /* current DA */ int zsize; xd->dind = 0; /* init for filling */ xd->doff = 0; if( ! xd->dstore ) { if( xd->verb > 3 ) fprintf(stderr,"-- skipping data[%d]\n",xd->gim->numDA-1); xd->skip = xd->depth; return 1; } if( update_partial_buffer(&xd->ddata, &xd->dlen, da->nbyper*da->nvals, 0) ) return 1; if( da->encoding == GIFTI_ENCODING_B64GZ ) { #ifndef HAVE_ZLIB /* we don't know the encoding until push_darray */ if( g_first_zlib_err_msg ) { fprintf(stderr,"** no ZLIB: skipping all compressed data\n"); g_first_zlib_err_msg = 0; } xd->skip = xd->depth; return 1; /* return and skip this element */ #endif zsize = da->nbyper*da->nvals * 1.01 + 12; /* zlib.net */ if( xd->verb > 2 ) fprintf(stderr,"++ creating extra zdata for zlib extraction\n"); if( update_partial_buffer(&xd->zdata, &xd->zlen, zsize, 1) ) return 1; } /* allocate space for data */ if( da->nvals <= 0 || da->nbyper <= 0 ) { fprintf(stderr,"** PD: bad vals,bytes = %u, %d\n", (unsigned)da->nvals,da->nbyper); return 1; } da->data = calloc(da->nvals, da->nbyper); if( ! da->data ) { fprintf(stderr,"** PD: failed to alloc %lld bytes for darray[%d]\n", da->nvals*da->nbyper, xd->gim->numDA-1); return 1; } else if ( xd->verb > 3 ) fprintf(stderr,"++ PD: alloc %lld bytes for darray[%d]\n", da->nvals*da->nbyper, xd->gim->numDA-1); return 0; } /* point cdata to the correct location and init */ static int push_dspace(gxml_data * xd) { int CSind = xd->gim->darray[xd->gim->numDA-1]->numCS-1; if( CSind < 0 ) { fprintf(stderr,"** PD: bad numCS %d in darray %d, skipping...", CSind+1, xd->gim->numDA-1); xd->skip = xd->depth; return 1; } if( !xd->gim->darray[xd->gim->numDA-1]->coordsys[CSind] ) { fprintf(stderr,"** found dataspace without coordsys, skipping...\n"); xd->skip = xd->depth; return 1; } xd->cdata = &xd->gim->darray[xd->gim->numDA-1]->coordsys[CSind]->dataspace; *xd->cdata = NULL; /* init to empty */ xd->clen = 0; return 0; } /* point cdata to the correct location and init */ static int push_xspace(gxml_data * xd) { int CSind = xd->gim->darray[xd->gim->numDA-1]->numCS-1; if( CSind < 0 ) { fprintf(stderr,"** PX: bad numCS %d in darray %d, skipping...", CSind+1, xd->gim->numDA-1); xd->skip = xd->depth; return 1; } if( !xd->gim->darray[xd->gim->numDA-1]->coordsys[CSind] ) { fprintf(stderr,"** found xformspace without coordsys, skipping...\n"); xd->skip = xd->depth; return 1; } xd->cdata = &xd->gim->darray[xd->gim->numDA-1]->coordsys[CSind]->xformspace; *xd->cdata = NULL; /* init to empty */ xd->clen = 0; return 0; } /* verify the processing buffer space */ static int push_xform(gxml_data * xd) { int CSind = xd->gim->darray[xd->gim->numDA-1]->numCS-1; if( CSind < 0 ) { fprintf(stderr,"** PXform: bad numCS %d in darray %d, skipping...", CSind+1, xd->gim->numDA-1); xd->skip = xd->depth; return 1; } if( !xd->gim->darray[xd->gim->numDA-1]->coordsys[CSind] ) { fprintf(stderr,"** found xform without coordsys, skipping...\n"); xd->skip = xd->depth; return 1; } /* just make sure we have a text buffer to work with */ if( !xd->xdata || xd->xlen <= 0 ) { xd->xlen = 2048; xd->xdata = (char *)malloc(xd->xlen * sizeof(char)); if( !xd->xdata ) { fprintf(stderr,"** cannot alloc %d bytes for xform\n",xd->xlen); return 1; } } xd->dind = 0; /* init for filling */ xd->doff = 0; return 0; } static int epop( gxml_data * xd, int etype, const char * ename ) { giiDataArray * da; xd->cdata = NULL; /* clear fields for future use */ xd->clen = 0; if( xd->skip == xd->depth ) { /* just completed skip element */ if( xd->verb > 2 ) fprintf(stderr,"-- popping skip element '%s' at depth %d\n", ename, xd->depth); xd->skip = 0; /* clear skip level */ } else { /* may peform pop action for this element */ switch( etype ) { default: /* do nothing special */ break; case GXML_ETYPE_DATA : if(xd->verb>3)fprintf(stderr,"-- data dind = %lld\n",xd->dind); /* if we have not read data, but allocated for it, free */ da = xd->gim->darray[xd->gim->numDA-1]; if( da->data && xd->dind == 0 ) { if( xd->verb > 3 ) fprintf(stderr," (freeing data)\n"); free(da->data); da->data = NULL; } break; case GXML_ETYPE_DATAARRAY : pop_darray(xd); break; case GXML_ETYPE_GIFTI : if(xd->eleDA != xd->expDA) fprintf(stderr,"** found %d DAs, expected %d\n", xd->eleDA, xd->expDA); else if(xd->da_list && (xd->da_len != xd->da_ind)) fprintf(stderr,"** stored %d DAs, wanted %d\n", xd->da_ind, xd->da_len); if(xd->verb > 2) gifti_disp_gifti_image("pop:", xd->gim, xd->verb > 4); if(xd->verb > 1) { /* check flags */ if(xd->gim->swapped) fprintf(stderr,"++ data was byte-swapped\n"); if(xd->gim->compressed) fprintf(stderr,"++ data was compressed\n"); } break; } } xd->depth--; if( xd->verb > 5 ) { show_depth(xd->depth, 1, stderr); fprintf(stderr,"++ pop %02d : '%s'\n", etype, enames[etype]); } if( xd->depth < 0 || xd->depth > GXML_MAX_DEPTH ) { fprintf(stderr,"** pop: stack depth %d out of [0,%d] range\n", xd->depth, GXML_MAX_DEPTH); xd->errors++; return -1; } return 0; } /* return the number of bytes of leading whitespace, up to a max of len */ static int whitespace_len(const char * str, int len) { int c; if( !str || !*str || len < 1 ) return 0; for( c = 0; c < len; c++ ) if( !isspace(str[c]) ) return c; return len; } static void show_attrs(gxml_data * xd, int etype, const char ** attr) { int count; show_depth(xd->depth, 1, stderr); fprintf(stderr, ": element %s\n", enames[etype]); for( count = 0; attr[count]; count += 2 ){ show_depth(xd->depth, 0, stderr); fprintf(stderr," attr: %s='%s'\n", attr[count], attr[count+1]); } } static void XMLCALL cb_start_ele(void *udata, const char *ename, const char **attr) { gxml_data * xd = (gxml_data *)udata; int etype; etype = ename2type(ename); if( xd->verb > 3 ) show_attrs(xd, etype, attr); /* process attributes and push() */ (void)epush(xd, etype, ename, attr); } /* if ending Data, clear prev_end_check */ static void XMLCALL cb_end_ele(void *udata, const char * ename) { gxml_data * xd = (gxml_data *)udata; epop(xd, ename2type(ename), ename); } /* May divide Data, but apparently not attributes, perhaps because the Data section is longer than the buffer is wide. if in Data: if prev_end_check if( ! char_is_whitespace(first) && concat_is_number() ) concatencate as number to adjust previous number verify rest is whitespace return (we don't expect to start a new number) else apply previous number if( !char_is_whitespace(last) ) store trailing non-space in concat_buf else prev_end_check = 0 apply number (though it may change later) */ static void XMLCALL cb_char(void *udata, const char * cdata, int length) { gxml_data * xd = (gxml_data *)udata; const char * str = cdata; int len = length, wlen = 0, parent; if( xd->skip > 0 ) { if(xd->verb > 3) fprintf(stderr,"-- skipping char [%d]\n",len); return; } /* act based on the parent type */ parent = xd->stack[xd->depth-1]; if( parent == GXML_ETYPE_CDATA ) parent = xd->stack[xd->depth-2]; if( parent != GXML_ETYPE_DATA ) wlen = whitespace_len(str,length); switch( parent ) { case GXML_ETYPE_DATA : (void)append_to_data(xd, cdata, length); break; case GXML_ETYPE_MATRIXDATA : (void)append_to_xform(xd, cdata, length); break; case GXML_ETYPE_GIFTI : case GXML_ETYPE_META : case GXML_ETYPE_MD : case GXML_ETYPE_LABELTABLE : case GXML_ETYPE_DATAARRAY : case GXML_ETYPE_CSTM : if( wlen != length && xd->verb ) { fprintf(stderr,"** invalid chars under %s: '%.*s'\n", enames[parent], length, cdata); } break; case GXML_ETYPE_NAME : case GXML_ETYPE_VALUE : case GXML_ETYPE_LABEL : case GXML_ETYPE_DATASPACE : case GXML_ETYPE_XFORMSPACE : if( xd->verb > 4 ) fprintf(stderr,"++ append cdata, parent %s\n",enames[parent]); (void)append_to_cdata(xd, cdata, length); break; case GXML_ETYPE_CDATA : fprintf(stderr,"** CDATA is the parent of CDATA???\n"); return; default: /* drop through */ fprintf(stderr,"** unknown parent of char: %d\n", parent); return; } if( wlen == length ) { /* if it is all whitespace */ if( xd->verb < 5 ) return; str = "whitespace"; /* just note the whitespace */ len = strlen(str); } if( xd->verb > 4 ) { show_depth(xd->depth, 1, stderr); if( parent == GXML_ETYPE_DATA && len > 40 ) len = 40; fprintf(stderr, "char[%d]: %.*s\n", length, len, str); } } /* ---------------------------------------------------------------------- * xd->cdata points to one of: * md->name[k], md->value[k], lt->label[k], * da[k]->coordsys->dataspace, da[k]->coordsys->xformspace * * append the new data and null terminate * ---------------------------------------------------------------------- */ static int append_to_cdata(gxml_data * xd, const char * cdata, int len) { int offset; if( !xd || !cdata || len <= 0 ) { fprintf(stderr,"** A2CD, bad params (%p,%p,%d)\n", (void *)xd,(void *)cdata, len); return 1; } if( !*xd->cdata ) { offset = 0; xd->clen = len + 1; /* first time, alloc for null */ } else { offset = xd->clen - 1; xd->clen += len; } if( xd->verb > 4 ) fprintf(stderr,"++ a2cdata, len %d, clen %d, data '%.*s'\n", len, xd->clen, len, cdata); *xd->cdata = (char *)realloc(*xd->cdata, xd->clen*sizeof(char)); if(!*xd->cdata) { fprintf(stderr,"** A2CD, failed to realloc %d bytes\n",xd->clen); return 1; } memcpy(*xd->cdata + offset, cdata, len); /* append the new data */ (*xd->cdata)[xd->clen-1] = '\0'; /* and null terminate */ return 0; } /* this must go to the data of the latest darray struct */ static int append_to_data(gxml_data * xd, const char * cdata, int len) { giiDataArray * da = xd->gim->darray[xd->gim->numDA-1]; /* current DA */ if( !da || !xd->dlen || !xd->ddata || xd->dind < 0 ) { fprintf(stderr,"** A2D: bad setup (%p,%d,%p,%lld)\n", (void *)da, xd->dlen, (void *)xd->ddata, xd->dind); return 1; } else if( !da->data ) { fprintf(stderr,"** A2D: no data allocated\n"); return 1; } switch( da->encoding ){ case GIFTI_ENCODING_ASCII: return append_to_data_ascii(xd, cdata, len); case GIFTI_ENCODING_B64BIN: return append_to_data_b64(xd, (char *)da->data, da->nvals*da->nbyper, cdata, len); case GIFTI_ENCODING_B64GZ: return append_to_data_b64(xd, xd->zdata, xd->zlen, cdata, len); default: fprintf(stderr,"** A2D: invalid encoding value %d (%s)\n", da->encoding, gifti_list_index2string(gifti_encoding_list,da->encoding)); return 1; } } /* decode the b64 data, inserting it into da->data * * use intermediate buffer (ddata), length dlen+1, reprocess length doff * ddata format, in bytes per section: * +------+----------+--------+---+ * | doff | copy_len | unused | 1 | (last 1 assures null termination) * +------+----------+--------+---+ * * - while there are bytes left to process (rem_bytes_in > 0) * copy_len = bytes to process now * copy that many bytes to ddata * rem_bytes_out = number of output bytes left to fill in da->data * doff = decode_b64(xd, ddata, doff, da->data+dind, &rem_bytes_out) * (returns number of unprocessed bytes, in [0..3]) * if( doff > 0 ) mv last doff bytes to beginning of ddata * rem_bytes_in -= copy_len * dind = updated offset into output da->data buffer */ static int append_to_data_b64(gxml_data * xd, char * dest, long long tot_bytes, const char * cdata, int cdlen) { const char * cptr; long long rem_bytes_out; /* remaining length in darray->data */ int rem_bytes_in = cdlen; /* remaining length in cdata */ int copy_len, apply_len, unused; if( xd->verb > 4 ) fprintf(stderr,"++ appending %d base64 binary bytes to data\n",cdlen); /* Copy cdata to local buffer in pieces, for storage of trailing characters from a previous call. Given that, processing data as is done with ASCII seems reasonable. */ while( rem_bytes_in > 0 ) { /*--- prepare intermediate buffer ---*/ /* point to the current location */ cptr = cdata + cdlen - rem_bytes_in; /* decide how many bytes to copy (avail space w/max of rem_bytes_in) */ copy_len = xd->dlen - xd->doff - 1; if( copy_len > rem_bytes_in ) { unused = copy_len - rem_bytes_in; /* unused at end of buffer */ copy_len = rem_bytes_in; } else unused = 0; /* copy the data to our intermediate buffer (if we allow bad characters, skipping them, do it here) */ (void)copy_b64_data(xd, cptr, xd->ddata+xd->doff, copy_len, &apply_len); /*--- process the data ---*/ /* note how many bytes remain to be computed */ rem_bytes_out = tot_bytes - xd->dind; if(xd->verb > 5) fprintf(stderr,"-- %lld bytes left at offset %lld\n", rem_bytes_out, xd->dind); /* convert to binary bytes */ xd->doff = decode_b64(xd, xd->ddata, /* data source */ xd->doff+apply_len, /* data length */ dest + xd->dind, /* output destination */ &rem_bytes_out /* nbytes left to fill */ ); /*--- check results --- */ if( xd->doff < 0 ) { xd->doff = 0; return 1; } /* error */ if( xd->doff >= xd->dlen - 1 ) { if(xd->verb) fprintf(stderr,"** A2Db64: failed to process buffer\n"); fprintf(stderr,"** rem = %d\n", xd->doff); xd->doff = 0; /* blow away the buffer and continue */ } /*--- adjust intermediate buffer ---*/ /* move any unused bytes to the beginning (last doff, before unused) */ if( xd->doff > 0 ) { if( xd->verb > 5 ) fprintf(stderr,"++ A2Db64: move %d bytes from %d (blen %d)\n", xd->doff, xd->dlen - unused - xd->doff, xd->dlen); /* (subtract unused+1, since 1 byte is saved for null */ memmove(xd->ddata, xd->ddata+xd->dlen -(unused+1) - xd->doff, xd->doff); if( xd->verb > 6 ) fprintf(stderr," bytes are '%.*s'\n",xd->doff, (char *)xd->ddata); } /* adjust remaining bytes for next time */ rem_bytes_in -= copy_len; /* more than apply_len, if bad chars */ xd->dind = tot_bytes - rem_bytes_out; } return 0; } /* Copy the base64 data to the dest buffer, possibly noting, counting * and/or skipping any invalid characters, based on b64_check. * * return the number of bad characters noted */ static int copy_b64_data(gxml_data * xd, const char * src, char * dest, int src_len, int * dest_len) { const unsigned char * usrc = (const unsigned char *)src; int c, errs = 0, apply_len; if( xd->verb > 1 ) { /* in verbose mode, perform automatic check */ c = count_bad_b64_chars(src, src_len); if( c > 0 ) { fprintf(stderr, "CB64D: found %d bad b64 chars\n", c); if( xd->verb > 5 ) show_bad_b64_chars(src, src_len); } } switch( xd->b64_check ){ default: fprintf(stderr,"** CB64D: b64_check = %d\n", xd->b64_check); /* whine and fall through */ case GIFTI_B64_CHECK_NONE: /* basic case - just copy the data */ memcpy(dest, src, src_len); apply_len = src_len; break; case GIFTI_B64_CHECK_DETECT: /* check for existence of bad chars */ for(c = 0; c < src_len; c++) if( b64_decode_table[usrc[c]] == (unsigned char)0x80 ) { errs++; break; } memcpy(dest, src, src_len); apply_len = src_len; break; case GIFTI_B64_CHECK_COUNT: /* count bad characters */ for(c = 0; c < src_len; c++) if( b64_decode_table[usrc[c]] == (unsigned char)0x80 ) errs++; memcpy(dest, src, src_len); apply_len = src_len; break; case GIFTI_B64_CHECK_SKIP: /* skip bad characters, but don't count */ apply_len = 0; for(c = 0; c < src_len; c++){ if( b64_decode_table[usrc[c]] != (unsigned char)0x80 ) dest[apply_len++] = src[c]; } break; case GIFTI_B64_CHECK_SKIPNCOUNT: /* skip and count bad characters */ apply_len = 0; for(c = 0; c < src_len; c++){ if( b64_decode_table[usrc[c]] == (unsigned char)0x80 ) errs++; else dest[apply_len++] = src[c]; } break; } /* and null terminate */ xd->ddata[xd->doff+apply_len] = '\0'; /* note length and any errors */ *dest_len = apply_len; xd->b64_errors += errs; return errs; } static int count_bad_b64_chars(const char * src, int len) { const unsigned char * usrc = (const unsigned char *)src; int c, bad = 0; for(c = 0; c < len; c++) if( b64_decode_table[usrc[c]] == (unsigned char)0x80 ) bad++; return bad; } static int show_bad_b64_chars(const char * src, int len) { const unsigned char * usrc = (const unsigned char *)src; int c, bad = 0; fprintf(stderr,"-- bad b64 chars:"); for(c = 0; c < len; c++) if( b64_decode_table[usrc[c]] == (unsigned char)0x80 ) { bad++; fprintf(stderr," 0x%02x", usrc[c]); } if( bad ) fputc('\n', stderr); else fprintf(stderr," none"); return bad; } /* this must go to the data of the latest darray struct */ static int append_to_data_ascii(gxml_data * xd, const char * cdata, int len) { static int mod_prev = 0; giiDataArray * da = xd->gim->darray[xd->gim->numDA-1]; /* current DA */ char * dptr; char * cptr; long long rem_vals; int rem_len = len, copy_len, unused; int type = da->datatype; if( xd->verb > 4 ) fprintf(stderr,"++ appending %d ASCII bytes to data\n",len); /* if there is only whitespace, blow outta here */ if( whitespace_len(cdata, len) == len ) { xd->doff = 0; return 0; } /* Copy cdata to local buffer in pieces, for null termination and for storage of trailing characters that may need to be processed again (after more characters are read by the parser). */ while( rem_len > 0 ) { /*--- prepare intermediate buffer ---*/ /* point to the current location */ cptr = (char *)cdata + len - rem_len; /* if we're looking at whitespace, any unused data is garbage */ if( isspace(*cptr)) xd->doff = 0; /* decide how many bytes to copy (avail space w/max of rem_len) */ copy_len = xd->dlen - xd->doff - 1; if( copy_len > rem_len ) { unused = copy_len - rem_len; /* unused at end of buffer */ copy_len = rem_len; } else unused = 0; /* copy it to our buffer and null terminate */ memcpy(xd->ddata+xd->doff, cptr, copy_len); xd->ddata[xd->doff+copy_len] = '\0'; /*--- process the ascii data ---*/ /* note how many values remain to be computed */ rem_vals = da->nvals - xd->dind; if(xd->verb > 5) fprintf(stderr,"-- %lld vals left at offset %lld, nbyper %d\n", rem_vals, xd->dind, da->nbyper); if( xd->dind == 0 ) mod_prev = 0; /* nothing to modify at first */ dptr = (char *)da->data + (xd->dind)*da->nbyper; xd->doff = decode_ascii(xd, xd->ddata, /* data source */ xd->doff+copy_len, /* data length */ type, /* data type */ dptr, /* starting destination */ &rem_vals, /* nvals to read */ &mod_prev /* can we mod previous val */ ); /*--- check results --- */ if( xd->doff < 0 ) { xd->doff = 0; return 1; } /* error */ if( xd->doff >= xd->dlen - 1 ) { if(xd->verb) fprintf(stderr,"** A2D: failed to process buffer\n"); fprintf(stderr,"** rem = %d\n", xd->doff); xd->doff = 0; /* blow away the buffer and continue */ } /*--- adjust intermediate buffer ---*/ /* move any unused bytes to the beginning (last doff, before unused) */ if( xd->doff > 0 ) { if( xd->verb > 5 ) fprintf(stderr,"++ A2D: move %d bytes from %d (blen %d)\n", xd->doff, xd->dlen - unused - xd->doff, xd->dlen); /* (subtract unused+1, since 1 byte is saved for null */ memmove(xd->ddata, xd->ddata+xd->dlen -(unused+1) - xd->doff, xd->doff); if( xd->verb > 6 ) fprintf(stderr," bytes are '%.*s'\n",xd->doff, (char *)xd->ddata); } /* adjust rem_len for next time */ rem_len -= copy_len; xd->dind = da->nvals - rem_vals; /* note remaining values */ } return 0; } /* this must go to the xform of the latest darray struct */ /* (process as 1-D array) */ static int append_to_xform(gxml_data * xd, const char * cdata, int len) { static int mod_prev = 0; giiDataArray * da = xd->gim->darray[xd->gim->numDA-1]; /* current DA */ double * dptr; char * cptr; long long rem_vals; int rem_len = len, copy_len, unused, CSind; int type = gifti_str2datatype("NIFTI_TYPE_FLOAT64"); /* double */ if( !da || !xd->xlen || !xd->xdata || xd->dind < 0 || da->numCS <= 0) { fprintf(stderr,"** A2X: bad setup (%p,%d,%p,%lld,%d)\n", (void *)da, xd->xlen, (void *)xd->xdata, xd->dind, da->numCS); return 1; } else if( xd->verb > 4 ) fprintf(stderr,"++ appending %d bytes to xform\n",len); CSind = da->numCS-1; if( !da->coordsys || !da->coordsys[CSind] ) { fprintf(stderr,"** A2X: bad coordsys[%d]\n", CSind); return 1; } /* if there is only whitespace, blow outta here */ if( whitespace_len(cdata, len) == len ) { xd->doff = 0; return 0; } /* Copy cdata to local buffer in pieces, for null termination and for storage of trailing characters that may need to be processed again (after more characters are read by the parser). */ while( rem_len > 0 ) { /*--- prepare intermediate buffer ---*/ /* point to the current location */ cptr = (char *)cdata + len - rem_len; /* if we're looking at whitespace, any unused data is garbage */ if( isspace(*cptr)) xd->doff = 0; /* decide how many bytes to copy (avail space w/max of rem_len) */ copy_len = xd->xlen - xd->doff - 1; if( copy_len > rem_len ) { unused = copy_len - rem_len; /* unused at end of buffer */ copy_len = rem_len; } else unused = 0; /* copy it to our buffer and null terminate */ memcpy(xd->xdata+xd->doff, cptr, copy_len); xd->xdata[xd->doff+copy_len] = '\0'; /* note how many values remain to be computed */ rem_vals = 16 - xd->dind; /*--- process the ascii data ---*/ if( xd->dind == 0 ) mod_prev = 0; /* nothing to modify at first */ dptr = (double *)da->coordsys[CSind]->xform + (xd->dind); /* as array */ xd->doff = decode_ascii(xd, xd->xdata, /* data source */ xd->doff+copy_len, /* data length */ type, /* data type */ dptr, /* starting destination */ &rem_vals, /* nvals to read */ &mod_prev /* can we mod previous val */ ); /*--- check results --- */ if( xd->doff < 0 ) { xd->doff = 0; return 1; } /* error */ if( xd->doff >= xd->xlen - 1 ) { if(xd->verb) fprintf(stderr,"** A2X: failed to process buffer\n"); fprintf(stderr,"** rem = %d\n", xd->doff); xd->doff = 0; /* blow away the buffer and continue */ } /*--- adjust intermediate buffer ---*/ /* move any unused bytes to the beginning (last doff, before unused) */ if( xd->doff > 0 ) { if( xd->verb > 5 ) fprintf(stderr,"++ A2X: move %d bytes from %d (blen %d)\n", xd->doff, xd->dlen - unused - xd->doff, xd->dlen); /* (subtract unused+1, since 1 bytes is saved for null */ memmove(xd->xdata, xd->xdata+xd->xlen -(unused+1) -xd->doff, xd->doff); if( xd->verb > 6 ) fprintf(stderr," bytes are '%.*s'\n",xd->doff, (char *)xd->ddata); } /* adjust rem_len for next time */ rem_len -= copy_len; xd->dind = 16 - rem_vals; /* note remaining values */ } return 0; } #undef GII_B64_decode4 #define GII_B64_decode4(w,x,y,z,a,b,c) \ ( a = (b64_decode_table[w] << 2) | (b64_decode_table[x] >> 4) , \ b = (b64_decode_table[x] << 4) | (b64_decode_table[y] >> 2) , \ c = (b64_decode_table[y] << 6) | b64_decode_table[z] ) /* given: source pointer, length, dest loc and nbytes to set, (cdata is null-terminated) modify: needed (bytes) left for output return: nbytes unprocessed, so 0-3 (< 0 on error) Convert the base64 character data into binary. - read failure happens only when no characters are processed - characters are not checked for validity (maybe already done) note: the base64 defaults will be applied o EOL use is not allowed o padding is expected (using '=') */ static int decode_b64(gxml_data * xd, char * cdata, int cdlen, char * dptr, long long * needed) { unsigned char * din = (unsigned char *)cdata; unsigned char * dout = (unsigned char *)dptr; int blocks = cdlen/4, rem = cdlen % 4; int ind, assigned; if( xd->verb > 4) fprintf(stderr,"-- DB64: decode len %d, remain %lld\n", cdlen,*needed); if( *needed <= 0 ) { if( cdlen > 0 ) fprintf(stderr,"** DB64: %d bytes left without a home\n", cdlen); return 0; } for( ind = 0; ind < blocks && *needed >= 3; ind++, *needed -= 3 ){ GII_B64_decode4(din[0],din[1],din[2],din[3], dout[0],dout[1],dout[2]); din += 4; dout += 3; } assigned = 3*ind; /* the first blocks-1 sets should just work */ if( ind < blocks-1 || (ind < blocks && *needed == 0) ){ if( xd->verb > 6 ) gifti_disp_hex_data("decoded b64: 0x ", dptr, assigned, stderr); fprintf(stderr,"** decode_b64: more data than space\n"); return -1; } /* if we didn't finish, try to fill a partial block */ if( ind < blocks ) { /* so *needed < 3 */ unsigned char a, b, c; GII_B64_decode4(din[0],din[1],din[2],din[3], a, b, c); if( *needed >= 1 ) dout[0] = a; if( *needed >= 2 ) dout[1] = b; assigned += *needed; *needed = 0; } if( xd->verb > 6 ) gifti_disp_hex_data("decoded b64: 0x ", dptr, assigned, stderr); return rem; } /* given: source pointer, remaining length, nvals desired, dest loc and type (cdata is null-terminated) modify: nvals left for output, mod_prev for next call return: nbytes that may still need to processed (< 0 on error) read failure happens only when no characters are processed */ static int decode_ascii(gxml_data * xd, char * cdata, int cdlen, int type, void * dptr, long long * nvals, int * mod_prev) { char * p1, *p2; /* for strtoX */ char * prev; /* for remain */ double dval; /* for strtod */ long lval; /* for strtol */ int remain = 0; /* use bytes remaining */ int vals = 0; if( xd->verb > 4) fprintf(stderr,"-- DA: type %s, len %d, nvals %lld\n", gifti_datatype2str(type),cdlen,*nvals); /* if reprocessing, maybe let the user know */ if( xd->doff > 0 && *mod_prev ) { if( xd->verb > 4) fprintf(stderr,"++ DA: re-proc '%.*s' from '%.*s'...\n", xd->doff, cdata, xd->doff+15, cdata); vals--; /* back up */ } switch( type ) { default : fprintf(stderr,"** decode_ascii cannot decode type %d\n",type); return -1; case NIFTI_TYPE_UINT8: { unsigned char * ptr = (unsigned char *)dptr; p1 = cdata; prev = p1; /* vals could be < 0, but we must care for promotion to size_t */ while( (vals < 0 || vals < *nvals) && p1 ) { lval = strtol(p1, &p2, 10); /* try to read next value */ if( p1 == p2 ) break; /* nothing read, terminate loop */ prev = p1; /* store old success ptr */ p1 = p2; /* move to next posn */ ptr[vals] = lval; /* assign new value */ if(xd->verb>6)fprintf(stderr," v %d (%ld)",ptr[vals],lval); vals++; /* count new value */ } if(xd->verb > 6) fputc('\n', stderr); break; } case NIFTI_TYPE_INT16: { short * ptr = (short *)dptr; p1 = cdata; prev = p1; while( (vals < 0 || vals < *nvals) && p1 ) { lval = strtol(p1, &p2, 10); /* try to read next value */ if( p1 == p2 ) break; /* nothing read, terminate loop */ prev = p1; /* store old success ptr */ p1 = p2; /* move to next posn */ ptr[vals] = lval; /* assign new value */ if(xd->verb>6)fprintf(stderr," v %d (%ld)",ptr[vals],lval); vals++; /* count new value */ } if(xd->verb > 6) fputc('\n', stderr); break; } case NIFTI_TYPE_INT32: { int * ptr = (int *)dptr; p1 = cdata; prev = p1; while( (vals < 0 || vals < *nvals) && p1 ) { lval = strtol(p1, &p2, 10); /* try to read next value */ if( p1 == p2 ) break; /* nothing read, terminate loop */ prev = p1; /* store old success ptr */ p1 = p2; /* move to next posn */ ptr[vals] = lval; /* assign new value */ if(xd->verb>6)fprintf(stderr," v %d (%ld)",ptr[vals],lval); vals++; /* count new value */ } if(xd->verb > 6) fputc('\n', stderr); break; } case NIFTI_TYPE_FLOAT32: { float * ptr = (float *)dptr; p1 = cdata; prev = p1; while( (vals < 0 || vals < *nvals) && p1 ) { dval = strtod(p1, &p2); /* try to read next value */ if( p1 == p2 ) break; /* nothing read, terminate loop */ prev = p1; /* store old success ptr */ p1 = p2; /* move to next posn */ ptr[vals] = dval; /* assign new value */ if(xd->verb>6)fprintf(stderr," v %f (%f)",ptr[vals],dval); vals++; /* count new value */ } if(xd->verb > 6) fputc('\n', stderr); break; } case NIFTI_TYPE_FLOAT64: { double * ptr = (double *)dptr; p1 = cdata; prev = p1; while( (vals < 0 || vals < *nvals) && p1 ) { dval = strtod(p1, &p2); /* try to read next value */ if( p1 == p2 ) break; /* nothing read, terminate loop */ prev = p1; /* store old success ptr */ p1 = p2; /* move to next posn */ ptr[vals] = dval; /* assign new value */ if(xd->verb>6)fprintf(stderr," v %f (%f)",ptr[vals],dval); vals++; /* count new value */ } if(xd->verb > 6) fputc('\n', stderr); break; } case NIFTI_TYPE_INT8: { char * ptr = (char *)dptr; p1 = cdata; prev = p1; /* vals could be < 0, but we must care for promotion to size_t */ while( (vals < 0 || vals < *nvals) && p1 ) { lval = strtol(p1, &p2, 10); /* try to read next value */ if( p1 == p2 ) break; /* nothing read, terminate loop */ prev = p1; /* store old success ptr */ p1 = p2; /* move to next posn */ ptr[vals] = lval; /* assign new value */ if(xd->verb>6)fprintf(stderr," v %d (%ld)",ptr[vals],lval); vals++; /* count new value */ } if(xd->verb > 6) fputc('\n', stderr); break; } case NIFTI_TYPE_UINT16: { unsigned short * ptr = (unsigned short *)dptr; p1 = cdata; prev = p1; while( (vals < 0 || vals < *nvals) && p1 ) { lval = strtol(p1, &p2, 10); /* try to read next value */ if( p1 == p2 ) break; /* nothing read, terminate loop */ prev = p1; /* store old success ptr */ p1 = p2; /* move to next posn */ ptr[vals] = lval; /* assign new value */ if(xd->verb>6)fprintf(stderr," v %d (%ld)",ptr[vals],lval); vals++; /* count new value */ } if(xd->verb > 6) fputc('\n', stderr); break; } case NIFTI_TYPE_INT64: { long long * ptr = (long long *)dptr; long long llval; p1 = cdata; prev = p1; while( (vals < 0 || vals < *nvals) && p1 ) { llval = strtoll(p1, &p2, 10); /* try to read next value */ if( p1 == p2 ) break; /* nothing read, terminate loop */ prev = p1; /* store old success ptr */ p1 = p2; /* move to next posn */ ptr[vals] = llval; /* assign new value */ if(xd->verb>6)fprintf(stderr," v %lld (%lld)",ptr[vals],llval); vals++; /* count new value */ } if(xd->verb > 6) fputc('\n', stderr); break; } } /* update the number of values processed */ if( vals > 0 ) (*nvals) -= vals; /* ponder remaining: if *p1 is space, look from there, else from prev */ if( p1 ){ if( isspace(*p1) ) { remain = cdlen - (p1 - cdata); *mod_prev = 0; } else if( prev ) { remain = cdlen - (prev - cdata); *mod_prev = 1; /* still looking at previous val */ } } /* if only whitespace left, ignore */ if( whitespace_len(cdata + (cdlen-remain), remain) == remain ) remain = 0; if(xd->verb > 6) fprintf(stderr,"-- DA: remain = %d\n", remain); return remain; } static void XMLCALL cb_instr(void *udata, const char *target, const char *data) { gxml_data * xd = (gxml_data *)udata; if( xd->verb > 3 ){ show_depth(xd->depth, 1, stderr); fprintf(stderr, "instr: %s='%s'\n",target,data); } } static void XMLCALL cb_comment(void *udata, const char * str) { gxml_data * xd = (gxml_data *)udata; if( xd->verb > 1 ){ show_depth(xd->depth, 1, stderr); fprintf(stderr, "comment: '%s'\n",str); } } static void XMLCALL cb_cdata_start(void *udata) { gxml_data * xd = (gxml_data *)udata; if( xd->verb > 3 ){ show_depth(xd->depth, 1, stderr); fprintf(stderr, "cdata_start\n"); } (void)epush(xd, GXML_ETYPE_CDATA, enames[GXML_ETYPE_CDATA], NULL); } static void XMLCALL cb_cdata_end(void *udata) { gxml_data * xd = (gxml_data *)udata; epop(xd, GXML_ETYPE_CDATA, enames[GXML_ETYPE_CDATA]); } static void XMLCALL cb_default(void *udata, const char * str, int length) { gxml_data * xd = (gxml_data *)udata; int wlen = whitespace_len(str,length); int len = length; if( len == wlen ) { if( xd->verb < 4 ) return; str = "whitespace"; /* just note the whitespace */ len = strlen(str); } if( xd->verb > 3 ){ show_depth(xd->depth, 1, stderr); fprintf(stderr, "default XML element [%d]: '%.*s'\n",length,len,str); } } static void XMLCALL cb_xml_dec(void *udata, const char * ver, const char * enc, int standalone) { gxml_data * xd = (gxml_data *)udata; if( xd->verb > 2 ){ show_depth(xd->depth, 1, stderr); fprintf(stderr, "xmldec ver = %s, enc = %s, standalone = %d\n", ver,enc,standalone); } } static void XMLCALL cb_start_doctype(void *udata, const char * doctype, const char * sysid, const char * pubid, int has_subset ) { gxml_data * xd = (gxml_data *)udata; if( xd->verb > 2 ){ show_depth(xd->depth, 1, stderr); /* check for NULL in optional strings 4 Mar 2010 */ fprintf(stderr, "start_doctype, dt='%s', sid='%s',pid='%s', sub=%d\n", doctype, sysid?sysid:"NULL", pubid?pubid:"NULL", has_subset); } } static void XMLCALL cb_end_doctype(void *udata) { gxml_data * xd = (gxml_data *)udata; if( xd->verb > 2 ){ show_depth(xd->depth, 1, stderr); fprintf(stderr, "end_doctype\n"); } } static void XMLCALL cb_elem_dec(void *udata, const char * ename, XML_Content * content) { gxml_data * xd = (gxml_data *)udata; if( xd->verb > 2 ){ show_depth(xd->depth, 1, stderr); fprintf(stderr,"%s: type=%d, quant=%d, name=%s, numc=%d, cp=%p\n", ename, content->type, content->quant, content->name, content->numchildren, (void *)content->children); } } static XML_Parser init_xml_parser( void * user_data ) { XML_Parser parser; parser = XML_ParserCreate(NULL); XML_SetUserData(parser, user_data); XML_SetStartElementHandler(parser, cb_start_ele); XML_SetEndElementHandler(parser, cb_end_ele); XML_SetCharacterDataHandler(parser, cb_char); XML_SetProcessingInstructionHandler(parser, cb_instr); XML_SetCommentHandler(parser, cb_comment); XML_SetStartCdataSectionHandler(parser, cb_cdata_start); XML_SetEndCdataSectionHandler(parser, cb_cdata_end); XML_SetDefaultHandler(parser, cb_default); XML_SetXmlDeclHandler(parser, cb_xml_dec); XML_SetStartDoctypeDeclHandler(parser, cb_start_doctype); XML_SetEndDoctypeDeclHandler(parser, cb_end_doctype); XML_SetElementDeclHandler(parser, cb_elem_dec); if( GXD.verb > 3 ) fprintf(stderr,"-- parser initialized\n"); return parser; } static int show_stack(char * mesg, gxml_data * xd) { int c; if( !xd ) return 1; if( mesg ) fputs(mesg, stderr); fprintf(stderr,"stack[%d]", xd->depth); for( c = 0; c < xd->depth; c++ ) fprintf(stderr," : %s", enames[xd->stack[c]]); fputc('\n', stderr); return 0; } static int stack_is_valid(gxml_data * xd) { int valid, etype, parent, bad_parent; if( xd->depth < 0 ) return 0; if( xd->depth == 0 ) return 1; etype = xd->stack[xd->depth-1]; /* depth is at least 1 */ /* process depth 1 separately, so we can assume a parent later */ if( xd->depth == 1 ) { if( etype != GXML_ETYPE_GIFTI ) { show_stack("** invalid element on ", xd); return 0; } return 1; } /* verify proper parent (or invalid type) */ valid = 1; bad_parent = 0; parent = xd->stack[xd->depth-2]; /* depth is at least 2 */ switch( etype ) { default: case GXML_ETYPE_INVALID: case GXML_ETYPE_GIFTI: /* should only be at depth 1 */ valid = 0; break; case GXML_ETYPE_META: if( parent != GXML_ETYPE_GIFTI && parent != GXML_ETYPE_DATAARRAY ) bad_parent = 1; break; case GXML_ETYPE_MD: if( parent != GXML_ETYPE_META ) bad_parent = 1; break; case GXML_ETYPE_NAME: if( parent != GXML_ETYPE_MD ) bad_parent = 1; break; case GXML_ETYPE_VALUE: if( parent != GXML_ETYPE_MD ) bad_parent = 1; break; case GXML_ETYPE_LABELTABLE: if( parent != GXML_ETYPE_GIFTI ) bad_parent = 1; break; case GXML_ETYPE_LABEL: if( parent != GXML_ETYPE_LABELTABLE ) bad_parent = 1; break; case GXML_ETYPE_DATAARRAY: if( parent != GXML_ETYPE_GIFTI ) bad_parent = 1; break; case GXML_ETYPE_CSTM: if( parent != GXML_ETYPE_DATAARRAY ) bad_parent = 1; break; case GXML_ETYPE_DATA: if( parent != GXML_ETYPE_DATAARRAY ) bad_parent = 1; break; case GXML_ETYPE_DATASPACE: if( parent != GXML_ETYPE_CSTM ) bad_parent = 1; break; case GXML_ETYPE_XFORMSPACE: if( parent != GXML_ETYPE_CSTM ) bad_parent = 1; break; case GXML_ETYPE_MATRIXDATA: if( parent != GXML_ETYPE_CSTM ) bad_parent = 1; break; case GXML_ETYPE_CDATA: if( parent != GXML_ETYPE_NAME && parent != GXML_ETYPE_VALUE && parent != GXML_ETYPE_LABEL && parent != GXML_ETYPE_DATASPACE && parent != GXML_ETYPE_XFORMSPACE && parent != GXML_ETYPE_MATRIXDATA ) bad_parent = 1; break; } /* possibly print a message if the stack looks bad */ if( bad_parent && GXD.verb ) fprintf(stderr,"** %s: bad parent '%s'\n",enames[etype],enames[parent]); if( (!valid || bad_parent) && GXD.verb > 1 ) show_stack("** invalid ", xd); return valid; } /* if bsize is no longer correct, update it and realloc the buffer */ static int reset_xml_buf(gxml_data * xd, char ** buf, int * bsize) { if( *bsize == xd->buf_size ) { if( xd->verb > 3 ) fprintf(stderr,"-- buffer kept at %d bytes\n", *bsize); return 0; } if( xd->verb > 2 ) fprintf(stderr,"++ update buf, %d to %d bytes\n",*bsize,xd->buf_size); *bsize = xd->buf_size; *buf = (char *)realloc(*buf, *bsize * sizeof(char)); if( ! *buf ) { fprintf(stderr,"** failed to alloc %d bytes of xml buf!\n", *bsize); *bsize = 0; return 1; } return 0; } /* decide how big a processing buffer should be (either for a small xform matrix or a Data element) */ static int partial_buf_size(long long nbytes) { int ibytes = (int)nbytes; /* never more than 10 MB, anyway */ if( ibytes <= GXML_MIN_BSIZE ) return GXML_MIN_BSIZE; if( ibytes <= 64*1024 ) return ibytes; if( ibytes <= 10*1024*1024 ) /* divide by 10, but round up to a block */ return (ibytes/10 + 0xfff) & ~0xfff; return 1024*1024; } /* update xd->buf_size, used prior to reset_xml_buf */ static int update_xml_buf_size(gxml_data * xd, long long bytes) { int new_size; if( !xd || bytes < 0 ){ if( xd->verb > 1 ) fprintf(stderr,"** bad update_xml_buf_size with %p and %lld\n", (void *)xd,bytes); return 0; } new_size = partial_buf_size(bytes); if( new_size != xd->buf_size ){ if( xd->verb > 2 ) fprintf(stderr,"++ update XML buf size, %d to %d (for %lld)\n", xd->buf_size, new_size, bytes); xd->buf_size = new_size; } return 0; } /* used to update any buffer, as the pointer address is passed in */ static int update_partial_buffer(char ** buf, int * blen, long long bytes, int full) { int bsize = partial_buf_size(bytes); if( full ) bsize = bytes; /* want entire buffer */ if( !buf || !blen || bytes <= 0 ) { fprintf(stderr,"** UPB: bad params (%p,%p,%lld)\n", (void *)buf, (void *)blen, bytes); return 1; } /* just make sure we have a text buffer to work with */ if( *buf || *blen != bsize ) { if( GXD.verb > 2 ) fprintf(stderr,"++ UPB, alloc %d bytes (from %lld, %d) for buff\n", bsize, bytes, full); *buf = (char *)realloc(*buf, bsize * sizeof(char)); if( !*buf ) { fprintf(stderr,"** UPB: cannot alloc %d bytes for buffer\n",bsize); return 1; } *blen = bsize; } return 0; } static int gxml_write_gifti(gxml_data * xd, FILE * fp) { gifti_image * gim = xd->gim; int c, offset; int first = 1; /* first attr to print? */ if( !gim || !fp ) return 1; if( xd->verb > 1 ) fprintf(stderr,"++ gifti image, numDA = %d, size = %lld MB\n", gim->numDA, gifti_gim_DA_size(gim,1)); gxml_write_preamble(fp); fprintf(fp,"<%s",enames[GXML_ETYPE_GIFTI]); if(gim->version){ fprintf(fp," Version=\"%s\"", gim->version); first = 0; } /* add space if no version, requested by E Anderson */ fprintf(fp,"%sNumberOfDataArrays=\"%d\"", first ? " " : " ", gim->numDA); /* add any extra attributes */ offset = strlen(enames[GXML_ETYPE_GIFTI]) + 2; ewrite_ex_atrs(xd, &gim->ex_atrs, offset, 0, fp); fputs(">\n",fp); xd->depth++; ewrite_meta(xd, &gim->meta, fp); ewrite_LT(xd, &gim->labeltable, 1, fp); /* write the giiDataArray */ if(!gim->darray) { if( xd->verb > 0 ) fprintf(stderr,"** gifti_image, missing darray\n"); } else { for( c = 0; c < gim->numDA; c++ ) ewrite_darray(xd, gim->darray[c], fp); } xd->depth--; fprintf(fp,"\n",enames[GXML_ETYPE_GIFTI]); return 0; } static int ewrite_darray(gxml_data * xd, giiDataArray * da, FILE * fp) { int spaces = xd->indent * xd->depth; int offset, c; char dimstr[5] = "Dim0"; if( xd->verb > 3 ) fprintf(stderr,"++ write giiDataArray\n"); if( !da ) return 0; offset = strlen(enames[GXML_ETYPE_DATAARRAY]) + 2 + spaces; fprintf(fp, "%*sintent), offset,1,fp); ewrite_str_attr("DataType", gifti_datatype2str(da->datatype), offset,0,fp); ewrite_str_attr("ArrayIndexingOrder", gifti_list_index2string(gifti_index_order_list,da->ind_ord), offset,0,fp); ewrite_int_attr("Dimensionality", da->num_dim, offset, 0, fp); for( c = 0; c < da->num_dim; c++ ) { ewrite_int_attr(dimstr, da->dims[c], offset, 0, fp); dimstr[3]++; /* too devious?? iterate '0', '1', ... */ } ewrite_str_attr("Encoding", gifti_list_index2string(gifti_encoding_list,da->encoding),offset,0,fp); ewrite_str_attr("Endian", /* set endian to that of this CPU */ gifti_list_index2string(gifti_endian_list, gifti_get_this_endian()), offset,0,fp); ewrite_str_attr("ExternalFileName", da->ext_fname, offset, 0, fp); if( da->ext_fname && *da->ext_fname ) ewrite_long_long_attr("ExternalFileOffset",da->ext_offset, offset,0,fp); else ewrite_str_attr("ExternalFileOffset", NULL, offset, 0, fp); fprintf(fp, ">\n"); /* write sub-elements */ xd->depth++; ewrite_meta(xd, &da->meta, fp); for( c = 0; c < da->numCS; c++ ) ewrite_coordsys(xd, da->coordsys[c], fp); ewrite_data(xd, da, fp); xd->depth--; fprintf(fp, "%*s\n", spaces, ""); return 0; } /* this depends on ind_ord, how to write out lines */ static int ewrite_data(gxml_data * xd, giiDataArray * da, FILE * fp) { long long c, rows, cols; int spaces = xd->indent * xd->depth; int errs = 0; if( !da ) return 0; /* okay, may not exist */ if( xd->verb > 3 ) fprintf(stderr,"++ write %s Data\n", gifti_list_index2string(gifti_encoding_list, da->encoding)); /* maybe there is no data to write */ if( !da->data || da->nvals <= 0 || da->nbyper <= 0 ) { fprintf(fp, "%*s<%s/>\n", spaces, "", enames[GXML_ETYPE_DATA]); return 0; } if (da->encoding == GIFTI_ENCODING_EXTBIN) /* then write as empty */ fprintf(fp, "%*s<%s/>\n", spaces, "", enames[GXML_ETYPE_DATA]); else /* write normal Data tag */ fprintf(fp, "%*s<%s>", spaces, "", enames[GXML_ETYPE_DATA]); if( xd->dstore ) { if( da->encoding == GIFTI_ENCODING_ASCII ) { fprintf(fp, "\n"); gifti_DA_rows_cols(da, &rows, &cols); /* product will be nvals */ for(c = 0; c < rows; c++ ) ewrite_data_line(da->data,da->datatype,c,cols, spaces+xd->indent,fp); fprintf(fp, "%*s", spaces, ""); } else if( da->encoding == GIFTI_ENCODING_B64BIN ) { gxml_disp_b64_data(NULL, da->data, da->nvals*da->nbyper, fp); } else if( da->encoding == GIFTI_ENCODING_B64GZ ) { #ifdef HAVE_ZLIB /* for compiling, higher level test elsewhere */ uLongf blen = da->nvals*da->nbyper * 1.01 + 12; /* zlib.net */ int rv = 0; if( update_partial_buffer(&xd->zdata, &xd->zlen, blen, 1) ) return 1; rv = compress2((Bytef *)xd->zdata, &blen, da->data, da->nvals*da->nbyper, xd->zlevel); if ( xd->verb > 2 ) fprintf(stderr,"-- compress buffer (%.2f%% of %lld bytes)...\n", 100.0*blen/(da->nvals*da->nbyper),da->nvals*da->nbyper); if( rv != Z_OK ) { fprintf(stderr,"** zlib compression failure: "); if( rv == Z_MEM_ERROR ) fprintf(stderr,"not enough memory\n"); if( rv == Z_BUF_ERROR ) fprintf(stderr,"buffer too short\n"); else fprintf(stderr,"unknown error %d\n",rv); errs++; } else if ( xd->verb > 2 ) fprintf(stderr,"-- compression succeeded\n"); gxml_disp_b64_data(NULL, xd->zdata, blen, fp); #else fprintf(stderr,"** ewrite_data: no ZLIB to compress with\n"); #endif } else if (da->encoding == GIFTI_ENCODING_EXTBIN) { /* write to external file */ if( gifti_write_extern_DA_data(da) ) errs = 1; } else { fprintf(stderr,"** unknown data encoding, %d\n", da->encoding); errs = 1; } } if (da->encoding != GIFTI_ENCODING_EXTBIN) fprintf(fp, "\n", enames[GXML_ETYPE_DATA]); return errs; } #undef GII_B64_encode3 #define GII_B64_encode3(a,b,c,w,x,y,z) \ ( w = b64_encode_table[(a)>>2] , \ x = b64_encode_table[((a & 3) << 4) | (b >> 4)] , \ y = b64_encode_table[((b & 0xF) << 2) | (c >> 6)] , \ z = b64_encode_table[c & 0x3F] ) static int gxml_disp_b64_data(const char *mesg, const void *data, int len, FILE *fp) { const unsigned char * dp = (const unsigned char *)data; unsigned char w, x, y, z; FILE * stream; int c, rem = len % 3; stream = fp ? fp : stdout; if( !data || len < 1 ) return -1; if( mesg ) fputs(mesg, stream); /* first get all of the 3-byte blocks */ for( c = 0; c < len/3; c++, dp += 3 ) { GII_B64_encode3(dp[0], dp[1], dp[2], w, x, y, z); fprintf(stream, "%c%c%c%c", w, x, y, z); } /* finish off the last bytes */ if( rem == 1 ) { GII_B64_encode3(dp[0], 0, 0, w, x, y, z); fprintf(stream, "%c%c==", w, x); } else if ( rem == 2 ) { GII_B64_encode3(dp[0], dp[1], 0, w, x, y, z); fprintf(stream, "%c%c%c=", w, x, y); } /* else we're done */ return 0; } static int ewrite_coordsys(gxml_data * xd, giiCoordSystem * cs, FILE * fp) { int c, spaces = xd->indent * xd->depth; if( !cs ) return 0; /* okay, may not exist */ if( xd->verb > 3 ) fprintf(stderr,"++ write giiCoordSystem\n"); fprintf(fp, "%*s<%s>\n", spaces, "", enames[GXML_ETYPE_CSTM]); spaces += xd->indent; ewrite_text_ele(GXML_ETYPE_DATASPACE, cs->dataspace, NULL, spaces, 1, fp); ewrite_text_ele(GXML_ETYPE_XFORMSPACE, cs->xformspace, NULL, spaces, 1, fp); fprintf(fp, "%*s\n", spaces, ""); for(c = 0; c < 4; c++ ) ewrite_double_line(cs->xform[c], 4, spaces+xd->indent, fp); fprintf(fp, "%*s\n", spaces, ""); spaces -= xd->indent; fprintf(fp, "%*s\n", spaces, "", enames[GXML_ETYPE_CSTM]); return 0; } /* write one 'row' ('cols' values) of data in text */ static int ewrite_data_line(void * data, int type, long long row, long long cols, int space, FILE * fp) { int c; if( !data || row < 0 || cols <= 0 || !fp ) return 1; fprintf(fp, "%*s", space, ""); switch( type ) { default : fprintf(stderr,"** write_data_line, unknown type %d\n",type); return -1; case NIFTI_TYPE_UINT8: { unsigned char * ptr = (unsigned char *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c]); break; } case NIFTI_TYPE_INT16: { short * ptr = (short *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c]); break; } case NIFTI_TYPE_INT32: { int * ptr = (int *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c]); break; } case NIFTI_TYPE_FLOAT32: { float * ptr = (float *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%f ", ptr[c]); break; } case NIFTI_TYPE_COMPLEX64: { float * ptr = (float *)data + row * cols; for(c = 0; c < 2*cols; c+=2)fprintf(fp, "%f %f ",ptr[c],ptr[c+1]); break; } case NIFTI_TYPE_FLOAT64: { double * ptr = (double *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%f ", ptr[c]); break; } case NIFTI_TYPE_RGB24: { unsigned char * ptr = (unsigned char *)data + row * cols; for( c = 0; c < 3*cols; c+=3 ) fprintf(fp, "%u %u %u ", ptr[c], ptr[c+1], ptr[c+2]); break; } case NIFTI_TYPE_INT8: { char * ptr = (char *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c]); break; } case NIFTI_TYPE_UINT16: { unsigned short * ptr = (unsigned short *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c]); break; } case NIFTI_TYPE_UINT32: { unsigned int * ptr = (unsigned int *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c]); break; } case NIFTI_TYPE_INT64: { long long * ptr = (long long *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%lld ", ptr[c]); break; } case NIFTI_TYPE_UINT64: { unsigned long long * ptr = (unsigned long long *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%llu ", ptr[c]); break; } case NIFTI_TYPE_FLOAT128: { long double * ptr = (long double *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%Lf ", ptr[c]); break; } case NIFTI_TYPE_COMPLEX128: { double * ptr = (double *)data + row * cols; for(c = 0; c < 2*cols; c+=2)fprintf(fp, "%f %f ",ptr[c],ptr[c+1]); break; } case NIFTI_TYPE_COMPLEX256: { long double * ptr = (long double *)data + row * cols; for(c = 0; c<2*cols; c+=2)fprintf(fp, "%Lf %Lf ",ptr[c],ptr[c+1]); break; } } fputc('\n', fp); return 0; } static int ewrite_double_line(double * data, int nvals, int space, FILE * fp) { int c; if( !data || nvals <= 0 || !fp ) return 1; fprintf(fp, "%*s", space, ""); for( c = 0; c < nvals; c++ ) /* duplicate trailing space for diff */ fprintf(fp, "%f ", data[c]); fputc('\n', fp); return 0; } static int ewrite_text_ele(int ele, const char * cdata, const char * attr, int spaces, int in_CDATA, FILE * fp) { int index = ele; if(ele < 0 || ele > GXML_MAX_ELEN) index = 0; /* be safe */ fprintf(fp, "%*s<%s%s>%s%s%s\n", spaces, "", enames[index], attr ? attr : "", in_CDATA ? "" : "", enames[index]); return 0; } static int ewrite_LT(gxml_data *xd, giiLabelTable *lt, int in_CDATA, FILE *fp) { char attr[256] = ""; float * rgba; int c, spaces = xd->indent * xd->depth; if( xd->verb > 3 ) fprintf(stderr,"++ write giiLabelTable\n"); if( !lt || lt->length == 0 || !lt->key || !lt->label ) { fprintf(fp, "%*s\n", spaces, ""); return 0; } fprintf(fp, "%*s\n", spaces, ""); rgba = lt->rgba; for( c = 0; c < lt->length; c++ ) { if( !lt->label[c] ) { if(xd->verb > 1) fprintf(stderr,"** label[%d] unset\n", c); continue; } /* store the Key and optional RGBA attributes */ if( lt->rgba ) { sprintf(attr, " Key=\"%d\"" " Red=\"%g\" Green=\"%g\" Blue=\"%g\" Alpha=\"%g\"", lt->key[c], rgba[0], rgba[1], rgba[2], rgba[3]); rgba += 4; } else sprintf(attr, " Key=\"%d\"", lt->key[c]); ewrite_text_ele(GXML_ETYPE_LABEL, lt->label[c], attr, spaces+xd->indent, in_CDATA, fp); } fprintf(fp, "%*s\n", spaces, ""); return 0; } static int ewrite_meta(gxml_data * xd, giiMetaData * md, FILE * fp) { int c, spaces = xd->indent * xd->depth; if( xd->verb > 3 ) fprintf(stderr,"++ write giiMetaData\n"); if( !md || md->length == 0 || !md->name || !md->value ) { fprintf(fp, "%*s\n", spaces, ""); return 0; } if( xd->verb > 3 ) fprintf(stderr," MD length = %d\n", md->length); fprintf(fp, "%*s\n", spaces, ""); for( c = 0; c < md->length; c++ ) { if( !md->name[c] ) { /* allow empty value, but not name */ if(xd->verb > 1) fprintf(stderr,"** MD[%d] unset\n", c); continue; } spaces += xd->indent; fprintf(fp,"%*s\n", spaces, ""); spaces += xd->indent; ewrite_text_ele(GXML_ETYPE_NAME, md->name[c], NULL, spaces, 1,fp); ewrite_text_ele(GXML_ETYPE_VALUE,md->value[c],NULL, spaces, 1,fp); spaces -= xd->indent; fprintf(fp,"%*s\n", spaces, ""); spaces -= xd->indent; } fprintf(fp, "%*s\n", spaces, ""); return 0; } /* print a list of attributes, indented to the same level */ static int ewrite_ex_atrs(gxml_data * xd, nvpairs * nvp, int offset, int first, FILE * fp) { int c, spaces = xd->indent * xd->depth + offset; if(xd->verb > 2) fprintf(stderr,"++ write %d ex_atr's\n", nvp->length); for( c = 0; c < nvp->length; c++ ) { ewrite_str_attr(nvp->name[c], nvp->value[c], spaces, first, fp); if( first ) first = 0; } return 0; } static int ewrite_int_attr(const char *name, int value, int spaces, int first, FILE * fp) { fprintf(fp, "%s%*s%s=\"%d\"", (first) ? "" : "\n", /* maybe a newline */ (first) ? 1 : spaces, "", /* 1 or many spaces */ name, value); return 0; } static int ewrite_long_long_attr(const char *name, long long value, int spaces, int first, FILE * fp) { fprintf(fp, "%s%*s%s=\"%lld\"", (first) ? "" : "\n", /* maybe a newline */ (first) ? 1 : spaces, "", /* 1 or many spaces */ name, value); return 0; } static int ewrite_str_attr(const char * name, const char * value, int spaces, int first, FILE * fp) { fprintf(fp, "%s%*s%s=\"%s\"", (first) ? "" : "\n", /* maybe a newline */ (first) ? 1 : spaces, "", /* 1 or many spaces */ name, value ? value : ""); return 0; } static int gxml_write_preamble(FILE * fp) { char * version = GIFTI_XML_VERSION; char * encoding = GIFTI_XML_ENCODING; char * dtd = GIFTI_XML_DTD_SOURCE; fprintf(fp, "\n", version, encoding); fprintf(fp, "\n", dtd); return 0; } static int disp_gxml_data(char * mesg, gxml_data * dp, int show_all ) { if( mesg ) fputs(mesg, stderr); if( !dp ) return 1; fprintf(stderr,"gxml_data :\n" " verb : %d\n" " dstore : %d\n" " indent : %d\n" " buf_size : %d\n" " b64_check : %d\n" " zlevel : %d\n" " da_len : %d\n" , dp->verb, dp->dstore, dp->indent, dp->buf_size, dp->b64_check, dp->zlevel, dp->da_len); if( show_all ) fprintf(stderr, " da_list : %p\n" " da_ind : %d\n" " eleDA : %d\n" " expDA : %d\n" " b64_errors : %d\n" " errors : %d\n" " skip : %d\n" " depth : %d\n" " dind : %lld\n" " clen : %d\n" " doff : %d\n" " zlen : %d\n" " cdata : %p\n" " xdata : %p\n" " ddata : %p\n" " zdata : %p\n" " gim : %p\n" , (void *)dp->da_list, dp->da_ind, dp->eleDA, dp->expDA, dp->b64_errors, dp->errors, dp->skip, dp->depth, dp->dind, dp->clen, dp->doff, dp->zlen, (void *)dp->cdata, (void *)dp->xdata, (void *)dp->ddata, (void *)dp->zdata, (void *)dp->gim); return 0; } gifticlib-1.0.9/gifti.get.times0000755007023700001440000000125210735264604015451 0ustar rickrusers#!/bin/tcsh # either include the names of the gifti files on the command line, # or be sitting in the directory with them set narg = $#argv set arg0 = 1 set prog = gifti_tool # was gifti_test set check = "" if ( $narg > 0 ) then if ( "$argv[1]" == "-none" ) then set check = "-b64_check NONE" @ narg -= 1 @ arg0 += 1 endif endif echo using `which $prog` ... if ( $narg > 1 ) then set files = ( $argv[$arg0-] ) else set files = ( gifti.*.gii ) endif echo "" foreach file ( $files ) echo "---------------- $file ----------------" /usr/bin/time $prog $check -infile $file if( $status ) echo "****** FAILURE ********" end gifticlib-1.0.9/Makefile0000644007023700001440000000261211412212575014155 0ustar rickrusers # quick and dirty (getting dirtier) for now... # might not have zlib APPLY_ZLIB = -DHAVE_ZLIB NIFTI_DIR = ../nifti LIBTOOL = libtool C_LIBFLAGS = -03 -fPIC -DPIC $(APPLY_ZLIB) INST_DIR = /usr/lib VER = 1.0.0 # CFLAGS = -Wall -Wextra -g -pedantic -std=c99 $(APPLY_ZLIB) CFLAGS = -O3 $(APPLY_ZLIB) IFLAGS = -I$(NIFTI_DIR)/include LFLAGS = -L$(NIFTI_DIR)/lib CC = gcc $(CFLAGS) # for macs (getting expat from fink) # IFLAGS = -I/sw/include $(IFLAGS) # LFLAGS = -L/sw/lib $(LFLAGS) gifti_tool: gifti_tool.o gifti_io.o gifti_xml.o $(RM) $@ $(CC) -o $@ gifti_tool.o gifti_io.o gifti_xml.o \ $(LFLAGS) -lexpat -lniftiio -lznz -lz -lm gifti_test: gifti_test.o gifti_io.o gifti_xml.o $(RM) $@ $(CC) -o $@ gifti_test.o gifti_io.o gifti_xml.o \ $(LFLAGS) -lexpat -lniftiio -lznz -lz -lm libgiftiio_la: $(LIBTOOL) --mode=compile $(CC) $(IFLAGS) -o gifti_io.lo -c gifti_io.c $(LIBTOOL) --mode=compile $(CC) $(IFLAGS) -o gifti_xml.lo -c gifti_xml.c $(LIBTOOL) --mode=link $(CC) -release $(VER) -o libgiftiio.la gifti_io.lo gifti_xml.lo -rpath $(INST_DIR) $(LFLAGS) -lexpat -lniftiio -lznz -lz -lm libgiftiio: libgiftiio_la $(LIBTOOL) --mode=install install -c libgiftiio.la $(INST_DIR) all: gifti_tool gifti_test libgiftiio clean: $(RM) gifti_tool *.o clean_all: $(RM) gifti_test gifti_tool *.o $(RM) gifti*.lo* $(RM) libgifti*.la $(RM) *.so %.o: %.c %.h $(RM) $@ $(CC) $(IFLAGS) -c $< gifticlib-1.0.9/gifti_test.c0000644007023700001440000003446510735264605015045 0ustar rickrusers #include #include #include #include "gifti_io.h" #include "gifti_test.h" int show_help() { fprintf(stderr, "------------------------------------------------------------\n" "gifti_test - test reading/writing a GIFTI dataset\n" "\n" " examples:\n" " 1. read in a GIFTI dataset (verbose, show output?)\n" "\n" " gifti_test -infile dset.gii\n" " gifti_test -infile dset.gii -verb 3\n" " gifti_test -infile dset.gii -show\n" "\n" " 2. copy a GIFTI dataset (check differences?)\n" "\n" " gifti_test -infile dset.gii -gfile copy.gii\n" " diff dset.gii copy.gii\n" "\n" " 3. copy a GIFTI data, but write out only 3 surf indices: 0,4,5\n" "\n" " gifti_test -infile time_series.gii -gfile ts3.gii \\\n" " -slist 3 0 4 5\n" "\n" " options:\n" " -help : show this help\n" " -gifti_hist : show giftilib history\n" " -gifti_ver : show giftilib version\n" "\n" " -encoding TYPE : set the data encoding for any output file\n" " TYPE = ASCII : ASCII encoding\n" " TYPE = BASE64 : base64 binary\n" " TYPE = BASE64GZIP : base64 compressed binary\n" " -gfile OUTPUT : write out dataset as gifti image\n" " -infile INPUT : specify INPUT as the GIFTI dataset to read\n" " -no_data : do not write out data\n" " -show : show final gifti image\n" " -slist LEN s0...: restrict output to list of length LEN\n" " -verb VERB : set verbose level\n" "------------------------------------------------------------\n" ); return 0; } int main( int argc, char * argv[] ) { gifti_image * gim; char * infile = NULL, * gfile = NULL; int * slist = NULL, slen = 0; int c, ac, show = 0, data = 1; int encoding = 0; /* no change, else 1,2,3 */ if( argc <= 1 ) { show_help(); return 1; } for( ac = 1; ac < argc; ac++ ) { if( !strcmp(argv[ac], "-encoding") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-encoding"); if ( !strcmp(argv[ac], "ASCII" ) ) encoding = GIFTI_ENCODING_ASCII; else if( !strcmp(argv[ac], "BASE64") ) encoding = GIFTI_ENCODING_B64BIN; else if( !strcmp(argv[ac], "BASE64GZIP") ) encoding = GIFTI_ENCODING_B64GZ; else { fprintf(stderr,"** invalid parm to -encoding: %s\n",argv[ac]); return 1; } } else if( !strcmp(argv[ac], "-gifti_hist") ) { gifti_disp_lib_hist(); return 0; } else if( !strcmp(argv[ac], "-gifti_ver") ) { gifti_disp_lib_version(); return 0; } else if( !strcmp(argv[ac], "-gfile") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-gfile"); gfile = argv[ac]; } else if( !strcmp(argv[ac], "-help") ) { show_help(); return 1; } else if( !strcmp(argv[ac], "-infile") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-infile"); infile = argv[ac]; } else if( !strcmp(argv[ac], "-no_data") ) { data = 0; } else if( !strcmp(argv[ac], "-show") ) { show = 1; } else if( !strcmp(argv[ac], "-slist") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-slist"); slen = atol(argv[ac]); if( slen <= 0 ){ fprintf(stderr,"** bad -slist length, '%s'\n", argv[ac]); return 1; } slist = (int *)malloc(slen*sizeof(int)); if( !slist ) { fprintf(stderr,"** failed alloc of len %d slist\n",slen); return 1; } for( c = 0; c < slen; c++ ) { ac++; if( ac >= argc ) { fprintf(stderr,"** have only %d of %d -slist files\n", c, slen); return 1; } slist[c] = atol(argv[ac]); if( slist[c] < 0 ){ fprintf(stderr,"** bad slist index[%d], '%s'\n",c,argv[ac]); return 1; } } } else if( !strcmp(argv[ac], "-verb") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-verb"); gifti_set_verb( atoi(argv[ac]) ); } else { fprintf(stderr,"** unknown option: '%s'\n",argv[ac]); return 1; } } /* be sure we have something to read */ if( !infile ) { fprintf(stderr,"** missing option: -infile\n"); return 1; } /* actually read the dataset */ gim = gifti_read_da_list(infile, 1, slist, slen); if( !gim ) { fprintf(stderr,"** failed gifti_read_da_list()\n"); return 1; } if( show ) gifti_disp_gifti_image("FINAL IMAGE", gim, 1 ); /* possibly adjust encoding */ if( encoding > GIFTI_ENCODING_UNDEF && encoding <= GIFTI_ENCODING_MAX ) for( c = 0; c < gim->numDA; c++ ) if( gim->darray[c]->encoding ) gim->darray[c]->encoding = encoding; if( gfile ) gifti_write_image(gim, gfile, data); /* clean up */ gifti_free_image(gim); gim = NULL; if( slist ){ free(slist); slist = NULL; slen = 0; } return 0; } int write_surf_file(giiDataArray * dc, giiDataArray * dt, char * prefix, int add_suf) { giiDataArray * da; FILE * fp; char * name = prefix; char * nbuf = NULL; long long crows, ccols, trows, tcols, rows, cols, c; if( add_suf ) { /* create a new name */ nbuf = (char *)malloc(strlen(prefix) + strlen(".asc") + 1); strcpy(nbuf, prefix); strcat(nbuf, ".asc"); name = nbuf; } if( !(fp = fopen(name, "w")) ) { fprintf(stderr,"** failed to open '%s' for 'w'\n",name); if( nbuf ) free(nbuf); return 1; } /* note the number of rows and columns */ if( gifti_DA_rows_cols(dc, &crows, &ccols) ) { fclose(fp); if( nbuf ) free(nbuf); return 1; } else if( gifti_DA_rows_cols(dt, &trows, &tcols) ) { fclose(fp); if( nbuf ) free(nbuf); return 1; } fprintf(fp, "#!ascii version of surface\n" "%lld %lld\n", crows, trows); /* write out the coordinates */ da = dc; rows = crows; cols = ccols; if( da->ind_ord == GIFTI_IND_ORD_COL_MAJOR ) { fprintf(stderr,"-- writing coord rows in reverse order\n"); for(c = rows-1; c >= 0; c-- ) ewrite_data_line(da->data, da->datatype, c, cols, 0, 1, fp); } else { fprintf(stderr,"-- writing coord rows in normal order\n"); for(c = 0; c < rows; c++ ) ewrite_data_line(da->data, da->datatype, c, cols, 0, 1, fp); } /* write out the triangles */ da = dt; rows = trows; cols = tcols; if( da->ind_ord == GIFTI_IND_ORD_COL_MAJOR ) { fprintf(stderr,"-- writing triangle rows in reverse order\n"); for(c = rows-1; c >= 0; c-- ) ewrite_data_line(da->data, da->datatype, c, cols, 0, 1, fp); } else { fprintf(stderr,"-- writing triangle rows in normal order\n"); for(c = 0; c < rows; c++ ) ewrite_data_line(da->data, da->datatype, c, cols, 0, 1, fp); } fclose(fp); return 0; } int ewrite_data_line(void * data, int type, int row, int cols, int spaces, int trail0, FILE * fp) { int c; if( !data || row < 0 || cols <= 0 || !fp ) return 1; fprintf(fp, "%*s", spaces, " "); switch( type ) { default : fprintf(stderr,"** write_data_line, unknown type %d\n",type); return -1; case 2: { /* NIFTI_TYPE_UINT8 */ unsigned char * ptr = (unsigned char *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c]); break; } case 4: { /* NIFTI_TYPE_INT16 */ short * ptr = (short *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c]); break; } case 8: { /* NIFTI_TYPE_INT32 */ int * ptr = (int *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c]); break; } case 16: { /* NIFTI_TYPE_FLOAT32 */ float * ptr = (float *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%f ", ptr[c]); break; } case 32: { /* NIFTI_TYPE_COMPLEX64 */ float * ptr = (float *)data + row * cols; for(c = 0; c < 2*cols; c+=2)fprintf(fp, "%f %f ",ptr[c],ptr[c+1]); break; } case 64: { /* NIFTI_TYPE_FLOAT64 */ double * ptr = (double *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%f ", ptr[c]); break; } case 128: { /* NIFTI_TYPE_RGB24 */ unsigned char * ptr = (unsigned char *)data + row * cols; for( c = 0; c < 3*cols; c+=3 ) fprintf(fp, "%u %u %u ", ptr[c], ptr[c+1], ptr[c+2]); break; } case 256: { /* NIFTI_TYPE_INT8 */ char * ptr = (char *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c]); break; } case 512: { /* NIFTI_TYPE_UINT16 */ unsigned short * ptr = (unsigned short *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c]); break; } case 768: { /* NIFTI_TYPE_UINT32 */ unsigned int * ptr = (unsigned int *)data + row * cols; for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c]); break; } case 1024: { /* NIFTI_TYPE_INT64 */ /* rcr - do we need to check #defines? */ break; } case 1280: { /* NIFTI_TYPE_UINT64 */ /* rcr - do we need to check #defines? */ break; } case 1536: { /* NIFTI_TYPE_FLOAT128 */ /* rcr - do we need to check #defines? */ break; } case 1792: { /* NIFTI_TYPE_COMPLEX128 */ double * ptr = (double *)data + row * cols; for(c = 0; c < 2*cols; c+=2)fprintf(fp, "%f %f ",ptr[c],ptr[c+1]); break; } case 2048: { /* NIFTI_TYPE_COMPLEX256 */ /* rcr - do we need to check #defines? */ break; } } if( trail0 ) fputs(" 0", fp); /* maybe write trailing zero */ fputc('\n', fp); return 0; } /* write out as cols by rows (else we'd use ewrite_data_line) */ int ewrite_many_lines(void ** data, int type, long long cols, long long rows, int spaces, FILE * fp) { long long r, c; if( !data || rows == 0 || cols == 0 || !fp ) return 1; fprintf(fp, "%*s", spaces, " "); switch( type ) { default : fprintf(stderr,"** write_data_line, unknown type %d\n",type); return -1; case 2: { /* NIFTI_TYPE_UINT8 */ unsigned char ** ptr = (unsigned char **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c][r]); fputc('\n', fp); } break; } case 4: { /* NIFTI_TYPE_INT16 */ short ** ptr = (short **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c][r]); fputc('\n', fp); } break; } case 8: { /* NIFTI_TYPE_INT32 */ int ** ptr = (int **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c][r]); fputc('\n', fp); } break; } case 16: { /* NIFTI_TYPE_FLOAT32 */ float ** ptr = (float **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%f ", ptr[c][r]); fputc('\n', fp); } break; } case 32: { /* NIFTI_TYPE_COMPLEX64 */ break; } case 64: { /* NIFTI_TYPE_FLOAT64 */ double ** ptr = (double **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%f ", ptr[c][r]); fputc('\n', fp); } break; } case 128: { /* NIFTI_TYPE_RGB24 */ break; } case 256: { /* NIFTI_TYPE_INT8 */ char ** ptr = (char **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%d ", ptr[c][r]); fputc('\n', fp); } break; } case 512: { /* NIFTI_TYPE_UINT16 */ unsigned short ** ptr = (unsigned short **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c][r]); fputc('\n', fp); } break; } case 768: { /* NIFTI_TYPE_UINT32 */ unsigned int ** ptr = (unsigned int **)data; for( r = 0; r < rows; r++ ) { for( c = 0; c < cols; c++ ) fprintf(fp, "%u ", ptr[c][r]); fputc('\n', fp); } break; } case 1024: { /* NIFTI_TYPE_INT64 */ /* rcr - do we need to check #defines? */ break; } case 1280: { /* NIFTI_TYPE_UINT64 */ /* rcr - do we need to check #defines? */ break; } case 1536: { /* NIFTI_TYPE_FLOAT128 */ /* rcr - do we need to check #defines? */ break; } case 1792: { /* NIFTI_TYPE_COMPLEX128 */ break; } case 2048: { /* NIFTI_TYPE_COMPLEX256 */ /* rcr - do we need to check #defines? */ break; } } return 0; } gifticlib-1.0.9/gifti_test.h0000644007023700001440000000204310735264605015035 0ustar rickrusers#ifndef GIFTI_TEST_H #define GIFTI_TEST_H #define CHECK_NEXT_OPT(n,m,str) \ do { if ( (n) >= (m) ) { \ fprintf(stderr,"** option '%s': missing parameter\n",str); \ fprintf(stderr," consider: 'prog -help'\n"); \ return 1; } \ } while(0) #define CHECK_NEXT_OPT2(n,m,s1,s2) \ do { if ( (n) >= (m) ) { \ fprintf(stderr,"** option '%s': missing parameter '%s'\n",s1,s2);\ fprintf(stderr," consider: 'prog -help'\n"); \ return 1; } \ } while(0) int ewrite_data_line (void *, int, int, int, int, int, FILE *); int ewrite_many_lines(void **, int, long long, long long, int, FILE *); int write_surf_file (giiDataArray *, giiDataArray *, char *, int); #endif /* GIFTI_TEST_H */ gifticlib-1.0.9/gifti_io.c0000644007023700001440000046566311412211602014463 0ustar rickrusers#include #include #include #include #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" }; static char gifti_version[] = "gifti library version 1.09, 28 June, 2010"; /* ---------------------------------------------------------------------- */ /*! 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 ) { 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]); 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 */ else { if( G.verb > 1 ) /* might go into ex_atrs */ fprintf(stderr,"** unknown giiDataArray attr, '%s'='%s'\n", G_CHECK_NULL_STR(attr),G_CHECK_NULL_STR(value)); return 1; } return 0; } /* return 0 (UNDEFINED) on failure */ static int str2list_index( char * list[], int max, const char *str ) { int index; if( !list || !str ) { if( G.verb > 0 ) fprintf(stderr,"** str2list: bad params (%p,%p)\n", (void *)list, (void *)str); return 0; /* should be *_UNDEFINED */ } for( index = max; index > 0; index-- ) if( !strcmp(str, list[index]) ) return index; return 0; /* failure */ } /*---------------------------------------------------------------------- *! return the index for a GIFTI_IND_ORD_* string *//*-------------------------------------------------------------------*/ int gifti_str2ind_ord( const char * str ) { int rv = str2list_index(gifti_index_order_list,GIFTI_IND_ORD_MAX,str); if( rv <= GIFTI_IND_ORD_UNDEF && G.verb > 1 ) fprintf(stderr,"** bad index order, '%s'\n", str); return rv; } /*---------------------------------------------------------------------- *! return the index for a GIFTI_ENDODING_* string *//*-------------------------------------------------------------------*/ int gifti_str2encoding( const char * str ) { int rv = str2list_index(gifti_encoding_list, GIFTI_ENCODING_MAX, str); if( rv <= GIFTI_ENCODING_UNDEF && G.verb > 1 ) fprintf(stderr,"** bad data encoding, '%s'\n", str); return rv; } /*---------------------------------------------------------------------- *! return the string at the given index of the given list * * This function is meant to index into one of the gifti_*_list arrays, * while being certain that the index is not out of range. *//*-------------------------------------------------------------------*/ char * gifti_list_index2string(char * list[], int index) { int lsize; /* list size cannot be computed from the passed pointer */ if ( list == gifti_index_order_list ) lsize = sizeof(gifti_index_order_list)/sizeof(char *); else if( list == gifti_encoding_list ) lsize = sizeof(gifti_encoding_list)/sizeof(char *); else if( list == gifti_endian_list ) lsize = sizeof(gifti_endian_list)/sizeof(char *); else { fprintf(stderr,"** GLI2S: invalid list\n"); return "UNKNOWN LIST"; } if( index < 0 || index >= lsize ) { if( G.verb > 0) fprintf(stderr,"** GLI2S: index %d out of range {0..%d}\n", index,lsize-1); return "INDEX OUT OF RANGE"; } /* all that work, just for the expected indexing... */ return list[index]; } /*---------------------------------------------------------------------- *! return the NIFTI_TYPE_ value corresponding to the given string *//*-------------------------------------------------------------------*/ int gifti_str2datatype(const char * str) { int len = sizeof(gifti_type_list)/sizeof(gifti_type_ele); int c; for( c = len - 1; c > 0; c-- ) if( !strcmp(str, gifti_type_list[c].name) ) break; return gifti_type_list[c].type; } /*---------------------------------------------------------------------- *! return the GIFTI_ENDIAN_ value corresponding to the given string *//*-------------------------------------------------------------------*/ int gifti_str2endian( const char * str ) { int rv = str2list_index(gifti_endian_list, GIFTI_ENDIAN_MAX, str); if( rv <= GIFTI_ENCODING_UNDEF && G.verb > 1 ) fprintf(stderr,"** bad endian, '%s'\n", G_CHECK_NULL_STR(str)); return rv; } /*---------------------------------------------------------------------- *! return the NIFTI_TYPE_ value string corresponding to the given type *//*-------------------------------------------------------------------*/ char * gifti_datatype2str(int type) { int len = sizeof(gifti_type_list)/sizeof(gifti_type_ele); int c; for( c = len - 1; c > 0; c-- ) if( type == gifti_type_list[c].type) break; return gifti_type_list[c].name; } /*---------------------------------------------------------------------- *! simply set the struct contents to empty *//*-------------------------------------------------------------------*/ int gifti_clear_nvpairs(nvpairs * p) { if( !p ) return 1; p->length = 0; p->name = NULL; p->value = NULL; return 0; } /*---------------------------------------------------------------------- *! simply set the struct contents to empty *//*-------------------------------------------------------------------*/ int gifti_clear_LabelTable(giiLabelTable * p) { if( !p ) return 1; p->length = 0; p->key = NULL; p->label = NULL; p->rgba = NULL; return 0; } /*---------------------------------------------------------------------- *! simply set the struct contents to empty *//*-------------------------------------------------------------------*/ int gifti_clear_CoordSystem(giiCoordSystem * p) { if( !p ) return 1; p->dataspace = NULL; p->xformspace = NULL; memset(p->xform,0,sizeof(p->xform)); return 0; } /*---------------------------------------------------------------------- *! add an empty CoordSystem struct to the DataArray *//*-------------------------------------------------------------------*/ int gifti_add_empty_CS(giiDataArray * da) { if( !da ) return 1; /* be safe, if anything looks bad, start clean */ if(da->numCS <= 0 || !da->coordsys) { da->numCS = 0; da->coordsys = NULL; } if(G.verb > 3 )fprintf(stderr,"++ adding empty CS[%d]\n", da->numCS); /* realloc coordsys pointer array, and add an empty structure */ da->coordsys = (giiCoordSystem **)realloc(da->coordsys, (da->numCS+1) * sizeof(giiCoordSystem *)); if( !da->coordsys ) { fprintf(stderr,"** AECS: failed to alloc %d CoordSys pointers\n", da->numCS+1); da->numCS = 0; return 1; } da->coordsys[da->numCS] = (giiCoordSystem *)malloc(sizeof(giiCoordSystem)); if( !da->coordsys[da->numCS] ) { fprintf(stderr,"** push_cstm: failed to alloc new CoordSystem\n"); return 1; } gifti_clear_CoordSystem(da->coordsys[da->numCS]); da->numCS++; return 0; } /*---------------------------------------------------------------------- *! add an empty DataArray struct to the gim->darray list * * this both reallocates gim->darray and allocates gim->darray[new] * * if num_to_add > 0: add that many elements * if defaults : init each element with default values * * return 0 on success * 1 on error *//*-------------------------------------------------------------------*/ int gifti_add_empty_darray(gifti_image * gim, int num_to_add) { giiDataArray * dptr; int c, ntot, nnew = num_to_add > 0 ? num_to_add : 1; if( !gim ) return 1; if(G.verb > 3)fprintf(stderr,"++ alloc darray[%d] (+%d)\n",gim->numDA,nnew); /* allocate for additional pointers */ ntot = gim->numDA + nnew; gim->darray = (giiDataArray **)realloc(gim->darray, ntot*sizeof(giiDataArray *)); if( !gim->darray ) { fprintf(stderr,"** failed realloc darray, len %d\n", ntot); gim->numDA = 0; return 1; } /* allocate the actual giiDataArray structs, inserted at the end */ for( c = 0; c < nnew; c++ ) { dptr = (giiDataArray *)calloc(1, sizeof(giiDataArray)); if( !dptr ) { fprintf(stderr,"** failed to alloc DA element #%d\n",gim->numDA); return 1; /* leave allocated list as is */ } gim->darray[gim->numDA] = dptr; gim->numDA++; /* clear any non-value attributes/elements */ gifti_clear_DataArray(dptr); } return 0; } /*---------------------------------------------------------------------- *! add the given name=value pair to the nvpairs struct * * this allocates memory for the p->name and p->value arrays, along * with duplicating the passed name/value strings *//*-------------------------------------------------------------------*/ int gifti_add_to_nvpairs(nvpairs * p, const char * name, const char * value) { int index; if( !p || !name || !value ) { if(G.verb > 1) fprintf(stderr,"** GATN: bad params(%p,%p,%p)\n", (void *)p, (void *)name, (void *)value); return 1; } p->length++; p->name = (char **)realloc(p->name, p->length * sizeof(char *)); p->value = (char **)realloc(p->value, p->length * sizeof(char *)); if( !p->name || !p->value ) { fprintf(stderr,"** GATN: failed to realloc %d pointers\n",p->length); return 1; } else if ( G.verb > 3 ) fprintf(stderr,"++ add_nvp [%d]: '%s', '%s'\n", p->length, name ? name : "NULL", value ? value : "NULL"); index = p->length - 1; p->name[index] = gifti_strdup(name); p->value[index] = gifti_strdup(value); if( !p->name[index] || !p->value[index] ) { fprintf(stderr,"** GATN: failed to copy pair '%s'='%s'\n",name,value); return 1; } return 0; } /*---------------------------------------------------------------------- *! display the contents of the nvpairs struct *//*-------------------------------------------------------------------*/ int gifti_disp_nvpairs(const char * mesg, const nvpairs * p) { int c; if( mesg ) { fputs(mesg, stderr); fputc(' ', stderr); } if( !p ){ fputs("disp: nvpairs = NULL\n", stderr); return 1; } fprintf(stderr,"nvpairs struct, len = %d :\n", p->length); for(c = 0; c < p->length; c++ ) fprintf(stderr," nvpair: '%s' = '%s'\n", G_CHECK_NULL_STR(p->name[c]), G_CHECK_NULL_STR(p->value[c])); if( p->length > 0 ) fputc('\n', stderr); return 0; } /*---------------------------------------------------------------------- *! display the contents of the LabelTable struct *//*-------------------------------------------------------------------*/ int gifti_disp_LabelTable(const char * mesg, const giiLabelTable * p) { float * rgba; int c; if( mesg ) { fputs(mesg, stderr); fputc(' ', stderr); } if( !p ){ fputs("disp: giiLabelTable = NULL\n", stderr); return 1; } fprintf(stderr,"giiLabelTable struct, len = %d :\n", p->length); rgba = p->rgba; for(c = 0; c < p->length; c++ ) { fprintf(stderr," key %d, ", p->key[c]); if( rgba ) { fprintf(stderr,"rgba (%5.3f, %5.3f, %5.3f, %5.3f), ", rgba[0], rgba[1], rgba[2], rgba[3]); rgba += 4; } fprintf(stderr,"label '%s'\n", G_CHECK_NULL_STR(p->label[c])); } if( p->length > 0 ) fputc('\n', stderr); return 0; } /*---------------------------------------------------------------------- *! display the contents of the CoordSystem struct *//*-------------------------------------------------------------------*/ int gifti_disp_CoordSystem(const char * mesg, const giiCoordSystem * p) { int c1, c2; if( mesg ) { fputs(mesg, stderr); fputc(' ', stderr); } if( !p ){ fputs("disp: giiCoordSystem = NULL\n", stderr); return 1; } fprintf(stderr,"giiCoordSystem struct\n" " dataspace = %s\n" " xformspace = %s\n", G_CHECK_NULL_STR(p->dataspace), G_CHECK_NULL_STR(p->xformspace)); for( c1 = 0; c1 < 4; c1++ ) { fprintf(stderr," xform[%d] :", c1); for( c2 = 0; c2 < 4; c2++ ) fprintf(stderr," %f", p->xform[c1][c2]); fputc('\n', stderr); } return 0; } /*---------------------------------------------------------------------- *! display the contents of the DataArray struct * * if 'subs' is set, display the contents of the sub-structures *//*-------------------------------------------------------------------*/ int gifti_disp_DataArray(const char * mesg, const giiDataArray * p, int subs) { int c; fprintf(stderr,"--------------------------------------------------\n"); if( mesg ) { fputs(mesg, stderr); fputc(' ', stderr); } if( !p ){ fputs("disp: giiDataArray = NULL\n", stderr); return 1; } fprintf(stderr,"giiDataArray struct\n" " intent %4d = %s\n" " datatype %2d = %s\n" " ind_ord %2d = %s\n" " num_dim = %d\n" " dims = %d, %d, %d, %d, %d, %d\n" " encoding %2d = %s\n" " endian %2d = %s\n" " ext_fname = %s\n" " ext_offset = %lld\n" , p->intent, gifti_intent_to_string(p->intent), p->datatype, gifti_datatype2str(p->datatype), p->ind_ord, gifti_list_index2string(gifti_index_order_list, p->ind_ord), p->num_dim, p->dims[0], p->dims[1], p->dims[2], p->dims[3], p->dims[4], p->dims[5], p->encoding, gifti_list_index2string(gifti_encoding_list, p->encoding), p->endian, gifti_list_index2string(gifti_endian_list, p->endian), G_CHECK_NULL_STR(p->ext_fname), p->ext_offset ); if( subs ) gifti_disp_nvpairs("darray->meta", &p->meta); if( subs ) for( c = 0; c < p->numCS; c++ ) gifti_disp_CoordSystem("darray->coordsys", p->coordsys[c]); fprintf(stderr," data = %s\n" " nvals = %u\n" " nbyper = %d\n" " numCS = %d\n", p->data ? "" : "NULL", (unsigned)p->nvals, p->nbyper, p->numCS); if( subs ) gifti_disp_nvpairs("darray->ex_atrs", &p->ex_atrs); fprintf(stderr,"--------------------------------------------------\n"); return 0; } /*---------------------------------------------------------------------- *! display the contents of the gifti_image struct * * if 'subs' is set, display the contents of the sub-structures, such * as all of the DataArray elements *//*-------------------------------------------------------------------*/ int gifti_disp_gifti_image(const char * mesg, const gifti_image * p, int subs) { fprintf(stderr,"==================================================\n"); if( mesg ) { fputs(mesg, stderr); fputc(' ', stderr); } if( !p ){ fputs("disp: gifti_image = NULL\n", stderr); return 1; } fprintf(stderr,"gifti_image struct\n" " version = %s\n" " numDA = %d\n", G_CHECK_NULL_STR(p->version), p->numDA); if( subs ) { char buf[32]; int c; gifti_disp_nvpairs("gim->meta", &p->meta); gifti_disp_LabelTable("gim->labeltable", &p->labeltable); for( c = 0; c < p->numDA; c++ ) { sprintf(buf, "gim->darray[%d]", c); gifti_disp_DataArray(buf, p->darray[c], subs); } } fprintf(stderr,"gifti_image struct\n" " swapped = %d\n" " compressed = %d\n", p->swapped, p->compressed); fprintf(stderr," -- darray totals: %lld MB\n",gifti_gim_DA_size(p,1)); if( subs ) gifti_disp_nvpairs("gim->ex_atrs" , &p->ex_atrs); fprintf(stderr,"==================================================\n"); return 0; } /*---------------------------------------------------------------------- *! compute the number of bytes summed over all DataArray elements * * if in_mb is set, return the (rounded) number of megabytes * (i.e. 17 is 17 MB) *//*-------------------------------------------------------------------*/ long long gifti_gim_DA_size(const gifti_image * p, int in_mb) { long long bytes = 0; int c; if( !p ) return -1; if( !p->darray || p->numDA <= 0 ) return 0; for( c = 0; c < p->numDA; c++ ) { if( ! p->darray[c]->data ) continue; /* skip anything without data */ if( p->darray[c]->nvals <= 0 || p->darray[c]->nbyper <= 0 ) { fprintf(stderr,"** have data[%d], but nvals = %lld, nbyper = %d\n", c, p->darray[c]->nvals, p->darray[c]->nbyper); return 0; } bytes += p->darray[c]->nvals * p->darray[c]->nbyper; } if( bytes <= 0LL ) return 0; if( in_mb ) bytes = (bytes + (1<<19) ) >> 20; /* round to nearest MB */ return bytes; } /*---------------------------------------------------------------------- *! given a datatype, return the corresponding bytes per value and swapsize * * nbyper and swapsize are filled only if the pointers are set *//*-------------------------------------------------------------------*/ int gifti_datatype_sizes(int datatype, int *nbyper, int *swapsize) { int c; for( c = sizeof(gifti_type_list) / sizeof(gifti_type_ele) - 1; c > 0; c-- ) if( datatype == gifti_type_list[c].type ) { if( nbyper ) *nbyper = gifti_type_list[c].nbyper; if( swapsize ) *swapsize = gifti_type_list[c].swapsize; return 0; } if( G.verb > 0 ) fprintf(stderr,"** GDS with bad datatype %d\n", datatype); if( nbyper ) *nbyper = 0; if( swapsize ) *swapsize = 0; return 1; } /*---------------------------------------------------------------------- *! compute the total number of data values in a DataArray element *//*-------------------------------------------------------------------*/ long long gifti_darray_nvals(const giiDataArray * da) { long long ndim = 1; int c; if(!da){ fprintf(stderr,"** GDND, no ptr\n"); return 0; } if( ! gifti_valid_num_dim(da->num_dim, 0) ) { fprintf(stderr,"** giiDataArray has illegal num_dim = %d\n", da->num_dim); return 0; } for( c = 0; c < da->num_dim; c++ ) ndim *= da->dims[c]; if( ndim <= 0 ) { gifti_disp_DataArray("** bad Dim list in ", da, 0); return 0; } return ndim; } /*---------------------------------------------------------------------- *! find giiDataArray element #index of the given intent *//*-------------------------------------------------------------------*/ giiDataArray * gifti_find_DA(gifti_image * gim, int intent, int index) { int c, nfound; if( !gim || !gifti_intent_is_valid(intent) || index < 0 ) { fprintf(stderr,"** find_DA: bad inputs (%p, %d, %d)\n", (void*)gim, intent, index); return NULL; } if ( !gim-> darray ) return NULL; for( c = 0, nfound = 0; c < gim->numDA; c++ ) if( gim->darray[c] && gim->darray[c]->intent == intent ) { if( nfound == index ) return gim->darray[c]; /* success */ nfound++; /* else, increment counter and keep looking */ } return NULL; } /*---------------------------------------------------------------------- *! return an allocated list of giiDataArray pointers of the given intent * * 'list' should be freed or taken *//*-------------------------------------------------------------------*/ int gifti_find_DA_list(gifti_image * gim, int intent, giiDataArray *** list, int * len) { int c, nfound; if( !gim || !gifti_intent_is_valid(intent) || !list || !len ) { fprintf(stderr,"** find_DA: bad inputs (%p, %d, %p, %p)\n", (void *)gim, intent, (void *)list, (void *)len); return 1; } if ( !gim->darray ) return 1; /* create one big enough to hold everything */ *len = gim->numDA; *list = (giiDataArray **)calloc(*len, sizeof(giiDataArray *)); if( !*list ) { fprintf(stderr,"** find_DA_list: failed to alloc %d ptrs\n",*len); *len = 0; return 1; } for( c = 0, nfound = 0; c < gim->numDA; c++ ) if( gim->darray[c] && gim->darray[c]->intent == intent ) (*list)[nfound++] = gim->darray[c]; /* if we didn't find any, nuke list, but do not return an error */ if( nfound == 0 ) { free(*list); *list = NULL; *len = 0; return 0; } /* otherwise, reallocate a smaller list */ if( nfound < *len ) { *len = nfound; *list = (giiDataArray**)realloc(*list,*len*sizeof(giiDataArray*)); if( !*list ) { fprintf(stderr,"** find_DA_list: failed realloc of %d ptrs\n",*len); *len = 0; return 1; } } return 0; } /*---------------------------------------------------------------------- *! given metadata name, return the corresponding value (or NULL) * * no allocation is done here *//*-------------------------------------------------------------------*/ char * gifti_get_meta_value(const nvpairs * nvp, const char * name) { int c; if( !nvp || !name ) { if( G.verb > 3 ) fprintf(stderr,"** get_meta_value: NULL input (%p, %p)\n", (void*)nvp, name); return NULL; } if( G.verb > 5 ) fprintf(stderr,"-- G_get_meta_value: looking for name = '%s'\n", name); if ( !nvp->name || !nvp->value || nvp->length <= 0 ) { if( G.verb > 3 ) fprintf(stderr,"-- G_get_meta_value: no name/value array\n"); return NULL; } for( c = 0; c < nvp->length; c++ ) if( !strcmp(nvp->name[c], name) ) break; /* found */ if( c >= nvp->length ) return NULL; if( G.verb > 3 ) fprintf(stderr,"++ found meta '%s'='%s'\n",nvp->name[c],nvp->value[c]); return nvp->value[c]; } /*---------------------------------------------------------------------- *! return the number of 'rows' and 'columns' of a DataArray element * * define rows to be the number of nodes, which should be the slowest * changing element, depending on the index order (kuru kuru pa) *//*-------------------------------------------------------------------*/ int gifti_DA_rows_cols(giiDataArray * da, long long * rows, long long * cols) { *rows = da->dims[0]; /* init */ *cols = 1; if( da->num_dim == 1 ) return 0; /* use default */ if( da->ind_ord == GIFTI_IND_ORD_ROW_MAJOR ) { /* treat Dim[0] as nodes (they change most slowly) */ *rows = da->dims[0]; *cols = (*rows) ? da->nvals / *rows : 1; /* be safe */ } else { if( ! gifti_valid_num_dim(da->num_dim, 1) ){ fprintf(stderr,"** cannot assign DA_rows_cols"); return 1; } *rows = da->dims[da->num_dim-1]; /* take highest index */ *cols = (*rows > 0) ? da->nvals / *rows : 1; } return 0; } /*---------------------------------------------------------------------- *! print the gifti library history string *//*-------------------------------------------------------------------*/ void gifti_disp_lib_hist(void) { int c, len = sizeof(gifti_history)/sizeof(char *); for( c = 0; c < len; c++ ) fputs(gifti_history[c], stdout); } /*---------------------------------------------------------------------- *! print the gifti library version string *//*-------------------------------------------------------------------*/ void gifti_disp_lib_version(void) { printf("%s, compiled %s\n", gifti_version, __DATE__); } /*---------------------------------------------------------------------- *! return the gifti library version string *//*-------------------------------------------------------------------*/ char * gifticlib_version(void) { return gifti_version; } /*---------------------------------------------------------------------- *! print the gifti DTD URL *//*-------------------------------------------------------------------*/ void gifti_disp_dtd_url(void) { printf("The GIFTI Document Type Definition (DTD) is at:\n %s\n", GIFTI_XML_DTD_SOURCE); } /*---------------------------------------------------------------------- *! display data in hexidecimal, on one line * * if mesg is set, print the message first * if fp is not set, print to stdout *//*-------------------------------------------------------------------*/ int gifti_disp_hex_data(const char *mesg, const void *data, int len, FILE *fp) { const char * dp = (const char *)data; FILE * stream; int c; stream = fp ? fp : stdout; if( !data || len < 1 ) return -1; if( mesg ) fputs(mesg, stream); for( c = 0; c < len; c++ ) fprintf(stream, " %02x", dp[c]); return 0; } /*---------------------------------------------------------------------- *! swap sets of 2-byte values *//*-------------------------------------------------------------------*/ int gifti_swap_2bytes(void * data, long long nsets) { char * cp1 = (char *)data, * cp2; char tval; long long c; for( c = 0; c < nsets; c++ ) { cp2 = cp1 + 1; tval = *cp1; *cp1 = *cp2; *cp2 = tval; cp1 += 2; } return 0; } /*---------------------------------------------------------------------- *! swap sets of 4-byte values *//*-------------------------------------------------------------------*/ int gifti_swap_4bytes(void * data, long long nsets) { char * cp0 = (char *)data, * cp1, * cp2; char tval; long long c; for( c = 0; c < nsets; c++ ) { cp1 = cp0; cp2 = cp0 + 3; tval = *cp1; *cp1 = *cp2; *cp2 = tval; cp1++; cp2--; tval = *cp1; *cp1 = *cp2; *cp2 = tval; cp0 += 4; } return 0; } /*---------------------------------------------------------------------- *! swap sets of N-byte values * * if N < 2 : just return * if N = 2 or N = 4: call explicit function for that size (speed) * else : swap in a loop *//*-------------------------------------------------------------------*/ int gifti_swap_Nbytes(void * data, long long nsets, int swapsize) { char * cp0, * cp1, * cp2; char tval; long long c; int offset; /* swapsize - 1, for speed */ if( ! data || nsets < 0 || swapsize < 0 ) { fprintf(stderr,"** swap_Nbytes: bad params (%p,%lld,%d)\n", (void *)data, nsets, swapsize); return 1; } if ( swapsize < 2 ) return 0; /* nothing to do */ else if( swapsize == 2 ) return gifti_swap_2bytes(data, nsets); else if( swapsize == 4 ) return gifti_swap_4bytes(data, nsets); /* peform a swap */ cp0 = (char *)data; offset = swapsize-1; /* just for speed */ for( c = 0; c < nsets; c++ ) { cp1 = cp0; cp2 = cp0 + offset; while( cp2 > cp1 ) { tval = *cp1; *cp1 = *cp2; *cp2 = tval; cp1++; cp2--; } cp0 += swapsize; } return 0; } /*---------------------------------------------------------------------- *! return the current CPU endian: GIFTI_ENDIAN_BIG or _LITTLE *//*-------------------------------------------------------------------*/ int gifti_get_this_endian(void) { int one = 1; char * cp = (char *)&one; if( *cp ) return GIFTI_ENDIAN_LITTLE; return GIFTI_ENDIAN_BIG; } /*---------------------------------------------------------------------- *! if endian does not match that of this CPU, swap the data bytes * * return whether bytes were swapped *//*-------------------------------------------------------------------*/ int gifti_check_swap(void * data, int endian, long long nsets, int swapsize) { if( !data || nsets < 0 || swapsize < 0 ) { fprintf(stderr,"** check_swap: bad params (%p,%lld, %d)\n", (void *)data, nsets, swapsize); return 0; } else if ( endian <= GIFTI_ENDIAN_UNDEF || endian > GIFTI_ENDIAN_MAX ) { fprintf(stderr, "** check_swap: invalid endian %d\n", endian); return 0; } /* if endian is the same as this one, just return */ if( endian == gifti_get_this_endian() ) { if( G.verb > 2 ) fprintf(stderr,"-- darray no swap needed : %lld sets of %d bytes\n", nsets, swapsize); return 0; } if( G.verb > 2 ) fprintf(stderr,"++ darray swap: %lld sets of %d bytes\n", nsets, swapsize); /* do the swap */ (void)gifti_swap_Nbytes(data, nsets, swapsize); return 1; } /*---------------------------------------------------------------------*/ /*! Allocate and fill the data array with data read from the given * external file. * * return 0 on success *//*-------------------------------------------------------------------*/ int gifti_read_extern_DA_data(giiDataArray * da) { FILE * fp; long long nbytes, nread; if( !da || !da->ext_fname || !*da->ext_fname ) return 0; if(G.verb > 4) fprintf(stderr,"-- external read of '%s'\n",da->ext_fname); if( da->ext_offset < 0 ) { fprintf(stderr,"** want external DA data with bad offset %lld\n", da->ext_offset); return 1; } else if( da->data ) { fprintf(stderr,"** want external DA data but data already allocated\n"); return 1; } else if ( !gifti_valid_dims(da, 1) ) { fprintf(stderr,"** cannot read external DA data with bad dims...\n"); return 1; } /* allocate data */ nbytes = da->nvals * da->nbyper; da->data = calloc(da->nvals, da->nbyper); /* zero in case of read failure */ if( !da->data ) { fprintf(stderr,"** failed to alloc %lld bytes for external read\n", nbytes); return 1; } /* open file, jump to offset and read */ fp = fopen(da->ext_fname, "r"); if( !fp ) { fprintf(stderr,"** ext read: failed to open '%s'\n",da->ext_fname); return 1; } if( fseek(fp, da->ext_offset, SEEK_SET) ) { fprintf(stderr,"** ext read: failed to seek to %lld in '%s'\n", da->ext_offset, da->ext_fname); fclose(fp); return 1; } nread = fread(da->data, sizeof(char), nbytes, fp); fclose(fp); /* close now in any case */ if( nread != nbytes ) { fprintf(stderr,"** ext_read: read only %lld of %lld bytes from %s\n", nread, nbytes, da->ext_fname); return 1; } if(G.verb > 2) fprintf(stderr,"-- read %lld bytes from external '%s' @ %lld\n", nbytes, da->ext_fname, da->ext_offset); return 0; } /*---------------------------------------------------------------------*/ /*! Write DA data to the given external file. * * Note: the given ext_offset _must_ refer to the current end of file. * * return 0 on success *//*-------------------------------------------------------------------*/ int gifti_write_extern_DA_data(giiDataArray * da) { FILE * fp; long long nbytes, nwritten, posn; if( !da || !da->ext_fname || !*da->ext_fname ) return 0; if(G.verb > 4) fprintf(stderr,"-- external write to '%s'\n",da->ext_fname); if( da->ext_offset < 0 ) { fprintf(stderr,"** bad offset for external DA data write, %lld\n", da->ext_offset); return 1; } else if( !da->data ) { fprintf(stderr,"** no data for external DA data write\n"); return 1; } else if ( !gifti_valid_dims(da, 1) ) { fprintf(stderr,"** cannot write external DA data with bad dims...\n"); return 1; } nbytes = da->nvals * da->nbyper; /* open file for append and verify that the file offset matches this one */ fp = fopen(da->ext_fname, "a+"); if( !fp ) { fprintf(stderr,"** ext write: failed to open '%s' for append\n", da->ext_fname); return 1; } /* we should be at the end of the file, which measn posn da->ext_offset */ fseek(fp, 0, SEEK_END); /* append should write to the end, but be sure */ posn = ftell(fp); if( posn != da->ext_offset ) { fprintf(stderr,"** ext write: cur posn (%lld) not ext_offset (%lld)" " in file %s\n", posn, da->ext_offset, da->ext_fname); fclose(fp); return 1; } nwritten = fwrite(da->data, sizeof(char), nbytes, fp); fclose(fp); /* close now in any case */ if( nwritten != nbytes ) { fprintf(stderr,"** ext_write: appended only %lld of %lld bytes to %s\n", nwritten, nbytes, da->ext_fname); return 1; } if(G.verb > 2) fprintf(stderr,"-- appended %lld bytes to external '%s' @ %lld\n", nbytes, da->ext_fname, da->ext_offset); return 0; } /*---------------------------------------------------------------------*/ /*! Apply the file list as external files. * * The files are assumed to be partitioned by DataArray entries. So * the list length must divide numDA evenly. * * External files are not checked for her, as this is independent of any * read or write operation. * * return 0 on success *//*-------------------------------------------------------------------*/ int gifti_set_extern_filelist(gifti_image * gim, int nfiles, char ** files) { giiDataArray * da; long long nbytes, offset; int nper; int daindex, findex, oindex; if(!gim || gim->numDA <= 0 || nfiles <= 0 || !files) { if(G.verb>1) fprintf(stderr,"-- set_extern_filelist: nothing to do\n"); return 1; } nper = gim->numDA / nfiles; if(G.verb>4) fprintf(stderr,"-- set_extern_flist for %d files (nper=%d)\n", nfiles, nper); if( nfiles * nper != gim->numDA ) { /* be sure division is integral */ fprintf(stderr,"** Cannot evenly divide %d DataArrays by %d" " external files\n", gim->numDA, nfiles); return 1; } daindex = 0; /* DataArray index */ for( findex = 0; findex < nfiles; findex++ ) { if( !files[findex] || !*files[findex] ) { fprintf(stderr,"** set_extern_flist: missing filename %d\n",findex); return 1; } /* note and check nbytes */ nbytes = gim->darray[daindex]->nvals * gim->darray[daindex]->nbyper; if( nbytes <= 0 ) { fprintf(stderr,"** gifti_set_extern_filelist: bad nbytes\n"); return 1; } /* within this file, offset will be multiples of nbytes */ for( oindex=0, offset=0; oindex < nper; oindex++, offset += nbytes ) { da = gim->darray[daindex]; if( nbytes != da->nvals * da->nbyper ) { fprintf(stderr,"** set_extern_flist: nbytes mismatch at DA[%d]\n" " (expected %lld, found %lld)\n", daindex, nbytes, da->nvals * da->nbyper); return 1; } /* set encoding and external file fields */ da->encoding = GIFTI_ENCODING_EXTBIN; da->ext_fname = gifti_strdup(files[findex]); da->ext_offset = offset; daindex++; /* increment DataArray index every time */ } } if(G.verb > 2) fprintf(stderr,"++ set extern file list, %d files, %d DAs per file", nfiles, nper); return 0; } /*---------------------------------------------------------------------*/ /*! Given a NIFTI_INTENT string, such as "NIFTI_INTENT_NODE_INDEX", * return the corresponding integral intent code. The intent code is * the macro value defined in nifti1.h. * * return 0 on failure (NIFTI_INTENT_NONE) *//*-------------------------------------------------------------------*/ int gifti_intent_from_string( const char * name ) { int tablen = sizeof(gifti_intent_list)/sizeof(gifti_intent_ele); int c; if( !name ) return 0; for( c = tablen-1; c > 0; c-- ) if( !strcmp(name, gifti_intent_list[c].name) ) break; return gifti_intent_list[c].code; } /*---------------------------------------------------------------------*/ /*! Given a NIFTI_TYPE value, such as NIFTI_TYPE_INT16, return the * corresponding macro label as a string. The dtype code is the * macro value defined in nifti1.h. *//*-------------------------------------------------------------------*/ char * gifti_intent_to_string( int code ) { int tablen = sizeof(gifti_intent_list)/sizeof(gifti_intent_ele); int c; for( c = tablen-1; c > 0; c-- ) if( gifti_intent_list[c].code == code ) break; return gifti_intent_list[c].name; } /*---------------------------------------------------------------------*/ /*! Return whether the given code is a valid NIFTI_INTENT code. *//*-------------------------------------------------------------------*/ int gifti_intent_is_valid( int code ) { int tablen = sizeof(gifti_intent_list)/sizeof(gifti_intent_ele); int c; for( c = tablen-1; c > 0; c-- ) if( gifti_intent_list[c].code == code ) break; return( c >= 0 ); } /*---------------------------------------------------------------------*/ /*! duplicate the given string *//*-------------------------------------------------------------------*/ char * gifti_strdup( const char * src ) { char * newstr; int len; if( !src ) return NULL; /* easy case */ len = strlen(src) + 1; newstr = (char *)malloc(len * sizeof(char)); if( !newstr ) { fprintf(stderr,"** failed gifti_strdup, len = %d\n", len); return NULL; } strcpy(newstr, src); return newstr; } /*---------------------------------------------------------------------*/ /*! duplicate the given giiDataArray struct, optionally including data * * Allocate for a new struct, and fill it so that the contents are * identical (sans pointers) to orig. Sub-structure arrays will need * to be allocated, also. * * If get_data is not set, gnew->data will be left as NULL. * * return the address of the newly allocated structure *//*-------------------------------------------------------------------*/ giiDataArray * gifti_copy_DataArray(const giiDataArray * orig, int get_data) { giiDataArray * gnew; int c; if( ! orig ){ fprintf(stderr,"** copy_DA: input is NULL\n"); return NULL; } if(G.verb > 5) fprintf(stderr,"++ copying giiDataArray...\n"); gnew = (giiDataArray *)calloc(1, sizeof(giiDataArray)); if(!gnew){fprintf(stderr,"** copy_DA, failed to alloc DA\n"); return NULL;} /* cheat - start by copying the entire struct contents */ *gnew = *orig; /* copy any pointer data or structures */ gnew->ext_fname = gifti_strdup(orig->ext_fname); gifti_copy_nvpairs(&gnew->meta, &orig->meta); if( orig->numCS > 0 && orig->coordsys ) { gnew->coordsys = (giiCoordSystem **)malloc(gnew->numCS * sizeof(giiCoordSystem *)); if(!gnew->coordsys) { fprintf(stderr,"** copy_DA: failed to alloc %d CS pointers\n", gnew->numCS); gnew->numCS = 0; } else for( c = 0; c < gnew->numCS; c++ ) gnew->coordsys[c] = gifti_copy_CoordSystem(orig->coordsys[c]); } /* maybe the needy user wants data, too */ if(orig->data && get_data) { if(G.verb > 5) fprintf(stderr,"++ copy_DA, adding data\n"); gnew->data = malloc(gnew->nvals * gnew->nbyper); if(!gnew->data) /* continue? */ fprintf(stderr,"** copy DA, failed to alloc %lld bytes for data\n", gnew->nvals * gnew->nbyper); memcpy(gnew->data, orig->data, gnew->nvals * gnew->nbyper); } else gnew->data = NULL; /* last and certainly least, ex_atrs */ gifti_copy_nvpairs(&gnew->ex_atrs, &orig->ex_atrs); return gnew; } /*---------------------------------------------------------------------*/ /*! dupliate the giiCoordSystem struct (passing NULL is okay) *//*-------------------------------------------------------------------*/ giiCoordSystem * gifti_copy_CoordSystem(const giiCoordSystem * src) { giiCoordSystem * csnew; int r, c; if( !src ) return NULL; /* this may be okay */ if( G.verb > 6 ) fprintf(stderr,"++ copy_CS\n"); csnew = (giiCoordSystem *)malloc(sizeof(giiCoordSystem)); if( !csnew ){ fprintf(stderr,"** copy_CS: failed alloc\n"); return NULL; } csnew->dataspace = gifti_strdup(src->dataspace); csnew->xformspace = gifti_strdup(src->xformspace); for( r = 0; r < 4; r++ ) for( c = 0; c < 4; c++ ) csnew->xform[r][c] = src->xform[r][c]; return csnew; } /*---------------------------------------------------------------------*/ /*! dupliate the contents of the giiLabelTable struct *//*-------------------------------------------------------------------*/ int gifti_copy_LabelTable(giiLabelTable * dest, const giiLabelTable * src) { int c; if( !src || !dest ) { fprintf(stderr,"** copy_LabelTable: bad params (%p,%p)\n", (void *)src, (void *)dest); return 1; } if( G.verb > 6 ) fprintf(stderr,"++ copy_LT\n"); /* quick case: empty table */ if( src->length <= 0 ) return gifti_clear_LabelTable(dest); /* otherwise, allocate and copy lists */ dest->length = src->length; dest->key = (int *)malloc(dest->length * sizeof(int)); dest->label = (char **)malloc(dest->length * sizeof(char *)); if( src->rgba ) dest->rgba = (float *)malloc(dest->length * 4 * sizeof(float)); /* check for failure */ if( !dest->key || !dest->label || (src->rgba && !dest->rgba) ) { fprintf(stderr,"** failed to dup label arrays of length %d\n", dest->length); gifti_free_LabelTable(dest); return 1; } /* copy any rgba list */ if( dest->rgba ) memcpy(dest->rgba, src->rgba, dest->length * 4 * sizeof(float)); /* copy indices */ for( c = 0; c < dest->length; c++ ) dest->key[c] = src->key[c]; /* copy labels */ for( c = 0; c < dest->length; c++ ) dest->label[c] = gifti_strdup(src->label[c]); return 0; } /*---------------------------------------------------------------------*/ /*! dupliate the contents of one nvpairs structure into an empty one * * return 0 on success *//*-------------------------------------------------------------------*/ int gifti_copy_nvpairs(nvpairs * dest, const nvpairs * src) { if( !dest || !src ){ fprintf(stderr,"** copy_NVP, bad params (%p,%p)\n", (void*)dest,(void*)src); return 1; } if( G.verb > 6 ) fprintf(stderr,"++ copy_nvp, length %d\n", src->length); /* check for a simple case */ if( src->length <= 0 || !src->name || !src->value ) { dest->length = 0; dest->name = dest->value = NULL; return 0; } /* else, copy the lists */ dest->length = src->length; dest->name = gifti_copy_char_list(src->name, src->length); dest->value = gifti_copy_char_list(src->value, src->length); return 0; } /*---------------------------------------------------------------------*/ /*! dupliate the list of strings *//*-------------------------------------------------------------------*/ char ** gifti_copy_char_list(char ** list, int len) { char ** newlist = NULL; int c; if( !list || len <= 0 ) return NULL; newlist = (char **)malloc(len * sizeof(char *)); if( !newlist ) { fprintf(stderr,"** copy_char_list fails for %d pointers\n", len); return NULL; } for( c = 0; c < len; c++) /* big finish */ newlist[c] = gifti_strdup(list[c]); return newlist; } /*---------------------------------------------------------------------*/ /*! copy any GIFTI MetaData named 'name' from dest to src (replace old) * * return 0 on success, 1 on failure to find, -1 on error *//*-------------------------------------------------------------------*/ int gifti_copy_gifti_meta(gifti_image * dest, gifti_image * src, const char * name) { char * value; if( !dest || !src || !name ) { if( G.verb > 0 ) fprintf(stderr,"** copy_gifti_meta: bad params(%p,%p,%p)\n", (void *)dest, (void *)src, name); return -1; } value = gifti_get_meta_value(&src->meta, name); if( !value ) { if( G.verb > 4 ) fprintf(stderr,"-- GCGM: did not find meta name '%s'\n", name); return 1; } return gifti_add_to_meta(&dest->meta, name, value, 1); } /*---------------------------------------------------------------------*/ /*! copy any DataArray MetaData named 'name' from dest to src (replace old) * (apply to list of DAs, or to all) * * return 0 on success, 1 on failure to find, -1 on error *//*-------------------------------------------------------------------*/ int gifti_copy_DA_meta_many(gifti_image * dest, gifti_image * src, const char * name, const int * dalist, int len) { int c, index, use_list, numDA, rv = 0; if( !dest || !dest->darray || !src || !src->darray || !name ) { if( G.verb > 1 ) fprintf(stderr,"** GCDAMM: bad params\n"); return -1; } /* if they are not equal, it is probably a user mistake to be here */ if( dest->numDA != src->numDA ) { if(G.verb>0) fprintf(stderr,"-- cannot copy DA meta, numDA %d != %d\n", src->numDA, dest->numDA); return -1; } /* the empty case is probably not an error */ if( dest->numDA <= 0 || src->numDA <= 0 ) { if( G.verb > 4 ) fprintf(stderr,"-- GCDAMM: numDA %d, %d\n", src->numDA, dest->numDA); return 0; } /* decide whether to use dalist or all DAs */ use_list = gifti_valid_int_list(dalist, len, 0, src->numDA-1, G.verb); if( use_list && G.verb > 2 ) fprintf(stderr,"++ copy_DA_meta_many, %s (list length %d)\n", use_list ? "DA in list" : "all DAs", len); /* finally, get to work */ numDA = use_list ? len : src->numDA; for( c = 0; c < numDA; c++ ) { index = use_list ? dalist[c] : c; /* choose appropriate DA index */ /* note any failures */ rv |= gifti_copy_DA_meta(dest->darray[index], src->darray[index], name); } return rv; } /*---------------------------------------------------------------------*/ /*! copy any DataArray MetaData named 'name' from dest to src (replace old) * * return 0 on success, 1 on failure to find, -1 on error *//*-------------------------------------------------------------------*/ int gifti_copy_DA_meta(giiDataArray *dest, giiDataArray *src, const char *name) { char * value; if( !dest || !src || !name ) { if( G.verb > 0 ) fprintf(stderr,"** copy_DA_meta: bad params(%p,%p,%p)\n", (void *)dest, (void *)src, name); return -1; } value = gifti_get_meta_value(&src->meta, name); if( !value ) { if( G.verb > 4 ) fprintf(stderr,"-- GCDAM: did not find meta name '%s'\n", name); return 1; } return gifti_add_to_meta(&dest->meta, name, value, 1); } /*---------------------------------------------------------------------*/ /*! copy ALL DataArray MetaData from dest to src (replace old) * * return 0 on success, 1 on failure to find, -1 on error *//*-------------------------------------------------------------------*/ int gifti_copy_all_DA_meta(giiDataArray *dest, giiDataArray *src) { int c, rv = 0; if( !dest || !src ) { if( G.verb > 0 ) fprintf(stderr,"** copy_all_DA_meta: bad params(%p,%p)\n", (void *)dest, (void *)src); return -1; } for( c = 0; c < src->meta.length; c++ ) rv |= gifti_copy_DA_meta(dest, src, src->meta.name[c]); return rv; } /*---------------------------------------------------------------------*/ /*! find any differences between the two images * * verb 0-3 = quiet, state diff, state per DA, state all diffs * * return 0 if they are the same, 1 if they differ *//*-------------------------------------------------------------------*/ int gifti_compare_gifti_images(const gifti_image * g1, const gifti_image * g2, int comp_data, int verb) { int diffs = 0, data_diffs = 0, gdiffs = 0, c, rv, numDA; int lverb = verb; /* possibly override passed 'verb' */ if( G.verb > lverb ) lverb = G.verb; if( !g1 || !g2 ) { if( !g1 && !g2 ) return 0; /* both NULL means equal */ if(lverb) printf("-- gifti_images differ (exactly one is NULL)\n"); return 1; } /* check main structs */ if( gifti_compare_gims_only(g1, g2, lverb) ) { if( lverb > 0 ) printf("++ gifti_images differ\n"); if( lverb < 2 ) return 1; /* all we need to know */ gdiffs++; } /* get min numDA, just to be safe */ numDA = g1->numDA < g2->numDA ? g1->numDA : g2->numDA; for( c = 0; c < numDA; c++ ) { rv = gifti_compare_DA_pair(g1->darray[c],g2->darray[c],comp_data,lverb); if( rv ) { diffs++; if( rv & 2 ) data_diffs++; if( lverb < 2 ) break; printf("++ DataArray[%d] - difference (data %s)\n", c, ! comp_data ? "untested" : data_diffs ? "differs" : "identical"); } } if( diffs && lverb > 0 ) printf("-- differences found in %d of %d DAs\n", diffs, numDA); /* state data diffs separately */ if( lverb > 2 && comp_data ) { if( ! data_diffs ) printf("-- no data differences found\n"); else printf("-- data differences found in %d of %d DAs\n", data_diffs, numDA); } if( diffs || gdiffs ) return 1; return 0; } /*---------------------------------------------------------------------*/ /*! find any differences between the two sets of image data * * verb 0-2+ = quiet, state diff, state per DA * * return 0 if they are the same, 1 if they differ *//*-------------------------------------------------------------------*/ int gifti_compare_gifti_data(const gifti_image * g1, const gifti_image * g2, int verb) { int lverb = verb, c, diffs = 0, numDA; if( G.verb > lverb ) lverb = G.verb; if( !g1 || !g2 ) { if( !g1 && !g2 ) return 0; /* both NULL means equal */ if(lverb) printf("-- gim data difference (exactly one gim is NULL)\n"); return 1; } /* if numDA does not match, they differ */ if( g1->numDA != g2->numDA ) { if( lverb > 0 ) printf("-- gim data differs: numDA differs, %d vs. %d\n", g1->numDA, g2->numDA); if( lverb < 2 ) return 1; } /* even if they differ, we may want to continue, so use minimum */ numDA = g1->numDA < g2->numDA ? g1->numDA : g2->numDA; for( c = 0; c < numDA; c++ ) { if( gifti_compare_DA_data(g1->darray[c],g2->darray[c],lverb) ) { diffs++; if( lverb > 0 ) printf("++ data difference at DataArray[%d]\n", c); if( lverb < 2 ) return 1; } } if( diffs ) { /* verb must be 2, so print */ printf("-- found data diffs in %d DataArrays\n", diffs); return 1; } if( G.verb > 1 ) fprintf(stderr,"-- no data diffs found\n"); return 0; } int gifti_compare_DA_data(const giiDataArray * d1, const giiDataArray * d2, int verb) { long long nbytes, offset; if( !d1 || !d2 ) { if( !d1 && !d2 ) return 0; /* both NULL means equal */ if(verb>1) printf("-- DA data difference (exactly one DA is NULL)\n"); return 1; } if( ! gifti_valid_dims(d1,verb>1) || ! gifti_valid_dims(d2,verb>1) ) { if(verb>1) printf("-- DA data diff: dims are not valid\n"); return 1; } nbytes = d1->nvals * d1->nbyper; if( nbytes != (d2->nvals * d2->nbyper) ) { if(verb>1) printf("-- DA data diff: nbytes differs, %lld vs. %lld\n", nbytes, d2->nvals * d2->nbyper); return 1; } /* okay, let's test the data */ offset = gifti_compare_raw_data(d1->data,d2->data,nbytes); if ( offset >= 0 ) { /* difference in data */ if(verb > 1) printf("-- diff in DA data at posn %lld\n", offset/d1->nbyper); return 1; } return 0; } /* compare everything but darray * (for diffs, only print if verb > 1) */ int gifti_compare_gims_only(const gifti_image * g1, const gifti_image * g2, int verb) { int diffs = 0; int lverb = verb; /* possibly override passed 'verb' */ if( G.verb > lverb ) lverb = G.verb; if( !g1 || !g2 ) { if( !g1 && !g2 ) return 0; /* equal */ if( lverb > 1 ) printf("-- comp gifti ims: have NULL %p, %p\n",(void*)g1,(void*)g2); return 1; /* not equal */ } if( g1->numDA != g2->numDA ) { diffs++; if( lverb > 1 ) fprintf(stderr,"-- diff in GIFTI numDA: %d vs %d\n", g1->numDA, g2->numDA); if( lverb <= 1 ) return 1; } if( !g1->version || !g2->version ) { /* handle at least one NULL */ if( g1->version || g2->version ) { diffs++; if( lverb > 1 ) fprintf(stderr,"-- diff in GIFTI version: one is NULL\n"); if( lverb <= 1 ) return 1; } /* else both NULL, which means equal */ } else if ( strcmp(g1->version, g2->version) ) { diffs++; if( lverb > 1 ) fprintf(stderr,"-- diff in GIFTI version: %s vs. %s\n", g1->version, g2->version); if( lverb <= 1 ) return 1; } if( gifti_compare_labeltable(&g1->labeltable, &g2->labeltable, verb) ) { diffs++; if( lverb > 1 ) printf("-- diff in gifti labeltable\n"); if( lverb <= 1 ) return 1; } if( gifti_compare_nvpairs(&g1->meta, &g2->meta, verb) ) { diffs++; if( lverb > 1 ) printf("-- diff in gifti meta\n"); if( lverb <= 1 ) return 1; } if( g1->swapped != g2->swapped ) { diffs++; if( lverb > 1 ) fprintf(stderr,"-- difference in GIM->swapped: %d vs %d\n", g1->swapped, g2->swapped); if( lverb <= 1 ) return 1; } if( g1->compressed != g2->compressed ) { diffs++; if( lverb > 1 ) fprintf(stderr,"-- difference in GIM->compressed: %d vs %d\n", g1->compressed, g2->compressed); if( lverb <= 1 ) return 1; } if( gifti_compare_nvpairs(&g1->ex_atrs, &g2->ex_atrs, verb) ) { diffs++; if( lverb > 1 ) printf("-- diff in gifti ex_atrs\n"); if( lverb <= 1 ) return 1; } return diffs; } /*! return 0 if equal, 1 if diffs, 2 if data diffs (and 3 if both diffs) */ int gifti_compare_DA_pair(const giiDataArray * d1, const giiDataArray * d2, int comp_data, int verb) { long long offset; int c, top, diffs = 0, data_diffs = 0; int lverb = verb; /* possibly override passed 'verb' */ if( G.verb > lverb ) lverb = G.verb; if( !d1 || !d2 ) { if( !d1 && !d2 ) return 0; /* equal */ if(lverb>2) printf("-- comp DA: have NULL: %p, %p\n", (void*)d1,(void*)d2); return 3; /* not equal */ } if( d1->intent != d2->intent ) { diffs = 1; if( lverb > 1 ) printf("-- diff in DA intent: %d (%s) vs. %d (%s)\n", d1->intent, gifti_intent_to_string(d1->intent), d2->intent, gifti_intent_to_string(d2->intent)); if( lverb < 3 ) return 1; } if( d1->datatype != d2->datatype ) { diffs = 1; if( lverb > 1 ) printf("-- diff in DA datatype: %d (%s) vs. %d (%s)\n", d1->datatype, gifti_datatype2str(d1->datatype), d2->datatype, gifti_datatype2str(d2->datatype)); if( lverb < 3 ) return 1; } if( d1->ind_ord != d2->ind_ord ) { diffs = 1; if( lverb > 1 ) printf("-- diff in DA ind_ord: %d (%s) vs. %d (%s)\n", d1->ind_ord, gifti_list_index2string(gifti_index_order_list, d1->ind_ord), d2->ind_ord, gifti_list_index2string(gifti_index_order_list, d2->ind_ord)); if( lverb < 3 ) return 1; } if( d1->num_dim != d2->num_dim ) { diffs = 1; data_diffs = 1; if( lverb > 1 ) printf("-- diff in DA num_dim: %d vs. %d\n", d1->num_dim, d2->num_dim ); if( lverb < 3 ) return 3; } /* get minimum num_dim */ top = d1->num_dim < d2->num_dim ? d1->num_dim : d2->num_dim; for( c = 0; c < top; c++ ) if( d1->dims[c] != d2->dims[c] ) break; if( c < top ) { diffs = 1; data_diffs = 1; if( lverb > 1 ) { printf("-- diff in DA dims (length %d)\n ", top); gifti_disp_raw_data(d1->dims, NIFTI_TYPE_INT32, top, 0, stdout); printf(" vs "); gifti_disp_raw_data(d2->dims, NIFTI_TYPE_INT32, top, 1, stdout); } if( lverb < 3 ) return 3; } if( d1->encoding != d2->encoding ) { diffs = 1; if( lverb > 1 ) printf("-- diff in DA encoding: %d (%s) vs. %d (%s)\n", d1->encoding, gifti_list_index2string(gifti_encoding_list, d1->encoding), d2->encoding, gifti_list_index2string(gifti_encoding_list, d2->encoding)); if( lverb < 3 ) return 1; } if( d1->endian != d2->endian ) { diffs = 1; if( lverb > 1 ) printf("-- diff in DA endian: %d (%s) vs. %d (%s)\n", d1->endian, gifti_list_index2string(gifti_endian_list, d1->endian), d2->endian, gifti_list_index2string(gifti_endian_list, d2->endian)); if( lverb < 3 ) return 1; } if( d1->ext_fname || d2->ext_fname ) { if( ! d1->ext_fname || !d2->ext_fname || strcmp(d1->ext_fname, d2->ext_fname) ) { diffs = 1; if( lverb > 1 ) printf("-- diff in DA ext_fname: %s vs. %s\n", G_CHECK_NULL_STR(d1->ext_fname), G_CHECK_NULL_STR(d2->ext_fname)); if( lverb < 3 ) return 1; } } if( d1->ext_offset != d2->ext_offset ) { diffs = 1; if( lverb > 1 ) printf("-- diff in DA ext_offset: %lld vs. %lld\n", d1->ext_offset, d2->ext_offset); if( lverb < 3 ) return 1; } if( gifti_compare_nvpairs(&d1->meta, &d2->meta, verb) ) { diffs = 1; if( lverb > 1 ) printf("-- diff in DA meta\n"); if( lverb < 3 ) return 1; } if( d1->numCS != d2->numCS ) { diffs = 1; if( lverb > 1 ) printf("-- diff in DA numCS\n"); if( lverb < 3 ) return 1; } /* compare each of the CoordSystem structs */ top = d1->numCS < d2->numCS ? d1->numCS : d2->numCS; for( c = 0; c < top; c++ ) if( gifti_compare_coordsys(d1->coordsys[c], d2->coordsys[c],1,verb) ) { diffs = 1; if( lverb > 1 ) printf("-- diff in DA coordsys[%d]\n", c); if( lverb < 3 ) return 1; } if( d1->nvals != d2->nvals ) { diffs = 1; data_diffs = 1; if( lverb > 1 ) printf("-- diff in DA nvals: %lld vs. %lld\n", d1->nvals, d2->nvals); if( lverb < 3 ) return 3; } if( d1->nbyper != d2->nbyper ) { diffs = 1; data_diffs = 1; if( lverb > 1 ) printf("-- diff in DA nbyper: %d vs. %d\n", d1->nbyper, d2->nbyper); if( lverb < 3 ) return 3; } if( gifti_compare_nvpairs(&d1->ex_atrs, &d2->ex_atrs, verb) ) { diffs = 1; if( lverb > 1 ) printf("-- diff in DA ex_atrs\n"); if( lverb < 3 ) return 1; } /* check data last, and only if no data diffs and dims are valid */ /* (set the 2^1 bit for a data diff) */ if( comp_data && !data_diffs && gifti_valid_dims(d1, 0) ) { offset = gifti_compare_raw_data(d1->data,d2->data,d1->nvals*d1->nbyper); if ( offset >= 0 ) { diffs |= 2; if(lverb>1) printf("-- diff in DA data at position %lld\n", offset/d1->nbyper); if(lverb<3) return 3; } } return diffs; } /*---------------------------------------------------------------------*/ /*! return 1 if gifti_images are approximately equal (from a data standpoint) * note: return value is opposite from gifti_compare_gifti_images * * verb 0-3 = quiet, state diff, state per DA, state all diffs * * compare information close to the data: * - numDA * - labeltable * - darray elements (pairwise) * ignore version, meta, swapped, encoding, endian, ext_*, ex_atrs, etc. * * return 1 if they are approximately the same, 0 if otherwise *//*-------------------------------------------------------------------*/ int gifti_approx_gifti_images(const gifti_image * g1, const gifti_image * g2, int comp_data, int verb) { int diffs = 0, c, numDA; int lverb = verb; /* possibly override passed 'verb' */ if( G.verb > lverb ) lverb = G.verb; if( !g1 || !g2 ) { if( !g1 && !g2 ) return 1; /* both NULL means equal */ if(lverb) printf("-- gifti_images not approx (exactly one is NULL)\n"); return 0; } if( g1->numDA != g2->numDA ) { if( lverb ) printf("-- gifti_images differ in numDA\n"); if( lverb < 2 ) return 0; diffs++; } if( ! gifti_approx_labeltables(&g1->labeltable, &g2->labeltable, lverb) ) { if( lverb ) printf("-- gifti labeltables not approx. equal\n"); if( lverb < 2 ) return 0; diffs++; } /* get min numDA, just to be safe */ numDA = g1->numDA < g2->numDA ? g1->numDA : g2->numDA; for( c = 0; c < numDA; c++ ) { if( !gifti_approx_DA_pair(g1->darray[c],g2->darray[c],comp_data,lverb)){ diffs++; if(lverb) printf("++ DataArrays[%d] - not approximately equal\n",c); if( lverb < 2 ) break; } } if( diffs && lverb > 0 ) printf("-- GIFTI: approx diffs found\n"); return ! diffs; } /* ------------------------------------------------------------------------- */ /*! return 1 if DAs are approximately equal (opposite of compare functions) * * test for difference in: * * transformation matrices : 16 values each (approx) * coordinates : 3 values per node (approx) * triangles : exact (starting node can be any of the 3) * data : approx * * lverb = 0 : no print (no print anywhere) * 1 : no print (print at higher level) * 2 : print DA level diff * 3 : print all diffs * */ int gifti_approx_DA_pair(const giiDataArray * d1, const giiDataArray * d2, int comp_data, int verb) { int c, top, can_comp, offset, diffs = 0; int lverb = verb; /* possibly override passed 'verb' */ if( G.verb > lverb ) lverb = G.verb; /* deal with any NULLs for starter */ if( !d1 && !d2 ) { if(lverb>2) printf("-- approx DA: have NULL\n"); return 1; /* yes, these are equal */ } else if( !d1 || !d2 ) { if(lverb>2) printf("-- approx DA: have one NULL\n"); return 0; /* not approximately equal */ } /* do early, to put higher level whining first */ can_comp = can_compare_DA_data(d1, d2, verb); if( d1->numCS != d2->numCS ) { diffs = 1; if( lverb > 1 ) printf("-- approx DA: diff in numCS\n"); if( lverb < 3 ) return 0; } /* compare each of the CoordSystem structs */ top = d1->numCS < d2->numCS ? d1->numCS : d2->numCS; for( c = 0; c < top; c++ ) { /* first compare without checking the data */ if( gifti_compare_coordsys(d1->coordsys[c], d2->coordsys[c],1,verb) ) { diffs = 1; if( lverb > 1 ) printf("-- diff in DA coordsys[%d]\n", c); if( lverb < 3 ) return 0; } } /* if we cannot or do not want to compare the data, return */ if( ! comp_data || ! can_comp ) return !diffs; /* if data is coordinates, compare percent diff * if trianges, compare exactly, but with any starting index * else, compare percent diff */ if( d1->intent == d2->intent && d1->intent==NIFTI_INTENT_TRIANGLE ) { /* verify that these look like triangles */ if( d1->num_dim < 2 || d1->dims[1] != 3 ) { if( lverb > 1 ) printf("-- approx DA: bad dims for TRIANGLEs: " "num_dim=%d, dims[1]=%d\n", d1->num_dim, d1->dims[1]); return 0; } offset = gifti_triangle_diff_offset(d1->data, d2->data, d1->dims[0], d1->datatype); if( offset >= 0 ) { diffs |= 2; if(lverb > 1) printf("-- approx DA: triange diff at offset %d\n", offset); if(lverb < 3) return 0; } } else { offset = gifti_approx_diff_offset(d1->data, d2->data, d1->nvals, d1->datatype, 1.0); if( offset >= 0 ) { diffs |= 2; if(lverb>1) printf("-- approx DA: data diff at offset %d\n",offset); if(lverb<3) return 0; } } return !diffs; } /* return whether the DA elements match so as to compare the data * * apply the same verb as above */ static int can_compare_DA_data(const giiDataArray *d1,const giiDataArray *d2, int verb) { int c, top, rv = 1; int lverb = verb; /* possibly override passed 'verb' */ if( G.verb > lverb ) lverb = G.verb; if( !d1 || !d2 ) { if(lverb>1) printf("-- comp DAs: have NULL DA(s) (%p, %p)\n", (void*)d1,(void*)d2); return 0; /* not equal */ } if( d1->datatype != d2->datatype ) { rv = 0; if( lverb > 1 ) printf("-- comp DAs: DA datatype diff: %d (%s) vs. %d (%s)\n", d1->datatype, gifti_datatype2str(d1->datatype), d2->datatype, gifti_datatype2str(d2->datatype)); if( lverb < 3 ) return 0; } if( d1->ind_ord != d2->ind_ord ) { rv = 0; if( lverb > 1 ) printf("-- comp DAs: ind_ord diff: %d (%s) vs. %d (%s)\n", d1->ind_ord, gifti_list_index2string(gifti_index_order_list, d1->ind_ord), d2->ind_ord, gifti_list_index2string(gifti_index_order_list, d2->ind_ord)); if( lverb < 3 ) return 0; } if( d1->num_dim != d2->num_dim ) { rv = 0; if( lverb > 1 ) printf("-- comp DAs: num_dim diff: %d vs. %d\n", d1->num_dim, d2->num_dim ); if( lverb < 3 ) return 0; } /* get minimum num_dim */ top = d1->num_dim < d2->num_dim ? d1->num_dim : d2->num_dim; for( c = 0; c < top; c++ ) if( d1->dims[c] != d2->dims[c] ) break; if( c < top ) { rv = 0; if( lverb > 1 ) { printf("-- comp DAs: DA dims diff (length %d)\n ", top); gifti_disp_raw_data(d1->dims, NIFTI_TYPE_INT32, top, 0, stdout); printf(" vs "); gifti_disp_raw_data(d2->dims, NIFTI_TYPE_INT32, top, 1, stdout); } if( lverb < 3 ) return 0; } if( d1->nvals != d2->nvals ) { rv = 0; if( lverb > 1 ) printf("-- comp DAs: nvals diff: %lld vs. %lld\n", d1->nvals, d2->nvals); if( lverb < 3 ) return 0; } if( d1->nbyper != d2->nbyper ) { rv = 0; if( lverb > 1 ) printf("-- comp DAs: nbyper diff: %d vs. %d\n", d1->nbyper, d2->nbyper); if( lverb < 3 ) return 0; } /* as a last test, make sure dims are valid, not just the same */ if( ! gifti_valid_dims(d1, 0) ) { rv = 0; if( lverb > 1 ) printf("-- comp DAs: dims not valid\n"); } return rv; } /*---------------------------------------------------------------------*/ /*! check pointers, compare lengths, then check the Names in each list, * and see if there is a matching Name=Value pari * * only state diffs in the verb=3 case *//*-------------------------------------------------------------------*/ int gifti_compare_nvpairs(const nvpairs * p1, const nvpairs * p2, int verb) { char * value; int lverb = verb; /* possibly override passed verb */ int c, len, diffs = 0; if( G.verb > lverb ) lverb = G.verb; if( !p1 || !p2 ) { if(!p1 && !p2) return 0; /* equal */ if(lverb>2) printf("-- comp nvpairs: have NULL: %p, %p\n",(void*)p1,(void*)p2); return 1; /* not equal */ } /* they must be valid to proceed */ if( ! gifti_valid_nvpairs(p1, 0) || ! gifti_valid_nvpairs(p2, 0) ) { if( lverb > 2 ) printf("-- cannot compare invalid nvpairs\n"); return 1; } if( p1->length != p2->length ) { if( lverb > 2 ) printf("-- nvp list lengths differ: %d vs %d\n", p1->length, p2->length); if( lverb < 3 ) return 1; } /* search for mis-matches or non-existence from list 1 into list 2 */ /* assume Names are unique (each that is not will show a mis-match) */ len = p1->length < p2->length ? p1->length : p2->length; for( c = 0; c < p1->length; c++ ) { if( ! p1->value[c] ) continue; /* skip anything that doesn't exist */ value = gifti_get_meta_value(p2, p1->name[c]); if( !value ) { if( lverb > 2 ) printf("-- nvp list 2 missing Name: '%s'\n",p1->name[c]); diffs++; } else if( strcmp(value, p1->value[c]) ) { if( lverb > 2 ) printf("-- nvp diff for Name '%s':\n '%s' vs. '%s'\n", p1->name[c], p1->value[c], value); diffs++; } if( diffs && lverb < 3 ) return 1; } /* now just search for non-existence (mis-matches have been found) */ for( c = 0; c < p2->length; c++ ) { if( ! p2->value[c] ) continue; /* skip anything that doesn't exist */ value = gifti_get_meta_value(p1, p2->name[c]); if( !value ) { if( lverb > 2 ) printf("-- nvp list 1 missing Name: '%s'\n",p2->name[c]); if( lverb < 3 ) return 1; diffs++; } } return diffs; } /*---------------------------------------------------------------------*/ /*! check pointers, lengths and contents * * return 0 if equal * * only state diffs in the verb=3 case *//*-------------------------------------------------------------------*/ int gifti_compare_labeltable(const giiLabelTable *t1, const giiLabelTable *t2, int verb) { return compare_labeltables(t1, t2, verb, 0); } /*---------------------------------------------------------------------*/ /*! return 1 if tables are approximately equal (opposite of compare function) * * RGBA data is compared approximately * * only state diffs in the verb=3 case *//*-------------------------------------------------------------------*/ int gifti_approx_labeltables(const giiLabelTable *t1, const giiLabelTable *t2, int verb) { return( ! compare_labeltables(t1, t2, verb, 1)); } /*---------------------------------------------------------------------*/ /*! check pointers, lengths and contents * * only state diffs in the verb=3 case * * if approx, compare RBGA approximately *//*-------------------------------------------------------------------*/ static int compare_labeltables(const giiLabelTable *t1, const giiLabelTable *t2, int verb, int approx) { int lverb = verb; /* possibly override passed verb */ int c, roff, offset, diffs = 0; if( G.verb > lverb ) lverb = G.verb; if( !t1 || !t2 ) { if(!t1 && !t2) return 0; /* equal */ if(lverb>2) printf("-- Comp LabTab: have NULL: %p, %p\n",(void*)t1,(void*)t2); return 1; /* not */ } /* if empty, return 0 */ if( t1->length <= 0 && t2->length <= 0 ) return 0; if( t1->length != t2->length ) { if(lverb>2)printf("-- labeltable lengths diff: %d vs. %d\n", t1->length, t2->length); return 1; /* cannot compare without equal lengths */ } /* exactly 1 RGBA list is a difference */ if( (t1->rgba && !t2->rgba) || (!t1->rgba && t2->rgba) ) { if(lverb>2)printf("-- only 1 labeltable has RGBA list\n"); if(lverb<3) return 1; } /* so lengths are positive and equal, compare index list and labels */ /* set limit to 0.0 to compare indicies exactly */ offset = (int)gifti_approx_diff_offset(t1->key, t2->key, t1->length, NIFTI_TYPE_INT32, approx?1.0:0.0); if( offset >= 0 ) { if(lverb>2)printf("-- labeltable Key diff at index %d\n", offset); if(lverb<3) return 1; diffs++; } /* walk through list to compare labels */ roff = 0; for( c = 0; c < t1->length; c++ ) { if( gifti_strdiff(t1->label[c], t2->label[c]) ) { if(lverb>2)printf("-- labeltable Label diff at index %d\n", c); if(lverb<3) return 1; diffs++; break; /* stop at first difference */ } } if( t1->rgba && t2->rgba ) { /* if not approx, set limit to 0.0 to compare exactly */ offset = (int)gifti_approx_diff_offset(t1->rgba, t2->rgba, 4*t1->length, NIFTI_TYPE_FLOAT32, approx?1.0:0.0); if( offset >= 0 ) { offset /= 4; /* convert from float index to RGBA index */ if(lverb>2)printf("-- labeltable RGBA diff at index %d\n", offset); if(lverb<3) return 1; diffs++; } } return diffs; } /*---------------------------------------------------------------------*/ /*! like strcmp, but also return: * 0: if both pointers are NULL * 1: if exactly one is NULL *//*-------------------------------------------------------------------*/ int gifti_strdiff(const char * s1, const char * s2) { if( !s1 || !s2 ) { if( s1 || s2 ) return 1; /* one NULL means different */ else return 0; /* both NULL mean equal */ } return strcmp(s1,s2); /* fall through to normal case */ } /*---------------------------------------------------------------------*/ /*! check pointers, compare names and xforms * * only state diffs in the verb=3 case *//*-------------------------------------------------------------------*/ int gifti_compare_coordsys(const giiCoordSystem *s1, const giiCoordSystem *s2, int comp_data, int verb) { long long offset; int lverb = verb; /* possibly override passed verb */ int diffs = 0; if( G.verb > lverb ) lverb = G.verb; if( !s1 || !s2 ) { if(!s1 && !s2) return 0; /* equal */ if(lverb>2) printf("-- Comp CoordSys: have NULL: %p, %p\n",(void*)s1,(void*)s2); return 1; } if( !s1->dataspace || !s2->dataspace ) { if( s1->dataspace || s2->dataspace ) { if(lverb>2)printf("-- coordsys dspace diff: exactly one is NULL\n"); if(lverb<3) return 1; diffs++; } } else if( strcmp(s1->dataspace, s2->dataspace) ) { if(lverb>2) printf("-- coordsys dspace diff: %s vs. %s\n", s1->dataspace, s2->dataspace); if( lverb < 3 ) return 1; diffs++; } if( !s1->xformspace || !s2->xformspace ) { if( s1->xformspace || s2->xformspace ) { if(lverb>2) printf("-- coordsys xformspace diff: exactly one is NULL\n"); if(lverb<3) return 1; diffs++; } } else if( strcmp(s1->xformspace, s2->xformspace) ) { if(lverb>2) printf("-- coordsys xformspace diff: %s vs. %s\n", s1->xformspace, s2->xformspace); if( lverb < 3 ) return 1; diffs++; } if( ! comp_data ) return diffs; /* maybe we are done */ offset = gifti_compare_raw_data(s1->xform, s2->xform, sizeof(s1->xform)); if( offset >= 0 ) { /* convert to index (to avoid printf warning) 2 Mar 2010 */ offset /= (long long)sizeof(double); if(lverb>2) printf("-- coordsys xform diff at offset %lld\n", offset); if( lverb < 3 ) return 1; diffs++; } return diffs; } /*---------------------------------------------------------------------*/ /*! compare raw data, returing the first location difference * * return byte position of difference, so that < 0 means no difference *//*-------------------------------------------------------------------*/ long long gifti_compare_raw_data(const void * p1, const void * p2, long long length) { long long posn; char * d1 = (char *)p1, * d2 = (char *)p2; if( !p1 || !p2 ) { if( !p1 && !p2 ) return -1; /* both NULL -> same */ if( G.verb > 3 ) fprintf(stderr,"-- raw_data pointer diff\n"); return 0; /* set difference */ } /* scan data until done or a difference is found */ for( d1 = (char *)p1, d2 = (char *)p2, posn = 0; posn < length && *d1 == *d2; posn++, d1++, d2++ ) ; if( posn < length ) return posn; /* differ at posn */ return -1; /* equal */ } /* make a local definition for this symmetric fractional difference */ #undef GIFTI_SFD #define GIFTI_SFD(a,b) (fabs((a)-(double)(b))/(fabs(a)+fabs(b))) /*---------------------------------------------------------------------*/ /*! approximate comparison of raw data, returing the first location difference * (>= 0 means difference, -1 means "approximately equal") * * Compute a symmetric fractional difference: * * SFD = abs(a-b)/(abs(a)+abs(b)) * * length - number of contiguous elements to test * ni_type - NIFTI_TYPE_*, denoting the type of data to compare * limit - maximum SFD to be considered approximately equal * * * if limit = 0.0, check is faster * * * if limit >= 1.0, apply a default requiring almost all * significant bits * * * for integers, all bits are considered significant * * for real numbers, mantissa bits are considered significant * * return offset index, so that < 0 (-1) means no difference * * (return -1 if the pointers differ in whether they are set) *//*-------------------------------------------------------------------*/ long long gifti_approx_diff_offset(const void * p1, const void * p2, long long length, int ni_type, double limit) { long long posn; double llim = limit; /* local limit (passed limit or default) */ if( !p1 || !p2 ) { if( !p1 && !p2 ) return -1; /* same */ return 0; /* different */ } switch( ni_type ) { default: fprintf(stderr,"** cannot test approx data with type %d (%s)\n", ni_type, nifti_datatype_to_string(ni_type)); return 0; case NIFTI_TYPE_INT8: { char * d1 = (char *)p1, * d2 = (char *)p2; if( llim >= 1.0 ) llim = 0.0; /* require equality for ints */ for( posn = 0; posn < length; posn++, d1++, d2++ ) { if( *d1 == *d2 ) continue; /* fast check for equality */ if( llim == 0.0 ) break; /* fast check for inequality */ if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */ } break; } case NIFTI_TYPE_INT16: { short * d1 = (short *)p1, * d2 = (short *)p2; if( llim >= 1.0 ) llim = 0.0; /* require equality for ints */ for( posn = 0; posn < length; posn++, d1++, d2++ ) { if( *d1 == *d2 ) continue; /* fast check for equality */ if( llim == 0.0 ) break; /* fast check for inequality */ if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */ } break; } case NIFTI_TYPE_INT32: { int * d1 = (int *)p1, * d2 = (int *)p2; if( llim >= 1.0 ) llim = 0.0; /* require equality for ints */ for( posn = 0; posn < length; posn++, d1++, d2++ ) { if( *d1 == *d2 ) continue; /* fast check for equality */ if( llim == 0.0 ) break; /* fast check for inequality */ if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */ } break; } case NIFTI_TYPE_INT64: { long long * d1 = (long long *)p1, * d2 = (long long *)p2; if( llim >= 1.0 ) llim = 0.0; /* require equality for ints */ for( posn = 0; posn < length; posn++, d1++, d2++ ) { if( *d1 == *d2 ) continue; /* fast check for equality */ if( llim == 0.0 ) break; /* fast check for inequality */ if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */ } break; } case NIFTI_TYPE_UINT8: { unsigned char *d1 = (unsigned char *)p1, *d2 = (unsigned char *)p2; if( llim >= 1.0 ) llim = 0.0; /* require equality for ints */ for( posn = 0; posn < length; posn++, d1++, d2++ ) { if( *d1 == *d2 ) continue; /* fast check for equality */ if( llim == 0.0 ) break; /* fast check for inequality */ if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */ } break; } case NIFTI_TYPE_UINT16: { unsigned short *d1=(unsigned short *)p1, *d2=(unsigned short *)p2; if( llim >= 1.0 ) llim = 0.0; /* require equality for ints */ for( posn = 0; posn < length; posn++, d1++, d2++ ) { if( *d1 == *d2 ) continue; /* fast check for equality */ if( llim == 0.0 ) break; /* fast check for inequality */ if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */ } break; } case NIFTI_TYPE_UINT32: { unsigned int * d1 = (unsigned int *)p1, * d2 = (unsigned int *)p2; if( llim >= 1.0 ) llim = 0.0; /* require equality for ints */ for( posn = 0; posn < length; posn++, d1++, d2++ ) { if( *d1 == *d2 ) continue; /* fast check for equality */ if( llim == 0.0 ) break; /* fast check for inequality */ if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */ } break; } case NIFTI_TYPE_UINT64: { unsigned long long * d1 = (unsigned long long *)p1; unsigned long long * d2 = (unsigned long long *)p2; if( llim >= 1.0 ) llim = 0.0; /* require equality for ints */ for( posn = 0; posn < length; posn++, d1++, d2++ ) { if( *d1 == *d2 ) continue; /* fast check for equality */ if( llim == 0.0 ) break; /* fast check for inequality */ if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */ } break; } case NIFTI_TYPE_FLOAT32: { float * d1 = (float *)p1, * d2 = (float *)p2; if( llim >= 1.0 ) llim = 1e-5; for( posn = 0; posn < length; posn++, d1++, d2++ ) { if( *d1 == *d2 ) continue; /* fast check for equality */ if( llim == 0.0 ) break; /* fast check for inequality */ if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */ } break; } case NIFTI_TYPE_FLOAT64: { double * d1 = (double *)p1, * d2 = (double *)p2; if( llim >= 1.0 ) llim = 1e-12; for( posn = 0; posn < length; posn++, d1++, d2++ ) { if( *d1 == *d2 ) continue; /* fast check for equality */ if( llim == 0.0 ) break; /* fast check for inequality */ if( GIFTI_SFD(*d1,*d2) > llim ) break; /* not approximate */ } break; } } if( posn < length ) return posn; /* differ at 1-based posn */ return -1; /* approximately equal */ } /*---------------------------------------------------------------------*/ /*! compare triangles - return triangle index of first difference * - so -1 means no difference * * require the type to be 1, 2 or 4-byte integers * could cheat and compare as unsigned... * * require consistent wrapping, but allow for varying first vertex *//*-------------------------------------------------------------------*/ int gifti_triangle_diff_offset(const void *p1, const void *p2, int ntri, int ni_type) { int posn = -1; /* if either pointer is not set, we're out of here */ if( !p1 || !p2 ) { if( !p1 && !p2 ) return -1; /* same */ return 0; /* different */ } if( ntri <= 0 ) return -1; switch( ni_type ) { case NIFTI_TYPE_INT8: { char * d1 = (char *)p1, * d2 = (char *)p2; for( posn = 0; posn < ntri; posn++, d1+=3, d2+=3 ) { if( *d1 == *d2 ) { /* same first index */ if( d1[1] != d2[1] || d1[2] != d2[2] ) break; } else if ( d1[0] == d2[1] ) { /* index off by 1 */ if( d1[1] != d2[2] || d1[2] != d2[0] ) break; } else if ( d1[0] == d2[2] ) { /* index off by 2 */ if( d1[1] != d2[0] || d1[2] != d2[1] ) break; } } break; } case NIFTI_TYPE_INT16: { short * d1 = (short *)p1, * d2 = (short *)p2; for( posn = 0; posn < ntri; posn++, d1+=3, d2+=3 ) { if( *d1 == *d2 ) { /* same first index */ if( d1[1] != d2[1] || d1[2] != d2[2] ) break; } else if ( d1[0] == d2[1] ) { /* index off by 1 */ if( d1[1] != d2[2] || d1[2] != d2[0] ) break; } else if ( d1[0] == d2[2] ) { /* index off by 2 */ if( d1[1] != d2[0] || d1[2] != d2[1] ) break; } } break; } case NIFTI_TYPE_INT32: { int * d1 = (int *)p1, * d2 = (int *)p2; for( posn = 0; posn < ntri; posn++, d1+=3, d2+=3 ) { if( *d1 == *d2 ) { /* same first index */ if( d1[1] != d2[1] || d1[2] != d2[2] ) break; } else if ( d1[0] == d2[1] ) { /* index off by 1 */ if( d1[1] != d2[2] || d1[2] != d2[0] ) break; } else if ( d1[0] == d2[2] ) { /* index off by 2 */ if( d1[1] != d2[0] || d1[2] != d2[1] ) break; } } break; } case NIFTI_TYPE_UINT8: { unsigned char *d1 = (unsigned char *)p1, *d2 = (unsigned char *)p2; for( posn = 0; posn < ntri; posn++, d1+=3, d2+=3 ) { if( *d1 == *d2 ) { /* same first index */ if( d1[1] != d2[1] || d1[2] != d2[2] ) break; } else if ( d1[0] == d2[1] ) { /* index off by 1 */ if( d1[1] != d2[2] || d1[2] != d2[0] ) break; } else if ( d1[0] == d2[2] ) { /* index off by 2 */ if( d1[1] != d2[0] || d1[2] != d2[1] ) break; } } break; } case NIFTI_TYPE_UINT16: { unsigned short *d1=(unsigned short *)p1, *d2=(unsigned short *)p2; for( posn = 0; posn < ntri; posn++, d1+=3, d2+=3 ) { if( *d1 == *d2 ) { /* same first index */ if( d1[1] != d2[1] || d1[2] != d2[2] ) break; } else if ( d1[0] == d2[1] ) { /* index off by 1 */ if( d1[1] != d2[2] || d1[2] != d2[0] ) break; } else if ( d1[0] == d2[2] ) { /* index off by 2 */ if( d1[1] != d2[0] || d1[2] != d2[1] ) break; } } break; } case NIFTI_TYPE_UINT32: { unsigned int * d1 = (unsigned int *)p1, * d2 = (unsigned int *)p2; for( posn = 0; posn < ntri; posn++, d1+=3, d2+=3 ) { if( *d1 == *d2 ) { /* same first index */ if( d1[1] != d2[1] || d1[2] != d2[2] ) break; } else if ( d1[0] == d2[1] ) { /* index off by 1 */ if( d1[1] != d2[2] || d1[2] != d2[0] ) break; } else if ( d1[0] == d2[2] ) { /* index off by 2 */ if( d1[1] != d2[0] || d1[2] != d2[1] ) break; } } break; } default: { fprintf(stderr,"** gifti_tri_diff: invalid type %d\n", ni_type); return 1; } } if( posn < ntri ) return posn; /* difference offset */ return -1; /* no difference */ } /*-----------------------------------------------------------------*/ /*! print raw data (nvals of type 'type') to the given file stream * * possibly write a trailing newline *//*-------------------------------------------------------------------*/ int gifti_disp_raw_data(const void * data, int type, int nvals, int newline, FILE * stream) { FILE * fp = stream ? stream : stdout; char * dp, fbuf[64]; int c, size; gifti_datatype_sizes(type, &size, NULL); /* get nbyper */ if( size == 0 ) { fprintf(stderr,"** GDRD: cannot print with size 0, type %d\n", type); return 1; } for( c = 0, dp = (char *)data; c < nvals; c++, dp += size ) { switch( type ) { case NIFTI_TYPE_INT8: fprintf(fp, "%d", *(char *)dp); break; case NIFTI_TYPE_INT16: fprintf(fp, "%d", *(short *)dp); break; case NIFTI_TYPE_INT32: fprintf(fp, "%d", *(int *)dp); break; case NIFTI_TYPE_INT64: fprintf(fp, "%lld", *(long long *)dp); break; case NIFTI_TYPE_UINT8: fprintf(fp, "%u", *(unsigned char *)dp); break; case NIFTI_TYPE_UINT16: fprintf(fp, "%u", *(unsigned short *)dp); break; case NIFTI_TYPE_UINT32: fprintf(fp, "%u", *(unsigned int *)dp); break; case NIFTI_TYPE_UINT64: fprintf(fp, "%llu", *(unsigned long long *)dp); break; case NIFTI_TYPE_FLOAT32: sprintf(fbuf,"%f", *(float *)dp); gifti_clear_float_zeros(fbuf); fprintf(fp, "%s", fbuf); break; case NIFTI_TYPE_FLOAT64: sprintf(fbuf,"%f", *(double *)dp); gifti_clear_float_zeros(fbuf); fprintf(fp, "%s", fbuf); break; default: fprintf(stderr,"** Gdisp_raw_data: invalid type %d\n", type); return 1; } if( c < nvals - 1 ) fputc(' ', fp); } if ( newline ) fputc('\n', fp); return 0; } /*---------------------------------------------------------------------- *! remove trailing zeros from string of printed float * return 1 if something was cleared * 0 if not *//*-------------------------------------------------------------------*/ int gifti_clear_float_zeros( char * str ) { char * dp, * valp; int len; if( !str || !*str ) return 0; /* that was easy */ dp = strchr(str, '.'); /* find '.' */ if( !dp ) return 0; /* no '.', easy too */ len = strlen(dp); /* never clear what is just to the right of '.' */ for( valp = dp+len-1; (valp > dp+1) && (*valp==' ' || *valp=='0'); valp-- ) *valp = '\0'; /* clear, so we don't worry about break conditions */ if( valp < dp + len - 1 ) return 1; return 0; } /*---------------------------------------------------------------------- *! set all DataArray attributes of the given name to the given value *//*-------------------------------------------------------------------*/ int gifti_set_atr_in_DAs(gifti_image *gim, const char *name, const char *value, const int * dalist, int len) { int c, ind; if( !gim || !name || !value ) { fprintf(stderr,"** set_DA_atrs: bad params (%p,%p,%p)\n", (void *)gim, (void *)name, (void *)value); return 1; } if( !gim->darray ) return 0; /* just leave */ if( dalist && len > 0 ) { /* set atrs for those DA in dalist */ if( ! gifti_valid_int_list(dalist, len, 0, gim->numDA-1, 1) ) return 1; /* good to go */ for( c = 0; c < len; c++ ) { ind = dalist[c]; /* for clarity */ if( ! gim->darray[ind] ) continue; /* trioanoid */ if( gifti_str2attr_darray(gim->darray[ind], name, value) ) { if( G.verb > 1 ) fprintf(stderr,"** bad DA attr '%s'='%s'\n",name,value); return 1; } } if( G.verb > 2 ) fprintf(stderr,"++ set atrs in %d DAs, '%s'='%s'\n",len,name,value); return 0; } /* else continue, do all of them */ for( c = 0; c < gim->numDA; c++ ) { if( ! gim->darray[c] ) continue; /* trioanoid */ if( gifti_str2attr_darray(gim->darray[c], name, value) ) { if(G.verb>1)fprintf(stderr,"** bad DA attr '%s'='%s'\n",name,value); return 1; } } if( G.verb > 4 ) fprintf(stderr,"++ set attr in all DAs, '%s'='%s'\n", name, value); return 0; } /*---------------------------------------------------------------------- *! set MetaData name/value pairs in all DAs in list (or all in gim) *//*-------------------------------------------------------------------*/ int gifti_set_DA_meta( gifti_image *gim, const char *name, const char *value, const int * dalist, int len, int replace ) { int c, ind; if( !gim || !name || !value ) { fprintf(stderr,"** set_DA_meta: bad params (%p,%p,%p)\n", (void *)gim, (void *)name, (void *)value); return 1; } if( !gim->darray ) return 0; /* just leave */ if( dalist && len > 0 ) { /* set meta for those DA in dalist */ if( ! gifti_valid_int_list(dalist, len, 0, gim->numDA-1, 1) ) return 1; /* good to go */ for( c = 0; c < len; c++ ) { ind = dalist[c]; /* for clarity */ if( ! gim->darray[ind] ) continue; /* trioanoid */ if( gifti_add_to_meta(&gim->darray[ind]->meta,name,value,replace) ) return 1; } if( G.verb > 2 ) fprintf(stderr,"++ set meta in %d DAs, '%s'='%s'\n",len,name,value); return 0; } /* else continue, do all of them */ for( c = 0; c < gim->numDA; c++ ) { if( ! gim->darray[c] ) continue; /* trioanoid */ if( gifti_add_to_meta(&gim->darray[c]->meta,name,value,replace) ) return 1; } if( G.verb > 4 ) fprintf(stderr,"++ set MetaData in all DAs, '%s'='%s'\n", name, value); return 0; } /*---------------------------------------------------------------------- *! allocate and return a newly created gifti_image_struct * * if numDA > 0, allocate and initialize gim->darray * if intent is a valid NIFTI_INTENT code, set it in all DataArray elements * if dtype is a valid NIFTI_TYPE, set it in all DA elements * if dims is set (MUST be of length 6), set the dims in all DA elements * if alloc_data, allocate zero-filled data in each DA element * * note that if numDA <= 0, the function returns an empty gifti_image *//*-------------------------------------------------------------------*/ gifti_image * gifti_create_image( int numDA, int intent, int dtype, int ndim, const int * dims, int alloc_data ) { gifti_image * gim; int c, errs = 0; if( G.verb > 1 ) { /* maybe start with some chit-chat */ fprintf(stderr,"++ creating gifti_image with %d DA elements\n", numDA); if( G.verb > 2 ) { fprintf(stderr," intent[%d] = %s, dtype[%d] = %s,\n" " alloc_data = %d, ndim = %d, dims: ", intent, gifti_intent_to_string(intent), dtype, gifti_datatype2str(dtype), alloc_data, ndim); if( !dims ) fprintf(stderr,"\n"); else gifti_disp_raw_data(dims, DT_INT32, GIFTI_DARRAY_DIM_LEN, 1, stderr); } } /* basic step - create empty image (with a version string) */ gim = (gifti_image *)calloc(1, sizeof(gifti_image)); if(!gim){ fprintf(stderr,"** failed to alloc gifti_image\n"); return NULL; } gifti_clear_gifti_image(gim); gim->version = gifti_strdup(GIFTI_XML_VERSION); if( numDA <= 0 ) return gim; /* done */ /* apply numDA, which is incremented in add_empty_darray() */ gim->numDA = 0; if( gifti_add_empty_darray(gim, numDA) ) { /* then cannot continue */ gifti_free_image(gim); return NULL; } /* init all to defaults */ for( c = 0; c < gim->numDA; c++ ) errs += gifti_set_DA_defaults(gim->darray[c]); /* and fill in any other pieces */ if( gifti_intent_is_valid(intent) ) errs += gifti_set_atr_in_DAs(gim,"Intent", gifti_intent_to_string(intent), NULL, 0); if( gifti_valid_datatype(dtype, 1) ) { errs += gifti_set_atr_in_DAs(gim,"DataType", gifti_datatype2str(dtype), NULL, 0); errs += gifti_update_nbyper(gim); } if( dims && ndim >= 0 ) errs += gifti_set_dims_all_DA(gim, ndim, dims); /* don't try this if there are errors */ if( !errs && alloc_data ) errs += gifti_alloc_DA_data(gim, NULL, 0); if( errs ) { /* then fail out */ gifti_free_image(gim); return NULL; } return gim; } /*---------------------------------------------------------------------- *! allocate nvals*nbyper bytes of (zero-filled) data in each DataArray * (in dalist or simply in gim) * * return 0 on success * 1 on error *//*-------------------------------------------------------------------*/ int gifti_alloc_DA_data(gifti_image * gim, const int * dalist, int len) { giiDataArray * da; long long nbytes, ntot = 0; int c, index, nset = 0, use_list, numDA; if( !gim || !gim->darray || gim->numDA <= 0 ) return 0; /* decide whether to use dalist or allocate all data */ use_list = gifti_valid_int_list(dalist, len, 0, gim->numDA-1, 0); if( use_list && G.verb > 2 ) fprintf(stderr,"++ allocating data for %s\n", use_list ? "DA in list" : "all DAs"); if( use_list && DA_data_exists(gim, dalist, len) ) { fprintf(stderr,"** data already exists for some DAs in list\n"); return 1; } numDA = use_list ? len : gim->numDA; for( c = 0; c < numDA; c++ ) { index = use_list ? dalist[c] : c; /* choose appropriate DA index */ da = gim->darray[index]; /* set convenient pointer */ if( ! da ) continue; /* if dimensions do not make sense, fail out */ if( ! gifti_valid_dims(da, G.verb > 0) ) return 1; if( da->nvals < 0 || da->nbyper < 0 ) { fprintf(stderr,"** bad nvals, nbyper in DA[%d]\n",index); return 1; } nbytes = da->nvals * da->nbyper; if( nbytes <= 0 ) continue; /* skip empty data */ ntot += nbytes; /* compute total bytes */ nset++; da->data = calloc(nbytes, sizeof(char)); if( !da->data ) { fprintf(stderr,"** gifti_alloc_DA_data: failed on DA %d of %d\n" " %lld bytes (%lld total)\n", index, numDA, nbytes, ntot); return 1; } } if( G.verb > 3) fprintf(stderr,"++ alloc'd %lld bytes in %d DA elements\n", ntot, nset); return 0; } /*---------------------------------------------------------------------- *! set num_dims, dims and nvals in every DataArray element * * return 0 on success * 1 on error *//*-------------------------------------------------------------------*/ int gifti_set_dims_all_DA(gifti_image * gim, int ndim, const int * dims) { long long nvals; int c, d, nset = 0; if(!gim || ndim < 0 || ndim > GIFTI_DARRAY_DIM_LEN || !dims) { fprintf(stderr,"** SDA_DA: bad params (%p, %d, %p)\n", (void *)gim, ndim, (void *)dims); return 1; } if( !gim->darray || gim->numDA == 0 ) return 0; /* first compute nvals */ for( d = 0, nvals = 1; d < ndim; d++) nvals *= dims[d]; if( nvals <= 0 ) { fprintf(stderr,"** GSDA_DA: malformed dims[%d]: ", ndim); gifti_disp_raw_data(dims, DT_INT32, GIFTI_DARRAY_DIM_LEN, 1, stderr); return 1; } if( ndim == 0 ) nvals = 0; /* insert num_dim and fill dims (pad with 0s) */ for( c = 0; c < gim->numDA; c++ ) { if( !gim->darray[c] ) continue; /* paranoid */ gim->darray[c]->num_dim = ndim; for( d = 0; d < ndim; d++ ) gim->darray[c]->dims[d] = dims[d]; for( /* continue */ ; d < GIFTI_DARRAY_DIM_LEN; d++ ) gim->darray[c]->dims[d] = 0; gim->darray[c]->nvals = nvals; nset++; } if(G.verb > 3) { fprintf(stderr,"++ set dims in %d of %d DA elements to: ", nset, gim->numDA); gifti_disp_raw_data(dims, DT_INT32, GIFTI_DARRAY_DIM_LEN, 1, stderr); } return 0; } /*---------------------------------------------------------------------- *! update nbyper/swapsize for all DataArray elements * * return 0 on success * 1 on error *//*-------------------------------------------------------------------*/ int gifti_update_nbyper(gifti_image * gim) { giiDataArray * da; int c, errs = 0; if( !gim ) return 1; if( !gim->darray || gim->numDA == 0 ) return 0; for( c = 0; c < gim->numDA; c++ ){ da = gim->darray[c]; /* just to look cleaner */ if( !da ) continue; errs += gifti_datatype_sizes(da->datatype, &da->nbyper, NULL); } return errs; } /*---------------------------------------------------------------------- *! fill DataArray element with default values * * return 0 on success * 1 on error *//*-------------------------------------------------------------------*/ int gifti_set_DA_defaults(giiDataArray * da) { int c; if(!da) { fprintf(stderr,"** NULL in set_DA_defaults\n"); return 1; } if( G.verb > 6 ) fprintf(stderr,"-- setting DA defaults\n"); gifti_clear_DataArray(da); /* start with empty struct */ /* and fill with any non-NULL, non-zero values */ da->intent = NIFTI_INTENT_NONE; da->datatype = NIFTI_TYPE_FLOAT32; da->ind_ord = GIFTI_IND_ORD_ROW_MAJOR; da->num_dim = 1; /* one value per node */ for( c = 0; c < GIFTI_DARRAY_DIM_LEN; c++ ) da->dims[c] = 0; da->encoding = GIFTI_ENCODING_B64BIN; /* zlib may not be available */ da->endian = gifti_get_this_endian(); da->ext_offset = 0; da->nvals = 0; da->nbyper = 0; gifti_datatype_sizes(da->datatype, &da->nbyper, NULL); return 0; } /*---------------------------------------------------------------------- *! clear the DataArray element *//*-------------------------------------------------------------------*/ int gifti_clear_DataArray(giiDataArray * da) { if(!da) { fprintf(stderr,"** NULL in clear_DataArray\n"); return 1; } if( G.verb > 5 ) fprintf(stderr,"-- clearing DataArray\n"); memset(da, 0, sizeof(giiDataArray)); da->ext_fname = NULL; gifti_clear_nvpairs(&da->meta); da->coordsys = NULL; da->data = NULL; gifti_clear_nvpairs(&da->ex_atrs); return 0; } /*---------------------------------------------------------------------- *! simply clear all contents of the passed gifti_image * (being explicit with pointers) * * return 0 on success * 1 on error *//*-------------------------------------------------------------------*/ int gifti_clear_gifti_image(gifti_image * gim) { if(!gim) { fprintf(stderr,"** NULL in clear_gifti_image\n"); return 1; } if( G.verb > 5 ) fprintf(stderr,"-- clearing gifti_image\n"); /* set the version and clear all pointers */ memset(gim, 0, sizeof(gim)); gim->version = NULL; gifti_clear_nvpairs(&gim->meta); gifti_clear_LabelTable(&gim->labeltable); gim->darray = NULL; gifti_clear_nvpairs(&gim->ex_atrs); return 0; } /*---------------------------------------------------------------------- *! read a dataset, just for numDA * * may write faster gxml function for this, if it seems important *//*-------------------------------------------------------------------*/ int gifti_read_dset_numDA(const char * fname) { gifti_image * gim; int numDA; if( !fname ) { fprintf(stderr,"** NULL to gifti_read_dset_numDA\n"); return -1; } if( G.verb > 2 ) fprintf(stderr,"++ read dset numDA, file '%s'\n",fname); gim = gifti_read_da_list(fname, 0, NULL, 0); if( !gim ) return -1; /* errors already printed */ numDA = gim->numDA; if(G.verb > 1) fprintf(stderr,"++ read dset numDA, file '%s', numDA = %d\n", fname, numDA); gifti_free_image(gim); /* lose dataset and return */ return numDA; } /*---------------------------------------------------------------------- *! return whether the list values are from min to max *//*-------------------------------------------------------------------*/ int gifti_valid_int_list(const int *list, int len, int min, int max, int whine) { int c; if( !list || len <= 0 ) return 0; for( c = 0; c < len; c++ ) if( list[c] < min || list[c] > max ) { if( whine ) fprintf(stderr,"** bad list index [%d] = %d, not in [%d,%d]\n", c, list[c], min, max); return 0; } return 1; } /* return whether any DAs in list have data */ static int DA_data_exists(gifti_image * gim, const int * dalist, int len) { int length, uselist = 0; int c, ind; if( !dalist || len <= 0 ) { /* then scan all DA elements */ length = gim->numDA; if( length <= 0 ) return 0; } else if( !gifti_valid_int_list(dalist, len, 0, gim->numDA-1, 1) ) { return 0; } else { uselist = 1; length = len; } for( c = 0; c < length; c++ ) { ind = uselist ? dalist[c] : c; if( gim->darray[ind] && gim->darray[ind]->data ) return 1; } return 0; } /*---------------------------------------------------------------------- *! add the name=value pair to the MetaData lists * * if the name already exists, fail, unless 'replace' is set * * return 0 on success, 1 on error *//*-------------------------------------------------------------------*/ int gifti_add_to_meta( giiMetaData * md, const char * name, const char * value, int replace ) { int c; if( !md || !name || !value ) return 1; if( G.verb > 5 ) fprintf(stderr,"++ GA2M: name '%s', value '%s', replace = %d\n", name, value, replace); /* see if 'name' is already here */ for( c = 0; c < md->length; c++ ) { if( !md->name[c] && G.verb > 2 ) { fprintf(stderr,"** G MD[%d]: no name to check for replacement\n",c); continue; } if( !strcmp(md->name[c], name) ) { /* a match, apply and return */ if( !md->value[c] && G.verb > 2 ) { fprintf(stderr,"** G MD[%d]: no value to replace\n",c); md->value[c] = gifti_strdup(value); return 0; } if( replace ) { if( G.verb > 5 ) fprintf(stderr," (add via REPLACE)\n"); if( md->value[c] ) free(md->value[c]); md->value[c] = gifti_strdup(value); return 0; } else { fprintf(stderr,"** G_add_to_meta: name '%s', already exists\n", name); return 1; } } } /* name is new, so just add it */ if( G.verb > 5 ) fprintf(stderr," (adding new entry)\n"); md->length++; md->name = (char **)realloc(md->name, md->length * sizeof(char *)); md->value = (char **)realloc(md->value, md->length * sizeof(char *)); if( !md->name || !md->value ) { fprintf(stderr,"** GA2M:failed to realloc %d MD pointers\n",md->length); md->length = 0; return 1; } md->name[md->length-1] = gifti_strdup(name); md->value[md->length-1] = gifti_strdup(value); if( ! md->name[md->length-1] || ! md->value[md->length-1] ) return 1; return 0; } /*---------------------------------------------------------------------- *! check for validity of the gifti_image (including sub-structures) * * if whine is set, complain about any errors * * return 1 if valid, 0 otherwise *//*-------------------------------------------------------------------*/ int gifti_valid_gifti_image( gifti_image * gim, int whine ) { int c, errs = 0; if( !gim ) { if(whine) fprintf(stderr,"** invalid: gifti_image ptr is NULL\n"); return 0; } if( G.verb > 3 ) fprintf(stderr,"-- checking for valid gifti_image...\n"); if( gim->numDA < 0 ) { if(whine) fprintf(stderr,"** invalid: numDA = %d\n", gim->numDA); errs ++; } if( !gim->version || strcmp(gim->version, GIFTI_XML_VERSION) ) { if(whine) fprintf(stderr, "** invalid: gim version = %s\n", G_CHECK_NULL_STR(gim->version)); errs++; } if( ! gifti_valid_nvpairs(&gim->meta, whine) ) errs ++; if( ! gifti_valid_LabelTable(&gim->labeltable, whine) ) errs ++; for( c = 0; c < gim->numDA; c++ ) { if( G.verb > 5 ) fprintf(stderr,"-- checking DA[%d]\n", c); if( ! gifti_valid_DataArray(gim->darray[c], whine) ) { if( G.verb > 3 ) fprintf(stderr,"-- DA[%d] has errors\n",c); errs++; } else if( G.verb > 4 ) fprintf(stderr,"-- DA[%d] is VALID\n",c); } /* no check on swapped or compressed */ if( ! gifti_valid_nvpairs(&gim->ex_atrs, whine) ) errs ++; if( G.verb > 2 ) { fprintf(stderr,"-- gifti_image: errors = %d", errs); if( errs ) fprintf(stderr," (INVALID)\n"); else fprintf(stderr," (VALID)\n"); } if( errs ) return 0; else return 1; } /*---------------------------------------------------------------------*/ /*! return whether data exists * * - darray, each darray[i] and darray[i]->data must be set * * return 1 if true, 0 otherwise *//*-------------------------------------------------------------------*/ int gifti_image_has_data(const gifti_image * gim) { int c; if( !gim || !gim->darray || gim->numDA <= 0 ) return 0; for( c = 0; c < gim->numDA; c++ ) if( !gim->darray[c] ) { if(G.verb > 3) fprintf(stderr,"** gim missing data at ind %d\n",c); return 0; } return 1; } /*---------------------------------------------------------------------*/ /*! duplicate the given gifti_image struct, optionally including data * * Allocate and copy all contents of the gifti_image structure and * sub-structures. If copy_data is not set, all data pointers within * DataArray elements will be left as NULL. * * return a pointer to the newly allocated structure *//*-------------------------------------------------------------------*/ gifti_image * gifti_copy_gifti_image(const gifti_image * gold, int copy_data) { gifti_image * gnew; int c, errs = 0; /* check for errors at each step */ if( !gold ){ fprintf(stderr,"** copy_gim: input is NULL\n"); return NULL; } if(G.verb > 3) fprintf(stderr,"++ copying gifti_image (%s data)...\n", copy_data ? "with" : "without" ); gnew = (gifti_image *)calloc(1, sizeof(gifti_image)); if(!gnew){fprintf(stderr,"** copy_gim, failed alloc\n"); return NULL;} /* copy one piece at a time */ gnew->numDA = gold->numDA; gnew->version = gifti_strdup(gold->version); errs = gifti_copy_nvpairs(&gnew->meta, &gold->meta); if(!errs) errs=gifti_copy_LabelTable(&gnew->labeltable, &gold->labeltable); /* if needed, create and copy the DataArray list */ if( !errs && gold->darray && gold->numDA > 0 ) { gnew->darray=(giiDataArray**)malloc(gold->numDA*sizeof(giiDataArray*)); if( !gnew->darray ) { fprintf(stderr,"** copy_gim: failed to alloc darray of len %d\n", gold->numDA); errs = 1; } for( c = 0; !errs && c < gold->numDA; c++ ) { gnew->darray[c] = gifti_copy_DataArray(gold->darray[c], copy_data); if( !gnew->darray[c]) errs++; } } /* and copy the extras */ if( !errs ) { gnew->swapped = gold->swapped; gnew->compressed = gold->compressed; errs = gifti_copy_nvpairs(&gnew->ex_atrs, &gold->ex_atrs); } /* on failure, blow everything away */ if( errs ) { gifti_free_image(gnew); return NULL; } return gnew; } /*---------------------------------------------------------------------*/ /*! convert all data to NIFTI_TYPE_FLOAT32 * * for each DataArray * if data exists, convert it (free old, allocate new) * else, leave as NULL *//*-------------------------------------------------------------------*/ int gifti_convert_to_float(gifti_image * gim) { giiDataArray * da; void * olddata; int oldtype, newtype = NIFTI_TYPE_FLOAT32; /* for future? */ int c, nbyper, oldnbyper; if( !gim ) return 1; if( !gim->darray || gim->numDA <= 0 ) { if( G.verb > 1 ) fprintf(stderr,"-- no darray to convert to float\n"); return 0; } if( G.verb > 1 ) fprintf(stderr,"++ converting gifti_image to float\n"); /* first, check for problems in any DA */ for( c = 0; c < gim->numDA; c++ ) { da = gim->darray[c]; if( !da ) continue; /* if the data has an unknown type, panic into error */ if( da->data && !gifti_valid_datatype(da->datatype, 0) ) { fprintf(stderr,"** unknown dtype %d, cannot convert to floats\n", da->datatype); return 1; } /* dimension information must be consistent */ if( !gifti_valid_dims(da, 1) ) return 1; } /* will update nbyper in each DA, below */ gifti_datatype_sizes(newtype, &nbyper, NULL); /* all is well, update all DA elements */ for( c = 0; c < gim->numDA; c++ ) { da = gim->darray[c]; if( !da ) continue; oldtype = da->datatype; oldnbyper = da->nbyper; if( oldtype == newtype ) { if(G.verb > 3) fprintf(stderr,"++ convert DA[%d] already type %s\n", c, gifti_datatype2str(newtype)); continue; /* no change needed */ } if(G.verb > 3) fprintf(stderr,"++ convert DA[%d] from %s to %s\n", c, gifti_datatype2str(oldtype), gifti_datatype2str(newtype)); if( oldtype == newtype ) continue; /* no change needed */ /* start trashing DataArray: adjust datatype and nbyper */ da->datatype = newtype; da->nbyper = nbyper; /* if there is no data, we are done with this DA */ if( !da->data ) { if( G.verb > 4 ) fprintf(stderr,"-- no data to convert\n"); continue; } /* store old data pointer, and allocate new data space */ olddata = da->data; da->data = NULL; /* so alloc_DA_data doesn't whine */ if( gifti_alloc_DA_data(gim, &c, 1) ) return 1; /* copy the data, and nuke the old stuff */ if( copy_data_as_float(da->data,newtype,olddata,oldtype,da->nvals) ) { /* undo this copy and return */ free(da->data); da->data = olddata; da->datatype = oldtype; da->nbyper = oldnbyper; return 1; } free(olddata); /* done with this, data has been copied */ } return 0; } /* copy old data to float array */ static int copy_data_as_float(void * dest, int dtype, void * src, int stype, long long nvals) { float * dptr = (float *)dest; long long c; if( !dest || !src ) { fprintf(stderr,"** copy_data_as_float: missing pointers\n"); return 1; } if( dtype != NIFTI_TYPE_FLOAT32 ) { fprintf(stderr,"** can't copy to float with dest type %d\n", dtype); return 1; } switch( stype ) { default: { fprintf(stderr,"** copy2float: can't handle src type %d\n",stype); return 1; } case NIFTI_TYPE_INT8: { char * sptr = (char *)src; for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c]; break; } case NIFTI_TYPE_INT16: { short * sptr = (short *)src; for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c]; break; } case NIFTI_TYPE_INT32: { int * sptr = (int *)src; for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c]; break; } case NIFTI_TYPE_INT64: { long long * sptr = (long long *)src; for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c]; break; } case NIFTI_TYPE_UINT8: { unsigned char * sptr = (unsigned char *)src; for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c]; break; } case NIFTI_TYPE_UINT16: { unsigned short * sptr = (unsigned short *)src; for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c]; break; } case NIFTI_TYPE_UINT32: { unsigned int * sptr = (unsigned int *)src; for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c]; break; } case NIFTI_TYPE_UINT64: { unsigned long long * sptr = (unsigned long long *)src; for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c]; break; } case NIFTI_TYPE_FLOAT32: { float * sptr = (float *)src; for( c = 0; c < nvals; c++ ) dptr[c] = sptr[c]; break; } case NIFTI_TYPE_FLOAT64: { double * sptr = (double *)src; for( c = 0; c < nvals; c++ ) dptr[c] = (float)sptr[c]; break; } } return 0; } gifticlib-1.0.9/gifti_tool.h0000644007023700001440000001165711314675645015052 0ustar rickrusers#ifndef GIFTI_TOOL_H #define GIFTI_TOOL_H typedef struct { int len; char ** list; } gt_str_list; typedef struct { int len; int * list; } gt_int_list; typedef struct { /* main action flags */ int gt_compare; /* somehow compare 2 datasets */ int gt_copy; /* copy things between 2 datasets */ int gt_display; /* display something */ int gt_write; /* create output datasets */ int gt_modify; /* sub-action: to modify datasets */ int gt_test; /* sub-action: check for valid datasets */ /* action options */ int new_numDA; /* numDA for new dataset */ int new_intent; /* intent for new dataset */ int new_dtype; /* dtype for new dataset */ int new_ndim; /* num_dims for new dataset */ int new_dims[GIFTI_DARRAY_DIM_LEN]; int new_data; /* allocate data in new dataset */ /* modify options */ int mod_add_data; /* add data to existing dataset */ int mod_gim_atr; /* modify gifti attribute */ int mod_gim_meta; /* modify gifti meta data */ int mod_DA_atr; /* modify DataArray attribute */ int mod_DA_meta; /* modify DataArray meta data */ int mod_to_float; /* convert all input data to FLOAT32 */ /* compare options */ int comp_gifti; /* compare structures */ int comp_data; /* compare data in DataArrays */ int comp_verb; /* set verbose level for compare_gifti */ int approx_gifti; /* approximate comparison of structures */ /* copy options */ int copy_gim_meta;/* copy metadata between GIFTI elements */ int copy_DA_meta; /* copy metadata between DA elements */ /* GIFTI user options */ int verb; /* verbose level */ int indent; /* spaces per indent level */ int buf_size; /* buffer space for expat library */ int b64_check; /* check level */ int update_ok; /* okay for library to update metadata */ int zlevel; /* compression level for output data */ int dstore; /* whether to store read data */ int encoding; /* encoding for output data */ int set_extern; /* set data to be external files */ int show_gifti; /* display the gifti_image */ char * ofile_1D; /* 1D output filename */ char * ofile_asc; /* 'asc' output filename */ char * ofile_gifti; /* GIFTI output filename */ gt_int_list DAlist; /* list of DA indices to operate on */ gt_int_list DAlistr; /* list of DataArray indices to read */ gt_int_list DAmodlist; /* list of DA indices for modification */ gt_str_list gim_atrs; gt_str_list gim_meta; gt_str_list DA_atrs; gt_str_list DA_meta; gt_str_list ext_files; /* external files as data source */ gt_str_list infiles; } gt_opts; #undef CHECK_NEXT_OPT #define CHECK_NEXT_OPT(n,m,str) \ do { if ( (n) >= (m) ) { \ fprintf(stderr,"** option '%s': missing parameter\n",str); \ fprintf(stderr," consider: '-help' option\n"); \ return 1; } \ } while(0) #undef CHECK_NEXT_OPT2 #define CHECK_NEXT_OPT2(n,m,s1,s2) \ do { if ( (n) >= (m) ) { \ fprintf(stderr,"** option '%s': missing parameter '%s'\n",s1,s2);\ fprintf(stderr," consider: '-help' option\n"); \ return 1; } \ } while(0) /* protos */ gifti_image * gt_read_dataset(gt_opts * opts, char * fname); int gt_compare (gt_opts * opts); int gt_copy (gt_opts * opts); int gt_display (gt_opts *); int gt_modify_dset (gt_opts *, gifti_image * gim); int gt_test (gt_opts *); int gt_write (gt_opts *); int gt_write_dataset (gt_opts *, gifti_image * gim); int ewrite_data_line (void *, int, int, int, int, int, FILE *); int ewrite_many_lines(void **, int, long long, long long, int, FILE *); int write_1D_file (giiDataArray **, int, char *, int); int write_as_asc (gifti_image *, char *); int write_surf_file (giiDataArray *, giiDataArray *, char *, int); #endif /* GIFTI_TOOL_H */ gifticlib-1.0.9/gifti_xml.h0000644007023700001440000001362711345213733014662 0ustar rickrusers#ifndef GIFTI_XML_H #define GIFTI_XML_H #define GXML_MAX_DEPTH 10 /* maximum stack depth */ #define GXML_MAX_ELEN 128 /* maximum element length */ #define GIFTI_XML_VERSION "1.0" #define GIFTI_XML_ENCODING "UTF-8" /* use non-changing address 2 Mar 2010 */ #define GIFTI_XML_DTD_SOURCE "http://gifti.projects.nitrc.org/gifti.dtd" /* ---------------------------------------------------------------------- element depths parent(s) children ------- ------ -------------- ----------------------- GIFTI 0 MetaData, LabelTable, DataArray MetaData 1 GIFTI MD 2 DataArray MD 2,+1 MetaData Name, Value Name 3,+1 MD CDATA/char Value 3,+1 MD CDATA/char LabelTable 1 GIFTI Label Label 2 LabelTable CDATA/char DataArray 1 GIFTI MetaData, CSTM, Data CSTM 2 DataArray DataSpace, TransformedSpace, MatrixData Data 2 DataArray DataSpace 3 CSTM CDATA/char TransformedSpace 3 CSTM CDATA/char MatrixData 3 CSTM char CDATA 4,+1 Name, Value char 4 DataSpace char 4 TransformedSpace char char any any whitespace 5 CDATA -- other objects to handle -- XML declaration: version, encoding, standalone DOCTYPE: type=GIFTI, sid=.../gifti.dtd, pid, sub default: ---------------------------------------------------------------------- */ /* this list must match enames, and is ordered via the above comment */ #define GXML_ETYPE_INVALID 0 #define GXML_ETYPE_GIFTI 1 /* GIFTI element */ #define GXML_ETYPE_META 2 /* MetaData element */ #define GXML_ETYPE_MD 3 /* MD element */ #define GXML_ETYPE_NAME 4 /* Name element */ #define GXML_ETYPE_VALUE 5 /* Value element */ #define GXML_ETYPE_LABELTABLE 6 /* LabelTable element */ #define GXML_ETYPE_LABEL 7 /* Label element */ #define GXML_ETYPE_DATAARRAY 8 /* DataArray element */ #define GXML_ETYPE_CSTM 9 /* CSTM element */ #define GXML_ETYPE_DATA 10 /* Data element */ #define GXML_ETYPE_DATASPACE 11 /* DataSpace element */ #define GXML_ETYPE_XFORMSPACE 12 /* TransformedSpace element */ #define GXML_ETYPE_MATRIXDATA 13 /* MatrixData element */ #define GXML_ETYPE_CDATA 14 /* CDATA element */ #define GXML_ETYPE_LAST 14 /* should match last entry */ typedef struct { long long nalloc; /* allocation length */ long long nused; /* number of bytes used */ char * buf; /* buffer */ } gxml_buffer; typedef struct { int verb; /* verbose level */ int dstore; /* flag: store data */ int indent; /* spaces per depth level */ int buf_size; /* for XML buffer */ int b64_check; /* 0=no, 1=check, 2=count, 3=skip */ int update_ok; /* library can update metadata */ int zlevel; /* compression level -1..9 */ int * da_list; /* DA index list to store */ int da_len; /* DA index list length */ int da_ind; /* current DA index list index */ int eleDA; /* number of elements found */ int expDA; /* number of elements expected */ int b64_errors; /* bad chars, per DATA element */ int errors; /* number of errors encountered */ int skip; /* stack depth to skip */ int depth; /* current stack depth */ int stack[GXML_MAX_DEPTH+1]; /* stack of etypes */ long long dind; /* index into data->data/xform */ int clen; /* length of current CDATA */ int xlen; /* length of xform buffer */ int dlen; /* length of Data buffer */ int doff; /* offset into data buffer */ int zlen; /* length of compression buffer */ char ** cdata; /* pointer to current CDATA */ char * xdata; /* xform buffer */ char * ddata; /* I/O buffer xml->ddata->data */ char * zdata; /* zlib compression buffer */ gifti_image * gim; /* pointer to returning image */ } gxml_data; /* protos */ /* main interface */ gifti_image * gxml_read_image (const char * fname, int read_data, const int * dalist, int len); int gxml_write_image(gifti_image * gim, const char * fname, int write_data); int gxml_set_verb ( int val ); int gxml_get_verb ( void ); int gxml_set_dstore ( int val ); int gxml_get_dstore ( void ); int gxml_set_indent ( int val ); int gxml_get_indent ( void ); int gxml_set_buf_size ( int val ); int gxml_get_buf_size ( void ); int gxml_set_b64_check ( int val ); int gxml_get_b64_check ( void ); int gxml_set_update_ok ( int val ); int gxml_get_update_ok ( void ); int gxml_set_zlevel ( int val ); int gxml_get_zlevel ( void ); #endif /* GIFTI_XML_H */ gifticlib-1.0.9/gifti_io.h0000644007023700001440000003465211345213733014472 0ustar rickrusers#ifndef GIFTI_IO_H #define GIFTI_IO_H #include #include #include /* also #include "gifti_xml.h", but at the end */ /* ---------------------------------------------------------------------- */ /* These must be 0-based and sequential. - 0 matches _UNDEF - highest maches _MAX - list matches corresponding gifti_*_list */ #define GIFTI_IND_ORD_UNDEF 0 #define GIFTI_IND_ORD_ROW_MAJOR 1 #define GIFTI_IND_ORD_COL_MAJOR 2 #define GIFTI_IND_ORD_MAX 2 #define GIFTI_DATALOC_UNDEF 0 #define GIFTI_DATALOC_INT 1 #define GIFTI_DATALOC_EXT 2 #define GIFTI_DATALOC_MAX 2 #define GIFTI_ENCODING_UNDEF 0 #define GIFTI_ENCODING_ASCII 1 /* human readable ASCII data */ #define GIFTI_ENCODING_B64BIN 2 /* base64 encoded binary data */ #define GIFTI_ENCODING_B64GZ 3 /* base64 compressed binary */ #define GIFTI_ENCODING_EXTBIN 4 /* external unencoded binary */ #define GIFTI_ENCODING_MAX 4 #define GIFTI_ENDIAN_UNDEF 0 #define GIFTI_ENDIAN_BIG 1 #define GIFTI_ENDIAN_LITTLE 2 #define GIFTI_ENDIAN_MAX 2 #define GIFTI_B64_CHECK_UNDEF 0 #define GIFTI_B64_CHECK_NONE 1 /* no checking */ #define GIFTI_B64_CHECK_DETECT 2 /* simply detect errors */ #define GIFTI_B64_CHECK_COUNT 3 /* count the number of errors */ #define GIFTI_B64_CHECK_SKIP 4 /* skip any bad chars, no count */ #define GIFTI_B64_CHECK_SKIPNCOUNT 5 /* skip and count bad characters */ #define GIFTI_B64_CHECK_MAX 5 #define GIFTI_DARRAY_DIM_LEN 6 /* length of dims[] array */ /* use our own #def, in case we don't have zlib */ #undef GZ_DEFAULT_COMPRESSION #ifdef HAVE_ZLIB #define GZ_DEFAULT_COMPRESSION Z_DEFAULT_COMPRESSION #define GIFTI_COMP_WITH_ZLIB 1 /* to show at run-time */ #else #define GZ_DEFAULT_COMPRESSION -1 #define GIFTI_COMP_WITH_ZLIB 0 #endif /* global declarations of matching lists */ extern char * gifti_index_order_list[]; extern char * gifti_dataloc_list[]; extern char * gifti_encoding_list[] ; extern char * gifti_endian_list[]; /* ---------------------------------------------------------------------- */ /* notes: - all data should be owned by the struct, i.e. strings should be allocated copies, never assigned as a pointer used elsewhere */ typedef struct { int length; char ** name; char ** value; } nvpairs; typedef nvpairs giiMetaData; typedef struct { int length; /* length of each array, if allocated */ int * key; /* changed from index 7 Mar 2010 */ char ** label; float * rgba; /* (optional) RGBA tuples (4*length, in [0,1.0]) */ } giiLabelTable; typedef struct { char * dataspace; char * xformspace; double xform[4][4]; /* ******** no type specified ********** */ } giiCoordSystem; typedef struct { /* attributes */ int intent; /* NIFTI_INTENT code, describing data */ int datatype; /* numerical type of Data values */ int ind_ord; /* lowest Dim to highest, or reverse */ int num_dim; /* level of DimX applied */ int dims[6]; /* dimension lengths (first num_dim set) */ int encoding; /* format of Data on disk */ int endian; /* endian, if binary Encoding */ char * ext_fname; /* external filename, in cur directory */ long long ext_offset; /* offset of data within external file */ /* elements */ giiMetaData meta; giiCoordSystem ** coordsys; /* array of pointers to giiCoordSystem */ void * data; /* unencoded, uncompressed, swapped */ /* extras */ long long nvals; /* number of values (product of Dims) */ int nbyper; /* number of bytes per value */ int numCS; /* number of giiCoordSystem structs */ nvpairs ex_atrs; /* extra attributes */ } giiDataArray; typedef struct { /* attributes */ int numDA; /* number of DataArrays */ char * version; /* GIFTI version string */ /* elements */ giiMetaData meta; giiLabelTable labeltable; giiDataArray ** darray; /* extras */ int swapped; /* were the bytes swapped */ int compressed; /* was the data compressed */ nvpairs ex_atrs; /* extra attributes */ } gifti_image; typedef struct { int verb; } gifti_globals; typedef struct { int type; /* should match NIFTI_TYPE_* */ int nbyper; /* bytes per value */ int swapsize; /* bytes per swap piece */ char * name; /* text string match type */ } gifti_type_ele; /* prototypes */ /* main interface protos */ gifti_image * gifti_read_image (const char * fname, int read_data ); gifti_image * gifti_read_da_list(const char * fname, int read_data, const int * dalist, int len ); int gifti_free_image (gifti_image * gim); int gifti_valid_gifti_image (gifti_image * gim, int whine); int gifti_write_image (gifti_image *gim, const char *fname, int write_data); gifti_image * gifti_create_image(int numDA, int intent, int dtype, int ndim, const int * dims, int alloc_data); /* end main interface protos */ int gifti_get_b64_check (void); int gifti_set_b64_check (int level); int gifti_get_indent (void); int gifti_set_indent (int level); int gifti_get_verb (void); int gifti_set_verb (int level); int gifti_get_update_ok (void); int gifti_set_update_ok (int level); int gifti_get_zlevel (void); int gifti_set_zlevel (int level); /* data copy routines */ int gifti_convert_to_float(gifti_image * gim); char ** gifti_copy_char_list (char ** list, int len); int gifti_copy_all_DA_meta(giiDataArray *dest, giiDataArray *src); int gifti_copy_DA_meta (giiDataArray *dest, giiDataArray *src, const char *name); int gifti_copy_DA_meta_many(gifti_image * dest, gifti_image * src, const char * name, const int * dalist, int len); int gifti_copy_gifti_meta (gifti_image * dest, gifti_image * src, const char * name); int gifti_copy_LabelTable (giiLabelTable * dest, const giiLabelTable * src); int gifti_copy_nvpairs (nvpairs *dest, const nvpairs *src); char * gifti_strdup (const char * src); gifti_image * gifti_copy_gifti_image(const gifti_image *gold, int copy_data); giiCoordSystem * gifti_copy_CoordSystem(const giiCoordSystem *src); giiDataArray * gifti_copy_DataArray (const giiDataArray *orig, int get_data); long long gifti_darray_nvals (const giiDataArray * da); long long gifti_gim_DA_size (const gifti_image * p, int in_mb); int gifti_check_swap (void *data, int endian, long long nsets, int swapsize); int gifti_datatype_sizes (int datatype, int *nbyper, int *swapsize); char * gifti_datatype2str (int type); char * gifti_get_meta_value (const nvpairs * nvp, const char * name); int gifti_get_this_endian (void); int gifti_image_has_data (const gifti_image * gim); int gifti_intent_from_string (const char * name); int gifti_intent_is_valid (int code); char * gifti_intent_to_string (int code); char * gifti_list_index2string (char * list[], int index); int gifti_get_xml_buf_size (void); int gifti_set_xml_buf_size (int buf_size); int gifti_str2attr_gifti (gifti_image * gim, const char * attr, const char * val); int gifti_str2attr_darray (giiDataArray * DA, const char * attr, const char * value); int gifti_str2ind_ord (const char * str); int gifti_str2dataloc (const char * str); int gifti_str2encoding (const char * str); int gifti_str2endian (const char * str); int gifti_str2datatype (const char * str); int gifti_swap_2bytes (void *data, long long nsets); int gifti_swap_4bytes (void *data, long long nsets); int gifti_swap_Nbytes (void *data, long long nsets, int swapsize); int gifti_alloc_DA_data (gifti_image * gim, const int *dalist, int len); int gifti_add_empty_CS (giiDataArray * da); int gifti_add_empty_darray (gifti_image * gim, int num_to_add); int gifti_add_to_meta (giiMetaData * md, const char * name, const char * value, int replace); int gifti_add_to_nvpairs (nvpairs * p, const char * name, const char * value); int gifti_free_CoordSystem (giiCoordSystem * cs); int gifti_free_CS_list (giiDataArray * da); int gifti_free_DataArray_list(giiDataArray ** darray, int numDA); int gifti_free_DataArray (giiDataArray * darray); int gifti_free_LabelTable (giiLabelTable * t); int gifti_free_nvpairs (nvpairs * p); int gifti_read_dset_numDA (const char * fname); int gifti_read_extern_DA_data(giiDataArray * da); int gifti_set_atr_in_DAs (gifti_image *gim, const char *name, const char *value, const int *dalist, int len); int gifti_set_DA_atrs (giiDataArray * da, const char ** attr, int len, int add_to_extras); int gifti_set_DA_defaults (giiDataArray * da); int gifti_set_DA_meta (gifti_image *gim, const char *name, const char *value, const int * dalist, int len, int replace); int gifti_set_dims_all_DA (gifti_image * gim, int ndim, const int * dims); int gifti_set_extern_filelist(gifti_image * gim, int nfiles, char ** files); int gifti_update_nbyper (gifti_image * gim); int gifti_valid_DataArray (const giiDataArray * da, int whine); int gifti_valid_datatype (int dtype, int whine); int gifti_valid_dims (const giiDataArray * da, int whine); int gifti_valid_int_list (const int *list, int len, int min, int max, int whine); int gifti_valid_LabelTable (const giiLabelTable * T, int whine); int gifti_valid_nbyper (int nbyper, int whine); int gifti_valid_num_dim (int num_dim, int whine); int gifti_valid_nvpairs (const nvpairs * nvp, int whine); int gifti_write_extern_DA_data(giiDataArray * da); /* comparison functions */ int gifti_approx_gifti_images (const gifti_image * g1, const gifti_image * g2, int comp_data, int verb); int gifti_compare_gifti_images (const gifti_image * g1, const gifti_image * g2, int comp_data, int verb); int gifti_approx_DA_pair (const giiDataArray*d1, const giiDataArray *d2, int comp_data, int verb); int gifti_approx_labeltables (const giiLabelTable*t1,const giiLabelTable *t2, int verb); int gifti_compare_coordsys (const giiCoordSystem * s1, const giiCoordSystem * s2,int comp_data, int verb); int gifti_compare_DA_data (const giiDataArray *d1, const giiDataArray *d2, int verb); int gifti_compare_DA_pair (const giiDataArray *d1, const giiDataArray *d2, int comp_data, int verb); int gifti_compare_gifti_data (const gifti_image * g1, const gifti_image * g2, int verb); int gifti_compare_gims_only (const gifti_image * g1, const gifti_image * g2, int verb); int gifti_compare_labeltable (const giiLabelTable*t1, const giiLabelTable*t2, int verb); int gifti_compare_nvpairs (const nvpairs *p1, const nvpairs *p2,int verb); int gifti_strdiff (const char * s1, const char * s2); long long gifti_approx_diff_offset(const void * p1, const void * p2, long long length, int ni_type, double limit); long long gifti_compare_raw_data(const void * p1, const void * p2, long long length); int gifti_triangle_diff_offset(const void *p1, const void *p2, int ntri, int ni_type); /* display functions */ void gifti_disp_dtd_url (void); void gifti_disp_lib_hist (void); void gifti_disp_lib_version (void); int gifti_disp_nvpairs (const char *mesg, const nvpairs *p); int gifti_disp_LabelTable (const char *mesg, const giiLabelTable *p); int gifti_disp_CoordSystem (const char *mesg, const giiCoordSystem *p); int gifti_disp_DataArray (const char *mesg, const giiDataArray *p, int subs); int gifti_disp_gifti_image (const char *mesg, const gifti_image *p, int subs); int gifti_disp_hex_data (const char *mesg, const void *data, int len, FILE * fp); int gifti_disp_raw_data (const void *data, int type, int nvals, int newline, FILE * stream); int gifti_clear_DataArray (giiDataArray * da); int gifti_clear_float_zeros (char * str); int gifti_clear_gifti_image (gifti_image * gim); int gifti_clear_nvpairs (nvpairs * p); int gifti_clear_LabelTable (giiLabelTable * p); int gifti_clear_CoordSystem (giiCoordSystem * p); giiDataArray * gifti_find_DA (gifti_image * gim, int intent, int index); int gifti_find_DA_list (gifti_image * gim, int intent, giiDataArray *** list,int *len); int gifti_DA_rows_cols (giiDataArray * da, long long *rows, long long *cols); char * gifticlib_version (void); #undef G_CHECK_NULL_STR #define G_CHECK_NULL_STR(s) (s ? s : "NULL") #include "gifti_xml.h" /* needs gifti_io.h, but users should not #include it */ #endif /* GIFTI_IO_H */ gifticlib-1.0.9/LICENSE.gifti0000644007023700001440000000053311021026034014610 0ustar rickrusersThe gifticlib code is released into the public domain. Developers are encouraged to incorporate the library into their application, and to contribute changes or enhancements to gifticlib. Author: Richard Reynolds, SSCC, DIRP, NIMH, National Institutes of Health May 13, 2008 (release version 1.0.0) http://www.nitrc.org/projects/gifti