/*--------------------------------------------------------------------------*/
/*! \file nifti_tool.c
* \brief a tool for nifti file perusal, manipulation and copying
* written by Rick Reynolds, SSCC, NIMH, January 2005
*
*
* usage: nifti_tool [options] -infiles files...
*
* Via this tool, one should be able to:
*
* - copy a set of volumes (sub-bricks) from one dataset to another
* - copy a dataset, restricting some dimensions to given indices
*
* - display the contents of a nifti_image (or various fields)
* - display the contents of a nifti1_header (or various fields)
* - display AFNI extensions (they are text)
* - display the time series at coordinates i,j,k
* - display the data from any collapsed image
*
* - do a diff on two nifti_image structs (or various fields)
* - do a diff on two nifti1_header structs (or various fields)
*
* - add an AFNI extension
* - remove any extension
*
* - modify any field(s) of a nifti_image
* - modify any field(s) of a nifti1_struct
*
* usage forms:
*
* nifti_tool -help
* nifti_tool -help_hdr
* nifti_tool -help_nim
* nifti_tool -help_ana
* nifti_tool -help_datatypes
* nifti_tool -hist
* nifti_tool -ver
* nifti_tool -nifti_hist
* nifti_tool -nifti_ver
* nifti_tool -with_zlib
*
* nifti_tool -check_hdr -infiles f1 ...
* nifti_tool -check_nim -infiles f1 ...
* nifti_tool -disp_exts -infiles f1 ...
* nifti_tool -disp_hdr [-field fieldname] [...] -infiles f1 ...
* nifti_tool -disp_nim [-field fieldname] [...] -infiles f1 ...
* nifti_tool -disp_ana [-field fieldname] [...] -infiles f1 ...
* nifti_tool -disp_ts I J K [-dci_lines] -infiles f1 ...
* nifti_tool -disp_ci I J K T U V W [-dci_lines] -infiles f1 ...
*
* nifti_tool -diff_hdr [-field fieldname] [...] -infiles f1 f2
* nifti_tool -diff_nim [-field fieldname] [...] -infiles f1 f2
*
* nifti_tool -add_afni_ext "extension in quotes" -infiles f1 ...
* nifti_tool -add_comment_ext "extension in quotes" -infiles f1 ...
* nifti_tool -rm_ext ext_index -infiles f1 ...
*
* nifti_tool -mod_hdr [-mod_field fieldname new_val] [...] -infiles f1 ...
* nifti_tool -mod_nim [-mod_field fieldname new_val] [...] -infiles f1 ...
*
*
*/
/*-------------------------------------------------------------------------*/
/*! module history */
static const char * g_history[] =
{
"----------------------------------------------------------------------\n"
"nifti_tool modification history:\n"
"\n",
"0.1 30 December 2004 [rickr]\n"
" (Rick Reynolds of the National Institutes of Health, SSCC/DIRP/NIMH)\n"
" - skeleton version: options read and printed\n"
"\n",
"1.0 07 January 2005 [rickr]\n"
" - initial release version\n"
"\n",
"1.1 14 January 2005 [rickr]\n"
" - changed all non-error/non-debug output from stderr to stdout\n"
" note: creates a mismatch between normal output and debug messages\n"
" - modified act_diff_hdrs and act_diff_nims to do the processing in\n"
" lower-level functions\n",
" - added functions diff_hdrs, diff_hdrs_list, diff_nims, diff_nims_list\n"
" - added function get_field, to return a struct pointer via a fieldname\n"
" - made 'quiet' output more quiet (no description on output)\n"
" - made hdr and nim_fields arrays global, so do not pass in main()\n"
" - return (from main()) after first act_diff() difference\n"
"\n",
"1.2 9 February 2005 [rickr] - minor\n"
" - defined a local NTL_FERR macro (so it does not come from nifti1_io.h)\n"
" - added new set_byte_order parameter to nifti_set_filenames\n"
"\n",
"1.3 23 February 2005 [rickr] - sourceforge.net merge\n"
" - moved to utils directory\n"
" - added simple casts of 3 pointers for -pedantic warnings\n"
" - added a doxygen comment for the file\n"
"\n",
"1.4 02 March 2005 [rickr] - small update\n"
" - no validation in nifti_read_header calls\n"
"\n",
"1.5 05 April 2005 [rickr] - small update\n"
" - refuse mod_hdr for gzipped files (we cannot do partial overwrites)\n"
"\n",
"1.6 08 April 2005 [rickr] - added cbl, cci and dts functionality\n"
" - added -cbl: 'copy brick list' dataset copy functionality\n"
" - added -ccd: 'copy collapsed data' dataset copy functionality\n"
" - added -disp_ts: 'disp time series' data display functionality\n"
" - moved raw data display to disp_raw_data()\n"
"\n",
"1.7 14 April 2005 [rickr] - added data display functionality\n"
" - added -dci: 'display collapsed image' functionality\n"
" - modified -dts to use -dci\n"
" - modified and updated the help in use_full()\n"
" - changed copy_collapsed_dims to copy_collapsed_image, etc.\n",
" - fixed problem in disp_raw_data() for printing NT_DT_CHAR_PTR\n"
" - modified act_disp_ci():\n"
" o was act_disp_ts(), now displays arbitrary collapsed image data\n"
" o added missed debug filename act_disp_ci()\n"
" o can now save free() of data pointer for end of file loop\n",
" - modified disp_raw_data()\n"
" o takes a flag for whether to print newline\n"
" o trailing spaces and zeros are removed from printing floats\n"
" - added clear_float_zeros(), to remove trailing zeros\n"
"\n",
"1.8 19 April 2005 [rickr] - COMMENT extensions\n"
" - added int_list struct, and keep_hist,etypes,command fields to nt_opts\n"
" - added -add_comment_ext action\n"
" - allowed for removal of multiple extensions, including option of ALL\n"
" - added -keep_hist option, to store the command as a COMMENT extension\n",
" (includes fill_cmd_string() and add_int(), is done for all actions)\n"
" - added remove_ext_list(), for removing a list of extensions by indices\n"
" - added -strip_extras action, to strip all exts and descrip fields\n"
"\n",
"1.9 25 Aug 2005 [rickr] - const/string cleanup for warnings\n",
"1.10 18 Nov 2005 [rickr] - added check_hdr and check_nim actions\n",
"1.11 31 Jan 2006 [rickr] - check for new vox_offset in act_mod_hdrs\n",
"1.12 02 Mar 2006 [rickr]\n"
" - in act_cbl(), check for nt = 0 because of niftilib update 1.17\n",
"1.13 24 Apr 2006 [rickr] - act_disp_ci(): remove time series length check\n",
"1.14 04 Jun 2007 [rickr] - free_opts_mem(), to appease valgrind\n",
"1.15 05 Jun 2007 [rickr] - act_check_hdrs: free(nim)->nifti_image_free()\n",
"1.16 12 Jun 2007 [rickr] - allow creation of datasets via MAKE_IM\n",
" - added nt_image_read, nt_read_header and nt_read_bricks\n"
" to wrap nifti read functions, allowing creation of new datasets\n"
" - added -make_im, -new_dim, -new_datatype and -copy_im\n"
"1.17 13 Jun 2007 [rickr] - added help for -copy_im, enumerate examples\n",
"1.18 23 Jun 2007 [rickr] - main returns 0 on -help, -hist, -ver\n"
"1.19 28 Nov 2007 [rickr] - added -help_datatypes\n",
"1.20 13 Jun 2008 [rickr]\n"
" - added -with_zlib\n"
" - added ability to create extension from text file (for J. Gunter)\n",
"1.21 03 Aug 2008 [rickr] - ANALYZE 7.5 support\n"
" - added -help_ana, -disp_ana,\n"
" -swap_as_analyze, -swap_as_nifti, -swap_as_old\n"
"1.22 08 Oct 2008 [rickr] - allow cbl with indices in 0..nt*nu*nv*nw-1\n"
"1.23 06 Jul 2010 [rickr]\n",
" - in nt_read_bricks, bsize computation should allow for large integers\n"
"1.24 26 Sep 2012 [rickr]\n",
" - changed ana originator from char to short\n"
"----------------------------------------------------------------------\n"
};
static char g_version[] = "version 1.24 (September 26, 2012)";
static int g_debug = 1;
#include
#include
#include
#include "nifti1_io.h"
#include "nifti1_tool.h"
/* local prototypes */
static int free_opts_mem(nt_opts * nopt);
static int num_volumes(nifti_image * nim);
static char * read_file_text(const char * filename, int * length);
#define NTL_FERR(func,msg,file) \
fprintf(stderr,"** ERROR (%s): %s '%s'\n",func,msg,file)
/* val may be a function call, so evalulate first, and return result */
#define FREE_RETURN(val) \
do{ int tval=(val); free_opts_mem(&opts); return tval; } while(0)
/* these are effectively constant, and are built only for verification */
static field_s g_hdr_fields[NT_HDR_NUM_FIELDS]; /* nifti_1_header fields */
static field_s g_ana_fields[NT_ANA_NUM_FIELDS]; /* nifti_analyze75 */
static field_s g_nim_fields[NT_NIM_NUM_FIELDS]; /* nifti_image fields */
int main( int argc, char * argv[] )
{
nt_opts opts;
int rv;
if( (rv = process_opts(argc, argv, &opts)) != 0) /* then return */
{
if( rv < 0 ) FREE_RETURN(1); /* free opts memory, and return */
else FREE_RETURN(0); /* valid usage */
}
if( (rv = verify_opts(&opts, argv[0])) != 0 )
FREE_RETURN(rv);
/* now perform the requested action(s) */
if( (rv = fill_hdr_field_array(g_hdr_fields)) != 0 )
FREE_RETURN(rv);
if( (rv = fill_nim_field_array(g_nim_fields)) != 0 )
FREE_RETURN(rv);
if( (rv = fill_ana_field_array(g_ana_fields)) != 0 )
FREE_RETURN(rv);
/* 'check' functions, first */
if( opts.check_hdr || opts.check_nim ) /* allow for both */
FREE_RETURN( act_check_hdrs(&opts) );
/* copy or dts functions -- do not continue after these */
if( opts.cbl ) FREE_RETURN( act_cbl(&opts) );
if( opts.cci ) FREE_RETURN( act_cci(&opts) );
if( opts.dts || opts.dci ) FREE_RETURN( act_disp_ci(&opts) );
/* perform modifications early, in case we allow multiple actions */
if( opts.strip && ((rv = act_strip (&opts)) != 0) ) FREE_RETURN(rv);
if( opts.add_exts && ((rv = act_add_exts (&opts)) != 0) ) FREE_RETURN(rv);
if( opts.rm_exts && ((rv = act_rm_ext (&opts)) != 0) ) FREE_RETURN(rv);
if( opts.mod_hdr && ((rv = act_mod_hdrs (&opts)) != 0) ) FREE_RETURN(rv);
if( opts.mod_nim && ((rv = act_mod_nims (&opts)) != 0) ) FREE_RETURN(rv);
if((opts.swap_hdr || opts.swap_ana || opts.swap_old )
&& ((rv = act_swap_hdrs (&opts)) != 0) ) FREE_RETURN(rv);
/* if a diff, return whether, a difference exists (like the UNIX command) */
if( opts.diff_hdr && ((rv = act_diff_hdrs(&opts)) != 0) ) FREE_RETURN(rv);
if( opts.diff_nim && ((rv = act_diff_nims(&opts)) != 0) ) FREE_RETURN(rv);
/* last action type is display */
if( opts.disp_exts && ((rv = act_disp_exts(&opts)) != 0) ) FREE_RETURN(rv);
if( opts.disp_hdr && ((rv = act_disp_hdrs(&opts)) != 0) ) FREE_RETURN(rv);
if( opts.disp_nim && ((rv = act_disp_nims(&opts)) != 0) ) FREE_RETURN(rv);
if( opts.disp_ana && ((rv = act_disp_anas(&opts)) != 0) ) FREE_RETURN(rv);
FREE_RETURN(0);
}
/*----------------------------------------------------------------------
* process user options, return 0 on success
*----------------------------------------------------------------------*/
int process_opts( int argc, char * argv[], nt_opts * opts )
{
int ac;
memset(opts, 0, sizeof(*opts));
opts->prefix = NULL;
opts->debug = 1; /* init debug level to basic output */
/* init options for creating a new dataset via "MAKE_IM" */
opts->new_datatype = NIFTI_TYPE_INT16;
opts->new_dim[0] = 3;
opts->new_dim[1] = 1; opts->new_dim[2] = 1; opts->new_dim[3] = 1;
if( argc < 2 ) return usage(argv[0], USE_FULL);
/* terminal options are first, the rest are sorted */
for( ac = 1; ac < argc; ac++ )
{
if( ! strncmp(argv[ac], "-help_datatypes", 9) )
{
ac++;
if( ac >= argc )
nifti_disp_type_list(3); /* show all types */
else if( argv[ac][0] == 'd' || argv[ac][0] == 'D' )
nifti_disp_type_list(1); /* show DT_* types */
else if( argv[ac][0] == 't' || argv[ac][0] == 'T' )
nifti_test_datatype_sizes(1); /* test each nbyper and swapsize */
else
nifti_disp_type_list(2); /* show NIFTI_* types */
return 1;
}
else if( ! strncmp(argv[ac], "-help_hdr", 9) )
return usage(argv[0], USE_FIELD_HDR);
else if( ! strncmp(argv[ac], "-help_nim", 9) )
return usage(argv[0], USE_FIELD_NIM);
else if( ! strncmp(argv[ac], "-help_ana", 9) )
return usage(argv[0], USE_FIELD_ANA);
else if( ! strncmp(argv[ac], "-help", 5) )
return usage(argv[0], USE_FULL);
else if( ! strncmp(argv[ac], "-hist", 5) )
return usage(argv[0], USE_HIST);
else if( ! strncmp(argv[ac], "-ver", 2) )
return usage(argv[0], USE_VERSION);
else if( ! strncmp(argv[ac], "-nifti_hist", 11) )
{
nifti_disp_lib_hist();
return 1;
}
else if( ! strncmp(argv[ac], "-nifti_ver", 10) )
{
nifti_disp_lib_version();
return 1;
}
else if( ! strncmp(argv[ac], "-with_zlib", 5) ) {
printf("Was NIfTI library compiled with zlib? %s\n",
nifti_compiled_with_zlib() ? "YES" : "NO");
return 1;
}
/* begin normal execution options... */
else if( ! strncmp(argv[ac], "-add_afni_ext", 9) )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-add_afni_ext");
if( add_string(&opts->elist, argv[ac]) ) return -1; /* add extension */
if( add_int(&opts->etypes, NIFTI_ECODE_AFNI) ) return -1;
opts->add_exts = 1;
}
else if( ! strncmp(argv[ac], "-add_comment_ext", 9) )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-add_comment_ext");
if( add_string(&opts->elist, argv[ac]) ) return -1; /* add extension */
if( add_int(&opts->etypes, NIFTI_ECODE_COMMENT) ) return -1;
opts->add_exts = 1;
}
else if( ! strncmp(argv[ac], "-check_hdr", 10) )
opts->check_hdr = 1;
else if( ! strncmp(argv[ac], "-check_nim", 10) )
opts->check_nim = 1;
else if( ! strncmp(argv[ac], "-copy_brick_list", 11) ||
! strncmp(argv[ac], "-copy_im", 10) ||
! strncmp(argv[ac], "-cbl", 4) )
{
opts->cbl = 1;
}
else if( ! strncmp(argv[ac], "-copy_collapsed_image", 10) ||
! strncmp(argv[ac], "-cci", 4) )
{
/* we need to read in the 7 dimension values */
int index;
opts->ci_dims[0] = 0;
for( index = 1; index < 8; index++ )
{
ac++;
CHECK_NEXT_OPT_MSG(ac,argc,"-cci","7 dimension values are required");
if( ! isdigit(argv[ac][0]) && strcmp(argv[ac],"-1") ){
fprintf(stderr,"** -cci param %d (= '%s') is not a valid\n"
" consider: 'nifti_tool -help'\n",index,argv[ac]);
return -1;
}
opts->ci_dims[index] = atoi(argv[ac]);
}
opts->cci = 1;
}
else if( ! strncmp(argv[ac], "-debug", 6) )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-debug");
opts->debug = atoi(argv[ac]);
}
else if( ! strncmp(argv[ac], "-diff_hdr", 8) )
opts->diff_hdr = 1;
else if( ! strncmp(argv[ac], "-diff_nim", 8) )
opts->diff_nim = 1;
else if( ! strncmp(argv[ac], "-disp_exts", 7) )
opts->disp_exts = 1;
else if( ! strncmp(argv[ac], "-disp_hdr", 8) )
opts->disp_hdr = 1;
else if( ! strncmp(argv[ac], "-disp_nim", 8) )
opts->disp_nim = 1;
else if( ! strncmp(argv[ac], "-disp_ana", 8) )
opts->disp_ana = 1;
else if( ! strncmp(argv[ac], "-dci_lines", 6) || /* before -dts */
! strncmp(argv[ac], "-dts_lines", 6) )
{
opts->dci_lines = 1;
}
else if( ! strncmp(argv[ac], "-disp_collapsed_image", 10) ||
! strncmp(argv[ac], "-disp_ci", 8) )
{
/* we need to read in the 7 dimension values */
int index;
opts->ci_dims[0] = 0;
for( index = 1; index < 8; index++ )
{
ac++;
CHECK_NEXT_OPT_MSG(ac,argc,"-disp_ci",
"7 dimension values are required");
if( ! isdigit(argv[ac][0]) && strcmp(argv[ac],"-1") ){
fprintf(stderr,"** -disp_ci param %d (= '%s') is not a valid\n"
" consider: 'nifti_tool -help'\n",index,argv[ac]);
return -1;
}
opts->ci_dims[index] = atoi(argv[ac]);
}
opts->dci = 1;
}
else if( ! strncmp(argv[ac], "-disp_ts", 10) ||
! strncmp(argv[ac], "-dts", 4) )
{
/* we need to read in the ijk indices into the ci_dims array */
int index;
for( index = 1; index <= 3; index++ )
{
ac++;
CHECK_NEXT_OPT_MSG(ac,argc,"-dts","i,j,k indices are required\n");
if( ! isdigit(argv[ac][0]) ){
fprintf(stderr,"** -dts param %d (= '%s') is not a number\n"
" consider: 'nifti_tool -help'\n",index,argv[ac]);
return -1;
}
opts->ci_dims[index] = atoi(argv[ac]);
}
/* and fill the rest of the array */
opts->ci_dims[0] = 0;
for( index = 4; index < 8; index++ ) opts->ci_dims[index] = -1;
opts->dts = 1;
}
else if( ! strncmp(argv[ac], "-field", 2) )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-field");
if( add_string(&opts->flist, argv[ac]) ) return -1; /* add field */
}
else if( ! strncmp(argv[ac], "-infiles", 3) )
{
int count;
/* for -infiles, get all next arguments until a '-' or done */
ac++;
for( count = 0; (ac < argc) && (argv[ac][0] != '-'); ac++, count++ )
if( add_string(&opts->infiles, argv[ac]) ) return -1;/* add field */
if( count > 0 && ac < argc ) ac--; /* more options to process */
if( g_debug > 2 ) fprintf(stderr,"+d have %d file names\n", count);
}
else if( ! strncmp(argv[ac], "-make_image", 8) )
{
opts->make_im = 1; /* will setup later, as -cbl and MAKE_IM */
}
else if( ! strncmp(argv[ac], "-mod_field", 6) )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-mod_field");
if( add_string(&opts->flist, argv[ac]) ) return -1; /* add field */
ac++;
CHECK_NEXT_OPT(ac, argc, "-mod_field (2)");
if( add_string(&opts->vlist, argv[ac]) ) return -1; /* add value */
}
else if( ! strncmp(argv[ac], "-mod_hdr", 7) )
opts->mod_hdr = 1;
else if( ! strncmp(argv[ac], "-mod_nim", 7) )
opts->mod_nim = 1;
else if( ! strncmp(argv[ac], "-keep_hist", 5) )
opts->keep_hist = 1;
else if( ! strncmp(argv[ac], "-new_dim", 8) )
{
/* we need to read in the 8 dimension values */
int index;
for( index = 0; index < 8; index++ )
{
ac++;
CHECK_NEXT_OPT_MSG(ac,argc,"-new_dim","8 dim values are required");
if( ! isdigit(argv[ac][0]) && strcmp(argv[ac],"-1") ){
fprintf(stderr,"** -new_dim param %d (= '%s') is not a valid\n"
" consider: 'nifti_tool -help'\n",index,argv[ac]);
return -1;
}
opts->new_dim[index] = atoi(argv[ac]);
}
}
else if( ! strncmp(argv[ac], "-new_datatype", 10) )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-new_datatype");
opts->new_datatype = atoi(argv[ac]);
}
else if( ! strncmp(argv[ac], "-overwrite", 6) )
opts->overwrite = 1;
else if( ! strncmp(argv[ac], "-prefix", 4) )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-prefix");
opts->prefix = argv[ac];
}
else if( ! strncmp(argv[ac], "-quiet", 3) )
opts->debug = 0;
else if( ! strncmp(argv[ac], "-rm_ext", 7) )
{
ac++;
CHECK_NEXT_OPT(ac, argc, "-rm_ext");
if( strcmp(argv[ac],"ALL") == 0 ) /* special case, pass -1 */
{
if( add_string(&opts->elist, "-1") ) return -1;
}
else
{
int index = atoi(argv[ac]);
if( (index != -1) && ((index > 1000) || !isdigit(*argv[ac])) ){
fprintf(stderr,
"** '-rm_ext' requires an extension index (read '%s')\n",
argv[ac]);
return -1;
}
if( add_string(&opts->elist, argv[ac]) ) return -1;
}
opts->rm_exts = 1;
}
else if( ! strncmp(argv[ac], "-strip_extras", 6) )
opts->strip = 1;
else if( ! strncmp(argv[ac], "-swap_as_analyze", 12) )
opts->swap_ana = 1;
else if( ! strncmp(argv[ac], "-swap_as_nifti", 12) )
opts->swap_hdr = 1;
else if( ! strncmp(argv[ac], "-swap_as_old", 12) )
opts->swap_old = 1;
else
{
fprintf(stderr,"** unknown option: '%s'\n", argv[ac]);
return -1;
}
}
if( opts->make_im )
{
if( opts->infiles.len > 0 )
{
fprintf(stderr,"** -infiles is invalid when using -make_im\n");
return -1;
}
/* apply -make_im via -cbl and "MAKE_IM" */
opts->cbl = 1;
if( add_string(&opts->infiles, NT_MAKE_IM_NAME) ) return -1;
}
/* verify for programming purposes */
if( opts->add_exts && ( opts->elist.len != opts->etypes.len ) )
{
fprintf(stderr,"** ext list length (%d) != etype length (%d)\n",
opts->elist.len, opts->etypes.len);
return -1;
}
g_debug = opts->debug;
nifti_set_debug_level(g_debug);
fill_cmd_string(opts, argc, argv); /* copy this command */
if( g_debug > 2 ) disp_nt_opts("options read: ", opts);
return 0;
}
/*----------------------------------------------------------------------
* verify that the options make sense
*----------------------------------------------------------------------*/
int verify_opts( nt_opts * opts, char * prog )
{
int ac, errs = 0; /* number of requested action types */
/* check that only one of disp, diff, mod or add_*_ext is used */
ac = (opts->check_hdr || opts->check_nim ) ? 1 : 0;
ac += (opts->diff_hdr || opts->diff_nim ) ? 1 : 0;
ac += (opts->disp_hdr || opts->disp_nim ||
opts->disp_ana || opts->disp_exts ) ? 1 : 0;
ac += (opts->mod_hdr || opts->mod_nim ) ? 1 : 0;
ac += (opts->swap_hdr || opts->swap_ana || opts->swap_old ) ? 1 : 0;
ac += (opts->add_exts || opts->rm_exts ) ? 1 : 0;
ac += (opts->strip ) ? 1 : 0;
ac += (opts->cbl ) ? 1 : 0;
ac += (opts->cci ) ? 1 : 0;
ac += (opts->dts || opts->dci ) ? 1 : 0;
if( ac < 1 )
{
fprintf(stderr,
"** no action option, so nothing to do...\n"
" (try one of '-add...', '-diff...', '-disp...' or '-mod...')\n"
" (see '%s -help' for details)\n", prog);
return 1;
}
else if( ac > 1 )
{
fprintf(stderr,
"** only one action option is allowed, please use only one of:\n"
" '-add_...', '-check_...', '-diff_...', '-disp_...',\n"
" '-mod_...', '-strip', '-dts', '-cbl' or '-cci'\n"
" (see '%s -help' for details)\n", prog);
return 1;
}
/* can modify nifti_1_header or nifti_image, but not both */
if( opts->mod_hdr && opts->mod_nim )
{
fprintf(stderr,"** cannot use both '-mod_hdr' and '-mod_nim'\n");
return 1;
}
/* can add or remove extensions, but not both */
if( opts->add_exts && opts->rm_exts )
{
fprintf(stderr,"** cannot use both '-add_*_ext' and '-rm_ext'\n");
return 1;
}
if( (opts->add_exts || opts->rm_exts) && opts->elist.len <= 0 )
{
fprintf(stderr,"** missing extensions to add or remove\n");
return 1;
}
/* if modify, then we need fields and corresponding values */
if( opts->mod_hdr || opts->mod_nim )
{
if( opts->flist.len <= 0 )
{
fprintf(stderr,"** missing field to modify (need '-mod_field' opt)\n");
return 1;
}
if( opts->flist.len != opts->vlist.len )
{
fprintf(stderr,"** error: modifying %d fields with %d values\n",
opts->flist.len, opts->vlist.len);
return 1;
}
}
/* verify the number of files given for each of 4 action types */
/* -diff_... : require nfiles == 2 */
if( opts->diff_hdr || opts->diff_nim )
{
if( opts->infiles.len != 2 )
{
fprintf(stderr,"** '-diff_XXX' options require exactly 2 inputs files\n");
return 1;
}
}
/* if we are making changes, but not overwriting... */
else if( (opts->elist.len > 0 || opts->mod_hdr || opts->mod_nim ||
opts->swap_hdr || opts->swap_ana || opts->swap_old ) &&
!opts->overwrite )
{
if( opts->infiles.len > 1 )
{
fprintf(stderr,"** without -overwrite, only one input file may be"
" modified at a time\n");
errs++;
}
else if( ! opts->prefix )
{
fprintf(stderr,"** missing -prefix for output file\n");
errs++;
}
}
if( opts->dci_lines && ! opts->dts && ! opts->dci )
{
fprintf(stderr,"** option '-dci_lines' must only be used with '-dts'\n");
errs++;
}
if( opts->infiles.len <= 0 ) /* in any case */
{
fprintf(stderr,"** missing input files (see -infiles option)\n");
errs++;
}
if ( opts->overwrite && opts->prefix )
{
fprintf(stderr, "** please specify only one of -prefix and -overwrite\n");
errs++;
}
if( errs ) return 1;
if( g_debug > 1 ) fprintf(stderr,"+d options seem valid\n");
return 0;
}
/*----------------------------------------------------------------------
* re-assemble the command string into opts->command
*----------------------------------------------------------------------*/
int fill_cmd_string( nt_opts * opts, int argc, char * argv[])
{
char * cp;
int len, remain = (int)sizeof(opts->command); /* max command len */
int c, ac;
int has_space; /* arguments containing space must be quoted */
int skip = 0; /* counter to skip some of the arguments */
/* get the first argument separately */
len = snprintf( opts->command, sizeof(opts->command),
"\n command: %s", argv[0] );
if( len < 0 || len >= (int)sizeof(opts->command) ) {
fprintf(stderr,"FCS: no space remaining for command, continuing...\n");
return 1;
}
cp = opts->command + len;
remain -= len;
/* get the rest, with special attention to input files */
for( ac = 1; ac < argc; ac++ )
{
if( skip ){ skip--; continue; } /* then skip these arguments */
len = (int)strlen(argv[ac]);
if( len + 3 >= remain ) { /* extra 3 for space and possible '' */
fprintf(stderr,"FCS: no space remaining for command, continuing...\n");
return 1;
}
/* put the argument in, possibly with '' */
has_space = 0;
for( c = 0; c < len-1; c++ )
if( isspace(argv[ac][c]) ){ has_space = 1; break; }
if( has_space ) len = snprintf(cp, remain, " '%s'", argv[ac]);
else len = snprintf(cp, remain, " %s", argv[ac]);
remain -= len;
/* infiles is okay, but after the *next* argument, we may skip files */
/* (danger, will robinson! hack alert!) */
if( !strncmp(argv[ac-1],"-infiles",3) )
{
/* if more than 4 (just to be arbitrary) input files,
include only the first and last */
if( opts->infiles.len > 4 )
skip = opts->infiles.len - 2;
}
cp += len;
}
if( g_debug > 1 ){
fprintf(stderr,"+d filled command string, %d args, %d bytes\n",
argc, (int)(cp - opts->command));
if( g_debug > 2 ) fprintf(stderr,"%s\n", opts->command);
}
return 0;
}
/*----------------------------------------------------------------------
* - only bother to alloc one pointer at a time (don't need efficiency here)
* - return 0 on success
*----------------------------------------------------------------------*/
int add_int(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,"** 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
*----------------------------------------------------------------------*/
int add_string(str_list * slist, const char * str)
{
if( slist->len == 0 ) slist->list = NULL; /* just to be safe */
slist->len++;
slist->list = (const char **)realloc(slist->list,slist->len*sizeof(char *));
if( ! slist->list ){
fprintf(stderr,"** failed to alloc %d (char *) elements\n",slist->len);
return -1;
}
slist->list[slist->len-1] = str;
return 0;
}
/*----------------------------------------------------------------------
* display information on using the program
*----------------------------------------------------------------------*/
int usage(const char * prog, int level)
{
int c, len;
if( level == USE_SHORT )
{
fprintf(stdout,"usage %s [options] -infiles files...\n", prog);
fprintf(stdout,"usage %s -help\n", prog);
return -1;
}
else if( level == USE_FULL )
use_full("nifti_tool"); /* let's not allow paths in here */
else if( level == USE_HIST )
{
len = sizeof(g_history)/sizeof(char *);
for( c = 0; c < len; c++)
fputs(g_history[c], stdout);
}
else if( level == USE_FIELD_HDR )
{
field_s nhdr_fields[NT_HDR_NUM_FIELDS]; /* just do it all here */
fill_hdr_field_array(nhdr_fields);
disp_field_s_list("nifti_1_header: ", nhdr_fields, NT_HDR_NUM_FIELDS);
}
else if( level == USE_FIELD_ANA )
{
field_s nhdr_fields[NT_ANA_NUM_FIELDS]; /* just do it all here */
fill_ana_field_array(nhdr_fields);
disp_field_s_list("nifti_analyze75: ",nhdr_fields,NT_ANA_NUM_FIELDS);
}
else if( level == USE_FIELD_NIM )
{
field_s nim_fields[NT_NIM_NUM_FIELDS];
fill_nim_field_array(nim_fields);
disp_field_s_list("nifti_image: ", nim_fields, NT_NIM_NUM_FIELDS);
}
else if( level == USE_VERSION )
fprintf(stdout, "%s, %s\n", prog, g_version);
else {
fprintf(stdout,"** illegal level for usage(): %d\n", level);
return -1;
}
return 1;
}
/*----------------------------------------------------------------------
* full usage
*----------------------------------------------------------------------*/
int use_full(const char * prog )
{
printf(
"%s\n"
"\n"
" - display, modify or compare nifti structures in datasets\n"
" - copy a dataset by selecting a list of volumes from the original\n"
" - copy a dataset, collapsing any dimensions, each to a single index\n"
" - display a time series for a voxel, or more generally, the data\n"
" from any collapsed image, in ASCII text\n", prog);
printf(
"\n"
" This program can be used to display information from nifti datasets,\n"
" to modify information in nifti datasets, to look for differences\n"
" between two nifti datasets (like the UNIX 'diff' command), and to copy\n"
" a dataset to a new one, either by restricting any dimensions, or by\n"
" copying a list of volumes (the time dimension) from a dataset.\n"
"\n");
printf(
" Only one action type is allowed, e.g. one cannot modify a dataset\n"
" and then take a 'diff'.\n"
"\n");
printf(
" one can display - any or all fields in the nifti_1_header structure\n"
" - any or all fields in the nifti_image structure\n"
" - any or all fields in the nifti_analyze75 structure\n"
" - the extensions in the nifti_image structure\n"
" - the time series from a 4-D dataset, given i,j,k\n"
" - the data from any collapsed image, given dims. list\n"
"\n");
printf(
" one can check - perform internal check on the nifti_1_header struct\n"
" (by nifti_hdr_looks_good())\n"
" - perform internal check on the nifti_image struct\n"
" (by nifti_nim_is_valid())\n"
"\n");
printf(
" one can modify - any or all fields in the nifti_1_header structure\n"
" - any or all fields in the nifti_image structure\n"
" - swap all fields in NIFTI or ANALYZE header structure\n"
" add/rm - any or all extensions in the nifti_image structure\n"
" remove - all extensions and descriptions from the datasets\n"
"\n");
printf(
" one can compare - any or all field pairs of nifti_1_header structures\n"
" - any or all field pairs of nifti_image structures\n"
"\n"
" one can copy - an arbitrary list of dataset volumes (time points)\n"
" - a dataset, collapsing across arbitrary dimensions\n"
" (restricting those dimensions to the given indices)\n"
"\n"
" one can create - a new dataset out of nothing\n"
"\n");
printf(
" Note: to learn about which fields exist in either of the structures,\n"
" or to learn a field's type, size of each element, or the number\n"
" of elements in the field, use either the '-help_hdr' option, or\n"
" the '-help_nim' option. No further options are required.\n"
" ------------------------------\n");
printf(
"\n"
" usage styles:\n"
"\n"
" nifti_tool -help : show this help\n"
" nifti_tool -help_hdr : show nifti_1_header field info\n"
" nifti_tool -help_nim : show nifti_image field info\n"
" nifti_tool -help_ana : show nifti_analyze75 field info\n"
" nifti_tool -help_datatypes : show datatype table\n"
"\n");
printf(
" nifti_tool -ver : show the current version\n"
" nifti_tool -hist : show the modification history\n"
" nifti_tool -nifti_ver : show the nifti library version\n"
" nifti_tool -nifti_hist : show the nifti library history\n"
" nifti_tool -with_zlib : was library compiled with zlib\n"
"\n"
"\n");
printf(
" nifti_tool -check_hdr -infiles f1 ...\n"
" nifti_tool -check_nim -infiles f1 ...\n"
"\n");
printf(
" nifti_tool -copy_brick_list -infiles f1'[indices...]'\n"
" nifti_tool -copy_collapsed_image I J K T U V W -infiles f1\n"
" nifti_tool -copy_im -infiles f1\n"
"\n");
printf(
" nifti_tool -make_im -prefix new_im.nii\n"
"\n");
printf(
" nifti_tool -disp_hdr [-field FIELDNAME] [...] -infiles f1 ...\n"
" nifti_tool -disp_nim [-field FIELDNAME] [...] -infiles f1 ...\n"
" nifti_tool -disp_ana [-field FIELDNAME] [...] -infiles f1 ...\n"
" nifti_tool -disp_exts -infiles f1 ...\n"
" nifti_tool -disp_ts I J K [-dci_lines] -infiles f1 ...\n"
" nifti_tool -disp_ci I J K T U V W [-dci_lines] -infiles f1 ...\n"
"\n");
printf(
" nifti_tool -mod_hdr [-mod_field FIELDNAME NEW_VAL] [...] -infiles f1\n"
" nifti_tool -mod_nim [-mod_field FIELDNAME NEW_VAL] [...] -infiles f1\n"
"\n"
" nifti_tool -swap_as_nifti -overwrite -infiles f1\n"
" nifti_tool -swap_as_analyze -overwrite -infiles f1\n"
" nifti_tool -swap_as_old -overwrite -infiles f1\n"
"\n");
printf(
" nifti_tool -add_afni_ext 'extension in quotes' [...] -infiles f1\n"
" nifti_tool -add_comment_ext 'extension in quotes' [...] -infiles f1\n"
" nifti_tool -add_comment_ext 'file:FILENAME' [...] -infiles f1\n"
" nifti_tool -rm_ext INDEX [...] -infiles f1 ...\n"
" nifti_tool -strip_extras -infiles f1 ...\n"
"\n");
printf(
" nifti_tool -diff_hdr [-field FIELDNAME] [...] -infiles f1 f2\n"
" nifti_tool -diff_nim [-field FIELDNAME] [...] -infiles f1 f2\n"
"\n"
" ------------------------------\n");
printf(
"\n"
" selected examples:\n"
"\n"
" A. checks header (for problems):\n"
"\n"
" 1. nifti_tool -check_hdr -infiles dset0.nii dset1.nii\n"
" 2. nifti_tool -check_hdr -infiles *.nii *.hdr\n"
" 3. nifti_tool -check_hdr -quiet -infiles *.nii *.hdr\n"
"\n");
printf(
" B. show header differences:\n"
"\n"
" 1. nifti_tool -diff_hdr -field dim -field intent_code \\\n"
" -infiles dset0.nii dset1.nii \n"
" 2. nifti_tool -diff_hdr -new_dims 3 10 20 30 0 0 0 0 \\\n"
" -infiles my_dset.nii MAKE_IM \n"
"\n"
" C. display structures or fields:\n"
"\n");
printf(
" 1. nifti_tool -disp_hdr -infiles dset0.nii dset1.nii dset2.nii\n"
" 2. nifti_tool -disp_hdr -field dim -field descrip -infiles dset.nii\n"
" 3. nifti_tool -disp_exts -infiles dset0.nii dset1.nii dset2.nii\n"
" 4. nifti_tool -disp_ts 23 0 172 -infiles dset1_time.nii\n"
" 5. nifti_tool -disp_ci 23 0 172 -1 0 0 0 -infiles dset1_time.nii\n"
"\n");
printf(
" 6. nifti_tool -disp_ana -infiles analyze.hdr\n"
" 7. nifti_tool -disp_nim -infiles nifti.nii\n"
"\n");
printf(
" D. create a new dataset from nothing:\n"
"\n"
" 1. nifti_tool -make_im -prefix new_im.nii \n"
" 2. nifti_tool -make_im -prefix float_im.nii \\\n"
" -new_dims 3 10 20 30 0 0 0 0 -new_datatype 16\n");
printf(
" 3. nifti_tool -mod_hdr -mod_field descrip 'dataset with mods' \\\n"
" -new_dims 3 10 20 30 0 0 0 0 \\\n"
" -prefix new_desc.nii -infiles MAKE_IM\n"
"\n");
printf(
" E. copy dataset, brick list or collapsed image:\n"
"\n"
" 1. nifti_tool -copy_im -prefix new.nii -infiles dset0.nii\n"
" 2. nifti_tool -cbl -prefix new_07.nii -infiles dset0.nii'[0,7]'\n"
" 3. nifti_tool -cbl -prefix new_partial.nii \\\n"
" -infiles dset0.nii'[3..$(2)]'\n"
"\n"
" 4. nifti_tool -cci 5 4 17 -1 -1 -1 -1 -prefix new_5_4_17.nii\n"
" 5. nifti_tool -cci 5 0 17 -1 -1 2 -1 -keep_hist \\\n"
" -prefix new_5_0_17_2.nii\n"
"\n");
printf(
" F. modify the header (modify fields or swap entire header):\n"
"\n"
" 1. nifti_tool -mod_hdr -prefix dnew -infiles dset0.nii \\\n"
" -mod_field dim '4 64 64 20 30 1 1 1 1'\n"
" 2. nifti_tool -mod_hdr -prefix dnew -infiles dset0.nii \\\n"
" -mod_field descrip 'beer, brats and cheese, mmmmm...'\n"
);
printf(
" 3. cp old_dset.hdr nifti_swap.hdr \n"
" nifti_tool -swap_as_nifti -overwrite -infiles nifti_swap.hdr\n"
" 4. cp old_dset.hdr analyze_swap.hdr \n"
" nifti_tool -swap_as_analyze -overwrite -infiles analyze_swap.hdr\n"
" 5. nifti_tool -swap_as_old -prefix old_swap.hdr -infiles old_dset.hdr\n"
" nifti_tool -diff_hdr -infiles nifti_swap.hdr old_swap.hdr\n"
"\n");
printf(
" G. strip, add or remove extensions:\n"
" (in example #3, the extension is copied from a text file)\n"
"\n"
"\n"
" 1. nifti_tool -strip_extras -overwrite -infiles *.nii\n"
" 2. nifti_tool -add_comment 'converted from MY_AFNI_DSET+orig' \\\n"
" -prefix dnew -infiles dset0.nii\n"
);
printf(
" 3. nifti_tool -add_comment 'file:my.extension.txt' \\\n"
" -prefix dnew -infiles dset0.nii\n"
" 4. nifti_tool -rm_ext ALL -prefix dset1 -infiles dset0.nii\n"
" 5. nifti_tool -rm_ext 2 -rm_ext 3 -rm_ext 5 -overwrite \\\n"
" -infiles dset0.nii\n"
"\n"
" ------------------------------\n");
printf(
"\n"
" options for check actions:\n"
"\n");
printf(
" -check_hdr : check for a valid nifti_1_header struct\n"
"\n"
" This action is used to check the nifti_1_header structure for\n"
" problems. The nifti_hdr_looks_good() function is used for the\n"
" test, and currently checks:\n"
" \n"
" dim[], sizeof_hdr, magic, datatype\n"
" \n"
" More tests can be requested of the author.\n"
"\n");
printf(
" e.g. perform checks on the headers of some datasets\n"
" nifti_tool -check_hdr -infiles dset0.nii dset1.nii\n"
" nifti_tool -check_hdr -infiles *.nii *.hdr\n"
" \n"
" e.g. add the -quiet option, so that only errors are reported\n"
" nifti_tool -check_hdr -quiet -infiles *.nii *.hdr\n"
"\n");
printf(
" -check_nim : check for a valid nifti_image struct\n"
"\n"
" This action is used to check the nifti_image structure for\n"
" problems. This is tested via both nifti_convert_nhdr2nim()\n"
" and nifti_nim_is_valid(), though other functions are called\n"
" below them, of course. Current checks are:\n"
"\n");
printf(
" dim[], sizeof_hdr, datatype, fname, iname, nifti_type\n"
" \n"
" Note that creation of a nifti_image structure depends on good\n"
" header fields. So errors are terminal, meaning this check would\n"
" probably report at most one error, even if more exist. The\n"
" -check_hdr action is more complete.\n"
"\n");
printf(
" More tests can be requested of the author.\n"
"\n");
printf(
" e.g. nifti_tool -check_nim -infiles dset0.nii dset1.nii\n"
" e.g. nifti_tool -check_nim -infiles *.nii *.hdr\n"
"\n");
printf(
" ------------------------------\n");
printf(
"\n"
" options for create action:\n"
"\n");
printf(
" -make_im : create a new dataset from nothing\n"
"\n"
" With this the user can create a new dataset of a basic style,\n"
" which can then be modified with other options. This will create\n"
" zero-filled data of the appropriate size.\n"
" \n");
printf(
" The default is a 1x1x1 image of shorts. These settings can be\n"
" modified with the -new_dim option, to set the 8 dimension values,\n"
" and the -new_datatype, to provide the integral type for the data.\n"
"\n");
printf(
" See -new_dim, -new_datatype and -infiles for more information.\n"
" \n"
" Note that any -infiles dataset of the name MAKE_IM will also be\n"
" created on the fly.\n"
"\n");
printf(
" -new_dim D0 .. D7 : specify the dim array for the a new dataset.\n"
"\n"
" e.g. -new_dim 4 64 64 27 120 0 0 0\n"
"\n"
" This dimension list will apply to any dataset created via\n"
" MAKE_IM or -make_im. All 8 values are required. Recall that\n"
" D0 is the number of dimensions, and D1 through D7 are the sizes.\n"
" \n");
printf(
" -new_datatype TYPE : specify the dim array for the a new dataset.\n"
"\n"
" e.g. -new_datatype 16\n"
" default: -new_datatype 4 (short)\n"
"\n"
" This dimension list will apply to any dataset created via\n"
" MAKE_IM or -make_im. TYPE should be one of the NIFTI_TYPE_*\n"
" numbers, from nifti1.h.\n"
" \n");
printf(
" ------------------------------\n");
printf(
"\n"
" options for copy actions:\n"
"\n"
" -copy_brick_list : copy a list of volumes to a new dataset\n"
" -cbl : (a shorter, alternative form)\n"
" -copy_im : (a shorter, alternative form)\n"
"\n");
printf(
" This action allows the user to copy a list of volumes (over time)\n"
" from one dataset to another. The listed volumes can be in any\n"
" order and contain repeats, but are of course restricted to\n"
" the set of values {1, 2, ..., nt-1}, from dimension 4.\n"
"\n");
printf(
" This option is a flag. The index list is specified with the input\n"
" dataset, contained in square brackets. Note that square brackets\n"
" are special to most UNIX shells, so they should be contained\n"
" within single quotes. Syntax of an index list:\n"
"\n"
" notes:\n"
"\n");
printf(
" - indices start at zero\n"
" - indices end at nt-1, which has the special symbol '$'\n"
" - single indices should be separated with commas, ','\n"
" e.g. -infiles dset0.nii'[0,3,8,5,2,2,2]'\n"
" - ranges may be specified using '..' or '-' \n");
printf(
" e.g. -infiles dset0.nii'[2..95]'\n"
" e.g. -infiles dset0.nii'[2..$]'\n"
" - ranges may have step values, specified in ()\n"
" example: 2 through 95 with a step of 3, i.e. {2,5,8,11,...,95}\n"
" e.g. -infiles dset0.nii'[2..95(3)]'\n"
"\n");
printf(
" This functionality applies only to 3 or 4-dimensional datasets.\n"
"\n"
" e.g. to copy a dataset:\n"
" nifti_tool -copy_im -prefix new.nii -infiles dset0.nii\n"
"\n");
printf(
" e.g. to copy sub-bricks 0 and 7:\n"
" nifti_tool -cbl -prefix new_07.nii -infiles dset0.nii'[0,7]'\n"
"\n"
" e.g. to copy an entire dataset:\n"
" nifti_tool -cbl -prefix new_all.nii -infiles dset0.nii'[0..$]'\n"
"\n");
printf(
" e.g. to copy every other time point, skipping the first three:\n"
" nifti_tool -cbl -prefix new_partial.nii \\\n"
" -infiles dset0.nii'[3..$(2)]'\n"
"\n"
"\n"
" -copy_collapsed_image ... : copy a list of volumes to a new dataset\n"
" -cci I J K T U V W : (a shorter, alternative form)\n"
"\n");
printf(
" This action allows the user to copy a collapsed dataset, where\n"
" some dimensions are collapsed to a given index. For instance, the\n"
" X dimension could be collapsed to i=42, and the time dimensions\n"
" could be collapsed to t=17. To collapse a dimension, set Di to\n"
" the desired index, where i is in {0..ni-1}. Any dimension that\n"
" should not be collapsed must be listed as -1.\n"
"\n");
printf(
" Any number (of valid) dimensions can be collapsed, even down to a\n"
" a single value, by specifying enough valid indices. The resulting\n"
" dataset will then have a reduced number of non-trivial dimensions.\n"
"\n"
" Assume dset0.nii has nim->dim[8] = { 4, 64, 64, 21, 80, 1, 1, 1 }.\n"
" Note that this is a 4-dimensional dataset.\n"
"\n");
printf(
" e.g. copy the time series for voxel i,j,k = 5,4,17\n"
" nifti_tool -cci 5 4 17 -1 -1 -1 -1 -prefix new_5_4_17.nii\n"
"\n"
" e.g. read the single volume at time point 26\n"
" nifti_tool -cci -1 -1 -1 26 -1 -1 -1 -prefix new_t26.nii\n"
"\n");
printf(
" Assume dset1.nii has nim->dim[8] = { 6, 64, 64, 21, 80, 4, 3, 1 }.\n"
" Note that this is a 6-dimensional dataset.\n"
"\n"
" e.g. copy all time series for voxel i,j,k = 5,0,17, with v=2\n"
" (and add the command to the history)\n"
" nifti_tool -cci 5 0 17 -1 -1 2 -1 -keep_hist \\\n"
" -prefix new_5_0_17_2.nii\n"
"\n");
printf(
" e.g. copy all data where i=3, j=19 and v=2\n"
" (I do not claim to know a good reason to do this)\n"
" nifti_tool -cci 3 19 -1 -1 -1 2 -1 -prefix new_mess.nii\n"
"\n"
" See '-disp_ci' for more information (which displays/prints the\n"
" data, instead of copying it to a new dataset).\n"
"\n"
" ------------------------------\n");
printf(
"\n"
" options for display actions:\n"
"\n"
" -disp_hdr : display nifti_1_header fields for datasets\n"
"\n"
" This flag means the user wishes to see some of the nifti_1_header\n"
" fields in one or more nifti datasets. The user may want to specify\n"
" multiple '-field' options along with this. This option requires\n"
" one or more files input, via '-infiles'.\n"
"\n");
printf(
" If no '-field' option is present, all fields will be displayed.\n"
"\n"
" e.g. to display the contents of all fields:\n"
" nifti_tool -disp_hdr -infiles dset0.nii\n"
" nifti_tool -disp_hdr -infiles dset0.nii dset1.nii dset2.nii\n"
"\n"
" e.g. to display the contents of select fields:\n"
" nifti_tool -disp_hdr -field dim -infiles dset0.nii\n"
" nifti_tool -disp_hdr -field dim -field descrip -infiles dset0.nii\n"
"\n");
printf(
" -disp_nim : display nifti_image fields for datasets\n"
"\n"
" This flag option works the same way as the '-disp_hdr' option,\n"
" except that the fields in question are from the nifti_image\n"
" structure.\n"
"\n");
printf(
" -disp_ana : display nifti_analyze75 fields for datasets\n"
"\n"
" This flag option works the same way as the '-disp_hdr' option,\n"
" except that the fields in question are from the nifti_analyze75\n"
" structure.\n"
"\n");
printf(
" -disp_exts : display all AFNI-type extensions\n"
"\n"
" This flag option is used to display all nifti_1_extension data,\n"
" for only those extensions of type AFNI (code = 4). The only\n"
" other option used will be '-infiles'.\n"
"\n");
printf(
" e.g. to display the extensions in datasets:\n"
" nifti_tool -disp_exts -infiles dset0.nii\n"
" nifti_tool -disp_exts -infiles dset0.nii dset1.nii dset2.nii\n"
"\n");
printf(
" -disp_ts I J K : display ASCII time series at i,j,k = I,J,K\n"
"\n"
" This option is used to display the time series data for the voxel\n"
" at i,j,k indices I,J,K. The data is displayed in text, either all\n"
" on one line (the default), or as one number per line (via the\n"
" '-dci_lines' option).\n"
"\n");
printf(
" Notes:\n"
"\n"
" o This function applies only to 4-dimensional datasets.\n"
" o The '-quiet' option can be used to suppress the text header,\n"
" leaving only the data.\n"
" o This option is short for using '-disp_ci' (display collapsed\n"
" image), restricted to 4-dimensional datasets. i.e. :\n"
" -disp_ci I J K -1 -1 -1 -1\n"
"\n");
printf(
" e.g. to display the time series at voxel 23, 0, 172:\n"
" nifti_tool -disp_ts 23 0 172 -infiles dset1_time.nii\n"
" nifti_tool -disp_ts 23 0 172 -dci_lines -infiles dset1_time.nii\n"
" nifti_tool -disp_ts 23 0 172 -quiet -infiles dset1_time.nii\n"
"\n");
printf(
" -disp_collapsed_image : display ASCII values for collapsed dataset\n"
" -disp_ci I J K T U V W : (a shorter, alternative form)\n"
"\n"
" This option is used to display all of the data from a collapsed\n"
" image, given the dimension list. The data is displayed in text,\n"
" either all on one line (the default), or as one number per line\n"
" (by using the '-dci_lines' flag).\n"
"\n");
printf(
" The '-quiet' option can be used to suppress the text header.\n"
"\n"
" e.g. to display the time series at voxel 23, 0, 172:\n"
" nifti_tool -disp_ci 23 0 172 -1 0 0 0 -infiles dset1_time.nii\n"
"\n"
" e.g. to display z-slice 14, at time t=68:\n"
" nifti_tool -disp_ci -1 -1 14 68 0 0 0 -infiles dset1_time.nii\n"
"\n"
" See '-ccd' for more information, which copies such data to a new\n"
" dataset, instead of printing it to the terminal window.\n"
"\n"
" ------------------------------\n");
printf(
"\n"
" options for modification actions:\n"
"\n"
" -mod_hdr : modify nifti_1_header fields for datasets\n"
"\n"
" This action is used to modify some of the nifti_1_header fields in\n"
" one or more datasets. The user must specify a list of fields to\n"
" modify via one or more '-mod_field' options, which include field\n"
" names, along with the new (set of) values.\n"
"\n");
printf(
" The user can modify a dataset in place, or use '-prefix' to\n"
" produce a new dataset, to which the changes have been applied.\n"
" It is recommended to normally use the '-prefix' option, so as not\n"
" to ruin a dataset.\n"
"\n");
printf(
" Note that some fields have a length greater than 1, meaning that\n"
" the field is an array of numbers, or a string of characters. In\n"
" order to modify an array of numbers, the user must provide the\n"
" correct number of values, and contain those values in quotes, so\n"
" that they are seen as a single option.\n"
"\n");
printf(
" To modify a string field, put the string in quotes.\n"
"\n"
" The '-mod_field' option takes a field_name and a list of values.\n"
"\n"
" e.g. to modify the contents of various fields:\n"
"\n");
printf(
" nifti_tool -mod_hdr -prefix dnew -infiles dset0.nii \\\n"
" -mod_field qoffset_x -17.325\n"
" nifti_tool -mod_hdr -prefix dnew -infiles dset0.nii \\\n"
" -mod_field dim '4 64 64 20 30 1 1 1 1'\n"
" nifti_tool -mod_hdr -prefix dnew -infiles dset0.nii \\\n"
" -mod_field descrip 'beer, brats and cheese, mmmmm...'\n"
"\n");
printf(
" e.g. to modify the contents of multiple fields:\n"
" nifti_tool -mod_hdr -prefix dnew -infiles dset0.nii \\\n"
" -mod_field qoffset_x -17.325 -mod_field slice_start 1\n"
"\n"
" e.g. to modify the contents of multiple files (must overwrite):\n"
" nifti_tool -mod_hdr -overwrite -mod_field qoffset_x -17.325 \\\n"
" -infiles dset0.nii dset1.nii\n"
"\n");
printf(
" -mod_nim : modify nifti_image fields for datasets\n"
"\n"
" This action option is used the same way that '-mod_hdr' is used,\n"
" except that the fields in question are from the nifti_image\n"
" structure.\n"
"\n");
printf(
" -strip_extras : remove extensions and descriptions from datasets\n"
"\n"
" This action is used to attempt to 'clean' a dataset of general\n"
" text, in order to make it more anonymous. Extensions and the\n"
" nifti_image descrip field are cleared by this action.\n"
"\n");
printf(
" e.g. to strip all *.nii datasets in this directory:\n"
" nifti_tool -strip_extras -overwrite -infiles *.nii\n"
"\n");
printf(
" -swap_as_nifti : swap the header according to nifti_1_header\n"
"\n"
" Perhaps a NIfTI header is mal-formed, and the user explicitly\n"
" wants to swap it before performing other operations. This action\n"
" will swap the field bytes under the assumption that the header is\n"
" in the NIfTI format.\n"
"\n");
printf(
" ** The recommended course of action is to make a copy of the\n"
" dataset and overwrite the header via -overwrite. If the header\n"
" needs such an operation, it is likely that the data would not\n"
" otherwise be read in correctly.\n"
"\n");
printf(
" -swap_as_analyze : swap the header according to nifti_analyze75\n"
"\n"
" Perhaps an ANALYZE header is mal-formed, and the user explicitly\n"
" wants to swap it before performing other operations. This action\n"
" will swap the field bytes under the assumption that the header is\n"
" in the ANALYZE 7.5 format.\n"
"\n");
printf(
" ** The recommended course of action is to make a copy of the\n"
" dataset and overwrite the header via -overwrite. If the header\n"
" needs such an operation, it is likely that the data would not\n"
" otherwise be read in correctly.\n"
"\n");
printf(
" -swap_as_old : swap the header using the old method\n"
"\n"
" As of library version 1.35 (3 Aug, 2008), nifticlib now swaps all\n"
" fields of a NIfTI dataset (including UNUSED ones), and it swaps\n"
" ANALYZE datasets according to the nifti_analyze75 structure.\n"
" This is a significant different in the case of ANALYZE datasets.\n"
"\n");
printf(
" The -swap_as_old option was added to compare the results of the\n"
" swapping methods, or to undo one swapping method and replace it\n"
" with another (such as to undo the old method and apply the new).\n"
"\n");
printf(" ------------------------------\n");
printf(
"\n"
" options for adding/removing extensions:\n"
"\n"
" -add_afni_ext EXT : add an AFNI extension to the dataset\n"
"\n"
" This option is used to add AFNI-type extensions to one or more\n"
" datasets. This option may be used more than once to add more than\n"
" one extension.\n"
"\n"
" If EXT is of the form 'file:FILENAME', then the extension will\n"
" be read from the file, FILENAME.\n"
"\n");
printf(
" The '-prefix' option is recommended, to create a new dataset.\n"
" In such a case, only a single file may be taken as input. Using\n"
" '-overwrite' allows the user to overwrite the current file, or\n"
" to add the extension(s) to multiple files, overwriting them.\n"
"\n");
printf(
" e.g. to add a generic AFNI extension:\n"
" nifti_tool -add_afni_ext 'wow, my first extension' -prefix dnew \\\n"
" -infiles dset0.nii\n"
"\n"
" e.g. to add multiple AFNI extensions:\n"
" nifti_tool -add_afni_ext 'wow, my first extension :)' \\\n"
" -add_afni_ext 'look, my second...' \\\n"
" -prefix dnew -infiles dset0.nii\n"
"\n");
printf(
" e.g. to add an extension, and overwrite the dataset:\n"
" nifti_tool -add_afni_ext 'some AFNI extension' -overwrite \\\n"
" -infiles dset0.nii dset1.nii \n"
"\n");
printf(
" -add_comment_ext EXT : add a COMMENT extension to the dataset\n"
"\n"
" This option is used to add COMMENT-type extensions to one or more\n"
" datasets. This option may be used more than once to add more than\n"
" one extension. This option may also be used with '-add_afni_ext'.\n"
"\n"
" If EXT is of the form 'file:FILENAME', then the extension will\n"
" be read from the file, FILENAME.\n"
"\n");
printf(
" The '-prefix' option is recommended, to create a new dataset.\n"
" In such a case, only a single file may be taken as input. Using\n"
" '-overwrite' allows the user to overwrite the current file, or\n"
" to add the extension(s) to multiple files, overwriting them.\n"
"\n");
printf(
" e.g. to add a comment about the dataset:\n"
" nifti_tool -add_comment 'converted from MY_AFNI_DSET+orig' \\\n"
" -prefix dnew \\\n"
" -infiles dset0.nii\n"
"\n");
printf(
" e.g. to add multiple extensions:\n"
" nifti_tool -add_comment 'add a comment extension' \\\n"
" -add_afni_ext 'and an AFNI XML style extension' \\\n"
" -add_comment 'dataset copied from dset0.nii' \\\n"
" -prefix dnew -infiles dset0.nii\n"
"\n");
printf(
" -rm_ext INDEX : remove the extension given by INDEX\n"
"\n"
" This option is used to remove any single extension from the\n"
" dataset. Multiple extensions require multiple options.\n"
"\n"
" notes - extension indices begin with 0 (zero)\n"
" - to view the current extensions, see '-disp_exts'\n"
" - all extensions can be removed using ALL or -1 for INDEX\n"
"\n");
printf(
" e.g. to remove the extension #0:\n"
" nifti_tool -rm_ext 0 -overwrite -infiles dset0.nii\n"
"\n"
" e.g. to remove ALL extensions:\n"
" nifti_tool -rm_ext ALL -prefix dset1 -infiles dset0.nii\n"
" nifti_tool -rm_ext -1 -prefix dset1 -infiles dset0.nii\n"
"\n");
printf(
" e.g. to remove the extensions #2, #3 and #5:\n"
" nifti_tool -rm_ext 2 -rm_ext 3 -rm_ext 5 -overwrite \\\n"
" -infiles dset0.nii\n"
"\n"
" ------------------------------\n");
printf(
"\n"
" options for showing differences:\n"
"\n"
" -diff_hdr : display header field diffs between two datasets\n"
"\n"
" This option is used to find differences between two datasets.\n"
" If any fields are different, the contents of those fields is\n"
" displayed (unless the '-quiet' option is used).\n"
"\n");
printf(
" A list of fields can be specified by using multiple '-field'\n"
" options. If no '-field' option is given, all fields will be\n"
" checked.\n"
"\n"
" Exactly two dataset names must be provided via '-infiles'.\n"
"\n"
" e.g. to display all nifti_1_header field differences:\n"
" nifti_tool -diff_hdr -infiles dset0.nii dset1.nii\n"
"\n");
printf(
" e.g. to display selected nifti_1_header field differences:\n"
" nifti_tool -diff_hdr -field dim -field intent_code \\\n"
" -infiles dset0.nii dset1.nii \n"
"\n"
" -diff_nim : display nifti_image field diffs between datasets\n"
"\n"
" This option works the same as '-diff_hdr', except that the fields\n"
" in question are from the nifti_image structure.\n"
"\n"
" ------------------------------\n");
printf(
"\n"
" miscellaneous options:\n"
"\n"
" -debug LEVEL : set the debugging level\n"
"\n"
" Level 0 will attempt to operate with no screen output, but errors.\n"
" Level 1 is the default.\n"
" Levels 2 and 3 give progressively more information.\n"
"\n"
" e.g. -debug 2\n"
"\n");
printf(
" -field FIELDNAME : provide a field to work with\n"
"\n"
" This option is used to provide a field to display, modify or\n"
" compare. This option can be used along with one of the action\n"
" options presented above.\n"
"\n"
" See '-disp_hdr', above, for complete examples.\n"
"\n"
" e.g. nifti_tool -field descrip\n"
" e.g. nifti_tool -field descrip -field dim\n"
"\n");
printf(
" -infiles file0... : provide a list of files to work with\n"
"\n"
" This parameter is required for any of the actions, in order to\n"
" provide a list of files to process. If input filenames do not\n"
" have an extension, the directory we be searched for any\n"
" appropriate files (such as .nii or .hdr).\n"
"\n");
printf(
" Note: if the filename has the form MAKE_IM, then a new dataset\n"
" will be created, without the need for file input.\n"
"\n");
printf(
" See '-mod_hdr', above, for complete examples.\n"
"\n"
" e.g. nifti_tool -infiles file0.nii\n"
" e.g. nifti_tool -infiles file1.nii file2 file3.hdr\n"
"\n");
printf(
" -mod_field NAME 'VALUE_LIST' : provide new values for a field\n"
"\n"
" This parameter is required for any the modification actions.\n"
" If the user wants to modify any fields of a dataset, this is\n"
" where the fields and values are specified.\n"
"\n");
printf(
" NAME is a field name (in either the nifti_1_header structure or\n"
" the nifti_image structure). If the action option is '-mod_hdr',\n"
" then NAME must be the name of a nifti_1_header field. If the\n"
" action is '-mod_nim', NAME must be from a nifti_image structure.\n"
"\n");
printf(
" VALUE_LIST must be one or more values, as many as are required\n"
" for the field, contained in quotes if more than one is provided.\n"
"\n"
" Use 'nifti_tool -help_hdr' to get a list of nifti_1_header fields\n"
" Use 'nifti_tool -help_nim' to get a list of nifti_image fields\n"
"\n"
" See '-mod_hdr', above, for complete examples.\n"
"\n");
printf(
" e.g. modifying nifti_1_header fields:\n"
" -mod_field descrip 'toga, toga, toga'\n"
" -mod_field qoffset_x 19.4 -mod_field qoffset_z -11\n"
" -mod_field pixdim '1 0.9375 0.9375 1.2 1 1 1 1'\n"
"\n");
printf(
" -keep_hist : add the command as COMMENT (to the 'history')\n"
"\n"
" When this option is used, the current command will be added\n"
" as a NIFTI_ECODE_COMMENT type extension. This provides the\n"
" ability to keep a history of commands affecting a dataset.\n"
"\n"
" e.g. -keep_hist\n"
"\n");
printf(
" -overwrite : any modifications will be made to input files\n"
"\n"
" This option is used so that all field modifications, including\n"
" extension additions or deletions, will be made to the files that\n"
" are input.\n"
"\n");
printf(
" In general, the user is recommended to use the '-prefix' option\n"
" to create new files. But if overwriting the contents of the\n"
" input files is preferred, this is how to do it.\n"
"\n"
" See '-mod_hdr' or '-add_afni_ext', above, for complete examples.\n"
"\n"
" e.g. -overwrite\n"
"\n");
printf(
" -prefix : specify an output file to write change into\n"
"\n"
" This option is used to specify an output file to write, after\n"
" modifications have been made. If modifications are being made,\n"
" then either '-prefix' or '-overwrite' is required.\n"
"\n"
" If no extension is given, the output extension will be '.nii'.\n"
"\n");
printf(
" e.g. -prefix new_dset\n"
" e.g. -prefix new_dset.nii\n"
" e.g. -prefix new_dset.hdr\n"
"\n"
" -quiet : report only errors or requested information\n"
"\n"
" This option is equivalent to '-debug 0'.\n"
"\n"
" ------------------------------\n");
printf(
"\n"
" basic help options:\n"
"\n"
" -help : show this help\n"
"\n"
" e.g. nifti_tool -help\n"
"\n"
" -help_hdr : show nifti_1_header field info\n"
"\n"
" e.g. nifti_tool -help_hdr\n"
"\n"
" -help_nim : show nifti_image field info\n"
"\n"
" e.g. nifti_tool -help_nim\n"
"\n"
" -help_ana : show nifti_analyze75 field info\n"
"\n"
" e.g. nifti_tool -help_ana\n"
);
printf(
"\n"
" -help_datatypes [TYPE] : display datatype table\n"
"\n"
" e.g. nifti_tool -help_datatypes\n"
" e.g. nifti_tool -help_datatypes N\n"
"\n"
" This displays the contents of the nifti_type_list table.\n"
" An additional 'D' or 'N' parameter will restrict the type\n"
" name to 'DT_' or 'NIFTI_TYPE_' names, 'T' will test.\n");
printf(
"\n"
" -ver : show the program version number\n"
"\n"
" e.g. nifti_tool -ver\n"
"\n"
" -hist : show the program modification history\n"
"\n"
" e.g. nifti_tool -hist\n"
"\n");
printf(
" -nifti_ver : show the nifti library version number\n"
"\n"
" e.g. nifti_tool -nifti_ver\n"
"\n"
" -nifti_hist : show the nifti library modification history\n"
"\n"
" e.g. nifti_tool -nifti_hist\n"
"\n"
" -with_zlib : print whether library was compiled with zlib\n"
"\n"
" e.g. nifti_tool -with_zlib\n"
"\n"
" ------------------------------\n"
"\n"
" R. Reynolds\n"
" %s\n\n",
g_version );
return 1;
}
/*----------------------------------------------------------------------
* display the contents of the struct and all lists
*----------------------------------------------------------------------*/
int disp_nt_opts( const char *mesg, nt_opts * opts)
{
int c;
if( mesg ) fputs(mesg, stderr);
if( ! opts )
{
fprintf(stderr,"** disp_nt_opts: missing opts\n");
return -1;
}
fprintf(stderr,"nt_opts @ %p\n"
" check_hdr, check_nim = %d, %d\n"
" diff_hdr, diff_nim = %d, %d\n"
" disp_hdr, disp_nim = %d, %d\n"
" disp_ana, disp_exts = %d, %d\n"
" add_exts, rm_exts = %d, %d\n"
" mod_hdr, mod_nim = %d, %d\n"
" swap_hdr, swap_ana = %d, %d\n"
" swap_old = %d\n"
" cbl, cci = %d, %d\n"
" dts, dci_lines = %d, %d\n"
" make_im = %d\n",
(void *)opts,
opts->check_hdr, opts->check_nim,
opts->diff_hdr, opts->diff_nim, opts->disp_hdr, opts->disp_nim,
opts->disp_ana, opts->disp_exts, opts->add_exts, opts->rm_exts,
opts->mod_hdr, opts->mod_nim,
opts->swap_hdr, opts->swap_ana, opts->swap_old,
opts->cbl, opts->cci,
opts->dts, opts->dci_lines, opts->make_im );
fprintf(stderr," ci_dims[8] = ");
disp_raw_data(opts->ci_dims, DT_INT32, 8, ' ', 1);
fprintf(stderr," new_dim[8] = ");
disp_raw_data(opts->new_dim, DT_INT32, 8, ' ', 1);
fprintf(stderr,"\n"
" new_datatype = %d\n"
" debug, keep_hist = %d, %d\n"
" overwrite = %d\n"
" prefix = '%s'\n",
opts->new_datatype, opts->debug, opts->keep_hist, opts->overwrite,
opts->prefix ? opts->prefix : "(NULL)" );
fprintf(stderr," elist (length %d) :\n", opts->elist.len);
for( c = 0; c < opts->elist.len; c++ )
fprintf(stderr," %d : %s\n", c, opts->elist.list[c]);
fprintf(stderr," etypes (length %d) : ", opts->etypes.len);
disp_raw_data(opts->etypes.list, DT_INT32, opts->etypes.len, ' ', 0);
fputc('\n',stderr);
fprintf(stderr," flist (length %d) :\n", opts->flist.len);
for( c = 0; c < opts->flist.len; c++ )
fprintf(stderr," %d : %s\n", c, opts->flist.list[c]);
fprintf(stderr," vlist (length %d) :\n", opts->vlist.len);
for( c = 0; c < opts->vlist.len; c++ )
fprintf(stderr," %d : %s\n", c, opts->vlist.list[c]);
fprintf(stderr," infiles (length %d) :\n", opts->infiles.len);
for( c = 0; c < opts->infiles.len; c++ )
fprintf(stderr," %d : %s\n", c, opts->infiles.list[c]);
fprintf(stderr," command len : %d\n",(int)strlen(opts->command));
return 0;
}
/*----------------------------------------------------------------------
* For each file, add all extensions with type NIFTI_ECODE_AFNI.
* Though it should not matter, copy the trailing null characters.
*----------------------------------------------------------------------*/
int act_add_exts( nt_opts * opts )
{
nifti_image * nim;
const char * ext;
char * edata = NULL;
int fc, ec, elen;
if( g_debug > 2 ){
fprintf(stderr,"+d adding %d extensions to %d files...\n"
" extension types are: ",
opts->elist.len, opts->infiles.len);
disp_raw_data(opts->etypes.list, DT_INT32, opts->etypes.len, ' ', 1);
}
if( opts->prefix && opts->infiles.len != 1 ){
fprintf(stderr,"** error: we have a prefix but %d files\n",
opts->infiles.len);
return 1;
}
if( opts->elist.len <= 0 ) return 0;
for( fc = 0; fc < opts->infiles.len; fc++ )
{
nim = nt_image_read( opts, opts->infiles.list[fc], 1 );
if( !nim ) return 1; /* errors come from the library */
for( ec = 0; ec < opts->elist.len; ec++ ){
ext = opts->elist.list[ec];
elen = (int)strlen(ext);
if( !strncmp(ext,"file:",5) ){
edata = read_file_text(ext+5, &elen);
if( !edata || elen <= 0 ) {
fprintf(stderr,"** failed to read extension data from '%s'\n",
ext+5);
continue;
}
ext = edata;
}
if( nifti_add_extension(nim, ext, elen, opts->etypes.list[ec]) ){
nifti_image_free(nim);
return 1;
}
/* if extension came from file, free the data */
if( edata ){ free(edata); edata = NULL; }
}
if( opts->keep_hist && nifti_add_extension(nim, opts->command,
(int)strlen(opts->command), NIFTI_ECODE_COMMENT) )
fprintf(stderr,"** failed to add command to image as extension\n");
if( opts->prefix &&
nifti_set_filenames(nim, opts->prefix, !opts->overwrite, 1) )
{
nifti_image_free(nim);
return 1;
}
if( g_debug > 1 )
fprintf(stderr,"+d writing %s with %d new extension(s)\n",
opts->infiles.list[fc], opts->elist.len);
if( nifti_image_write_status(nim) ) {
fprintf(stderr,"** failed to write image %s\n",
opts->infiles.list[fc]);
nifti_image_free(nim);
return 1;
}
nifti_image_free(nim);
}
if( g_debug > 0 )
fprintf(stderr,"+d added %d extension(s) to %d files\n",
opts->elist.len, opts->infiles.len);
return 0;
}
/*----------------------------------------------------------------------
* Return the allocated file contents.
*----------------------------------------------------------------------*/
static char * read_file_text(const char * filename, int * length)
{
FILE * fp;
char * text;
int len, bytes;
if( !filename || !length ) {
fprintf(stderr,"** bad params to read_file_text\n");
return NULL;
}
len = nifti_get_filesize(filename);
if( len <= 0 ) {
fprintf(stderr,"** RFT: file '%s' appears empty\n", filename);
return NULL;
}
fp = fopen(filename, "r");
if( !fp ) {
fprintf(stderr,"** RFT: failed to open '%s' for reading\n", filename);
return NULL;
}
/* allocate the bytes, and fill them with the file contents */
text = (char *)malloc(len * sizeof(char));
if( !text ) {
fprintf(stderr,"** RFT: failed to allocate %d bytes\n", len);
fclose(fp);
return NULL;
}
bytes = (int)fread(text, sizeof(char), len, fp);
fclose(fp); /* in any case */
if( bytes != len ) {
fprintf(stderr,"** RFT: read only %d of %d bytes from %s\n",
bytes, len, filename);
free(text);
return NULL;
}
/* success */
if( g_debug > 1 ) {
fprintf(stderr,"++ found extension of length %d in file %s\n",
len, filename);
if( g_debug > 2 )
fprintf(stderr,"++ text is:\n%s\n", text);
}
*length = len;
return text;
}
/*----------------------------------------------------------------------
* For each file, strip the extra fields.
*
* Clear extensions and descrip field. No other generic strings will get
* passed to nifti_1_header struct.
*
* - this may make the datasets more anonymous
* - no history is appended here
*----------------------------------------------------------------------*/
int act_strip( nt_opts * opts )
{
nifti_image * nim;
int fc;
if( g_debug > 2 )
fprintf(stderr,"+d stripping extras from %d files\n", opts->infiles.len);
if( opts->prefix && opts->infiles.len != 1 ){
fprintf(stderr,"** error: we have a prefix but %d files\n",
opts->infiles.len);
return 1;
}
for( fc = 0; fc < opts->infiles.len; fc++ )
{
nim = nt_image_read( opts, opts->infiles.list[fc], 1 );
if( !nim ) return 1; /* errors come from the library */
/* now remove the extensions */
nifti_free_extensions(nim);
memset(nim->descrip, 0, 80);
if( opts->prefix &&
nifti_set_filenames(nim, opts->prefix, !opts->overwrite, 1) ){
nifti_image_free(nim);
return 1;
}
if( g_debug > 1 )
fprintf(stderr,"+d writing %s without extensions or 'descrip'\n",
nim->fname);
nifti_image_write(nim);
if( nifti_image_write_status(nim) ) {
fprintf(stderr,"** failed to write image %s\n", nim->fname);
nifti_image_free(nim);
return 1;
}
if( g_debug > 3 ) nifti_image_infodump(nim);
nifti_image_free(nim);
}
if( g_debug > 0 )
fprintf(stderr,"+d stripped extras from %d files\n", opts->infiles.len);
return 0;
}
/*----------------------------------------------------------------------
* For each file, remove the given extension for the given indices.
*
* Note that index = -1 means to remove them all.
*----------------------------------------------------------------------*/
int act_rm_ext( nt_opts * opts )
{
nifti_image * nim;
int fc, ext_ind, num_ext;
if( g_debug > 2 )
fprintf(stderr,"+d removing %d extensions from %d files...\n",
opts->elist.len, opts->infiles.len);
if( opts->elist.len <= 0 ) return 0;
if( opts->prefix && opts->infiles.len != 1 ){
fprintf(stderr,"** error: we have a prefix but %d files\n",
opts->infiles.len);
return 1;
}
else if( opts->overwrite && opts->infiles.len != 1 &&
strcmp(opts->elist.list[0], "-1") ) {
fprintf(stderr,"** error: for multiple files, can only delete ALL\n");
return 1;
}
ext_ind = atoi(opts->elist.list[0]);
if( ext_ind < -1 ){
fprintf(stderr,"** bad extension index to remove: %d\n", ext_ind);
return 1;
}
if( g_debug > 1 ) fprintf(stderr,"+d removing extension index %d\n",ext_ind);
for( fc = 0; fc < opts->infiles.len; fc++ )
{
nim = nt_image_read( opts, opts->infiles.list[fc], 1 );
if( !nim ) return 1; /* errors come from the library */
/* note the number of extensions for later */
num_ext = nim->num_ext;
/* now remove the extensions */
if( remove_ext_list(nim, opts->elist.list, opts->elist.len) )
return 1;
if( opts->keep_hist && nifti_add_extension(nim, opts->command,
(int)strlen(opts->command), NIFTI_ECODE_COMMENT) )
fprintf(stderr,"** failed to add command to image as extension\n");
if( opts->prefix &&
nifti_set_filenames(nim, opts->prefix, !opts->overwrite, 1) ){
nifti_image_free(nim);
return 1;
}
if( g_debug > 1 )
fprintf(stderr,"+d writing %s with %d fewer extension(s)\n",
nim->fname, ext_ind == -1 ? num_ext : opts->elist.len);
if( nifti_image_write_status(nim) ) {
fprintf(stderr,"** failed to write image %s\n", nim->fname);
nifti_image_free(nim);
return 1;
}
nifti_image_free(nim);
}
if( g_debug > 0 )
fprintf(stderr,"+d removed %s extension(s) from %d files\n",
ext_ind == -1 ? "ALL" : "1", opts->infiles.len);
return 0;
}
/*----------------------------------------------------------------------
* remove extensions by index
*
* return: 0 on success, -1 on failure
*----------------------------------------------------------------------*/
int remove_ext_list( nifti_image * nim, const char ** elist, int len )
{
int * marks;
int c, ec, extval;
if( len > nim->num_ext ){
fprintf(stderr, "** cannot remove %d exts from image '%s' with only %d\n",
len, nim->fname, nim->num_ext);
return -1;
}
if( len <= 0 ){
fprintf(stderr,"** REL: (%d) no extensions to remove?\n",len);
return -1;
}
extval = atoi(elist[0]); /* check the first value */
/* first special case, elist[0] == -1 */
if( extval == -1 )
{
if( g_debug > 1 )
fprintf(stderr,"+d removing ALL (%d) extensions from '%s'\n",
nim->num_ext, nim->fname );
nifti_free_extensions(nim);
return 0;
}
if( g_debug > 2 )
fprintf(stderr,"+d removing %d exts from '%s'\n", len, nim->fname );
if( ! (marks = (int *)calloc(nim->num_ext, sizeof(int))) ) {
fprintf(stderr,"** failed to alloc %d marks\n",nim->num_ext);
return -1;
}
/* mark all extensions for removal */
for( ec = 0; ec < len; ec++ )
{
extval = atoi(elist[ec]);
if( extval < 0 || extval >= nim->num_ext ){
fprintf(stderr,"** ext #%d (= %d) is out of range [0,%d] for %s\n",
ec, extval, nim->num_ext-1, nim->fname);
free(marks); return -1;
}
if( marks[extval] ){
fprintf(stderr,"** ext #%d (= %d) is a duplicate", ec, extval);
free(marks); return -1;
}
marks[extval]++;
}
/* now remove them - count from top down to do lazy programming */
for( ec = nim->num_ext-1; ec >= 0; ec-- )
{
if( !marks[ec] ) continue; /* do not delete this one */
if( g_debug > 2 )
disp_nifti1_extension("+d removing ext: ",nim->ext_list+ec,-1);
/* delete this data, and shift the list down (yeah, inefficient) */
if( nim->ext_list[ec].edata ) free( nim->ext_list[ec].edata );
/* move anything above down one */
for( c = ec+1; c < nim->num_ext; c++ )
nim->ext_list[c-1] = nim->ext_list[c];
nim->num_ext--;
}
if( g_debug > 3 ) fprintf(stderr,"-d done removing extensions\n");
if( nim->num_ext == 0 ){ /* did we trash the only extension? */
if( g_debug > 1 )
fprintf(stderr,"-d removed ALL extensions from %s\n",nim->fname);
free(nim->ext_list);
nim->ext_list = NULL;
}
free(marks);
return 0;
}
/*----------------------------------------------------------------------
* check for diffs between all fields in opts->flist, or in the
* entire nifti_1_header
*
* if quiet mode (debug == 0) return on first diff
*
* return: 1 if diffs exist, 0 otherwise
*----------------------------------------------------------------------*/
int act_diff_hdrs( nt_opts * opts )
{
nifti_1_header * nhdr0, * nhdr1;
int diffs = 0;
if( opts->infiles.len != 2 ){
fprintf(stderr,"** -diff_hdr requires 2 -infiles, have %d\n",
opts->infiles.len);
return 1;
}
if( g_debug > 2 )
fprintf(stderr,"-d nifti_1_header diff between %s and %s...\n",
opts->infiles.list[0], opts->infiles.list[1]);
/* get the nifiti headers (but do not validate them) */
nhdr0 = nt_read_header(opts, opts->infiles.list[0], NULL, 0);
if( ! nhdr0 ) return 1; /* errors have been printed */
nhdr1 = nt_read_header(opts, opts->infiles.list[1], NULL, 0);
if( ! nhdr1 ){ free(nhdr0); return 1; }
if( g_debug > 1 )
fprintf(stderr,"\n-d nifti_1_header diffs between '%s' and '%s'...\n",
opts->infiles.list[0], opts->infiles.list[1]);
if( opts->flist.len <= 0 )
diffs = diff_hdrs(nhdr0, nhdr1, g_debug > 0);
else
diffs = diff_hdrs_list(nhdr0, nhdr1, &opts->flist, g_debug > 0);
if( diffs == 0 && g_debug > 1 )
fprintf(stderr,"+d no differences found\n");
else if ( g_debug > 2 )
fprintf(stderr,"+d %d differences found\n", diffs);
free(nhdr0);
free(nhdr1);
return (diffs > 0);
}
/*----------------------------------------------------------------------
* check for diffs between all fields in opts->flist, or in the
* entire nifti_image
*
* if quiet mode (debug == 0) return on first diff
*
* return: 1 if diffs exist, 0 otherwise
*----------------------------------------------------------------------*/
int act_diff_nims( nt_opts * opts )
{
nifti_image * nim0, * nim1;
int diffs = 0;
if( opts->infiles.len != 2 ){
fprintf(stderr,"** -diff_nim requires 2 -infiles, have %d\n",
opts->infiles.len);
return 1;
}
if( g_debug > 2 )
fprintf(stderr,"-d nifti_image diff between %s and %s...\n",
opts->infiles.list[0], opts->infiles.list[1]);
/* get the nifiti images */
nim0 = nt_image_read(opts, opts->infiles.list[0], 0);
if( ! nim0 ) return 1; /* errors have been printed */
nim1 = nt_image_read(opts, opts->infiles.list[1], 0);
if( ! nim1 ){ free(nim0); return 1; }
if( g_debug > 1 )
fprintf(stderr,"\n-d nifti_image diffs between '%s' and '%s'...\n",
opts->infiles.list[0], opts->infiles.list[1]);
if( opts->flist.len <= 0 )
diffs = diff_nims(nim0, nim1, g_debug > 0);
else
diffs = diff_nims_list(nim0, nim1, &opts->flist, g_debug > 0);
if( diffs == 0 && g_debug > 1 )
fprintf(stderr,"+d no differences found\n");
else if ( g_debug > 2 )
fprintf(stderr,"+d %d differences found\n", diffs);
nifti_image_free(nim0);
nifti_image_free(nim1);
return (diffs > 0);
}
/*----------------------------------------------------------------------
* for each file, read nifti1_header
* if checking header, check it
* if checking nifti_image, convert and check it
*----------------------------------------------------------------------*/
int act_check_hdrs( nt_opts * opts )
{
nifti_1_header * nhdr;
nifti_image * nim;
int filenum, rv;
if( g_debug > 2 )
fprintf(stderr,"-d checking hdrs/nims for %d nifti datasets...\n",
opts->infiles.len);
for( filenum = 0; filenum < opts->infiles.len; filenum++ )
{
/* do not validate the header structure */
nhdr = nt_read_header(opts, opts->infiles.list[filenum], NULL, 0);
if( !nhdr ) continue; /* errors are printed from library */
if( opts->check_hdr )
{
if( g_debug > 1 )
fprintf(stdout,"\nchecking nifti_1_header for file '%s'\n",
opts->infiles.list[filenum]);
rv = nifti_hdr_looks_good(nhdr);
if( rv && g_debug > 0 ) /* if quiet, no GOOD response */
printf("header IS GOOD for file %s\n",opts->infiles.list[filenum]);
else if( ! rv )
printf("header FAILURE for file %s\n",opts->infiles.list[filenum]);
}
if( opts->check_nim )
{
nim = nifti_convert_nhdr2nim(*nhdr, opts->infiles.list[filenum]);
if( !nim ) continue; /* errors are printed from library */
if( g_debug > 1 )
fprintf(stdout,"\nchecking nifti_image for file '%s'\n",
opts->infiles.list[filenum]);
rv = nifti_nim_is_valid(nim, 1); /* complain about errors */
if( rv && g_debug > 0 ) /* if quiet, no GOOD response */
printf("nifti_image IS GOOD for file %s\n",
opts->infiles.list[filenum]);
else if( ! rv )
printf("nifti_image FAILURE for file %s\n",
opts->infiles.list[filenum]);
nifti_image_free(nim);
}
free(nhdr);
}
return 0;
}
/*----------------------------------------------------------------------
* display all extensions for each dataset
*----------------------------------------------------------------------*/
int act_disp_exts( nt_opts * opts )
{
nifti_image * nim;
char mesg[32];
int ec, fc;
if( g_debug > 2 )
fprintf(stderr,"-d displaying all extensions for %d files...\n",
opts->infiles.len);
for( fc = 0; fc < opts->infiles.len; fc++ )
{
nim = nt_image_read(opts, opts->infiles.list[fc], 0);
if( !nim ) return 1; /* errors are printed from library */
if( g_debug > 0 )
fprintf(stdout,"header file '%s', num_ext = %d\n",
nim->fname, nim->num_ext);
for( ec = 0; ec < nim->num_ext; ec++ )
{
snprintf(mesg, sizeof(mesg), " ext #%d : ", ec);
disp_nifti1_extension(mesg, nim->ext_list + ec, -1);
}
nifti_image_free(nim);
}
return 0;
}
/*----------------------------------------------------------------------
* for each file, read nifti1_header and display all fields
*----------------------------------------------------------------------*/
int act_disp_hdrs( nt_opts * opts )
{
nifti_1_header * nhdr;
field_s * fnhdr;
const char ** sptr;
int nfields, filenum, fc;
/* set the number of fields to display */
nfields = opts->flist.len > 0 ? opts->flist.len : NT_HDR_NUM_FIELDS;
if( g_debug > 2 )
fprintf(stderr,"-d displaying %d fields for %d nifti datasets...\n",
nfields, opts->infiles.len);
for( filenum = 0; filenum < opts->infiles.len; filenum++ )
{
/* do not validate the header structure */
nhdr = nt_read_header(opts, opts->infiles.list[filenum], NULL, 0);
if( !nhdr ) return 1; /* errors are printed from library */
if( g_debug > 0 )
fprintf(stdout,"\nheader file '%s', num_fields = %d\n",
opts->infiles.list[filenum], nfields);
if( g_debug > 1 )
fprintf(stderr,"-d header is: %s\n",
nifti_hdr_looks_good(nhdr) ? "valid" : "invalid");
if( opts->flist.len <= 0 ) /* then display all fields */
disp_field("\nall fields:\n", g_hdr_fields, nhdr, nfields, g_debug>0);
else /* print only the requested fields... */
{
/* must locate each field before printing it */
sptr = opts->flist.list;
for( fc = 0; fc < opts->flist.len; fc++ )
{
fnhdr = get_hdr_field(*sptr, filenum == 0);
if( fnhdr ) disp_field(NULL, fnhdr, nhdr, 1, g_debug>0 && fc == 0);
sptr++;
}
}
free(nhdr);
}
return 0;
}
/*----------------------------------------------------------------------
* for each file, read nifti_analyze75 and display all fields
*----------------------------------------------------------------------*/
int act_disp_anas( nt_opts * opts )
{
nifti_analyze75 * nhdr;
field_s * fnhdr;
const char ** sptr;
int nfields, filenum, fc;
/* set the number of fields to display */
nfields = opts->flist.len > 0 ? opts->flist.len : NT_ANA_NUM_FIELDS;
if( g_debug > 2 )
fprintf(stderr,"-d displaying %d fields for %d ANALYZE datasets...\n",
nfields, opts->infiles.len);
for( filenum = 0; filenum < opts->infiles.len; filenum++ )
{
/* do not validate the header structure */
nhdr = (nifti_analyze75 *)nt_read_header(opts,
opts->infiles.list[filenum], NULL, 0);
if( !nhdr ) return 1; /* errors are printed from library */
if( g_debug > 0 )
fprintf(stdout,"\nanalyze header file '%s', num_fields = %d\n",
opts->infiles.list[filenum], nfields);
if( g_debug > 1 )
fprintf(stderr,"-d analyze header is: %s\n",
nifti_hdr_looks_good((nifti_1_header *)nhdr) ?
"valid" : "invalid");
if( opts->flist.len <= 0 ) /* then display all fields */
disp_field("\nall fields:\n", g_ana_fields, nhdr, nfields, g_debug>0);
else /* print only the requested fields... */
{
/* must locate each field before printing it */
sptr = opts->flist.list;
for( fc = 0; fc < opts->flist.len; fc++ )
{
fnhdr = get_hdr_field(*sptr, filenum == 0);
if( fnhdr ) disp_field(NULL, fnhdr, nhdr, 1, g_debug>0 && fc == 0);
sptr++;
}
}
free(nhdr);
}
return 0;
}
/*----------------------------------------------------------------------
* for each file, get nifti_image and display all fields
*----------------------------------------------------------------------*/
int act_disp_nims( nt_opts * opts )
{
nifti_image * nim;
field_s * fnim;
const char ** sptr;
int nfields, filenum, fc;
/* set the number of fields to display */
nfields = opts->flist.len > 0 ? opts->flist.len : NT_NIM_NUM_FIELDS;
if( g_debug > 2 )
fprintf(stderr,"-d displaying %d fields for %d nifti datasets...\n",
nfields, opts->infiles.len);
for( filenum = 0; filenum < opts->infiles.len; filenum++ )
{
nim = nt_image_read(opts, opts->infiles.list[filenum], 0);
if( !nim ) return 1; /* errors are printed from library */
if( g_debug > 0 )
fprintf(stdout,"\nheader file '%s', num_fields = %d, fields:\n\n",
nim->fname, nfields);
if( opts->flist.len <= 0 ) /* then display all fields */
disp_field("all fields:\n", g_nim_fields, nim, nfields, g_debug > 0);
else /* print only the requested fields... */
{
/* must locate each field before printing it */
sptr = opts->flist.list;
for( fc = 0; fc < opts->flist.len; fc++ )
{
fnim = get_nim_field(*sptr, filenum == 0);
if( fnim ) disp_field(NULL, fnim, nim, 1, g_debug > 0 && fc == 0);
sptr++;
}
}
nifti_image_free(nim);
}
return 0;
}
/*----------------------------------------------------------------------
* - read header
* - modify header
* - if -prefix duplicate file
* - else if swapped, swap back
* - overwrite file header (allows (danger-of) no evaluation of data)
*----------------------------------------------------------------------*/
int act_mod_hdrs( nt_opts * opts )
{
nifti_1_header * nhdr;
nifti_image * nim; /* for reading/writing entire datasets */
int filec, swap=0;
const char * fname;
char * dupname;
char func[] = { "act_mod_hdrs" };
if( g_debug > 2 )
fprintf(stderr,"-d modifying %d fields for %d nifti headers...\n",
opts->flist.len, opts->infiles.len);
if( opts->flist.len <= 0 || opts->infiles.len <= 0 ) return 0;
for( filec = 0; filec < opts->infiles.len; filec++ )
{
fname = opts->infiles.list[filec]; /* for convenience and mod file */
if( nifti_is_gzfile(fname) ){
fprintf(stderr,"** sorry, cannot modify a gzipped file: %s\n", fname);
continue;
}
/* do not validate the header structure */
nhdr = nt_read_header(opts, fname, &swap, 0);
if( !nhdr ) return 1;
if( g_debug > 1 )
{
fprintf(stderr,"-d modifying %d fields of '%s' header\n",
opts->flist.len, fname);
fprintf(stderr,"-d header is: %s\n",
nifti_hdr_looks_good(nhdr) ? "valid" : "invalid");
}
/* okay, let's actually trash the data fields */
if( modify_all_fields(nhdr, opts, g_hdr_fields, NT_HDR_NUM_FIELDS) )
{
free(nhdr);
return 1;
}
dupname = NULL; /* unless we duplicate file */
/* possibly duplicate the current dataset before writing new header */
if( opts->prefix )
{
nim = nt_image_read(opts, fname, 1); /* get data */
if( !nim ) {
fprintf(stderr,"** failed to dup file '%s' before modifying\n",
fname);
return 1;
}
if( opts->keep_hist && nifti_add_extension(nim, opts->command,
(int)strlen(opts->command), NIFTI_ECODE_COMMENT) )
fprintf(stderr,"** failed to add command to image as extension\n");
if( nifti_set_filenames(nim, opts->prefix, 1, 1) )
{
NTL_FERR(func,"failed to set prefix for new file: ",opts->prefix);
nifti_image_free(nim);
return 1;
}
dupname = nifti_strdup(nim->fname); /* so we know to free it */
fname = dupname;
/* create the duplicate file */
if( nifti_image_write_status(nim) ) {
fprintf(stderr,"** failed to write image %s\n", nim->fname);
nifti_image_free(nim);
return 1;
}
/* if we added a history note, get the new offset into the header */
/* mod: if the new offset is valid, use it 31 Jan 2006 [rickr] */
if( nim->iname_offset >= 348 ) nhdr->vox_offset = nim->iname_offset;
nifti_image_free(nim);
}
else if ( swap )
swap_nifti_header(nhdr, NIFTI_VERSION(*nhdr));
/* if all is well, overwrite header in fname dataset */
(void)write_hdr_to_file(nhdr, fname); /* errors printed in function */
if( dupname ) free(dupname);
free(nhdr);
}
return 0;
}
/*----------------------------------------------------------------------
* - read header
* - swap header
* - if -prefix duplicate file
* - overwrite file header (allows (danger-of) no evaluation of data)
*----------------------------------------------------------------------*/
int act_swap_hdrs( nt_opts * opts )
{
nifti_1_header * nhdr;
nifti_image * nim; /* for reading/writing entire datasets */
int filec, swap;
const char * fname;
char * dupname;
char func[] = { "act_mod_hdrs" };
/* count requested operations: "there can be only one", and not Sean */
swap = opts->swap_hdr + opts->swap_ana + opts->swap_old;
if( swap > 1 ) {
fprintf(stderr,"** can perform only one swap method\n");
return 1;
} else if( ! swap )
return 0; /* probably shouldn't be here */
if( g_debug > 2 )
fprintf(stderr,"-d swapping headers of %d files...\n",opts->infiles.len);
for( filec = 0; filec < opts->infiles.len; filec++ )
{
fname = opts->infiles.list[filec]; /* for convenience and mod file */
if( nifti_is_gzfile(fname) ){
fprintf(stderr,"** sorry, cannot swap a gzipped header: %s\n", fname);
continue;
}
/* do not validate the header structure */
nhdr = nt_read_header(opts, fname, &swap, 0);
if( !nhdr ) return 1;
if( g_debug > 1 ) {
const char * str = "NIfTI";
if( opts->swap_ana || (opts->swap_old && !NIFTI_VERSION(*nhdr)) )
str = "ANALYZE";
fprintf(stderr,"-d %sswapping %s header of file %s\n",
opts->swap_old ? "OLD " : "", str, fname);
}
if( ! swap ) { /* if not yet swapped, do as the user requested */
if( opts->swap_old ) old_swap_nifti_header(nhdr, NIFTI_VERSION(*nhdr));
else swap_nifti_header(nhdr, opts->swap_ana ? 0 : 1);
} else { /* swapped already: if not correct, need to undo */
/* if swapped the wrong way, undo and swap as the user requested */
if ( opts->swap_ana && NIFTI_VERSION(*nhdr) ) {
/* want swapped as ANALYZE, but was swapped as NIFTI */
swap_nifti_header(nhdr, 1); /* undo NIFTI */
swap_nifti_header(nhdr, 0); /* swap ANALYZE */
} else if( opts->swap_hdr && !NIFTI_VERSION(*nhdr) ) {
/* want swapped as NIFTI, but was swapped as ANALYZE */
swap_nifti_header(nhdr, 0); /* undo ANALYZE */
swap_nifti_header(nhdr, 1); /* swap NIFTI */
} else if ( opts->swap_old ) {
/* undo whichever was done and apply the old way */
swap_nifti_header(nhdr, NIFTI_VERSION(*nhdr));
old_swap_nifti_header(nhdr, NIFTI_VERSION(*nhdr));
}
/* else it was swapped the right way to begin with */
}
dupname = NULL; /* unless we duplicate file */
/* possibly duplicate the current dataset before writing new header */
if( opts->prefix )
{
nim = nt_image_read(opts, fname, 1); /* get data */
if( !nim ) {
fprintf(stderr,"** failed to dup file '%s' before modifying\n",
fname);
return 1;
}
if( opts->keep_hist && nifti_add_extension(nim, opts->command,
(int)strlen(opts->command), NIFTI_ECODE_COMMENT) )
fprintf(stderr,"** failed to add command to image as extension\n");
if( nifti_set_filenames(nim, opts->prefix, 1, 1) )
{
NTL_FERR(func,"failed to set prefix for new file: ",opts->prefix);
nifti_image_free(nim);
return 1;
}
dupname = nifti_strdup(nim->fname); /* so we know to free it */
fname = dupname;
/* create the duplicate file */
if( nifti_image_write_status(nim) ) {
fprintf(stderr,"** failed to write image %s\n", nim->fname);
nifti_image_free(nim);
return 1;
}
/* if we added a history note, get the new offset into the header */
/* mod: if the new offset is valid, use it 31 Jan 2006 [rickr] */
if( nim->iname_offset >= 348 ) nhdr->vox_offset = nim->iname_offset;
nifti_image_free(nim);
}
/* if all is well, overwrite header in fname dataset */
(void)write_hdr_to_file(nhdr, fname); /* errors printed in function */
if( dupname ) free(dupname);
free(nhdr);
}
return 0;
}
/*----------------------------------------------------------------------
* - read image w/data, modify and write
*----------------------------------------------------------------------*/
int act_mod_nims( nt_opts * opts )
{
nifti_image * nim; /* for reading/writing entire datasets */
int filec;
char func[] = { "act_mod_nims" };
if( g_debug > 2 )
fprintf(stderr,"-d modifying %d fields for %d nifti images...\n",
opts->flist.len, opts->infiles.len);
if( opts->flist.len <= 0 || opts->infiles.len <= 0 ) return 0;
for( filec = 0; filec < opts->infiles.len; filec++ )
{
nim = nt_image_read(opts, opts->infiles.list[filec], 1); /* with data */
if( g_debug > 1 )
fprintf(stderr,"-d modifying %d fields from '%s' image\n",
opts->flist.len, opts->infiles.list[filec]);
/* okay, let's actually trash the data fields */
if( modify_all_fields(nim, opts, g_nim_fields, NT_NIM_NUM_FIELDS) )
{
nifti_image_free(nim);
return 1;
}
/* add command as COMMENT extension */
if( opts->keep_hist && nifti_add_extension(nim, opts->command,
(int)strlen(opts->command), NIFTI_ECODE_COMMENT) )
fprintf(stderr,"** failed to add command to image as extension\n");
/* possibly duplicate the current dataset before writing new header */
if( opts->prefix )
if( nifti_set_filenames(nim, opts->prefix, 1, 1) )
{
NTL_FERR(func,"failed to set prefix for new file: ",opts->prefix);
nifti_image_free(nim);
return 1;
}
/* and write it out, piece of cake :) */
if( nifti_image_write_status(nim) ) {
fprintf(stderr,"** failed to write image %s\n", nim->fname);
nifti_image_free(nim);
return 1;
}
nifti_image_free(nim);
}
return 0;
}
/*----------------------------------------------------------------------
* overwrite nifti_1_header in the given file
*----------------------------------------------------------------------*/
int write_hdr_to_file( nifti_1_header * nhdr, const char * fname )
{
znzFile fp;
size_t bytes;
char func[] = { "write_hdr_to_file" };
int rv = 0;
fp = znzopen(fname,"r+b",nifti_is_gzfile(fname));
if( znz_isnull(fp) ){
NTL_FERR(func, "failed to re-open mod file", fname);
return 1;
}
bytes = znzwrite(nhdr, 1, sizeof(nifti_1_header), fp);
if( bytes != sizeof(nifti_1_header)){
NTL_FERR(func, "failed to write header to file",fname);
fprintf(stderr," - wrote %d of %d bytes\n",
(int)bytes,(int)sizeof(nifti_1_header));
rv = 1;
}
if( g_debug > 3 )
disp_nifti_1_header("+d writing new header to file : ", nhdr);
znzclose(fp);
return rv;
}
/*----------------------------------------------------------------------
* modify all fields in the list
*----------------------------------------------------------------------*/
int modify_all_fields( void * basep, nt_opts * opts, field_s * fields, int flen)
{
field_s * fp;
int fc, lc; /* field and list counters */
if( opts->flist.len <= 0 ) return 0;
if( opts->flist.len != opts->vlist.len ){
fprintf(stderr,"** have %d fields but %d new values\n",
opts->flist.len, opts->vlist.len);
return 1;
}
for( lc = 0; lc < opts->flist.len; lc++ )
{
/* is it in the list? */
fp = fields;
for( fc = 0; fc < flen; fc++, fp++ )
if( strcmp(opts->flist.list[lc], fp->name) == 0 ) break;
if( fc == flen ) /* do no modifications on failure */
{
fprintf(stderr,"** field '%s' not found in structure\n",
opts->flist.list[lc]);
return 1;
}
if( modify_field( basep, fp, opts->vlist.list[lc]) )
return 1;
}
return 0;
}
/*----------------------------------------------------------------------
* modify a single field with the given value field
*
* pointer fields are not allowed here
*----------------------------------------------------------------------*/
int modify_field(void * basep, field_s * field, const char * data)
{
float fval;
const char * posn = data;
int val, max, fc, nchars;
if( g_debug > 1 )
fprintf(stderr,"+d modifying field '%s' with '%s'\n", field->name, data);
if( !data || strlen(data) == 0 )
{
fprintf(stderr,"** no data for '%s' field modification\n",field->name);
return 1;
}
switch( field->type )
{
case DT_UNKNOWN:
case NT_DT_POINTER:
case NT_DT_CHAR_PTR:
case NT_DT_EXT_PTR:
default:
fprintf(stderr,"** refusing to modify a pointer field, '%s'\n",
field->name);
return 1;
case DT_INT8:
{
max = 127;
for( fc = 0; fc < field->len; fc++ )
{
if( sscanf(posn, " %d%n", &val, &nchars) != 1 )
{
fprintf(stderr,"** found %d of %d modify values\n",
fc,field->len);
return 1;
}
if( val > max || val < -(max+1) )
{
fprintf(stderr,
"** mod val #%d (= %d) outside byte range [-%d,%d]\n",
fc, val, max+1, max);
return 1;
}
/* otherwise, we're good */
(((char *)basep + field->offset))[fc] = (char)val;
if( g_debug > 1 )
fprintf(stderr,"+d setting posn %d of '%s' to %d\n",
fc, field->name, val);
posn += nchars;
}
}
break;
case DT_INT16:
{
max = 32767;
for( fc = 0; fc < field->len; fc++ )
{
if( sscanf(posn, " %d%n", &val, &nchars) != 1 )
{
fprintf(stderr,"** found %d of %d modify values\n",
fc,field->len);
return 1;
}
if( val > max || val < -(max+1) )
{
fprintf(stderr,
"** mod val #%d (= %d) outside byte range [-%d,%d]\n",
fc, val, max+1, max);
return 1;
}
/* otherwise, we're good */
((short *)((char *)basep + field->offset))[fc] = (short)val;
if( g_debug > 1 )
fprintf(stderr,"+d setting posn %d of '%s' to %d\n",
fc, field->name, val);
posn += nchars;
}
}
break;
case DT_INT32:
{
for( fc = 0; fc < field->len; fc++ )
{
if( sscanf(posn, " %d%n", &val, &nchars) != 1 )
{
fprintf(stderr,"** found %d of %d modify values\n",
fc,field->len);
return 1;
}
((int *)((char *)basep + field->offset))[fc] = val;
if( g_debug > 1 )
fprintf(stderr,"+d setting posn %d of '%s' to %d\n",
fc, field->name, val);
posn += nchars;
}
}
break;
case DT_FLOAT32:
{
for( fc = 0; fc < field->len; fc++ )
{
if( sscanf(posn, " %f%n", &fval, &nchars) != 1 )
{
fprintf(stderr,"** found %d of %d modify values\n",
fc,field->len);
return 1;
}
/* otherwise, we're good */
((float *)((char *)basep + field->offset))[fc] = fval;
if( g_debug > 1 )
fprintf(stderr,"+d setting posn %d of '%s' to %f\n",
fc, field->name, fval);
posn += nchars;
}
}
break;
case NT_DT_STRING:
{
char * dest = (char *)basep + field->offset;
nchars = strlen(data);
strncpy(dest, data, field->len);
if( nchars < field->len ) /* clear the rest */
memset(dest+nchars, '\0', field->len-nchars);
}
break;
}
return 0;
}
/*----------------------------------------------------------------------
* fill the nifti_1_header field list
*----------------------------------------------------------------------*/
int fill_hdr_field_array( field_s * nh_fields )
{
nifti_1_header nhdr;
field_s * nhf = nh_fields;
int rv, errs;
memset(nhf, 0, NT_HDR_NUM_FIELDS*sizeof(field_s));
/* this macro takes (TYPE, NAME, NUM) and does:
fill_field(nhdr, TYPE, NT_OFF(nhdr,NAME), NUM, "NAME");
nhf++;
*/
errs = 0;
NT_SFILL(nhdr, nhf, DT_INT32, sizeof_hdr, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, NT_DT_STRING, data_type, 10, rv); errs += rv;
NT_SFILL(nhdr, nhf, NT_DT_STRING, db_name, 18, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT32, extents, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT16, session_error, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, NT_DT_STRING, regular, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT8, dim_info, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT16, dim, 8, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, intent_p1, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, intent_p2, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, intent_p3, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT16, intent_code, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT16, datatype, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT16, bitpix, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT16, slice_start, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, pixdim, 8, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, vox_offset, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, scl_slope, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, scl_inter, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT16, slice_end, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT8, slice_code, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT8, xyzt_units, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, cal_max, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, cal_min, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, slice_duration, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, toffset, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT32, glmax, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT32, glmin, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, NT_DT_STRING, descrip, 80, rv); errs += rv;
NT_SFILL(nhdr, nhf, NT_DT_STRING, aux_file, 24, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT16, qform_code, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_INT16, sform_code, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, quatern_b, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, quatern_c, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, quatern_d, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, qoffset_x, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, qoffset_y, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, qoffset_z, 1, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, srow_x, 4, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, srow_y, 4, rv); errs += rv;
NT_SFILL(nhdr, nhf, DT_FLOAT32, srow_z, 4, rv); errs += rv;
NT_SFILL(nhdr, nhf, NT_DT_STRING, intent_name, 16, rv); errs += rv;
NT_SFILL(nhdr, nhf, NT_DT_STRING, magic, 4, rv); errs += rv;
if( errs > 0 ){
fprintf(stderr, "** %d fill_fields errors!\n", errs);
return 1;
}
/* failure here is a serious problem */
if( check_total_size("nifti_1_header test: ", nh_fields,
NT_HDR_NUM_FIELDS, sizeof(nhdr)) )
return 1;
if( g_debug > 3 )
disp_field_s_list("nh_fields: ", nh_fields, NT_HDR_NUM_FIELDS);
return 0;
}
/*----------------------------------------------------------------------
* fill the nifti_image field list
*----------------------------------------------------------------------*/
int fill_nim_field_array( field_s * nim_fields )
{
nifti_image nim;
field_s * nif = nim_fields;
int rv, errs;
memset(nif, 0, NT_NIM_NUM_FIELDS*sizeof(field_s));
errs = 0;
NT_SFILL(nim, nif, DT_INT32, ndim, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, nx, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, ny, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, nz, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, nt, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, nu, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, nv, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, nw, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, dim, 8, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, nvox, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, nbyper, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, datatype, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, dx, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, dy, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, dz, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, dt, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, du, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, dv, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, dw, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, pixdim, 8, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, scl_slope, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, scl_inter, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, cal_min, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, cal_max, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, qform_code, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, sform_code, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, freq_dim, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, phase_dim, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, slice_dim, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, slice_code, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, slice_start, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, slice_end, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, slice_duration, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, quatern_b, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, quatern_c, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, quatern_d, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, qoffset_x, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, qoffset_y, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, qoffset_z, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, qfac, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, qto_xyz, 16, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, qto_ijk, 16, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, sto_xyz, 16, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, sto_ijk, 16, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, toffset, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, xyz_units, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, time_units, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, nifti_type, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, intent_code, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, intent_p1, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, intent_p2, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_FLOAT32, intent_p3, 1, rv); errs += rv;
NT_SFILL(nim, nif, NT_DT_STRING, intent_name, 16, rv); errs += rv;
NT_SFILL(nim, nif, NT_DT_STRING, descrip, 80, rv); errs += rv;
NT_SFILL(nim, nif, NT_DT_STRING, aux_file, 24, rv); errs += rv;
NT_SFILL(nim, nif, NT_DT_CHAR_PTR, fname, 1, rv); errs += rv;
NT_SFILL(nim, nif, NT_DT_CHAR_PTR, iname, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, iname_offset, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, swapsize, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, byteorder, 1, rv); errs += rv;
NT_SFILL(nim, nif, NT_DT_POINTER, data, 1, rv); errs += rv;
NT_SFILL(nim, nif, DT_INT32, num_ext, 1, rv); errs += rv;
NT_SFILL(nim, nif, NT_DT_EXT_PTR, ext_list, 1, rv); errs += rv;
if( errs > 0 ){
fprintf(stderr, "** %d fill_fields errors "
"(note that pointers get aligned)\n", errs);
return 1;
}
if( g_debug > 3 ) /* failure here is not an error condition */
check_total_size("nifti_image test: ", nim_fields,
NT_NIM_NUM_FIELDS, sizeof(nim));
if( g_debug > 3 )
disp_field_s_list("nim_fields: ", nim_fields, NT_NIM_NUM_FIELDS);
return 0;
}
/*----------------------------------------------------------------------
* fill the nifti_analyze75 field list
*----------------------------------------------------------------------*/
int fill_ana_field_array( field_s * ah_fields )
{
nifti_analyze75 nhdr;
field_s * ahf = ah_fields;
int rv, errs;
memset(ahf, 0, NT_ANA_NUM_FIELDS*sizeof(field_s));
/* this macro takes (TYPE, NAME, NUM) and does:
fill_field(nhdr, TYPE, NT_OFF(nhdr,NAME), NUM, "NAME");
nhf++;
*/
errs = 0;
NT_SFILL(nhdr, ahf, DT_INT32, sizeof_hdr, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, NT_DT_STRING, data_type, 10, rv); errs += rv;
NT_SFILL(nhdr, ahf, NT_DT_STRING, db_name, 18, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT32, extents, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT16, session_error, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, NT_DT_STRING, regular, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT8, hkey_un0, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT16, dim, 8, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT16, unused8, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT16, unused9, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT16, unused10, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT16, unused11, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT16, unused12, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT16, unused13, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT16, unused14, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT16, datatype, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT16, bitpix, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT16, dim_un0, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_FLOAT32, pixdim, 8, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_FLOAT32, vox_offset, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_FLOAT32, funused1, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_FLOAT32, funused2, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_FLOAT32, funused3, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_FLOAT32, cal_max, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_FLOAT32, cal_min, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_FLOAT32, compressed, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_FLOAT32, verified, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT32, glmax, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT32, glmin, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, NT_DT_STRING, descrip, 80, rv); errs += rv;
NT_SFILL(nhdr, ahf, NT_DT_STRING, aux_file, 24, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT8, orient, 1, rv); errs += rv;
/* originator is 5 (3) shorts, not 10 chars 26 Sep 2012 [rickr] */
NT_SFILL(nhdr, ahf, DT_INT16, originator, 5, rv); errs += rv;
NT_SFILL(nhdr, ahf, NT_DT_STRING, generated, 10, rv); errs += rv;
NT_SFILL(nhdr, ahf, NT_DT_STRING, scannum, 10, rv); errs += rv;
NT_SFILL(nhdr, ahf, NT_DT_STRING, patient_id, 10, rv); errs += rv;
NT_SFILL(nhdr, ahf, NT_DT_STRING, exp_date, 10, rv); errs += rv;
NT_SFILL(nhdr, ahf, NT_DT_STRING, exp_time, 10, rv); errs += rv;
NT_SFILL(nhdr, ahf, NT_DT_STRING, hist_un0, 3, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT32, views , 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT32, vols_added, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT32, start_field, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT32, field_skip, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT32, omax, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT32, omin, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT32, smax, 1, rv); errs += rv;
NT_SFILL(nhdr, ahf, DT_INT32, smin, 1, rv); errs += rv;
if( errs > 0 ){
fprintf(stderr, "** %d ana fill_fields errors!\n", errs);
return 1;
}
/* failure here is a serious problem */
if( check_total_size("nifti_analyze75 test: ", ah_fields, NT_ANA_NUM_FIELDS,
sizeof(nhdr)) )
return 1;
if( g_debug > 3 )
disp_field_s_list("ah_fields: ", ah_fields, NT_ANA_NUM_FIELDS);
return 0;
}
/*----------------------------------------------------------------------
* compare sizes to offset, including total
*----------------------------------------------------------------------*/
int check_total_size( const char *mesg, field_s * fields, int nfields, int tot_size )
{
field_s * fp;
int c, total;
int bad_offs;
total = 0;
bad_offs = 0;
for( c = 0, fp = fields; c < nfields; c++, fp++ ){
if( fp->offset != total ){
if( g_debug > 2 )
fprintf(stderr,"** bad offset for field '%s'\n"
" offset = %d, total = %d\n",
fp->name, fp->offset, total);
bad_offs++;
}
total += fp->size * fp->len;
}
if( g_debug > 1 || (g_debug > 0 && bad_offs > 0) ){
fputs(mesg, stderr); c = 0;
if( bad_offs > 0 ){
fprintf(stderr,"** found %d bad offsets\n", bad_offs); c++; }
if( total != tot_size ){
fprintf(stderr,"** computed total %d not equal to struct size %d\n",
total, tot_size); c++; }
if( c == 0 ) fputs("... okay\n", stderr);
}
if( bad_offs > 0 ) return 1;
return 0;
}
/*----------------------------------------------------------------------
* fill the field structure with the given data
*----------------------------------------------------------------------*/
int fill_field( field_s * fp, int type, int offset, int num, const char * name )
{
fp->type = type;
fp->offset = offset;
fp->size = 1; /* init before check */
fp->len = num;
strncpy(fp->name, name, NT_FIELD_NAME_LEN-1);
switch( type ){
case DT_UNKNOWN:
case DT_INT8:
case NT_DT_STRING:
fp->size = 1;
break;
case DT_INT16:
fp->size = 2;
break;
case DT_INT32:
case DT_FLOAT32:
fp->size = 4;
break;
case NT_DT_POINTER:
case NT_DT_CHAR_PTR:
case NT_DT_EXT_PTR:
fp->size = (int)sizeof(void *);
break;
default:
fprintf(stderr,"** fill_field: invalid type %d\n", type );
return 1;
}
return 0;
}
/*----------------------------------------------------------------------
* display the contents of all of the field structures
*----------------------------------------------------------------------*/
const char * field_type_str( int type )
{
if( type == DT_INT8 ) return "DT_INT8";
if( type == DT_INT16 ) return "DT_INT16";
if( type == DT_INT32 ) return "DT_INT32";
if( type == DT_FLOAT32 ) return "DT_FLOAT32";
if( type == NT_DT_STRING ) return "NT_DT_STRING";
if( type == NT_DT_POINTER ) return "NT_DT_POINTER";
if( type == NT_DT_CHAR_PTR ) return "NT_DT_CHAR_PTR"; /* longest: 14 */
if( type == NT_DT_EXT_PTR ) return "NT_DT_EXT_PTR";
return "DT_UNKNOWN"; /* for DT_UNKNOWN, or as an else */
}
/*----------------------------------------------------------------------
* display the contents of all of the field structures
*----------------------------------------------------------------------*/
int disp_field_s_list( const char *mesg, field_s * fp, int nfields )
{
int c;
if( mesg ) fputs(mesg, stdout);
fprintf(stdout," %d fields:\n"
" name size len offset type\n"
" ------------------- ---- --- ------ --------------\n",
nfields);
for( c = 0; c < nfields; c++, fp++ )
fprintf(stdout," %-*s %4d %3d %4d %-14s\n",
NT_FIELD_NAME_LEN-1, fp->name, fp->size, fp->len,
fp->offset, field_type_str(fp->type));
return 0;
}
/*----------------------------------------------------------------------
* display the contents of all of the field structures
*----------------------------------------------------------------------*/
int disp_field( const char *mesg, field_s *fieldp, void * str, int nfields, int header)
{
field_s * fp;
int c;
if( mesg ) fputs(mesg, stdout);
if( header && g_debug > 0 ){
fprintf(stdout, " name offset nvals values\n");
fprintf(stdout, " ------------------- ------ ----- ------\n");
}
fp = fieldp;
for( c = 0; c < nfields; c++, fp++ )
{
/* start by displaying the field information */
if( g_debug > 0 )
fprintf(stdout, " %-*.*s %4d %3d ",
NT_FIELD_NAME_LEN-1, NT_FIELD_NAME_LEN-1, fp->name,
fp->offset, fp->len);
/* now, print the value(s), depending on the type */
switch( fp->type ){
case DT_UNKNOWN:
default:
fprintf(stdout,"(unknown data type)\n");
break;
case DT_INT8: case DT_UINT8:
case DT_INT16: case DT_UINT16:
case DT_INT32: case DT_UINT32:
case DT_FLOAT32: case DT_FLOAT64:
disp_raw_data((char *)str+fp->offset, fp->type, fp->len, ' ', 1);
break;
case NT_DT_POINTER:
fprintf(stdout,"(raw data of unknown type)\n");
break;
case NT_DT_CHAR_PTR: /* look for string of length <= 40 */
{
char * sp;
int len;
/* start by sucking the pointer stored here */
sp = *(char **)((char *)str + fp->offset);
if( ! sp ){ fprintf(stdout,"(NULL)\n"); break; } /* anything? */
/* see if we have a printable string here */
for(len = 0; len <= 40 && *sp && isprint(*sp); len++, sp++ )
;
if( len > 40 )
fprintf(stdout,"(apparent long string)\n");
else if ( len == 0 )
fprintf(stdout,"(empty string)\n");
else if( *sp && !isprint(*sp) ) /* if no termination, it's bad */
fprintf(stdout,"(non-printable string)\n");
else /* woohoo! a good string */
fprintf(stdout,"'%.40s'\n",*(char **)((char *)str + fp->offset));
break;
}
case NT_DT_EXT_PTR:
{
nifti1_extension * extp;
/* yank the address sitting there into extp */
extp = *(nifti1_extension **)((char *)str + fp->offset);
/* the user may use -disp_exts to display all of them */
if( extp ) disp_nifti1_extension(NULL, extp, 6);
else fprintf(stdout,"(NULL)\n");
break;
}
case NT_DT_STRING:
{
char * charp = (char *)str + fp->offset;
fprintf(stdout,"%.*s\n", fp->len, charp);
break;
}
}
}
return 0;
}
/*----------------------------------------------------------------------
* no display, just return whether any fields differ
*----------------------------------------------------------------------*/
int diff_field(field_s *fieldp, void * str0, void * str1, int nfields)
{
field_s * fp;
char * cp0, * cp1;
int fnum, c, size;
fp = fieldp;
for( fnum = 0; fnum < nfields; fnum++, fp++ )
{
switch( fp->type ){
case DT_UNKNOWN: /* all basic types are easy */
case DT_INT8:
case DT_INT16:
case DT_INT32:
case DT_FLOAT32:
case NT_DT_STRING:
size = fp->size * fp->len; /* total field size */
cp0 = (char *)str0 + fp->offset;
cp1 = (char *)str1 + fp->offset;
for( c = 0; c < size; c++, cp0++, cp1++ )
if( *cp0 != *cp1 ) break;
if(c < size) return 1; /* found a diff */
break;
case NT_DT_POINTER: /* let's pass on these - no diff */
case NT_DT_CHAR_PTR:
break;
case NT_DT_EXT_PTR:
{
nifti1_extension * ext0, * ext1;
ext0 = *(nifti1_extension **)((char *)str0 + fp->offset);
ext1 = *(nifti1_extension **)((char *)str1 + fp->offset);
if( ! ext0 && ! ext1 ) break; /* continue on */
if( ext0 && ! ext1 ) return 1; /* pointer diff is diff */
if( ! ext0 && ext1 ) return 1;
/* just check size and type for a single extension */
if( ext0->esize != ext1->esize ) return 1;
if( ext0->ecode != ext1->ecode ) return 1;
break;
}
}
}
return 0; /* no diffs found */
}
/*----------------------------------------------------------------------
* display a single extension
*----------------------------------------------------------------------*/
int disp_nifti1_extension( const char *mesg, nifti1_extension * ext, int maxlen)
{
int len;
if( mesg ) fputs(mesg, stdout);
if( !ext )
{
fprintf(stderr,"** no extension to display\n");
return 1;
}
fprintf(stdout,"ecode = %d, esize = %d, edata = ",
ext->ecode, ext->esize);
if( !ext->edata )
fprintf(stdout,"(NULL)\n");
else if ( ext->ecode == NIFTI_ECODE_AFNI ||
ext->ecode == NIFTI_ECODE_COMMENT )
{
len = ext->esize-8;
if( maxlen >= 0 && len > maxlen ) len = maxlen;
fprintf(stdout,"%.*s\n", len, (char *)ext->edata);
}
else
fprintf(stdout,"(unknown data type)\n");
fflush(stdout);
return 0;
}
/*----------------------------------------------------------------------
* return the appropritate pointer into the g_hdr_fields struct
*----------------------------------------------------------------------*/
field_s * get_hdr_field( const char * fname, int show_fail )
{
field_s * fp;
int c;
if( ! fname || *fname == '\0' ) return NULL;
fp = g_hdr_fields;
for( c = 0; c < NT_HDR_NUM_FIELDS; c++, fp++ )
if( strcmp(fname, fp->name) == 0 ) break;
if( c == NT_HDR_NUM_FIELDS )
{
if( show_fail > 0 )
fprintf(stderr,"** get_hdr_field: field not found in hdr: %s\n",fname);
return NULL;
}
return fp;
}
/*----------------------------------------------------------------------
* return the appropritate pointer into the g_hdr_fields struct
*----------------------------------------------------------------------*/
field_s * get_nim_field( const char * fname, int show_fail )
{
field_s * fp;
int c;
if( ! fname || *fname == '\0' ) return NULL;
fp = g_nim_fields;
for( c = 0; c < NT_NIM_NUM_FIELDS; c++, fp++ )
if( strcmp(fname, fp->name) == 0 ) break;
if( c == NT_NIM_NUM_FIELDS )
{
if( show_fail > 0 )
fprintf(stderr,"** get_nim_field: field not found in hdr: %s\n",fname);
return NULL;
}
return fp;
}
/*----------------------------------------------------------------------
* return the number of fields that differ
*----------------------------------------------------------------------*/
int diff_hdrs( nifti_1_header * s0, nifti_1_header * s1, int display )
{
field_s * fp = g_hdr_fields;
int c, ndiff = 0;
for( c = 0; c < NT_HDR_NUM_FIELDS; c++, fp++ )
if( diff_field(fp, s0, s1, 1) )
{
if( display ) disp_field(NULL, fp, s0, 1, ndiff == 0);
if( display ) disp_field(NULL, fp, s1, 1, 0);
ndiff++;
}
return ndiff;
}
/*----------------------------------------------------------------------
* return the number of fields that differ
*----------------------------------------------------------------------*/
int diff_nims( nifti_image * s0, nifti_image * s1, int display )
{
field_s * fp = g_nim_fields;
int c, ndiff = 0;
for( c = 0; c < NT_NIM_NUM_FIELDS; c++, fp++ )
if( diff_field(fp, s0, s1, 1) )
{
if( display ) disp_field(NULL, fp, s0, 1, ndiff == 0);
if( display ) disp_field(NULL, fp, s1, 1, 0);
ndiff++;
}
return ndiff;
}
/*----------------------------------------------------------------------
* return the number of fields that differ
*----------------------------------------------------------------------*/
int diff_hdrs_list( nifti_1_header * s0, nifti_1_header * s1, str_list * slist,
int display )
{
field_s * fp;
const char ** sptr;
int c, ndiff = 0;
sptr = slist->list;
for( c = 0; c < slist->len; c++ )
{
fp = get_hdr_field(*sptr, 1); /* "not found" displayed in func */
if( fp && diff_field(fp, s0, s1, 1) )
{
if( display ) disp_field(NULL, fp, s0, 1, ndiff == 0);
if( display ) disp_field(NULL, fp, s1, 1, 0);
ndiff++;
}
sptr++;
}
return ndiff;
}
/*----------------------------------------------------------------------
* return the number of fields that differ
*----------------------------------------------------------------------*/
int diff_nims_list( nifti_image * s0, nifti_image * s1, str_list * slist,
int display )
{
field_s * fp;
const char ** sptr;
int c, ndiff = 0;
sptr = slist->list;
for( c = 0; c < slist->len; c++ )
{
fp = get_nim_field(*sptr, 1); /* "not found" displayed in func */
if( fp && diff_field(fp, s0, s1, 1) )
{
if( display ) disp_field(NULL, fp, s0, 1, ndiff == 0);
if( display ) disp_field(NULL, fp, s1, 1, 0);
ndiff++;
}
sptr++;
}
return ndiff;
}
/*----------------------------------------------------------------------
* display data from collapsed_image
*----------------------------------------------------------------------*/
int act_disp_ci( nt_opts * opts )
{
nifti_image * nim;
void * data = NULL;
char space = ' '; /* use space or newline */
int filenum, len, err;
if( opts->dci_lines ) space = '\n'; /* then use newlines as separators */
if( g_debug > 2 && opts->dts )
{
fprintf(stderr,"-d displaying time series at (i,j,k) = (%d,%d,%d)\n"
" for %d nifti datasets...\n\n", opts->ci_dims[1],
opts->ci_dims[2], opts->ci_dims[3], opts->infiles.len);
}
else if ( g_debug > 2 ) /* the general collapsed image form */
{
fprintf(stderr,"-d displaying collapsed image for %d datasets...\n\n"
" dims = ", opts->infiles.len);
disp_raw_data(opts->ci_dims, DT_INT32, 8, ' ', 1);
}
for( filenum = 0; filenum < opts->infiles.len; filenum++ )
{
err = 0;
nim = nt_image_read(opts, opts->infiles.list[filenum], 0);
if( !nim ) continue; /* errors are printed from library */
if( opts->dts && nim->ndim != 4 )
{
fprintf(stderr,"** error: dataset '%s' is not 4-dimensional\n",
nim->fname);
err++;
}
switch( nim->datatype )
{
case DT_INT8: case DT_INT16: case DT_INT32:
case DT_UINT8: case DT_UINT16: case DT_UINT32:
case DT_FLOAT32: case DT_FLOAT64:
if( g_debug > 1 )
fprintf(stderr,"-d datatype %d of size %d\n",
nim->datatype, nim->nbyper);
break;
default:
fprintf(stderr,"** dataset '%s' has unknown type %d\n",
nim->fname, nim->datatype);
err++;
break;
}
if( err ) { nifti_image_free(nim); continue; }
len = nifti_read_collapsed_image(nim, opts->ci_dims, &data);
if( len < 0 || !data )
{
fprintf(stderr,"** FAILURE for dataset '%s'\n", nim->fname);
if( data ) { free(data); data = NULL; }
err++;
}
/* remove check for length of time series 24 Apr 2006 */
if( err ){ nifti_image_free(nim); continue; }
/* now just print the results */
if( g_debug > 0 )
{
fprintf(stdout,"\ndataset '%s' @ (", nim->fname);
if( opts->dts ) disp_raw_data(opts->ci_dims+1, DT_INT32, 3, ' ', 0);
else disp_raw_data(opts->ci_dims+1, DT_INT32, 7, ' ', 0);
fprintf(stdout,")\n");
}
disp_raw_data(data, nim->datatype, len / nim->nbyper, space, 1);
nifti_image_free(nim);
}
if( data ) free(data);
return 0;
}
#define NT_LOC_MAX_FLOAT_BUF 32
int disp_raw_data( void * data, int type, int nvals, char space, int newline )
{
char * dp, fbuf[NT_LOC_MAX_FLOAT_BUF];
int c, size;
nifti_datatype_sizes( type, &size, NULL ); /* get nbyper */
for( c = 0, dp = (char *)data; c < nvals; c++, dp += size )
{
switch( type )
{
case DT_INT8:
printf("%d", *(char *)dp);
break;
case DT_INT16:
{
short temp;
memcpy(&temp, dp, sizeof(temp));
printf("%d", temp);
break;
}
case DT_INT32:
{
int temp;
memcpy(&temp, dp, sizeof(temp));
printf("%d", temp);
break;
}
case DT_UINT8:
{
unsigned char temp;
memcpy(&temp, dp, sizeof(temp));
printf("%u", temp);
break;
}
case DT_UINT16:
{
unsigned short temp;
memcpy(&temp, dp, sizeof(temp));
printf("%u", temp);
break;
}
case DT_UINT32:
{
unsigned int temp;
memcpy(&temp, dp, sizeof(temp));
printf("%u", temp);
break;
}
case DT_FLOAT32:
{
float temp;
memcpy(&temp, dp, sizeof(temp));
snprintf(fbuf, NT_LOC_MAX_FLOAT_BUF,"%f", temp);
clear_float_zeros(fbuf);
printf("%s", fbuf);
break;
}
case DT_FLOAT64:
{
double temp;
memcpy(&temp, dp, sizeof(temp));
snprintf(fbuf, NT_LOC_MAX_FLOAT_BUF,"%f", temp);
clear_float_zeros(fbuf);
printf("%s", fbuf);
break;
}
default:
fprintf(stderr,"** disp_raw_data: unknown type %d\n", type);
return 1;
}
if( c < nvals - 1 ) fputc(space,stdout);
}
if ( newline ) fputc('\n',stdout);
return 0;
}
/*----------------------------------------------------------------------
* remove trailing zeros from string of printed float
* (of a max NT_LOC_MAX_FLOAT_BUF (32) string)
* return 1 if something was cleared
* 0 if not
*----------------------------------------------------------------------*/
int clear_float_zeros( char * str )
{
char * dp = strchr(str, '.'), * valp;
size_t len;
if( !dp ) return 0; /* nothing to clear */
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;
}
/* return the number of volumes in the nifti_image */
static int num_volumes(nifti_image * nim)
{
int ind, nvols = 1;
if( nim->dim[0] < 1 ) return 0;
for( ind = 4; ind <= nim->dim[0]; ind++ )
nvols *= nim->dim[ind];
return nvols;
}
/*----------------------------------------------------------------------
* create a new dataset using sub-brick selection
*----------------------------------------------------------------------*/
int act_cbl( nt_opts * opts )
{
nifti_brick_list NBL;
nifti_image * nim;
char * fname, * selstr, * cp;
int * blist;
int err = 0;
if( g_debug > 2 )
fprintf(stderr,"-d copying file info from '%s' to '%s'\n",
opts->infiles.list[0], opts->prefix);
/* sanity checks */
if( ! opts->prefix ) {
fprintf(stderr,"** error: -prefix is required with -cbl function\n");
return 1;
} else if( opts->infiles.len > 1 ) {
fprintf(stderr,"** sorry, at the moment -cbl allows only 1 input\n");
return 1;
}
/* remove selector from fname, and copy selector string */
fname = nifti_strdup(opts->infiles.list[0]);
cp = strchr(fname,'['); if( !cp ) cp = strchr(fname,'{');
if( !cp ) {
if( g_debug > 1 )
fprintf(stderr,"-d using -cbl without brick list in '%s'\n",fname);
selstr = nifti_strdup("[0..$]");
} else {
selstr = nifti_strdup(cp);
*cp = '\0'; /* remove selection string from fname */
}
if( g_debug > 1 )
fprintf(stderr,"+d -cbl: using '%s' for selection string\n", selstr);
nim = nt_image_read(opts, fname, 0); /* get image */
if( !nim ) return 1;
/* since nt can be zero now (sigh), check for it 02 Mar 2006 [rickr] */
blist = nifti_get_intlist(nim->nt > 0 ? num_volumes(nim) : 1, selstr);
nifti_image_free(nim); /* throw away, will re-load */
if( !blist ){
fprintf(stderr,"** failed sub-brick selection using '%s'\n",selstr);
free(fname); free(selstr); return 1;
}
nim = nt_read_bricks(opts, fname, blist[0], blist+1, &NBL);
free(blist); /* with this */
if( !nim ){ free(fname); free(selstr); return 1; }
if( g_debug > 1 ) fprintf(stderr,"+d sub-bricks loaded\n");
/* add command as COMMENT extension */
if( opts->keep_hist && nifti_add_extension(nim, opts->command,
(int)strlen(opts->command), NIFTI_ECODE_COMMENT) )
fprintf(stderr,"** failed to add command to image as extension\n");
/* replace filenames using prefix */
if( nifti_set_filenames(nim, opts->prefix, 1, 1) )
{
fprintf(stderr,"** failed to set names, prefix = '%s'\n",opts->prefix);
err++;
}
if(g_debug>2) disp_field("new nim:\n",g_nim_fields,nim,NT_NIM_NUM_FIELDS,1);
/* and finally, write out results */
if( err == 0 && nifti_nim_is_valid(nim, g_debug) )
nifti_image_write_bricks(nim, &NBL);
nifti_image_free(nim);
nifti_free_NBL(&NBL);
free(fname);
free(selstr);
return 0;
}
/*----------------------------------------------------------------------
* create a new dataset using read_collapsed_image
*----------------------------------------------------------------------*/
int act_cci( nt_opts * opts )
{
nifti_image * nim;
int c;
if( g_debug > 2 )
fprintf(stderr,"-d collapsing file info from '%s' to '%s'\n",
opts->infiles.list[0], opts->prefix);
/* sanity checks */
if( ! opts->prefix ) {
fprintf(stderr,"** error: -prefix is required with -cci function\n");
return 1;
} else if( opts->infiles.len > 1 ) {
fprintf(stderr,"** sorry, at the moment -cci allows only 1 input\n");
return 1;
}
nim = nt_image_read(opts, opts->infiles.list[0], 0);
if( !nim ) return 1;
nim->data = NULL; /* just to be sure */
if( nifti_read_collapsed_image(nim, opts->ci_dims, &nim->data) < 0 )
{
nifti_image_free(nim);
return 1;
}
/* add command as COMMENT extension */
if( opts->keep_hist && nifti_add_extension(nim, opts->command,
(int)strlen(opts->command), NIFTI_ECODE_COMMENT) )
fprintf(stderr,"** failed to add command to image as extension\n");
/* replace filenames using prefix */
if( nifti_set_filenames(nim, opts->prefix, 1, 1) )
{
fprintf(stderr,"** failed to set names, prefix = '%s'\n",opts->prefix);
nifti_image_free(nim);
return 1;
}
for( c = 1; c < 8; c++ ) /* nuke any collapsed dimension */
if( opts->ci_dims[c] >= 0 ) nim->dim[c] = 1;
nifti_update_dims_from_array(nim);
if(g_debug>2) disp_field("new nim:\n",g_nim_fields,nim,NT_NIM_NUM_FIELDS,1);
/* and finally, write out results */
if( nifti_nim_is_valid(nim, g_debug) ) {
if( nifti_image_write_status(nim) ) {
fprintf(stderr,"** failed to write image %s\n", nim->fname);
nifti_image_free(nim);
return 1;
}
}
nifti_image_free(nim);
return 0;
}
/*----------------------------------------------------------------------
* free all of the lists in the struct
* note: strings were not allocated
*----------------------------------------------------------------------*/
static int free_opts_mem( nt_opts * nopt )
{
if( !nopt ) return 1;
if( nopt->elist.list ) free(nopt->elist.list);
if( nopt->etypes.list ) free(nopt->etypes.list);
if( nopt->flist.list ) free(nopt->flist.list);
if( nopt->vlist.list ) free(nopt->vlist.list);
if( nopt->infiles.list ) free(nopt->infiles.list);
return 0;
}
/*----------------------------------------------------------------------
* wrapper for nifti_image_read
*
* this adds the option to generage an empty image, if the
* filename starts with "MAKE_IM"
*----------------------------------------------------------------------*/
nifti_image * nt_image_read( nt_opts * opts, const char * fname, int doread )
{
if( !opts || !fname ) {
fprintf(stderr,"** nt_image_read: bad params (%p,%p)\n",
(void *)opts, (const void *)fname);
return NULL;
}
/* if the user does not want an empty image, do normal image_read */
if( strncmp(fname,NT_MAKE_IM_NAME,strlen(NT_MAKE_IM_NAME)) ) {
if(g_debug > 1)
fprintf(stderr,"-d calling nifti_image_read(%s,%d)\n",fname,doread);
return nifti_image_read(fname, doread);
}
/* so generate an empty image */
if(g_debug > 1) {
fprintf(stderr,"+d NT_IR: generating EMPTY IMAGE from %s...\n",fname);
if(g_debug > 2) {
printf(" new_dim[8] = ");
disp_raw_data(opts->new_dim, DT_INT32, 8, ' ', 1);
printf(" new_datatype = %d\n", opts->new_datatype);
fflush(stdout);
}
}
/* create a new nifti_image, with data depending on doread */
return nifti_make_new_nim(opts->new_dim, opts->new_datatype, doread);
}
/*----------------------------------------------------------------------
* wrapper for nifti_read_header
*
* this adds the option to generage an empty image, if the
* filename starts with "MAKE_IM"
*----------------------------------------------------------------------*/
nifti_1_header * nt_read_header(nt_opts * opts, const char * fname, int * swapped,
int check)
{
/* swapped is not necessary */
if( !opts || !fname ) {
fprintf(stderr,"** nt_read_header: bad params (%p,%p)\n",
(void *)opts,(const void *)fname);
return NULL;
}
/* if the user does not want an empty image, do normal image_read */
if( strncmp(fname,NT_MAKE_IM_NAME,strlen(NT_MAKE_IM_NAME)) ) {
if(g_debug > 1)
fprintf(stderr,"-d calling nifti_read_header(%s,...)\n", fname);
return nifti_read_header(fname, swapped, check);
}
/* so generate an empty image */
if(g_debug > 1) {
fprintf(stderr,"+d NT_RH: generating EMPTY IMAGE from %s...\n",fname);
if(g_debug > 2) {
printf(" new_dim[8] = ");
disp_raw_data(opts->new_dim, DT_INT32, 8, ' ', 1);
printf(" new_datatype = %d\n", opts->new_datatype);
fflush(stdout);
}
}
/* return creation of new header */
return nifti_make_new_header(opts->new_dim, opts->new_datatype);
}
/*----------------------------------------------------------------------
* wrapper for nifti_read_header
*
* this adds the option to generage an empty image, if the
* filename starts with "MAKE_IM"
*----------------------------------------------------------------------*/
nifti_image * nt_read_bricks(nt_opts * opts, const char * fname, int len, int * list,
nifti_brick_list * NBL)
{
nifti_image * nim;
int c;
/* swapped is not necessary */
if( !opts || !fname || !NBL ) {
fprintf(stderr,"** nt_read_bricks: bad params (%p,%p,%p)\n",
(void *)opts, (const void *)fname, (void *)NBL);
return NULL;
}
/* if the user does not want an empty image, do normal read_bricks */
if( strncmp(fname,NT_MAKE_IM_NAME,strlen(NT_MAKE_IM_NAME)) ) {
if(g_debug > 1)
fprintf(stderr,"-d calling nifti_image_read_bricks(%s,...)\n",fname);
return nifti_image_read_bricks(fname, len, list, NBL);
}
/* so generate an empty image */
if(g_debug > 1) {
fprintf(stderr,"+d NT_RB: generating EMPTY IMAGE from %s...\n",fname);
if(g_debug > 2) {
printf(" new_dim[8] = ");
disp_raw_data(opts->new_dim, DT_INT32, 8, ' ', 1);
printf(" new_datatype = %d\n", opts->new_datatype);
if( list && len > 0 ) {
printf(" brick_list[%d] = ", len);
disp_raw_data(list, DT_INT32, len, ' ', 1);
}
fflush(stdout); /* disp_raw_data uses stdout */
}
}
/* first, get nim struct without data */
nim = nifti_make_new_nim(opts->new_dim, opts->new_datatype, 0);
if( !nim ) {
fprintf(stderr,"** nt_read_bricks, nifti_make_new_nim failure\n");
return NULL;
}
/* now populate NBL (can be based only on len and nim) */
NBL->nbricks = len;
NBL->bsize = (size_t)nim->nbyper * nim->nx * nim->ny * nim->nz;
NBL->bricks = (void **)calloc(NBL->nbricks, sizeof(void *));
if( !NBL->bricks ){
fprintf(stderr,"** NRB: failed to alloc %d pointers\n",NBL->nbricks);
nifti_image_free(nim);
return NULL;
}
if(g_debug > 1)
fprintf(stderr,"+d NRB, allocating %d bricks of %u bytes...\n",
NBL->nbricks, (unsigned)NBL->bsize);
/* now allocate the data pointers */
for( c = 0; c < len; c++ ) {
NBL->bricks[c] = calloc(1, NBL->bsize);
if( !NBL->bricks[c] ){
fprintf(stderr,"** NRB: failed to alloc brick %d of %u bytes\n",
c, (unsigned)NBL->bsize);
nifti_free_NBL(NBL); nifti_image_free(nim); return NULL;
}
}
return nim;
}