#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; }