1 /*----------------------------------------------------------------------
2 * 19 May 2006: top-level routines to read NIML datasets [rickr]
3 * routines to process NI_SURF_DSET datasets
4 *----------------------------------------------------------------------
5 */
6 #include "mrilib.h"
7 #include "suma_objs.h" /* 21 Apr 2020 */
8 /*------------------------------------------------------------*/
9
10 /* globals to control I/O of niml data 3 Aug 2006 [rickr] */
11 typedef struct {
12 int add_nodes; /* add to output (AFNI_NSD_ADD_NODES == Y) */
13 int debug; /* debug level (AFNI_NIML_DEBUG level) */
14 int to_float; /* convert to float (AFNI_NSD_TO_FLOAT == Y) */
15 int write_mode; /* NI_TEXT_MODE (AFNI_NIML_TEXT_DATA == Y) */
16 } ni_globals;
17 static ni_globals gni = /* default values for globals */
18 {
19 0, /* add_nodes */
20 0, /* debug */
21 0, /* to_float */
22 NI_BINARY_MODE /* write_mode */
23 };
24
25 static int nsd_are_sorted_ints(int *, int);
26 static int loc_append_vals(char **, int *, char *, float, float, int, int);
27 static char * my_strndup(char *, int);
28 static int nsd_add_colms_range(NI_group *, THD_3dim_dataset *);
29 static char * afni2suma_typestring(int afnitype);
30 static int nsd_add_colms_type(int, int ctp, NI_group *);
31 static int nsd_add_sparse_data(NI_group *, THD_3dim_dataset *);
32 static int nsd_add_str_atr_to_group(char*, char*, THD_datablock*, NI_group*);
33 static int nsd_add_atr_to_group(char*, char*, THD_datablock*, NI_group*);
34 static int nsd_fill_index_list(NI_group *, THD_3dim_dataset *);
35 static int process_NSD_attrs(THD_3dim_dataset *);
36 static int process_NSD_labeltable(NI_group * ngr, THD_3dim_dataset *dset);
37 static int process_NSD_group_attrs(NI_group *, THD_3dim_dataset *);
38 static int process_NSD_index_list(NI_group *, THD_datablock *);
39 static int process_NSD_sparse_data(NI_group *, THD_3dim_dataset *);
40
41 static NI_group * nsd_pad_to_node(NI_group * ngr);
42
43 /* list of AFNI_dataset group attributes to copy along */
44 static char * ni_surf_dset_attrs[] = {
45 "label",
46 "domain_parent_idcode",
47 "geometry_parent_idcode",
48 "sorted_node_def"
49 };
50
51 #define NOTYPE_GET_MIN_MAX_POSN(data,len,min,minp,max,maxp) \
52 do { int ii; \
53 min=max=data[0]; minp=maxp=0; \
54 for(ii = 1; ii < len; ii++) \
55 if(data[ii]<min){ min=data[ii]; minp=ii; } \
56 else if(data[ii]>max){ max=data[ii]; maxp=ii; } \
57 } while (0)
58
59 #define NOTYPE_GETC_MIN_MAX_POSN(data,len,min,minp,max,maxp,phase) \
60 do { int ii; double dd; \
61 if (phase) min=max=CARG(data[0]); \
62 else min=max=CABS(data[0]); \
63 minp=maxp=0; \
64 for(ii = 1; ii < len; ii++){ \
65 if (phase) dd=CARG(data[ii]); \
66 else dd=CABS(data[ii]); \
67 if(dd<min){ min=dd; minp=ii; } \
68 else if(dd>max){ max=dd; maxp=ii; } \
69 } \
70 } while (0)
71
72 /* do not assume the dataset is of type MRI_float 4 Aug 2006 [rickr] */
get_blk_min_max_posn(THD_datablock * blk,int ind,int len,float * fmin,int * imin,float * fmax,int * imax)73 static int get_blk_min_max_posn(THD_datablock * blk, int ind, int len,
74 float * fmin, int * imin, float * fmax, int * imax)
75 {
76 float ffac = DBLK_BRICK_FACTOR(blk,ind);
77 static int iwarn = 0;
78
79 ENTRY("get_blk_min_max_posn");
80
81 if( ffac == 0.0 ) ffac = 1.0;
82
83 switch(DBLK_BRICK_TYPE(blk, ind)){
84 default:{
85 if (!iwarn) {
86 fprintf(stderr,"** GBMMP, bad or unsupported dtype %d\n"
87 "Similar warnings will be muted.\n",
88 DBLK_BRICK_TYPE(blk, ind));
89 ++iwarn;
90 }
91 *fmin = *fmax = 0.0; *imin = *imax = 0;
92 break;
93 }
94 case MRI_byte:
95 {
96 byte * data = DBLK_ARRAY(blk,ind);
97 byte min, max;
98 int minp, maxp;
99 NOTYPE_GET_MIN_MAX_POSN(data,len,min,minp,max,maxp);
100 *fmin = min*ffac; *fmax = max*ffac;
101 *imin = minp; *imax = maxp;
102 break;
103 }
104 case MRI_short:
105 {
106 short * data = DBLK_ARRAY(blk,ind);
107 short min, max;
108 int minp, maxp;
109 NOTYPE_GET_MIN_MAX_POSN(data,len,min,minp,max,maxp);
110 *fmin = min*ffac; *fmax = max*ffac;
111 *imin = minp; *imax = maxp;
112 break;
113 }
114 case MRI_int:
115 {
116 int * data = DBLK_ARRAY(blk,ind);
117 int min, max;
118 int minp, maxp;
119 NOTYPE_GET_MIN_MAX_POSN(data,len,min,minp,max,maxp);
120 *fmin = min*ffac; *fmax = max*ffac;
121 *imin = minp; *imax = maxp;
122 break;
123 }
124 case MRI_float:
125 {
126 float * data = DBLK_ARRAY(blk,ind);
127 float min, max;
128 int minp, maxp;
129 NOTYPE_GET_MIN_MAX_POSN(data,len,min,minp,max,maxp);
130 *fmin = min*ffac; *fmax = max*ffac;
131 *imin = minp; *imax = maxp;
132 break;
133 }
134 case MRI_double:
135 {
136 double * data = DBLK_ARRAY(blk,ind);
137 double min, max;
138 int minp, maxp;
139 NOTYPE_GET_MIN_MAX_POSN(data,len,min,minp,max,maxp);
140 *fmin = min*ffac; *fmax = max*ffac;
141 *imin = minp; *imax = maxp;
142 break;
143 }
144 case MRI_complex:
145 {
146 complex * data = DBLK_ARRAY(blk,ind);
147 double min, max;
148 int minp, maxp;
149 NOTYPE_GETC_MIN_MAX_POSN(data,len,min,minp,max,maxp,0);
150 *fmin = min*ffac; *fmax = max*ffac;
151 *imin = minp; *imax = maxp;
152 break;
153 }
154 }
155
156 RETURN(0);
157 }
158
159 /*----------------------------------------------------------------------*/
160 /*! Open a NIML file as an AFNI dataset.
161
162 - read as niml
163 *----------------------------------------------------------------------
164 */
THD_open_niml(char * fname)165 THD_3dim_dataset * THD_open_niml( char * fname )
166 {
167 THD_3dim_dataset * dset = NULL;
168 void * nel;
169 int smode;
170
171 ENTRY("THD_open_niml");
172
173 set_ni_globs_from_env(); /* 3 Aug 2006 [rickr] */
174
175 nel = read_niml_file(fname, 1); /* we need data for node_indices */
176 if( !nel ){
177 STATUS("read_niml_file returned NULL") ;
178 RETURN(NULL);
179 }
180
181 smode = storage_mode_from_niml(nel);
182 STATUSi("smode from niml",smode) ;
183 switch( smode )
184 {
185 case STORAGE_BY_3D:
186 STATUS("STORAGE_BY_3D") ;
187 NI_free_element_data(nel); /* nuke all data */
188 dset = THD_niml_3D_to_dataset(nel, fname);
189 if(gni.debug) fprintf(stderr,"-d opening 3D dataset '%s'\n",fname);
190 if( !dset && gni.debug )
191 fprintf(stderr,
192 "** THD_niml_3D_to_dataset failed on '%s'\n",fname);
193 break;
194
195 case STORAGE_BY_NIML:
196 STATUS("STORAGE_BY_NIML") ;
197 NI_free_element_data(nel); /* nuke all data */
198 if(gni.debug)fprintf(stderr,"-d opening NIML dataset '%s'\n",fname);
199 dset = THD_niml_to_dataset(nel, 1); /* no data */
200 if( !dset && gni.debug )
201 fprintf(stderr,"** THD_niml_to_dataset failed on '%s'\n",fname);
202 break;
203
204 case STORAGE_BY_NI_SURF_DSET:
205 STATUS("STORAGE_BY_NI_SURF_DSET") ;
206 if(gni.debug)fprintf(stderr,"-d opening NI_SURF_DSET '%s'\n",fname);
207 dset = THD_ni_surf_dset_to_afni(nel, 0); /* no data */
208 break;
209
210 default:
211 STATUS("Unknown smode :(") ;
212 if( gni.debug )
213 fprintf(stderr,"** unknown storage mode for '%s'\n", fname);
214 break;
215 }
216
217 NI_free_element(nel);
218
219 if( dset )
220 {
221 char * pp = THD_trailname(fname, 0);
222 STATUS("setting prefix etc") ;
223 EDIT_dset_items(dset, ADN_prefix, pp, ADN_none);
224 NI_strncpy(dset->dblk->diskptr->brick_name, fname, THD_MAX_NAME);
225 THD_set_storage_mode(dset, smode);
226 if(gni.debug > 1) fprintf(stderr,"+d success for dataset '%s'\n",fname);
227 }
228
229 RETURN(dset);
230 }
231
232
233 /*----------------------------------------------------------------------*/
234 /*! Open a NIML file as an AFNI dataset.
235
236 - read as niml
237 *----------------------------------------------------------------------
238 */
THD_load_niml(THD_datablock * dblk)239 int THD_load_niml( THD_datablock * dblk )
240 {
241 void * nel;
242 char * fname;
243 int smode, rv;
244
245 ENTRY("THD_load_niml");
246
247 if( !dblk || !dblk->diskptr || !dblk->diskptr->brick_name )
248 RETURN(1);
249
250 fname = dblk->diskptr->brick_name;
251 smode = dblk->diskptr->storage_mode;
252
253 if( gni.debug > 1 )
254 fprintf(stderr,"-d THD_load_niml: file %s, smode %d\n", fname, smode);
255
256 switch( smode )
257 {
258 case STORAGE_BY_3D:
259 if(gni.debug) fprintf(stderr,"-d loading 3D dataset '%s'\n",fname);
260 THD_load_3D(dblk);
261 break;
262 case STORAGE_BY_NIML:
263 if(gni.debug)fprintf(stderr,"-d loading NIML dataset '%s'\n",fname);
264 nel = read_niml_file(fname, 1); /* read in data now */
265 if( !nel ){
266 fprintf(stderr,"** failed to load niml file '%s'\n",fname);
267 RETURN(1);
268 }
269 rv = THD_add_bricks(dblk->parent, nel, NULL);
270 NI_free_element(nel); /* in any case */
271 if( rv <= 0 ){
272 fprintf(stderr,"** add bricks returned %d for '%s'\n",rv,fname);
273 RETURN(1);
274 }
275 else if( rv < dblk->nvals ){
276 fprintf(stderr,"** loaded only %d bricks for '%s'\n",rv,fname);
277 RETURN(1);
278 }
279 break;
280 case STORAGE_BY_NI_SURF_DSET:
281 if(gni.debug)fprintf(stderr,"-d loading NI_SURF_DSET '%s'\n",fname);
282 nel = read_niml_file(fname, 1); /* read in data now */
283 if( !nel ){
284 fprintf(stderr,"** failed to load NI_SURF_DSET '%s'\n",fname);
285 RETURN(1);
286 }
287 rv = THD_add_sparse_data(dblk->parent, nel);
288 NI_free_element(nel); /* in any case */
289 if( rv <= 0 ){
290 fprintf(stderr,"** add sdata returned %d for '%s'\n",rv,fname);
291 RETURN(1);
292 }
293 else if( rv < dblk->nvals ){
294 fprintf(stderr,"** loaded only %d vols for '%s'\n",rv,fname);
295 RETURN(1);
296 }
297 break;
298 default:
299 fprintf(stderr,"** cannot load NIML dataset '%s' of mode %d\n",
300 fname, smode);
301 break;
302 }
303
304 RETURN(0);
305 }
306
307
308 /*----------------------------------------------------------------------*/
309 /*! try to deduce the STORAGE mode from the niml data
310
311 tested modes are:
312 STORAGE_BY_3D
313 element, AFNI_3D_dataset
314 STORAGE_BY_NIML
315 group, AFNI_dataset
316 THD_niml_to_dataset()
317 ngr->part[i]->name == "VOLUME_DATA"
318 STORAGE_BY_NI_SURF_DSET
319 ----------------------------------------------------------------------*/
storage_mode_from_niml(void * nini)320 int storage_mode_from_niml( void * nini )
321 {
322 int ni_type;
323
324 ENTRY("storage_mode_from_niml");
325
326 ni_type = NI_element_type( nini );
327
328 if( ni_type == NI_ELEMENT_TYPE ) /* can only be 3D */
329 {
330 NI_element * nel = (NI_element *)nini;
331 if( ! strcmp(nel->name, "AFNI_3D_dataset") )
332 RETURN(STORAGE_BY_3D);
333
334 /* cannot deal with simple niml "3dVol2Surf_dataset", yet */
335
336 if(gni.debug)
337 fprintf(stderr,"** SMFN: unknown NI_element %s\n", nel->name);
338 }
339 else if( ni_type == NI_GROUP_TYPE ) /* AFNI or SUMA */
340 {
341 NI_group * ng = (NI_group *)nini;
342 char * atr;
343 if( ! strcmp(ng->name, "AFNI_dataset") )
344 {
345 atr = NI_get_attribute(ng, "dset_type");
346 if( atr &&
347 ( !strcmp(atr, "Node_Bucket") ||
348 !strcmp(atr, "Node_ROI") ||
349 !strcmp(atr, "Node_Label") ||
350 !strcmp(atr, "Voxel_Bucket")|| /* 5 Aug 2015 [rickr] */
351 !strcmp(atr, "Graph_Bucket")) ) /* then SUMA DSET */
352 RETURN(STORAGE_BY_NI_SURF_DSET);
353 RETURN(STORAGE_BY_NIML); /* else assume AFNI */
354 } else if ( ! strcmp(ng->name, "bundle") )
355 {
356 RETURN(STORAGE_BY_NI_TRACT);
357 }
358 else if(gni.debug)
359 fprintf(stderr,"** SMFN: NI_group, but bad name '%s'\n",ng->name);
360 }
361 else if(gni.debug) fprintf(stderr,"** SMFN: bad ni_type %d\n",ni_type);
362
363 RETURN(STORAGE_UNDEFINED);
364 }
365
366 #undef MY_BUFSIZE
367 #define MY_BUFSIZE (1024*1024*16) /* 21 Nov 2007 */
368
369 /*! inhale any NIML data within a file */
read_niml_file(char * fname,int get_data)370 void * read_niml_file( char * fname, int get_data )
371 {
372 NI_stream ns;
373 NI_element * nel;
374 char * nname;
375 int read_head_only_state=0;
376 ENTRY("read_niml_file");
377 STATUSs("filename",fname) ;
378
379 if( !fname || !*fname )
380 {
381 if(gni.debug) fprintf(stderr,"** read_niml_file: empty filename\n");
382 RETURN(NULL);
383 }
384
385 /* set the stream name */
386 nname = (char *)calloc(sizeof(char), strlen(fname)+10);
387 strcpy(nname, "file:");
388 strcat(nname, fname);
389
390 /* open the stream */
391 ns = NI_stream_open(nname, "r");
392 free(nname);
393 if( !ns )
394 {
395 if(gni.debug)fprintf(stderr,"** RNF: failed to open file '%s'\n",fname);
396 STATUS("read_niml_file failed to open") ;
397 RETURN(NULL);
398 }
399
400 if( get_data && NI_stream_getbufsize(ns) < MY_BUFSIZE ) /* 21 Nov 2007: RWCox */
401 NI_stream_setbufsize(ns,MY_BUFSIZE) ;
402
403 /* read the file */
404 read_head_only_state = NI_get_read_header_only();
405 NI_skip_procins(1); NI_set_read_header_only(!get_data);
406 nel = NI_read_element(ns, 333);
407 NI_skip_procins(0); NI_set_read_header_only(read_head_only_state);
408 if( nel == NULL ) STATUS("failed to read NIML data") ;
409
410 /* close the stream */
411 NI_stream_close(ns);
412
413 /* possibly check the results */
414 if(gni.debug && !nel) fprintf(stderr,"** RNF: failed to read '%s'\n",fname);
415 else if(gni.debug>1) fprintf(stderr,"+d success for niml file %s\n",fname);
416
417 RETURN(nel);
418 }
419
420
421 /*! write NIML data to a file */
write_niml_file(char * fname,NI_group * ngr)422 int write_niml_file( char * fname, NI_group * ngr )
423 {
424 NI_stream ns;
425 char * str_name;
426
427 ENTRY("write_niml_file");
428
429 if( !fname || !ngr ){
430 fprintf(stderr,"** write_niml_file: empty parameters\n");
431 RETURN(1);
432 }
433
434 /* set the output stream name (5 for 'file:' and 1 for '\0') */
435 str_name = (char *)malloc((strlen(fname)+6) * sizeof(char) );
436 strcpy(str_name, "file:");
437 strcat(str_name, fname);
438
439 ns = NI_stream_open(str_name, "w");
440 free(str_name); /* lose this either way */
441
442 if( !ns ){
443 fprintf(stderr,"** cannot open NIML stream for file '%s'\n", fname);
444 RETURN(1);
445 }
446
447 if( NI_write_element( ns, ngr, NI_TEXT_MODE ) <= 0 ){
448 fprintf(stderr,"** failed to write NIML output file '%s'\n", fname);
449 RETURN(1);
450 }
451
452 NI_stream_close(ns); /* close the stream */
453
454 RETURN(0);
455 }
456
457 /*! write NIML data to a stream
458 * (same as write_niml_file, but do not convert file to a stream)
459 * [10 Oct 2019 rickr] */
write_niml_stream(char * stream,NI_group * ngr)460 int write_niml_stream( char * stream, NI_group * ngr )
461 {
462 NI_stream ns;
463
464 ENTRY("write_niml_stream");
465
466 if( !stream || !ngr ){
467 fprintf(stderr,"** write_niml_stream: empty parameters\n");
468 RETURN(1);
469 }
470
471 ns = NI_stream_open(stream, "w");
472
473 if( !ns ){
474 fprintf(stderr,"** cannot open NIML stream '%s'\n", stream);
475 RETURN(1);
476 }
477
478 if( NI_write_element( ns, ngr, NI_TEXT_MODE ) <= 0 ){
479 fprintf(stderr,"** failed to write NIML output stream '%s'\n", stream);
480 RETURN(1);
481 }
482
483 NI_stream_close(ns); /* close the stream */
484
485 RETURN(0);
486 }
487
488
489 /*! Write out a NIML dataset (3D, NIML, NI_SURF_DSET).
490 Return True or False, based on success.
491 */
THD_write_niml(THD_3dim_dataset * dset,int write_data)492 RwcBoolean THD_write_niml( THD_3dim_dataset * dset, int write_data )
493 {
494 NI_group * ngr;
495 char * prefix, * outfile;
496 int smode, rv;
497 ENTRY("THD_write_niml");
498
499 set_ni_globs_from_env();
500 prefix = DSET_PREFIX(dset);
501 outfile = DSET_HEADNAME(dset);
502
503 if( !outfile ) {
504 if(gni.debug) fprintf(stderr,"** THD_write_niml: no dset headname\n");
505 RETURN(False);
506 }
507
508 smode = storage_mode_from_filename(outfile);
509 if( gni.debug )
510 fprintf(stderr,"-d THD_write_niml: file %s, smode %d\n",outfile,smode);
511
512 switch(smode)
513 {
514 case STORAGE_BY_3D:
515 THD_write_3D(NULL, NULL, dset);
516 break;
517
518 case STORAGE_BY_NIML:
519 if( write_data ) ngr = THD_dataset_to_niml(dset);
520 else ngr = THD_nimlize_dsetatr(dset);
521 if( !ngr ){
522 fprintf(stderr,"** failed dset to niml on '%s'\n", outfile);
523 RETURN(False);
524 }
525 NI_rename_group(ngr, "AFNI_dataset");
526 NI_set_attribute(ngr, "self_prefix", prefix);
527 rv = write_niml_file(outfile, ngr);
528 NI_free_element(ngr); /* either way */
529 if( rv ){
530 fprintf(stderr,"** write_niml_file failed for '%s'\n",outfile);
531 RETURN(False);
532 }
533 break;
534
535 case STORAGE_BY_NI_SURF_DSET:
536 ngr = THD_dset_to_ni_surf_dset(dset, write_data);
537 if( !ngr )
538 {
539 fprintf(stderr,"** failed dset to ni_SD on '%s'\n",outfile);
540 RETURN(False);
541 }
542 rv = write_niml_file(outfile, ngr);
543 NI_free_element(ngr); /* either way */
544 if( rv ){
545 fprintf(stderr,"** write_niml_file failed for '%s'\n",outfile);
546 RETURN(False);
547 }
548 break;
549
550 default:
551 fprintf(stderr,"** invalid storage mode %d to write '%s'\n",
552 smode, outfile);
553 RETURN(False);
554 break;
555 }
556
557 RETURN(True);
558 }
559
560 /*! Write a NIML heaer (3D, NIML, NI_SURF_DSET) to a text stream
561 if by_smode: allow for this to vary based on storage mode
562 (which will generally require adding some code...)
563 Return True or False, based on success. [10 Oct 2019 rickr]
564 */
THD_write_niml_to_stream(THD_3dim_dataset * dset,char * stream,int by_smode)565 RwcBoolean THD_write_niml_to_stream( THD_3dim_dataset * dset, char * stream,
566 int by_smode )
567 {
568 NI_group * ngr;
569 char * prefix;
570 char * func = "THD_write_niml_to_stream";
571 int smode, rv;
572
573 ENTRY("THD_write_niml_to_stream");
574
575 set_ni_globs_from_env();
576
577 if( ! ISVALID_DSET(dset) || ! stream ) {
578 fprintf(stderr,"-d %s: invaliad dset %d or stream %s\n",
579 func, ISVALID_DSET(dset), stream);
580 RETURN(False);
581 }
582
583 prefix = DSET_PREFIX(dset);
584 if( !prefix )
585 prefix = "PIZZA_314159";
586
587 if( by_smode )
588 smode = storage_mode_from_filename(prefix);
589 else
590 smode = STORAGE_BY_NIML;
591
592 if( gni.debug )
593 fprintf(stderr,"-d THD_write_niml_to_stream: %s, smode %d\n",
594 stream, smode);
595
596 switch(smode)
597 {
598 case STORAGE_BY_NI_SURF_DSET:
599 ngr = THD_dset_to_ni_surf_dset(dset, 0);
600 if( !ngr ) {
601 fprintf(stderr,"** failed dset to ni_SD on '%s'\n",prefix);
602 RETURN(False);
603 }
604 break;
605
606 case STORAGE_BY_NIML:
607 default:
608 ngr = THD_nimlize_dsetatr(dset);
609 if( !ngr ){
610 fprintf(stderr,"** failed dset to niml on '%s'\n",prefix);
611 RETURN(False);
612 }
613 break;
614 }
615
616 NI_rename_group(ngr, "AFNI_dataset");
617 NI_set_attribute(ngr, "self_prefix", prefix);
618
619 /* and write to the NI_stream */
620 rv = write_niml_stream(stream, ngr);
621
622 NI_free_element(ngr); /* either way */
623 if( rv ){
624 fprintf(stderr,"** write niml stream failed for '%s'\n", stream);
625 RETURN(False);
626 }
627
628 RETURN(True);
629 }
630
631
632 /*! Convert a string attribute (in NI_SURF_DSET form) to a list of
633 strings. Each element of the list will be allocated here.
634
635 The NI_SURF_DSET form for strings uses ';' to separate them.
636
637 slist pointer to string list - will be allocated
638 llen length of list to be set
639 atr string attribute to get list from
640 (if NULL, strings will get default "#%d")
641
642 return the number of strings found
643 */
nsd_string_atr_to_slist(char *** slist,int llen,ATR_string * atr)644 int nsd_string_atr_to_slist(char *** slist, int llen, ATR_string * atr)
645 {
646 int sind, posn, prev, copy_len;
647 int found = 0;
648
649 ENTRY("nsd_string_atr_to_slist");
650
651 if(!slist || llen < 1)
652 {
653 fprintf(stderr,"** NSATS: bad params\n");
654 RETURN(0);
655 }
656
657 if( !atr ) /* we're outta here */
658 {
659 *slist = NULL;
660 if(gni.debug > 1) fprintf(stderr,"NSATS: no attribute to parse\n");
661 RETURN(0);
662 }
663
664 if(gni.debug > 2)
665 {
666 if( atr ) fprintf(stderr,"+d getting string attrs from %s\n",atr->name);
667 else fprintf(stderr,"+d setting default strings\n");
668 }
669
670 /* allocate memory for the list */
671 *slist = (char **)malloc(llen * sizeof(char *));
672
673 posn = -1;
674 for( sind = 0; sind < llen && posn < atr->nch; sind++ )
675 {
676 /* find end of next string (end with nul or ';') */
677 prev = posn;
678 for( posn = prev+1;
679 posn < atr->nch && atr->ch[posn] && atr->ch[posn] != ';' ;
680 posn++ )
681 ; /* just search */
682
683 if( posn > prev+1 ) /* then we have found some */
684 {
685 copy_len = posn - prev - 1;
686 if( copy_len > THD_MAX_LABEL-1 ) copy_len = THD_MAX_LABEL-1;
687 (*slist)[sind] = my_strndup(atr->ch+prev+1, copy_len);
688 found++;
689
690 if(gni.debug>1)
691 fprintf(stderr,"-d string %d = %s\n",sind,(*slist)[sind]);
692 }
693 else
694 {
695 (*slist)[sind] = (char *)malloc(10 * sizeof(char));
696 sprintf((*slist)[sind], "#%d", sind);
697 }
698 }
699
700 for( ; sind < llen; sind++ )
701 {
702 (*slist)[sind] = (char *)malloc(10 * sizeof(char));
703 sprintf((*slist)[sind], "#%d", sind);
704 }
705
706 if(gni.debug>1) fprintf(stderr,"-d found %d of %d strings\n", found, llen);
707
708 RETURN(found);
709 }
710
711 /*! create an AFNI dataset from a NI_SURF_DSET group */
THD_ni_surf_dset_to_afni(NI_group * ngr,int read_data)712 THD_3dim_dataset * THD_ni_surf_dset_to_afni(NI_group * ngr, int read_data)
713 {
714 THD_3dim_dataset * dset = NULL;
715 int rv;
716
717 ENTRY("THD_ni_surf_dset_to_afni");
718
719 if( !ngr || NI_element_type(ngr) != NI_GROUP_TYPE ) RETURN(NULL);
720
721 dset = EDIT_empty_copy(NULL);
722
723 THD_dblkatr_from_niml(ngr, dset->dblk); /* store NIML attributes in dblk */
724
725 rv = process_NSD_index_list(ngr, dset->dblk); /* INDEX_LIST attr */
726 if( !rv ) rv = process_NSD_sparse_data(ngr, dset); /* SPARSE_DATA attr */
727 if( !rv ) rv = process_NSD_group_attrs(ngr, dset); /* store group attrs */
728 if( !rv ) rv = process_NSD_attrs(dset); /* apply other attrs */
729 if( !rv ) rv = process_NSD_labeltable(ngr, dset); /* get AFNI_labeltable */
730 RETURN(dset);
731 }
732
733 /*
734 Change AFNI_Labeltable, if any, to VALUE_LABEL_DTABLE
735 This is a lossy conversion, colors are not preserved in DTABLE
736 */
737
process_NSD_labeltable(NI_group * ngr,THD_3dim_dataset * dset)738 static int process_NSD_labeltable(NI_group * ngr, THD_3dim_dataset *dset)
739 {
740 NI_element * nel = NULL, * tel;
741 void ** elist = NULL;
742 int ind, ncols, length, c, ii = 0;
743 NI_group * ltg = NULL;
744 float * rgba = NULL;
745 char * cp, *label_table=NULL, sval[32]={""};
746 Dtable *dt = NULL;
747
748 ENTRY("process_NSD_labeltable");
749
750 if( !ngr || !ISVALID_DSET(dset) )
751 {
752 if(gni.debug) fprintf(stderr,"** PNSDLT: bad params\n");
753 RETURN(1);
754 }
755
756 /* find the SPARSE_DATA element of the AFNI_labeltable group */
757 ind = NI_search_group_shallow(ngr, "AFNI_labeltable", &elist);
758 if(ind > 0){ ltg = (NI_group *)elist[0]; NI_free(elist); elist = NULL; }
759 if( !ltg ) { /* not an error, but we are done */
760 if( gni.debug > 0) fprintf(stderr,"-- NSDG: no AFNI_labeltable\n");
761 RETURN(0);
762 }
763
764 ind = NI_search_group_shallow(ltg, "SPARSE_DATA", &elist);
765 if(ind > 0){ nel = (NI_element *)elist[0]; NI_free(elist); elist = NULL; }
766 if( !nel ) { /* probably an error */
767 if(gni.debug > 0)
768 fprintf(stderr,"-- NSDG: AFNI_labeltable: missing SPARSE_DATA\n");
769 RETURN(0);
770 }
771
772 ncols = nel->vec_num;
773 length = nel->vec_len;
774
775 /* verify either 2 or 6 columns */
776 if( ncols != 2 && ncols != 6 ) {
777 fprintf(stderr,"** NIML ALT SData, bad ncols = %d\n", ncols);
778 RETURN(1);
779 }
780 if( length <= 0 ) {
781 fprintf(stderr,"** NIML ALT SData, bad length = %d\n", length);
782 RETURN(1);
783 }
784
785 /* verify COLMS_LABS, if present (2 or 6 columns) */
786 tel = NI_find_element_by_aname(ltg,"AFNI_atr","atr_name","COLMS_LABS");
787 if( tel ) { /* then verify */
788 cp = ((char **)tel->vec[0])[0];
789 if( ncols == 6 ) {
790 if( strcmp(cp, "R;G;B;A;key;name") )
791 fprintf(stderr,"** have ALT CLABS '%s', should be '%s'\n",
792 cp, "R;G;B;A;key;name");
793 } else if( ncols == 2 ) {
794 if( strcmp(cp, "key;name") )
795 fprintf(stderr,"** have ALT CLABS '%s', should be '%s'\n",
796 cp, "key;name");
797 }
798 if(gni.debug>0) fprintf(stderr,"-- SData len %d, COLMS_LABS[%d]='%s'\n",
799 length,ncols,cp);
800 }
801
802 /* verify types: require 4*float,int,String or just int,String */
803
804 ind = 0;
805 if( ncols == 6 ) {
806 if( nel->vec_typ[ind ] != NI_FLOAT32 ||
807 nel->vec_typ[ind+1] != NI_FLOAT32 ||
808 nel->vec_typ[ind+2] != NI_FLOAT32 ||
809 nel->vec_typ[ind+3] != NI_FLOAT32 ) {
810 fprintf(stderr,"** bad types for NIML ALT RGBA\n");
811 RETURN(1);
812 }
813 ind += 4;
814 }
815 if( nel->vec_typ[ind] != NI_INT || nel->vec_typ[ind+1] != NI_STRING ) {
816 fprintf(stderr,"** bad types for NIML ALT key;name\n");
817 RETURN(1);
818 }
819
820 /* if there are colors, get them */
821 if( ncols == 6 ){ if(gni.debug) INFO_message("Colors will be ignored"); }
822 else { rgba = NULL; }
823
824 /* convert to label table */
825 ii = rint(sqrt(2*length+1.0l)) ;
826 if( ii < 7 ) ii = 7 ; else if( ii%2 == 0 ) ii++ ;
827
828 /* make table, insert strings */
829 dt = new_Dtable( ii ) ;
830 for( ii=0 ; ii < length ; ii++ ) {
831 sprintf(sval,"%d", ((int *)nel->vec[ind])[ii]);
832 addto_Dtable( sval , ((char **)nel->vec[ind+1])[ii] , dt ) ;
833 }
834 label_table = Dtable_to_nimlstring(dt, "VALUE_LABEL_DTABLE");
835 destroy_Dtable(dt); dt = NULL;
836 THD_set_string_atr( dset->dblk ,
837 "VALUE_LABEL_DTABLE" , label_table ) ;
838 free(label_table); label_table = NULL;
839
840 RETURN(0);
841 }
842
843
844 /* process any INDEX_LIST attribute, setting nnodes and node_list in
845 the datablock (going from NIML to AFNI)
846 */
process_NSD_index_list(NI_group * ngr,THD_datablock * dblk)847 static int process_NSD_index_list(NI_group * ngr, THD_datablock * dblk )
848 {
849 NI_element * nel = NULL;
850 void ** elist = NULL;
851 int byte_order, nvals;
852
853 ENTRY("process_NSD_index_list");
854
855 if( !ngr || !ISVALID_DBLK(dblk) )
856 {
857 if(gni.debug) fprintf(stderr,"** PNSDIL: bad params\n");
858 RETURN(1);
859 }
860
861 /* grab the any INDEX_LIST element (should be only one) */
862 nvals = NI_search_group_shallow(ngr, "INDEX_LIST", &elist);
863 if( nvals <= 0 )
864 {
865 if( gni.debug ) fprintf(stderr,"-d no INDEX_LIST element\n");
866 RETURN(0);
867 }
868
869 nel = (NI_element *)elist[0]; /* grab first element (only!?) */
870 NI_free(elist); /* and we're done with the list */
871
872 /* make sure this is a single array of ints, else ignore */
873 if( !nel || nel->vec_num != 1 || nel->vec_len <= 0 )
874 {
875 if(gni.debug) fprintf(stderr,"-- empty INDEX_LIST element\n");
876 RETURN(0);
877 }
878
879 if( nel->vec_typ[0] != NI_INT )
880 {
881 if(gni.debug)
882 fprintf(stderr,"** INDEX_LIST has bad type %d\n",nel->vec_typ[0]);
883 RETURN(0);
884 }
885
886 /* note the byte order, in case we need to swap the index bytes */
887 byte_order = NI_get_byte_order(nel);
888 if( byte_order == NATIVE_ORDER ) byte_order = mri_short_order();
889
890 /* and copy the node list */
891 dblk->nnodes = nel->vec_len;
892 dblk->node_list = (int *)RwcMalloc(dblk->nnodes * sizeof(int));
893 memcpy(dblk->node_list, nel->vec[0], dblk->nnodes*sizeof(int));
894 if( byte_order != mri_short_order() )
895 {
896 if(gni.debug > 1) fprintf(stderr,"+d swapping bytes in node list\n");
897 nifti_swap_4bytes(dblk->nnodes, dblk->node_list);
898 }
899
900 if(gni.debug) fprintf(stderr,"+d have node list of len, %d\n",dblk->nnodes);
901
902 RETURN(0);
903 }
904
905 /* initialize the datablock using the SPARSE_DATA NI_SURF_DSET element
906 and possibly the INDEX_LIST element
907
908 (going from NIML to AFNI)
909 */
process_NSD_sparse_data(NI_group * ngr,THD_3dim_dataset * dset)910 static int process_NSD_sparse_data(NI_group * ngr, THD_3dim_dataset * dset )
911 {
912 THD_datablock * blk;
913 THD_diskptr * dkptr;
914 THD_ivec3 nxyz;
915 NI_element * nel = NULL;
916 void ** elist = NULL;
917 float tr;
918 char * rhs;
919 int ind, ncomp, tpafni;
920
921 ENTRY("process_NSD_sparse_data");
922
923 if( !ngr || !ISVALID_DSET(dset) )
924 {
925 if(gni.debug) fprintf(stderr,"** PNSDSD: bad params\n");
926 RETURN(1);
927 }
928 blk = dset->dblk;
929 dkptr = blk->diskptr;
930
931 /* grab the first SPARSE_DATA element (should be only) */
932 ind = NI_search_group_shallow(ngr, "SPARSE_DATA", &elist);
933 if( ind > 0 ) { nel = (NI_element *)elist[0]; NI_free(elist); }
934
935 if(!nel || nel->vec_num <= 0 || nel->vec_len <= 0)
936 {
937 if(gni.debug) fprintf(stderr,"** missing SPARSE_DATA element\n");
938 RETURN(1);
939 }
940
941 /* so nel points to the SPARSE_DATA element */
942
943 if(gni.debug>1)fprintf(stderr,"-d found SPARSE_DATA in NI_SURF_DSET\n");
944
945 /* if we have use ni_form to set the byte_order */
946 dkptr->byte_order = NI_get_byte_order(nel);
947 if( dkptr->byte_order == NATIVE_ORDER )
948 dkptr->byte_order = mri_short_order();
949
950 if(gni.debug>1)
951 fprintf(stderr,"+d using byte order %s\n",
952 BYTE_ORDER_STRING(dkptr->byte_order));
953
954 /* verify that we have "data_type=Node_Bucket_data"
955 acceptable should also be Node_ROI_data but on
956 output, all will become Node_Bucket_data ZSS: Dec 07 */
957 rhs = NI_get_attribute(nel, "data_type");
958 /* added Voxel_Bucket_data, though it is not properly handled
959 (but headed in the right direction) 5 Aug 2015 [rickr] */
960 if( !rhs ||
961 ( strcmp(rhs, "Node_Bucket_data") &&
962 strcmp(rhs, "Node_ROI_data") &&
963 strcmp(rhs, "Node_Label_data") &&
964 strcmp(rhs, "Voxel_Bucket_data") &&
965 strcmp(rhs, "Graph_Bucket_data") ) )
966 {
967 if(gni.debug)
968 fprintf(stderr,"** SPARSE_DATA without data_type "
969 "Node_Bucket_data or Node_ROI_data or Node_Label_data "
970 "or Node_Bucket_data\n");
971 RETURN(1);
972 }
973 if(gni.debug && !strcmp(rhs, "Graph_Bucket_data"))
974 fprintf(stderr,"+d Reading graph data but output will not retain type\n");
975
976 if(!strcmp(rhs, "Voxel_Bucket_data"))
977 fprintf(stderr,"** Voxel_Bucket dataset will be collapsed to 1D...\n");
978
979 /* if we have a node list, verify that it matches the data in length */
980 if( blk->nnodes > 0 && (blk->nnodes != nel->vec_len) )
981 {
982 if( blk->nnodes != nel->vec_len )
983 {
984 fprintf(stderr,"** node list len (%d) != data len (%d)\n",
985 blk->nnodes, nel->vec_len);
986 RETURN(1);
987 }
988 if(gni.debug > 1) fprintf(stderr,"-d length of nodes and data match\n");
989 }
990
991 /* COMPLEX is OK, if all sub-bricks are of the same type */
992 for( ncomp = 0, ind = 0; ind < nel->vec_num; ind++ ) {
993 if (nel->vec_typ[ind] == NI_COMPLEX) ++ncomp;
994 }
995 if (ncomp == nel->vec_num) tpafni = MRI_complex;
996 else tpafni = MRI_float;
997
998 /* node index list is now in INDEX_LIST attribute 29 Aug 2006 [rickr] */
999 for( ind = 0; tpafni == MRI_float && ind < nel->vec_num; ind++ )
1000 if( nel->vec_typ[ind] != NI_FLOAT &&
1001 nel->vec_typ[ind] != NI_INT )
1002 {
1003 fprintf(stderr,"** NI_SURF_DSET has has invalid type %d\n",
1004 nel->vec_typ[ind]);
1005 RETURN(1);
1006 }
1007
1008 /* set nxyz */
1009 nxyz.ijk[0] = nel->vec_len; nxyz.ijk[1] = nxyz.ijk[2] = 1;
1010
1011 if(gni.debug > 1)
1012 fprintf(stderr,
1013 "+d setting datum, nxyz, nvals to %s, %d, %d\n",
1014 tpafni == MRI_float ? "float":"complex" ,
1015 nel->vec_len, nel->vec_num);
1016
1017 EDIT_dset_items(dset,
1018 ADN_datum_all, tpafni,
1019 ADN_nxyz, nxyz,
1020 ADN_nvals, nel->vec_num,
1021 ADN_none );
1022
1023 /*--- check for a ni_timestep attribute ---*/
1024 rhs = NI_get_attribute(nel, "ni_timestep");
1025 if( rhs && nel->vec_num > 1 ) /* then make time dependant */
1026 {
1027 tr = strtod(rhs, NULL);
1028 if(gni.debug > 1) fprintf(stderr,"-d found TR = %f\n", tr);
1029 if( tr <= 0.0 ) tr = 1.0; /* just be safe */
1030 EDIT_dset_items(dset,
1031 ADN_func_type, ANAT_EPI_TYPE,
1032 ADN_ntt , nel->vec_num,
1033 ADN_ttdel , tr,
1034 ADN_tunits , UNITS_SEC_TYPE,
1035 ADN_none);
1036 }
1037
1038 RETURN(0);
1039 }
1040
1041 /* apply known NI_SURF_DSET attributes (niml -> afni) */
process_NSD_attrs(THD_3dim_dataset * dset)1042 static int process_NSD_attrs(THD_3dim_dataset * dset)
1043 {
1044 THD_datablock * blk;
1045 THD_diskptr * dkptr;
1046 THD_ivec3 ori;
1047 THD_fvec3 del, org;
1048 ATR_string * atr_str;
1049 int ind, nvals;
1050
1051 ENTRY("process_NSD_attrs");
1052
1053 /* orientation, grid and origin are meaningless, but apply defaults */
1054
1055 /* set orientation as RAI */
1056 ori.ijk[0] = ORI_R2L_TYPE;
1057 ori.ijk[1] = ORI_A2P_TYPE;
1058 ori.ijk[2] = ORI_I2S_TYPE;
1059
1060 /* set grid spacings to 1 mm, and origin to 0.0 */
1061 del.xyz[0] = del.xyz[1] = del.xyz[2] = 1.0;
1062 org.xyz[0] = org.xyz[1] = org.xyz[2] = 0.0;
1063
1064 blk = dset->dblk;
1065 dkptr = blk->diskptr;
1066
1067 EDIT_dset_items(dset,
1068 ADN_xyzdel, del,
1069 ADN_xyzorg, org,
1070 ADN_xyzorient, ori,
1071 ADN_malloc_type, DATABLOCK_MEM_MALLOC,
1072 ADN_type, HEAD_ANAT_TYPE,
1073 ADN_none);
1074
1075 /* if not time dependant, set as bucket */
1076 if( ! dset->taxis || dset->taxis->ntt <= 1)
1077 EDIT_dset_items(dset, ADN_func_type, ANAT_BUCK_TYPE, ADN_none);
1078
1079 dkptr->storage_mode = STORAGE_BY_NI_SURF_DSET;
1080
1081 /* now process some attributes */
1082
1083 nvals = blk->nvals;
1084
1085 /*--- init and fill any column labels ---*/
1086 atr_str = THD_find_string_atr(blk, "COLMS_LABS");
1087 if( !atr_str ) atr_str = THD_find_string_atr(blk, ATRNAME_BRICK_LABS);
1088 nsd_string_atr_to_slist(&blk->brick_lab, nvals, atr_str);
1089
1090 /*--- init and fill any statistic symbols ---*/
1091 atr_str = THD_find_string_atr(blk , "COLMS_STATSYM");
1092 if( !atr_str ) atr_str = THD_find_string_atr(blk , "BRICK_STATSYM");
1093 if( atr_str ) /* only do this if we have some codes */
1094 {
1095 char **sar ; int scode,np ; float parm[3];
1096 np = nsd_string_atr_to_slist(&sar, nvals, atr_str);
1097 if( sar )
1098 {
1099 for( ind = 0; ind < nvals; ind++ )
1100 {
1101 NI_stat_decode(sar[ind], &scode, parm,parm+1,parm+2 );
1102 if(scode >= AFNI_FIRST_STATCODE && scode <= AFNI_LAST_STATCODE)
1103 {
1104 np = NI_stat_numparam(scode);
1105 THD_store_datablock_stataux(blk, ind, scode, np, parm);
1106 }
1107 free(sar[ind]);
1108 }
1109 free(sar);
1110 }
1111 }
1112
1113 RETURN(0);
1114 }
1115
1116 /* store any attribute in the ni_surf_dset_attrs[] list
1117
1118 - for each attr, if it has a valid rhs, store it
1119 - the self_idcode should be stored separately (as it
1120 will not be copied to a new dataset)
1121
1122 return 0 on success
1123 */
process_NSD_group_attrs(NI_group * ngr,THD_3dim_dataset * dset)1124 static int process_NSD_group_attrs(NI_group * ngr, THD_3dim_dataset * dset )
1125 {
1126 char ** aname;
1127 char * rhs;
1128 int ac, natr;
1129
1130 ENTRY("process_NSD_group_attrs");
1131
1132 natr = sizeof(ni_surf_dset_attrs) / sizeof(char *);
1133
1134 for( ac = 0, aname = ni_surf_dset_attrs; ac < natr; ac++, aname++ )
1135 {
1136 rhs = NI_get_attribute(ngr, *aname);
1137 if( rhs && *rhs )
1138 {
1139 if(gni.debug>1)
1140 fprintf(stderr,"-d found group attr %s = %s\n",*aname,rhs);
1141 THD_set_string_atr(dset->dblk, *aname, rhs);
1142 }
1143 else if(gni.debug>2)
1144 fprintf(stderr,"-d did not find group attr %s\n",*aname);
1145 }
1146
1147 /* idcode: from nel:self_idcode or ni_idcode */
1148 rhs = NI_get_attribute(ngr, "self_idcode");
1149 if( !rhs ) rhs = NI_get_attribute(ngr, "ni_idcode");
1150 if( rhs ) NI_strncpy(dset->idcode.str, rhs, MCW_IDSIZE);
1151 /* else, keep the one from EDIT_empty_copy() */
1152
1153 RETURN(0);
1154 }
1155
1156 /*------------------------------------------------------------------------*/
1157 /*! Load data from the SPARSE_DATA NIML element. 3 Jul 2006 [rickr]
1158 * (adding it to the dataset block)
1159 *
1160 * - Return value is the number of sub-bricks found.
1161 * - Data must be of type float or complex.
1162 * - Free NIML data as it is applied.
1163 *------------------------------------------------------------------------*/
THD_add_sparse_data(THD_3dim_dataset * dset,NI_group * ngr)1164 int THD_add_sparse_data(THD_3dim_dataset * dset, NI_group * ngr )
1165 {
1166 THD_datablock * blk;
1167 NI_element * nel = NULL;
1168 float * data = NULL;
1169 complex * cdata = NULL;
1170 void ** elist = NULL;
1171 int nvals, ind, mind, sub, swap, len, tpo;
1172 int * mlist = NULL; /* master list */
1173
1174 ENTRY("THD_add_sparse_data");
1175
1176 if( !dset || !ngr ) {
1177 if(gni.debug > 1) fprintf(stderr,"** bad params to add_sparse_data\n");
1178 RETURN(0);
1179 }
1180 blk = dset->dblk;
1181 nvals = blk->nvals;
1182
1183 ind = NI_search_group_shallow(ngr, "SPARSE_DATA", &elist);
1184 if( ind > 0 ) { nel = (NI_element *)elist[0]; NI_free(elist); }
1185 if( !nel ) {
1186 if(gni.debug > 1) fprintf(stderr,"-- no SPARSE_DATA to add\n");
1187 RETURN(0);
1188 }
1189
1190 /* if mlist is NULL, no mastery */
1191 if( DBLK_IS_MASTERED(blk) ) mlist = blk->master_ival;
1192
1193 /*-- verify sizes --*/
1194 if( nel->vec_num != nvals )
1195 {
1196 if(gni.debug)
1197 {
1198 fprintf(stderr,"** TASD: vec_num = %d, but nvals = %d\n",
1199 nel->vec_num, nvals);
1200 if( mlist ) fprintf(stderr," (dataset is mastered)\n");
1201 }
1202 if( !mlist ) RETURN(0); /* no mastery means failure here */
1203 }
1204 if( nel->vec_len != DSET_NX(dset) )
1205 {
1206 if(gni.debug) fprintf(stderr,"** TASD: vec_len = %d, but NX = %d\n",
1207 nel->vec_len, DSET_NX(dset));
1208 RETURN(0);
1209 }
1210
1211 /*-- verify types --*/
1212 for( ind = 0; ind < nvals; ind++ )
1213 {
1214 mind = mlist ? mlist[ind] : ind; /* maybe use master index */
1215 if( nel->vec_typ[mind] != NI_FLOAT &&
1216 nel->vec_typ[mind] != NI_INT &&
1217 nel->vec_typ[mind] != NI_COMPLEX)
1218 {
1219 if(gni.debug)
1220 fprintf(stderr,"** TASD: vec[%d] not float or complex\n",mind);
1221 RETURN(0);
1222 }
1223 else if( ! nel->vec[mind] )
1224 {
1225 if(gni.debug) fprintf(stderr,"** TASD: vec[%d] not filled!\n",mind);
1226 RETURN(0);
1227 }
1228 }
1229
1230 /* check for output type */
1231 tpo = DBLK_BRICK_TYPE(blk,0);
1232 if (tpo != MRI_float && tpo != MRI_complex) {
1233 fprintf(stderr,"** TASD: brick not float or complex\n");
1234 RETURN(0);
1235 }
1236
1237 /* check for necessary swapping */
1238 swap = (blk->diskptr->byte_order != mri_short_order());
1239 if(gni.debug>1 && swap) fprintf(stderr,"+d will byte_swap data\n");
1240 len = nel->vec_len;
1241
1242 /*-- we seem to have all of the data, now copy it --*/
1243 sub = 0;
1244 for( ind = 0; ind < nvals; ind++ )
1245 {
1246 mind = mlist ? mlist[ind] : ind; /* maybe use master index */
1247 if (tpo==MRI_float) {
1248 data = (float *)RwcMalloc(len * sizeof(float));
1249 } else {
1250 cdata = (complex *)RwcMalloc(len * sizeof(complex));
1251 }
1252 if(!data && !cdata){
1253 fprintf(stderr,"**ASD alloc fail: %d values\n",len);
1254 RETURN(0);
1255 }
1256 if( nel->vec_typ[mind] == NI_FLOAT ) {
1257 memcpy(data, nel->vec[mind], len * sizeof(float));
1258 if( swap ) nifti_swap_4bytes(len, data);
1259 } else if( nel->vec_typ[mind] == NI_INT ) {/* ZSS: Dec. 07. Note that*/
1260 int *idata=NULL, ii=0; /* int dsets become floats*/
1261 idata = (int *)RwcMalloc(len * sizeof(int));
1262 if(!idata){
1263 fprintf(stderr,"**ASD alloc fail: %d bytes\n",len);
1264 RETURN(0);
1265 }
1266 memcpy(idata, nel->vec[mind], len * sizeof(int));
1267 if( swap ) nifti_swap_4bytes(len, idata);
1268 for(ii=0; ii<len; ++ii) data[ii] = (float)idata[ii];
1269 RwcFree((char*)idata); idata=NULL;
1270 } else if( nel->vec_typ[mind] == NI_COMPLEX ) {
1271 memcpy(cdata, nel->vec[mind], len * sizeof(complex));
1272 /* in AFNI, complex is a float pair struct */
1273 if( swap ) nifti_swap_Nbytes(2*len, sizeof(complex)/2, data);
1274 } else {
1275 fprintf(stderr,"**ASD should never have been here.\n");
1276 RETURN(0);
1277 }
1278 if (tpo == MRI_float) mri_fix_data_pointer(data, DBLK_BRICK(blk,sub));
1279 else mri_fix_data_pointer(cdata, DBLK_BRICK(blk,sub));
1280 sub++;
1281
1282 /* we can only nuke the old stuff if we know we're done with it */
1283 if( !mlist ){ NI_free(nel->vec[mind]); nel->vec[mind] = NULL; }
1284 }
1285
1286 if( DBLK_IS_MASTER_SUBRANGED(blk) )
1287 THD_apply_master_subrange(blk);
1288
1289 RETURN(nvals);
1290 }
1291
1292 /*! convert an AFNI dataset to a NIML group of type NI_SURF_DSET
1293
1294 - set group attributes from ni_surf_dset_attrs
1295 - create SPARSE_DATA element, if requested
1296 - create attributes for COLMS_RANGE, COLMS_LABS, COLMS_TYPE, COLMS_STATSYM
1297 - apply HISTORY_NOTE
1298
1299 */
THD_dset_to_ni_surf_dset(THD_3dim_dataset * dset,int copy_data)1300 NI_group * THD_dset_to_ni_surf_dset( THD_3dim_dataset * dset, int copy_data )
1301 {
1302 THD_datablock * blk;
1303 NI_group * ngr;
1304 int nx, ibr=0;
1305 char name[100]={""};
1306
1307 ENTRY("THD_dset_to_ni_surf_dset");
1308
1309 if( !ISVALID_DSET(dset) ) RETURN(NULL);
1310 blk = dset->dblk;
1311 if( !blk ) RETURN(NULL);
1312 nx = DSET_NVOX(dset); /* I want it all */
1313
1314 if( blk->nnodes > 0 && blk->nnodes != nx ) {
1315 fprintf(stderr,"** datablock nnodes differs from nx %d, %d\n",
1316 blk->nnodes, nx);
1317 RETURN(NULL);
1318 } else if ( blk->nnodes > 0 && !blk->node_list ) {
1319 fprintf(stderr,"** datablock has nnodes but no node_list\n");
1320 RETURN(NULL);
1321 }
1322
1323 THD_set_dataset_attributes(dset); /* load attributes for processing */
1324
1325 /* create group element */
1326 /* All gets forced into Node_Bucket for now */
1327 ngr = NI_new_group_element();
1328 NI_rename_group(ngr, "AFNI_dataset");
1329 if (DSET_NY(dset) == 1) {
1330 NI_set_attribute(ngr, "dset_type", "Node_Bucket");
1331 } else {
1332 NI_set_attribute(ngr, "dset_type", "Voxel_Bucket");
1333 nsd_add_atr_to_group("DATASET_DIMENSIONS", NULL, blk, ngr);
1334 nsd_add_atr_to_group("IJK_TO_DICOM_REAL", NULL, blk, ngr);
1335 nsd_add_atr_to_group("BRICK_FLOAT_FACS", NULL, blk, ngr);
1336 nsd_add_atr_to_group("ORIENT_SPECIFIC", NULL, blk, ngr);
1337 }
1338 NI_set_attribute(ngr, "self_idcode", dset->idcode.str);
1339 NI_set_attribute(ngr, "filename", blk->diskptr->brick_name);
1340
1341 nsd_add_str_atr_to_group("BRICK_LABS", "COLMS_LABS", blk, ngr);
1342 nsd_add_colms_range(ngr, dset);
1343 if (gni.to_float) {
1344 if (DBLK_BRICK_TYPE(blk,0) == MRI_complex) {
1345 nsd_add_colms_type(blk->nvals, DBLK_BRICK_TYPE(blk,0), ngr);
1346 } else {
1347 nsd_add_colms_type(blk->nvals, MRI_float, ngr);
1348 }
1349 } else {
1350 nsd_add_colms_type(blk->nvals, DBLK_BRICK_TYPE(blk,0), ngr);
1351 }
1352 nsd_add_str_atr_to_group("BRICK_STATSYM", "COLMS_STATSYM", blk, ngr);
1353 nsd_add_str_atr_to_group("HISTORY_NOTE", NULL, blk, ngr);
1354 nsd_add_str_atr_to_group("ATLAS_LABEL_TABLE", NULL, blk, ngr);
1355 nsd_add_str_atr_to_group("VALUE_LABEL_DTABLE", NULL, blk, ngr);
1356
1357 for (ibr=0; ibr<DSET_NVALS(dset); ++ibr) {
1358 sprintf(name,"FDRCURVE_%06d",ibr) ;
1359 nsd_add_atr_to_group(name, NULL, blk, ngr);
1360 #if 0
1361 sprintf(name,"MDFCURVE_%06d",ibr) ;
1362 nsd_add_atr_to_group(name, NULL, blk, ngr);
1363 #endif
1364 }
1365
1366 nsd_fill_index_list(ngr, dset); /* add INDEX_LIST */
1367 if( copy_data ) nsd_add_sparse_data(ngr, dset); /* add SPARSE_DATA */
1368
1369 /* maybe pad the node list to a certain level */
1370 ngr = nsd_pad_to_node(ngr);
1371
1372 RETURN(ngr);
1373 }
1374
1375
1376 /*! possibly pad to a certain node index - use SUMA functionality
1377
1378 return NI_group * with any update
1379 */
nsd_pad_to_node(NI_group * ngr)1380 static NI_group * nsd_pad_to_node(NI_group * ngr)
1381 {
1382 SUMA_DSET * sdset, * sdnew;
1383 NI_group * new_nel;
1384 int pad2node = MRILIB_DomainMaxNodeIndex;
1385
1386 ENTRY("nsd_pad_to_node");
1387
1388 if( pad2node < 0 ) RETURN(ngr);
1389
1390 /* so there is something to do */
1391 sdset = SUMA_ngr_2_dset(ngr, 0);
1392 if( !sdset ) {
1393 fprintf(stderr,"** NPTN: failed SUMA_ngr_2_dset for pad2node\n");
1394 RETURN(ngr);
1395 }
1396
1397 if( pad2node == 0 ) {
1398 DSET_MAX_NODE_INDEX(sdset, pad2node);
1399 if( pad2node < 0 ) {
1400 fprintf(stderr,"** failed to get made node index for pad2node\n");
1401 RETURN(ngr);
1402 }
1403 }
1404
1405 if( pad2node <= 0 ) RETURN(ngr);
1406
1407 if(gni.debug > 1) fprintf(stderr,"-- applying pad2node = %d\n",pad2node);
1408
1409 /* make padded copy, steal pointer, free everything */
1410 sdnew = SUMA_PaddedCopyofDset(sdset, pad2node);
1411 if( !sdnew ) {
1412 fprintf(stderr,"** NPTN: failed pad to node %d\n", pad2node);
1413 RETURN(ngr);
1414 }
1415
1416 ngr = sdnew->ngr;
1417 sdnew->ngr = NULL;
1418
1419 SUMA_FreeDset(sdset);
1420 SUMA_FreeDset(sdnew);
1421
1422 RETURN(ngr);
1423 }
1424
1425 /* return the SUMA string corresponding to the AFNI type */
afni2suma_typestring(int afnitype)1426 static char * afni2suma_typestring(int afnitype)
1427 {
1428 switch(afnitype) {
1429 case MRI_byte: return "Generic_Byte;";
1430 case MRI_short: return "Generic_Short;";
1431 case MRI_int: return "Generic_Int;";
1432 case MRI_float: return "Generic_Float;";
1433 case MRI_complex: return "Generic_Complex;";
1434 }
1435
1436 return NULL; /* bad idea? */
1437 }
1438
1439 /*! add a COLMS_TYPE attribute element
1440
1441 return 0 on success
1442 */
nsd_add_colms_type(int nvals,int tp,NI_group * ngr)1443 static int nsd_add_colms_type(int nvals, int tp, NI_group * ngr)
1444 {
1445 NI_element * nel;
1446 char * str, * slist[1]; /* add_column requires a list of strings */
1447 int c, plen;
1448 char * tps;
1449
1450 ENTRY("nsd_add_colms_type");
1451
1452 /* check usage */
1453 if( nvals <= 0 || !ngr ) RETURN(1);
1454
1455 /* create a new string: "Generic_Float;Generic_Float;..." */
1456 if (!(tps = afni2suma_typestring(tp))) { /* ZSS, Nov. 2013 */
1457 fprintf(stderr,
1458 "** Could not determine column equivalent for afni type %d\n",
1459 tp);
1460 RETURN(1);
1461 }
1462
1463 /* rcr - update this with more types (that agree with SUMA) */
1464
1465 plen = (strlen(tps)+1)*nvals + 1;
1466 str = (char *)malloc(plen * sizeof(char));
1467
1468 /* insert first string */
1469 strcpy(str, tps);
1470
1471 /* and then the rest */
1472 for( c = 1; c < nvals; c++ )
1473 strcat(str, tps);
1474
1475 /* remove last ; */
1476 str[strlen(str)-1] = '\0';
1477
1478 /* now add it to the group */
1479 slist[0] = str;
1480 nel = NI_new_data_element("AFNI_atr", 1);
1481 nel->outmode = NI_TEXT_MODE;
1482 NI_set_attribute(nel, "atr_name", "COLMS_TYPE");
1483 NI_add_column(nel, NI_STRING, slist);
1484 NI_add_to_group(ngr, nel);
1485
1486 free(str); /* nuke local copy */
1487
1488 RETURN(0);
1489 }
1490
1491
1492 /* - find the given attribute in the datablock
1493 - put it in a data element
1494 - add it to the group
1495
1496 aname - AFNI attribute name
1497 niname - NIML attribute name (if NULL, use aname)
1498 blk - datablock
1499 ngr - NI_group to insert new element into
1500
1501 ZSS Feb 08: pilfered from THD_nimlize_dsetatr
1502
1503 return 0 on success
1504 */
nsd_add_atr_to_group(char * aname,char * niname,THD_datablock * blk,NI_group * ngr)1505 static int nsd_add_atr_to_group(char * aname, char * niname,
1506 THD_datablock * blk, NI_group * ngr)
1507 {
1508 ATR_any *atr_any ;
1509 ATR_string * atr_str;
1510 NI_element * nel;
1511 char * dest;
1512
1513 ENTRY("nsd_add_atr_to_group");
1514
1515 /* check usage */
1516 if( !aname || !blk || !ngr ) RETURN(1);
1517
1518 atr_any = THD_find_atr(blk, aname);
1519 if( !atr_any ) RETURN(0); /* nothing to add */
1520
1521 if(gni.debug > 1){
1522 fprintf(stderr, "-d adding '%s' atr: ", niname?niname:aname);
1523 }
1524
1525 switch( atr_any->type ){ /* pilfered from THD_nimlize_dsetatr */
1526 case ATR_FLOAT_TYPE:{
1527 ATR_float *atr_flo = (ATR_float *)atr_any ;
1528
1529 nel = NI_new_data_element( "AFNI_atr" , atr_flo->nfl ) ;
1530 nel->outmode = NI_TEXT_MODE ;
1531 NI_set_attribute( nel , "atr_name" , atr_flo->name ) ;
1532 NI_add_column( nel , NI_FLOAT , atr_flo->fl ) ;
1533 NI_add_to_group( ngr , nel ) ;
1534 }
1535 break ;
1536
1537 case ATR_INT_TYPE:{
1538 ATR_int *atr_int = (ATR_int *)atr_any ;
1539
1540 nel = NI_new_data_element( "AFNI_atr" , atr_int->nin ) ;
1541 nel->outmode = NI_TEXT_MODE ;
1542 NI_set_attribute( nel , "atr_name" , atr_int->name ) ;
1543 NI_add_column( nel , NI_INT , atr_int->in ) ;
1544 NI_add_to_group( ngr , nel ) ;
1545 }
1546 break ;
1547
1548 case ATR_STRING_TYPE:{
1549 nsd_add_str_atr_to_group(aname, niname, blk, ngr);
1550 }
1551 break;
1552
1553 default:
1554 fprintf(stderr, "*** unexpected type!\n");
1555 RETURN(1);
1556 }
1557
1558 RETURN(0);
1559 }
1560
1561 /* - find the given attribute in the datablock
1562 - now just add 1 to length (should we bother?)
1563 - put it in a data element
1564 - add it to the group
1565
1566 aname - AFNI attribute name
1567 niname - NIML attribute name (if NULL, use aname)
1568 blk - datablock
1569 ngr - NI_group to insert new element into
1570
1571 return 0 on success
1572 */
nsd_add_str_atr_to_group(char * aname,char * niname,THD_datablock * blk,NI_group * ngr)1573 static int nsd_add_str_atr_to_group(char * aname, char * niname,
1574 THD_datablock * blk, NI_group * ngr)
1575 {
1576 ATR_string * atr;
1577 NI_element * nel;
1578 char * dest;
1579
1580 ENTRY("nsd_add_str_atr_to_group");
1581
1582 /* check usage */
1583 if( !aname || !blk || !ngr ) RETURN(1);
1584
1585 atr = THD_find_string_atr(blk, aname);
1586 if( !atr ) RETURN(0); /* nothing to add */
1587
1588 if(gni.debug > 1){
1589 fprintf(stderr, "-d adding '%s' atr: ", niname?niname:aname);
1590 fwrite(atr->ch, sizeof(char), atr->nch, stderr);
1591 fputc('\n', stderr);
1592 }
1593
1594 /* create a new string */
1595 dest = (char *)calloc(atr->nch+1, sizeof(char)); /* +1 for last '\0' */
1596 memcpy(dest, atr->ch, atr->nch);
1597 if(gni.debug > 2) fprintf(stderr, "-d new atr (orig): '%s'\n", dest);
1598 THD_zblock_ch(atr->nch, dest, ZSBLOCK); /* swap out nul chars */
1599 dest[atr->nch] = '\0';
1600
1601 /* now add it to the group */
1602 nel = NI_new_data_element("AFNI_atr", 1);
1603 nel->outmode = NI_TEXT_MODE;
1604 NI_set_attribute(nel, "atr_name", niname ? niname : aname);
1605 NI_add_column(nel, NI_STRING, &dest);
1606 NI_add_to_group(ngr, nel);
1607
1608 if(gni.debug > 1) fprintf(stderr, "-d new atr is: '%s'\n", dest);
1609
1610 free(dest); /* nuke local copy */
1611
1612 RETURN(0);
1613 }
1614
1615
1616 /* add a COLMS_RANGE attribute element to the group
1617 *
1618 * do not assume that the data is of type float, though
1619 * evaluate ranges as if it is
1620 */
nsd_add_colms_range(NI_group * ngr,THD_3dim_dataset * dset)1621 static int nsd_add_colms_range(NI_group * ngr, THD_3dim_dataset * dset)
1622 {
1623 THD_datablock * blk;
1624 NI_element * nel;
1625 float fmin, fmax;
1626 char * str;
1627 int ind, nx;
1628 int len; /* dynamic length of str */
1629 int minp, maxp;
1630
1631 ENTRY("nsd_add_colms_range");
1632
1633 nx = DSET_NVOX(dset); /* I want it all. ZSS: Nov. 1 2013*/
1634 blk = dset->dblk;
1635
1636 /*-- create the string --*/
1637 len = 512;
1638 str = (char *)malloc(len * sizeof(char));
1639 str[0] = '\0';
1640
1641 /* stick the nodes in the list */
1642 get_blk_min_max_posn(blk, 0, nx, &fmin, &minp, &fmax, &maxp);
1643 loc_append_vals(&str, &len, "", fmin, fmax, minp, maxp);
1644
1645 for( ind = 1; ind < blk->nvals; ind++ ) /* keep appending the next set */
1646 {
1647 get_blk_min_max_posn(blk, ind, nx, &fmin, &minp, &fmax, &maxp);
1648 loc_append_vals(&str, &len, ";", fmin, fmax, minp, maxp);
1649 }
1650
1651 /*-- now we have the string, insert it as an attribute element --*/
1652
1653 /* create initial element */
1654 nel = NI_new_data_element("AFNI_atr", 1);
1655
1656 nel = NI_new_data_element("AFNI_atr", 1);
1657 nel->outmode = NI_TEXT_MODE;
1658 NI_set_attribute(nel, "atr_name", "COLMS_RANGE");
1659 NI_add_column(nel, NI_STRING, &str);
1660 NI_add_to_group(ngr, nel);
1661
1662 if(gni.debug > 1) fprintf(stderr,"+d added COLMS_RANGE atr: '%s'\n", str);
1663
1664 free(str); /* nuke allocated string */
1665
1666 RETURN(0);
1667 }
1668
1669
1670 /*------------------------------------------------------------------------*/
1671 /*! Add the INDEX_LIST attribute element from the AFNI dset to the
1672 NIML group.
1673 *
1674 * If dset has no node_list, the user may still want it filled to a
1675 * default list, based on AFNI_NSD_ADD_NODES (gni.add_nodes).
1676 * If the datum is not float, convert it.
1677 * -----------------------------------------------------------------------*/
nsd_fill_index_list(NI_group * ngr,THD_3dim_dataset * dset)1678 static int nsd_fill_index_list(NI_group * ngr, THD_3dim_dataset * dset)
1679 {
1680 NI_element * nel;
1681 THD_datablock * blk;
1682 char str[4];
1683 int * node_list, * new_list = NULL;
1684 int c, nx;
1685
1686 ENTRY("nsd_fill_index_list");
1687
1688 blk = dset->dblk;
1689 nx = DSET_NVOX(dset); /* I want it all. ZSS: Nov. 1 2013*/
1690
1691 node_list = blk->node_list;
1692 if( blk->nnodes <= 0 || ! blk->node_list ) /* no node list */
1693 {
1694 /* create a default list 30 Aug 2006 [rickr]
1695 * (either requested or in prep for pad2node) 6 Sep 2012 [rickr] */
1696 if( gni.add_nodes || MRILIB_DomainMaxNodeIndex >= 0 )
1697 {
1698 if(gni.debug) fprintf(stderr,"+d creating default INDEX_LIST\n");
1699 new_list = (int *)malloc(nx * sizeof(int));
1700 if( !new_list ){
1701 fprintf(stderr,"** NFIL: failed to alloc %d nodes\n",nx);
1702 RETURN(1);
1703 }
1704 for( c = 0; c < nx; c++ ) new_list[c] = c;
1705 node_list = new_list;
1706 }
1707 else
1708 {
1709 if(gni.debug) fprintf(stderr,"-d no INDEX_LIST to add\n");
1710 RETURN(0);
1711 }
1712 }
1713 else if( blk->nnodes != nx )
1714 {
1715 fprintf(stderr,"** node list len (%d) != NX (%d), skipping nodes\n",
1716 blk->nnodes, nx);
1717 RETURN(1);
1718 }
1719
1720 if(gni.debug) fprintf(stderr,"+d adding INDEX_LIST, len %d\n", nx);
1721
1722 nel = NI_new_data_element("INDEX_LIST", nx);
1723
1724 nel->outmode = gni.write_mode; /* ASCII or BINARY mode (from globals) */
1725
1726 if( nsd_are_sorted_ints(node_list, nx)) strcpy(str, "Yes");
1727 else strcpy(str, "No");
1728
1729 NI_set_attribute(nel, "sorted_node_def", str);
1730 if(gni.debug > 1) fprintf(stderr,"+d set sorted_node_def = %s\n", str);
1731
1732 NI_add_column(nel, NI_INT, node_list);
1733
1734 if( new_list ) free(new_list); /* lose any new list */
1735
1736 NI_add_to_group(ngr, nel);
1737
1738 RETURN(0);
1739 }
1740
1741 /*------------------------------------------------------------------------*/
1742 /*! Add SPARSE_DATA from the AFNI dset to the NIML group.
1743 *
1744 * If the datum is not float or complex, convert it.
1745 * -----------------------------------------------------------------------*/
nsd_add_sparse_data(NI_group * ngr,THD_3dim_dataset * dset)1746 static int nsd_add_sparse_data(NI_group * ngr, THD_3dim_dataset * dset)
1747 {
1748 NI_element * nel;
1749 THD_datablock * blk;
1750 float * fdata = NULL;
1751 int ind, nx, c;
1752
1753 ENTRY("nsd_add_sparse_data");
1754
1755 blk = dset->dblk;
1756 nx = DSET_NVOX(dset); /* I want it all, now carting volumes too.
1757 ZSS: Nov. 1 2013 */
1758
1759 if(gni.debug) fprintf(stderr,"+d adding SPARSE_DATA element\n");
1760
1761 /* check whether we have all floats, of not prepare for conversion */
1762 /* 4 Aug 2006 [rickr] */
1763 for( ind = 0; ind < blk->nvals; ind++ )
1764 if( DBLK_BRICK_TYPE(blk, ind) != MRI_float &&
1765 DBLK_BRICK_TYPE(blk, ind) != MRI_complex) /* then allocate floats */
1766 {
1767 if( ! gni.to_float &&
1768 DBLK_BRICK_TYPE(blk, ind) != MRI_short &&
1769 DBLK_BRICK_TYPE(blk, ind) != MRI_byte ){
1770 fprintf(stderr,
1771 "** dset has non-floats/complex/short/byte and\n"
1772 " AFNI_NSD_TO_FLOAT is NO life has become unbearable...\n");
1773 RETURN(1);
1774 }
1775
1776 fdata = malloc(nx * sizeof(float)); /* create our float array */
1777 if( !fdata ) {
1778 fprintf(stderr,"** NASD: failed to malloc conversion floats\n");
1779 RETURN(1);
1780 }
1781 if(gni.debug)
1782 fprintf(stderr,"+d converting NI_SURF_DSET to floats\n");
1783
1784 break; /* and terminate the loop */
1785 }
1786
1787 /* create initial element of length nx */
1788 nel = NI_new_data_element("SPARSE_DATA", nx);
1789
1790 if(gni.debug > 1)
1791 fprintf(stderr,"+d sparse_data: adding %d data columns\n", blk->nvals);
1792
1793 /* insert data */
1794 for( ind = 0; ind < blk->nvals; ind++ )
1795 {
1796 float fac;
1797 if( DBLK_BRICK_TYPE(blk, ind) == MRI_float )
1798 {
1799 NI_add_column(nel, NI_FLOAT, DBLK_ARRAY(blk, ind)); /* use dblk */
1800 }
1801 else if( DBLK_BRICK_TYPE(blk, ind) == MRI_complex )
1802 {
1803 NI_add_column(nel, NI_COMPLEX, DBLK_ARRAY(blk, ind)); /* use dblk */
1804 }
1805 else if( ! gni.to_float && DBLK_BRICK_TYPE(blk, ind) == MRI_short )
1806 {
1807 NI_add_column(nel, NI_SHORT, DBLK_ARRAY(blk, ind)); /* use dblk */
1808 }
1809 else if( ! gni.to_float && DBLK_BRICK_TYPE(blk, ind) == MRI_byte )
1810 {
1811 NI_add_column(nel, NI_BYTE, DBLK_ARRAY(blk, ind)); /* use dblk */
1812 }
1813 else
1814 {
1815 EDIT_convert_dtype(nx, DBLK_BRICK_TYPE(blk,ind),DBLK_ARRAY(blk,ind),
1816 MRI_float, fdata, 0);
1817 /* apply any factor */
1818 fac = DBLK_BRICK_FACTOR(blk,ind); if( fac == 0.0 ) fac = 1.0;
1819 if( fac != 1.0 ) for(c = 0; c < nx; c++) fdata[c] *= fac;
1820
1821 NI_add_column(nel, NI_FLOAT, fdata); /* and add to element */
1822 }
1823 }
1824
1825 if( fdata ) free(fdata); /* fly! (thud) be free! (thud) */
1826
1827 /* Next declare output to be Node_Bucket_data always. Someday
1828 we will change that IF we ever feel the need. ZSS Dec 07 */
1829 {
1830 char name[256], *att;
1831 if ((att = NI_get_attribute(ngr,"dset_type"))) {
1832 snprintf(name, 255,"%s_data", att);
1833 NI_set_attribute(nel, "data_type", name);
1834 } else {
1835 NI_set_attribute(nel, "data_type", "Node_Bucket_data");
1836 }
1837 }
1838
1839 set_sparse_data_attribs(nel, dset, 1);
1840
1841 NI_add_to_group(ngr, nel);
1842
1843 RETURN(0);
1844 }
1845
1846
1847 /*------------------------------------------------------------------------*/
1848 /*! set element attribute specific to SPARSE DATA and the dataset 3 Aug 2006
1849 --------------------------------------------------------------------------*/
set_sparse_data_attribs(NI_element * nel,THD_3dim_dataset * dset,int nodes_from_dset)1850 int set_sparse_data_attribs(NI_element * nel, THD_3dim_dataset * dset,
1851 int nodes_from_dset)
1852 {
1853 char str[32];
1854 float TR=0.0;
1855
1856 ENTRY("set_sparse_data_attribs");
1857
1858 if( !nel || !dset ) RETURN(1);
1859
1860 nel->outmode = gni.write_mode; /* ASCII or BINARY mode (from globals) */
1861
1862 /* check for need of the ni_timestep attribute */
1863 if( DSET_NUM_TIMES(dset) > 1 ) /* then it is time dependent */
1864 {
1865 TR = DSET_TIMESTEP(dset);
1866 if( DSET_TIMEUNITS(dset) == UNITS_MSEC_TYPE ) TR *= 0.001;
1867 strcpy(str, MV_format_fval(TR));
1868 NI_set_attribute(nel, "ni_timestep", str);
1869 if(gni.debug > 1) fprintf(stderr,"+d setting ni_timestep = %s\n", str);
1870 }
1871
1872 RETURN(0);
1873 }
1874
1875
1876 /*------------------------------------------------------------------------*/
1877 /*! return whether the given list is sorted 23 Aug 2006 [rickr]
1878 --------------------------------------------------------------------------*/
nsd_are_sorted_ints(int * list,int len)1879 int nsd_are_sorted_ints(int *list, int len)
1880 {
1881 int c;
1882
1883 ENTRY("nsd_are_sorted_ints");
1884
1885 if( !list || len <= 0 ) RETURN(0);
1886 for( c = 0; c < len - 1; c++ )
1887 if( list[c] > list[c+1] )
1888 RETURN(0);
1889 RETURN(1);
1890 }
1891
1892
1893 /*------------------------------------------------------------------------*/
1894 /*! Like strndup, relies on length, not nul 11 Jul 2006 [rickr]
1895 --------------------------------------------------------------------------*/
my_strndup(char * str,int len)1896 static char * my_strndup(char *str, int len)
1897 {
1898 char *dup;
1899 if( str == NULL || len < 0 ) return NULL;
1900 dup = (char *)calloc(len+1, sizeof(char));
1901 strncpy(dup,str,len);
1902 dup[len] = '\0';
1903 return dup;
1904 }
1905
1906 /* append 2 floats and ints to str, subject to total length, len,
1907 and pre-pended with sep */
loc_append_vals(char ** str,int * len,char * sep,float f1,float f2,int i1,int i2)1908 static int loc_append_vals(char ** str, int * len, char * sep,
1909 float f1, float f2, int i1, int i2)
1910 {
1911 char lbuf[256], fs1[32]; /* for first call to MV_format_fval */
1912 int req;
1913
1914 ENTRY("loc_append_vals");
1915
1916 if( !str || !*str || !len || !sep ) RETURN(1);
1917 if( strlen(sep) > 32 ) RETURN(1);
1918
1919 /* first, just stuff them in a sufficient buffer */
1920 /* (make a copy of first float, and then format it all) */
1921 strcpy(fs1, MV_format_fval(f1));
1922 sprintf(lbuf, "%s%s %s %d %d", sep, fs1, MV_format_fval(f2), i1, i2);
1923
1924 req = strlen(*str) + strlen(lbuf) + 1;
1925 if( req > *len )
1926 {
1927 *len = req + 512; /* include some extra space */
1928 *str = (char *)realloc(*str, *len * sizeof(char));
1929 }
1930
1931 strcat(*str, lbuf); /* finally, copy the data in */
1932
1933 RETURN(0);
1934 }
1935
1936 /* ----------------------------------------------------------------------
1937 * get the byte order from any ni_form attribute
1938 * return LSB_FIRST, MSB_FIRST, or NATIVE_ORDER (if none is found)
1939 */
NI_get_byte_order(NI_element * nel)1940 int NI_get_byte_order(NI_element * nel)
1941 {
1942 char * rhs;
1943 int order = NATIVE_ORDER;
1944
1945 ENTRY("NI_get_byte_order");
1946
1947 if( !nel ) RETURN(NATIVE_ORDER);
1948
1949 rhs = NI_get_attribute(nel, "ni_form");
1950 if( !rhs )
1951 {
1952 if(gni.debug > 1) fprintf(stderr,"-d no ni_form for byte order\n");
1953 RETURN(NATIVE_ORDER);
1954 }
1955
1956 if( strstr(rhs, "lsbfirst") ) order = LSB_FIRST;
1957 if( strstr(rhs, "msbfirst") ) order = MSB_FIRST;
1958
1959 if( gni.debug > 1 )
1960 fprintf(stderr,"-d found byte order string, %s\n",
1961 order == LSB_FIRST ? LSB_FIRST_STRING :
1962 order == MSB_FIRST ? MSB_FIRST_STRING :
1963 NATIVE_STRING );
1964
1965 RETURN(order);
1966 }
1967
1968
1969 /* ---------------------------------------------------------------------- */
1970 /* NIML globals access functions 3 Aug 2006 [rickr] */
1971
1972 /* return the corresponding NI_type, and -1 on failure (since 0 is used) */
dtype_nifti_to_niml(int dtype)1973 int dtype_nifti_to_niml(int dtype) {
1974 switch(dtype) {
1975 case NIFTI_TYPE_INT16: { return NI_SHORT; }
1976 case NIFTI_TYPE_INT32: { return NI_INT; }
1977 case NIFTI_TYPE_FLOAT32: { return NI_FLOAT32; }
1978 case NIFTI_TYPE_FLOAT64: { return NI_FLOAT64; }
1979 case NIFTI_TYPE_INT8: { return NI_BYTE; }
1980 case NIFTI_TYPE_COMPLEX64:{ return NI_COMPLEX; }
1981 }
1982
1983 return -1;
1984 }
1985
1986 /* return the corresponding NIFTI_type, and DT_UNKNOWN on failure */
dtype_niml_to_nifti(int dtype)1987 int dtype_niml_to_nifti(int dtype) {
1988 switch(dtype) {
1989 case NI_SHORT: { return NIFTI_TYPE_INT16; }
1990 case NI_INT: { return NIFTI_TYPE_INT32; }
1991 case NI_FLOAT32:{ return NIFTI_TYPE_FLOAT32; }
1992 case NI_FLOAT64:{ return NIFTI_TYPE_FLOAT64; }
1993 case NI_BYTE: { return NIFTI_TYPE_INT8; }
1994 case NI_COMPLEX:{ return NIFTI_TYPE_COMPLEX64;}
1995 }
1996
1997 return 0; /* some #define seems to get in the way of DT_UNKNOWN */
1998 }
1999
2000 /* return the first element where name is 'ename' and atr_name is 'atr_name' */
NI_find_element_by_aname(NI_group * ngr,char * ename,char * aname,char * aval)2001 NI_element * NI_find_element_by_aname(NI_group * ngr, char * ename,
2002 char * aname, char * aval)
2003 {
2004 NI_element * nel = NULL;
2005 void ** elist = NULL;
2006 char ** sar, * atr;
2007 int ind, c;
2008
2009 ENTRY("NI_find_element_by_aname");
2010
2011 if( !ngr || !ename || !aname || !aval ) RETURN(NULL);
2012
2013 ind = NI_search_group_shallow(ngr, ename, &elist);
2014 if( ind <= 0 ) RETURN(NULL); /* no such name */
2015
2016 for( c = 0; c < ind; c++ ) {
2017 atr = NI_get_attribute(elist[c], aname);
2018 if( !strcmp(atr, aval) ) { /* found! */
2019 nel = (NI_element *)elist[c];
2020 break;
2021 }
2022 }
2023
2024 NI_free(elist);
2025
2026 RETURN(nel);
2027 }
2028
2029 /* Read the NIML file and determine the order of labels in the
2030 * ColumnLabels element.
2031 *
2032 * return values are:
2033 * 0 : unknown order (includes error conditions)
2034 * 1 : slice-major order (labels are s0.*, s1,*, ...)
2035 * 2 : slice-minor order (labels are s0.L0, s1.L0, ...)
2036 */
niml_get_major_label_order(char * fname)2037 int niml_get_major_label_order(char * fname)
2038 {
2039 NI_element * nel=NULL; /* main read element */
2040 NI_str_array * lablist=NULL; /* array of parsed labels */
2041 char * labstr=NULL; /* unparsed label string */
2042 int c, order=0; /* init order as unknown */
2043
2044 ENTRY("niml_get_major_label_order");
2045
2046 gni.debug = AFNI_numenv("AFNI_NIML_DEBUG"); /* maybe we want info */
2047 if(gni.debug > 3) fprintf(stderr,"-- get_major_label_order\n");
2048
2049 /* check each step of the way ... */
2050
2051 if( !fname ) {
2052 fprintf(stderr,"** major_label_order: fname is NULL\n");
2053 RETURN(0);
2054 }
2055 if ( (nel = (NI_element*)read_niml_file(fname, 0)) == NULL ) {
2056 if( gni.debug )
2057 fprintf(stderr,"** MLO: failed to read %s as NIML\n", fname);
2058 RETURN(0);
2059 }
2060 if(gni.debug > 2) fprintf(stderr,"-- NGMLO: vec_num = %d, vec_len = %d\n",
2061 nel->vec_num, nel->vec_len);
2062
2063 labstr = NI_get_attribute(nel, "ColumnLabels");
2064 if( !labstr ) {
2065 if( gni.debug ) fprintf(stderr,"** MLO: no ColumnLabels in %s\n",fname);
2066 RETURN(0);
2067 }
2068 if(gni.debug > 3) fprintf(stderr,"-- NGMLO: labstr = %-.66s...\n", labstr);
2069 lablist = NI_decode_string_list(labstr, ";");
2070 if( !lablist ) {
2071 if(gni.debug) fprintf(stderr,"** MLO: bad ColumnLabels in %s\n",fname);
2072 RETURN(0);
2073 }
2074 if( lablist->num < 3 ) {
2075 if( gni.debug ) fprintf(stderr,"** MLO: vec_num = %d\n",nel->vec_num);
2076 RETURN(0);
2077 }
2078
2079 /* we have the label list, now just check the first 2 labels */
2080 if(gni.debug > 2) fprintf(stderr,"== NGMLO: l[0]=%s, l[1]=%s, l[2]=%s\n",
2081 lablist->str[0], lablist->str[1], lablist->str[2]);
2082
2083 if( !strncmp(lablist->str[0], "s0", 2) &&
2084 !strncmp(lablist->str[1], "s0", 2) ) {
2085 if(gni.debug>1) fprintf(stderr,"-- %s is slice-major order\n",fname);
2086 order = 1;
2087 } else if( !strncmp(lablist->str[0], "s0", 2) &&
2088 !strncmp(lablist->str[1], "s1", 2) ) {
2089 if(gni.debug>1) fprintf(stderr,"-- %s is slice-minor order\n",fname);
2090 order = 2;
2091 } else {
2092 if(gni.debug>1) fprintf(stderr,"-- %s has indeterminate order\n",fname);
2093 order = 0;
2094 }
2095
2096 NI_delete_str_array(lablist);
2097 NI_free(nel);
2098
2099 RETURN(order);
2100 }
2101
2102 /* apply any escape characters, and return a new string
2103 * * (which will not exceed the orignal string in length)
2104 * *
2105 * * \n, \t, \b 31 Jul 2009 */
unescape_unix_str(const char * ustr)2106 char * unescape_unix_str(const char * ustr)
2107 {
2108 char * newstr = NULL;
2109 int len, c, nind;
2110 if( !ustr ) return NULL;
2111 len = strlen(ustr);
2112 newstr = (char *)malloc(len+1);
2113
2114 for( c = 0, nind = 0; c < len; c++, nind++ ) {
2115 if( ustr[c] == '\\' ) {
2116 switch(ustr[c+1]) {
2117 case 'n':
2118 newstr[nind] = '\n';
2119 c++;
2120 break;
2121 case 't':
2122 newstr[nind] = '\t';
2123 c++;
2124 break;
2125 case 'b':
2126 newstr[nind] = '\b';
2127 c++;
2128 break;
2129 default:
2130 newstr[nind] = ustr[c]; /* no escape applied */
2131 break;
2132 }
2133 } else newstr[nind] = ustr[c]; /* no escape found */
2134 }
2135
2136 newstr[nind] = '\0';
2137
2138 return newstr;
2139 }
2140
2141
set_ni_globs_from_env(void)2142 int set_ni_globs_from_env(void)
2143 {
2144 ENTRY("set_ni_globs_from_env");
2145
2146 /* if datasets don't have nodes, the user may want to add a default list */
2147 gni.add_nodes = AFNI_yesenv("AFNI_NSD_ADD_NODES"); /* 30 Aug 2006 */
2148
2149 gni.debug = AFNI_numenv("AFNI_NIML_DEBUG"); /* maybe the user wants info */
2150
2151 /* if having no conversion is desired, block it */
2152 gni.to_float = AFNI_noenv("AFNI_NSD_TO_FLOAT") ? 0 : 1;
2153
2154 /* if text desired, use it for writing */
2155 gni.write_mode = AFNI_yesenv("AFNI_NIML_TEXT_DATA") ? NI_TEXT_MODE :
2156 NI_BINARY_MODE;
2157
2158 RETURN(0);
2159 }
2160
set_gni_add_nodes(int add_nodes)2161 void set_gni_add_nodes( int add_nodes ){ gni.add_nodes = add_nodes; }
get_gni_add_nodes(void)2162 int get_gni_add_nodes( void ){ return gni.add_nodes; }
2163
set_gni_debug(int debug)2164 void set_gni_debug( int debug ){ gni.debug = debug; }
get_gni_debug(void)2165 int get_gni_debug( void ){ return gni.debug; }
2166
set_gni_to_float(int flag)2167 void set_gni_to_float( int flag ){ gni.to_float = flag; } /* 4 Aug 2006 */
get_gni_to_float(void)2168 int get_gni_to_float( void ){ return gni.to_float; }
2169
set_gni_write_mode(int mode)2170 void set_gni_write_mode( int mode ){ gni.write_mode = mode; }
get_gni_write_mode(void)2171 int get_gni_write_mode( void ){ return gni.write_mode; }
2172
2173