1 #include "niml_private.h"
2
3 /***************************************************************************/
4 /***** Stuff for defining rowtypes from strings. RWCox - 09 Dec 2002. *****/
5 /***************************************************************************/
6
7 /*-------------------------------------------------------------------------*/
8
9 /* These typedefs are used to find the byte alignment
10 the compiler imposes on the 'basic' types supported by NIML. */
11
12 typedef struct { char a; byte b; } Qadgop_byte ; /* not a Mercotan */
13 typedef struct { char a; short b; } Qadgop_short ;
14 typedef struct { char a; int b; } Qadgop_int ;
15 typedef struct { char a; float b; } Qadgop_float ;
16 typedef struct { char a; double b; } Qadgop_double ;
17 typedef struct { char a; complex b; } Qadgop_complex ;
18 typedef struct { char a; rgb b; } Qadgop_rgb ;
19 typedef struct { char a; rgba b; } Qadgop_rgba ;
20
21 /* Arrays to hold the alignments, sizes, and names of the basic types. */
22
23 static int type_alignment[NI_NUM_BASIC_TYPES+1] ;
24 static int type_size [NI_NUM_BASIC_TYPES+1] ;
25 static char *type_name [NI_NUM_BASIC_TYPES+1] = {
26 "byte" , "short" , "int" ,
27 "float" , "double" , "complex" ,
28 "rgb" , "rgba" , "String"
29 } ;
30
31 static char *type_alias[NI_NUM_BASIC_TYPES+1] = { /* aliases */
32 "uint8" , "int16" , "int32" ,
33 "float32" , "float64" , "complex64" ,
34 "rgb8" , "rgba8" , "CString"
35 } ;
36
37 /* these are used to find/save the alignment and size of pointers */
38
39 typedef struct { char a; void *b; } Qadgop_pointer ;
40 static int pointer_alignment ;
41 static int pointer_size ;
42
43 /*---------------------------------------------------------------*/
44 /*! The Htable of user-defined rowtypes, indexed by type name. */
45
46 static Htable *rowtype_table = NULL ;
47
48 /*! The array of user-defined rowtypes, indexed by type code.
49 Note that rowtypes are never deleted - they just accumulate. */
50
51 static NI_rowtype **rowtype_array = NULL ;
52 static int rowtype_num = 0 ;
53 /*---------------------------------------------------------------*/
54
55 /*! Rowtype code for first user-defined type. */
56
57 #define ROWTYPE_OFFSET 1001
58
59 /*! Used to set the code for each new user-defined type.
60 (The '-1' is to allow for the String type, which isn't
61 a basic type but is a builtin type.) */
62
63 #define ROWTYPE_BASE_CODE (ROWTYPE_OFFSET-NI_NUM_BASIC_TYPES-1)
64
65 /*! Check if a rowtype code is a derived type or a builtin type */
66
67 #define ROWTYPE_is_builtin_code(cc) ((cc) >= 0 && (cc) < ROWTYPE_OFFSET)
68
69 /*! Register a rowtype into the table and array. */
70
71 #define ROWTYPE_register(rr) \
72 do{ int nn ; \
73 if( rowtype_table == NULL ) setup_basic_types() ; \
74 addto_Htable( (rr)->name , (rr) , rowtype_table ) ; \
75 nn = rowtype_num + 1 ; \
76 rowtype_array = NI_realloc( rowtype_array , \
77 NI_rowtype*, \
78 sizeof(NI_rowtype *)*nn ); \
79 rowtype_array[nn-1] = rr ; rowtype_num = nn ; \
80 } while(0)
81
82 /*--------------------------------*/
83 /*! Debug flag for rowtype stuff. */
84
85 static int ROWTYPE_debug = 0 ;
86
87 /*! Set debug flag for rowtype stuff. */
88
NI_rowtype_debug(int n)89 void NI_rowtype_debug( int n ){ ROWTYPE_debug = n ; }
90
91 /*--------------------------------------------------------------------------*/
92 /*! Setup the alignment of basic NI types inside a struct (depends on CPU). */
93
setup_basic_types(void)94 static void setup_basic_types(void)
95 {
96 NI_rowtype *rt ;
97 int ii ;
98
99 if( rowtype_table != NULL ) return ; /* don't run this twice */
100
101 /* get alignments and sizes of the basic types */
102
103 type_alignment[NI_BYTE ] = offsetof(Qadgop_byte ,b) ;
104 type_alignment[NI_SHORT ] = offsetof(Qadgop_short ,b) ;
105 type_alignment[NI_INT ] = offsetof(Qadgop_int ,b) ;
106 type_alignment[NI_FLOAT ] = offsetof(Qadgop_float ,b) ;
107 type_alignment[NI_DOUBLE ] = offsetof(Qadgop_double ,b) ;
108 type_alignment[NI_COMPLEX] = offsetof(Qadgop_complex,b) ;
109 type_alignment[NI_RGB ] = offsetof(Qadgop_rgb ,b) ;
110 type_alignment[NI_RGBA ] = offsetof(Qadgop_rgba ,b) ;
111
112 type_size[NI_BYTE ] = sizeof(byte ) ;
113 type_size[NI_SHORT ] = sizeof(short ) ;
114 type_size[NI_INT ] = sizeof(int ) ;
115 type_size[NI_FLOAT ] = sizeof(float ) ;
116 type_size[NI_DOUBLE ] = sizeof(double ) ;
117 type_size[NI_COMPLEX] = sizeof(complex) ;
118 type_size[NI_RGB ] = sizeof(rgb ) ;
119 type_size[NI_RGBA ] = sizeof(rgba ) ;
120
121 /* initialize the rowtype table with the basic types */
122
123 rowtype_table = new_Htable(19) ;
124
125 for( ii=0 ; ii < NI_NUM_BASIC_TYPES ; ii++ ){
126
127 rt = NI_new( NI_rowtype ) ;
128 rt->code = ii ;
129 rt->size = type_size[ii] ; /* size of "struct" */
130 rt->psiz = rt->size ; /* size of all parts */
131 rt->algn = type_alignment[ii] ; /* byte alignment */
132 rt->name = NI_strdup(type_name[ii]);
133 rt->userdef = NI_strdup(type_name[ii]);
134 rt->flag = 0 ;
135
136 rt->comp_num = 1 ; /* basic types have */
137 rt->comp_typ = NI_malloc(int, sizeof(int)) ; /* only one component */
138 rt->comp_typ[0] = ii ;
139 rt->comp_dim = NI_malloc(int, sizeof(int)) ;
140 rt->comp_dim[0] = -1 ; /* fixed dim component */
141
142 rt->part_num = 1 ; /* basic types have */
143 rt->part_typ = NI_malloc(int, sizeof(int)) ; /* only one part */
144 rt->part_typ[0] = ii ;
145 rt->part_off = NI_malloc(int, sizeof(int)) ;
146 rt->part_off[0] = 0 ;
147 rt->part_siz = NI_malloc(int, sizeof(int)) ;
148 rt->part_siz[0] = type_size[ii] ;
149 rt->part_dim = NI_malloc(int, sizeof(int)) ;
150 rt->part_dim[0] = -1 ; /* fixed dim part */
151 rt->part_rtp = NI_malloc(NI_rowtype*, sizeof(NI_rowtype *)) ;
152 rt->part_rtp[0] = rt ;
153
154 ROWTYPE_register( rt ) ; /* put in the Htable */
155 }
156
157 /* alignment and size of pointers */
158
159 pointer_alignment = offsetof(Qadgop_pointer,b) ;
160 pointer_size = sizeof(void *) ;
161
162 /* insert a special rowtype for String (really a pointer) */
163
164 type_alignment[NI_STRING] = pointer_alignment ;
165 type_size [NI_STRING] = pointer_size ;
166
167 rt = NI_new( NI_rowtype ) ;
168 rt->code = NI_STRING ;
169 rt->size = pointer_size ;
170 rt->psiz = 0 ; /* variable dim */
171 rt->algn = pointer_alignment ;
172 rt->name = NI_strdup("String") ;
173 rt->userdef = NI_strdup("String") ;
174 rt->flag = ROWTYPE_VARSIZE_MASK ; /* variable dim */
175
176 rt->comp_num = 1 ;
177 rt->comp_typ = NI_malloc(int, sizeof(int)) ;
178 rt->comp_typ[0] = NI_STRING ;
179 rt->comp_dim = NI_malloc(int, sizeof(int)) ;
180 rt->comp_dim[0] = -1 ;
181
182 rt->part_num = 1 ;
183 rt->part_typ = NI_malloc(int, sizeof(int)) ;
184 rt->part_typ[0] = NI_STRING ;
185 rt->part_off = NI_malloc(int, sizeof(int)) ;
186 rt->part_off[0] = 0 ;
187 rt->part_siz = NI_malloc(int, sizeof(int)) ;
188 rt->part_siz[0] = pointer_size ;
189 rt->part_dim = NI_malloc(int, sizeof(int)) ;
190 rt->part_dim[0] = -1 ;
191
192 rt->part_rtp = NI_malloc(NI_rowtype*, sizeof(NI_rowtype *)) ;
193 rt->part_rtp[0] = rt ;
194
195 ROWTYPE_register( rt ) ;
196
197 if( ROWTYPE_debug )
198 profile_Htable( "rowtype_table" , rowtype_table ) ;
199 }
200
201 /*-------------------------------------*/
202 /*! Error exit macro for next function */
203
204 #undef ERREX
205 #define ERREX(str) \
206 do { fprintf(stderr,"** NI_rowtype_define('%s','%s'): %s\n",tname,tdef,str); \
207 return -1 ; } while(0)
208
209 /*--------------------------------------------------------------------------*/
210 /* Define a NI_rowtype, which is an expression of a C struct type (with
211 some restrictions).
212 - tname = Name to call this thing (must be unique and can't be one
213 of the builtin types listed below).
214 - tdef = Definition of the type:
215 - A list of type names ('components') separated by commas.
216 - A type name is one of the NIML basic types
217 ("byte", "short", "int", "float", "double", "complex", "rgb", "rgba"),
218 or is "String",
219 or is a previously defined tname from a another NI_rowtype.
220 - Recursive types cannot be defined; that is, no component of
221 tdef can refer to the same tname that is being defined now.
222 - A type name may be preceded/appended by an integer count,
223 as in "int,4*float" or "int,float[4]". These are equivalent
224 to "int,float,float,float,float" (just shorter).
225 - Variable dimension arrays may be defined, IF the size of the
226 array is an int component of this new rowtype which occurs before
227 the array definition:
228 - "int,float[#1]" defines the second component to be
229 a float array whose length is given by the value of
230 the first component
231 - This example is analogous to this C fragment:
232 - typedef struct { int n; float *x; } far ;
233 - far xfar ;
234 - xfar.n = 373 ;
235 - xfar.x = malloc(sizeof(float)*xfar.n) ;
236 - You can't do something like "int,3*float[#1]" - only one
237 repeat count per component is allowed! The right way to
238 do this would be "int,float[#1],float[#1],float[#1]".
239 - All variable components in instances of these arrays
240 will be allocated with NI_malloc() and should be released
241 with NI_free().
242 - The type of a variable dim array must be fixed in size;
243 that is, that type itself cannot contain any var dim
244 array or String components.
245 - String components are also variable dimension arrays,
246 but whose size is given by the usual strlen().
247
248 The intention is that a C struct type is mapped to a NI_rowtype. Some
249 examples:
250 - typedef struct { int i; float x,y,z; } ifvec ;
251 - NI_rowtype_define( "ifvec" , "int,3*float" ) ;
252 - typedef struct { byte a,b; ifvec c; } abvec ;
253 - NI_rowtype_define( "abvec" , "2*byte,ifvec" ) ;
254
255 The return value is a positive integer code which can be used to
256 identify this NI_rowtype (the tname string can also be used for
257 this purpose). If -1 is returned, something bad transpired.
258
259 Also see
260 - NI_rowtype_find_name()
261 - NI_rowtype_find_code()
262 - NI_rowtype_name_to_code()
263 - NI_rowtype_code_to_name()
264 ----------------------------------------------------------------------------*/
265
NI_rowtype_define(char * tname,char * tdef)266 int NI_rowtype_define( char *tname , char *tdef )
267 {
268 NI_rowtype *rt , *qt ;
269 int ii,jj , id,jd,kd,isdim,nn , almax,cbase,np,pb , last_size ;
270 NI_str_array *sar ;
271 char *tp,*sp,*bp , str[256] ;
272
273 /*-- check inputs --*/
274
275 if( !NI_is_name(tname) ) ERREX("bad typename") ;
276 if( strlen(tname) > 255 ) ERREX("overlong typename") ;
277 if( tdef == NULL || *tdef == '\0' ) ERREX("empty type definition") ;
278
279 /*-- create Htable of basic types, if not already defined --*/
280
281 if( rowtype_table == NULL ) setup_basic_types() ;
282
283 /*-- see if type name already defined --*/
284 /*-- 25 Mar 2003: if it is, return the old code --*/
285
286 rt = NI_rowtype_find_name( tname ) ;
287 if( rt != NULL ){
288 if( strcmp(rt->userdef,tdef) != 0 ){
289 fprintf(stderr,
290 "++ NI_rowtype_define: illegal attempt to redefine type '%s'\n"
291 "++ old definition: %s\n"
292 "++ (failed) new definition: %s\n" ,
293 tname , rt->userdef , tdef ) ;
294 }
295 return rt->code ;
296 }
297
298 /*-- break defining string into components --*/
299
300 sar = NI_decode_string_list( tdef , ",;" ) ;
301
302 if( sar == NULL || sar->num < 1 ){
303 NI_free(sar) ; ERREX("illegal definition") ;
304 }
305
306 /*-- initialize the new rowtype --*/
307
308 rt = NI_new( NI_rowtype ) ;
309 rt->name = NI_strdup( tname ) ;
310 rt->userdef = NI_strdup( tdef ) ;
311 rt->flag = 0 ;
312
313 /*-- loop over components in tdef, loading the new rt with their info --*/
314
315 rt->part_num = rt->comp_num = 0 ;
316
317 for( ii=0 ; ii < sar->num ; ii++ ){
318
319 tp = sar->str[ii] ;
320 id = 0 ; kd = strlen(tp) ; /* type name of part will be in tp[id..kd-1] */
321 if( kd == 0 ){
322 delete_rowtype(rt); NI_delete_str_array(sar); ERREX("empty component name?");
323 }
324
325 /* get count, if present, into jd */
326
327 sp = strchr(tp,'*') ; /* format of component string: count*type */
328 bp = strchr(tp,'[') ; /* format of component string: type[count] */
329
330 if( sp != NULL || bp != NULL ){ /*** a count is present ***/
331
332 if( sp != NULL && bp != NULL ){ /* can't have both forms! */
333 delete_rowtype(rt); NI_delete_str_array(sar); ERREX("two repeat counts?");
334 }
335
336 if( sp != NULL ){ /* format: count*type */
337 nn = 0 ; /* - count starts at nn */
338 id = (sp-tp)+1 ; /* - type name starts at id */
339 } else { /* format: type[count] */
340 kd = (bp-tp) ; /* - type name ends at kd-1 */
341 nn = kd+1 ; /* - count starts at nn */
342 }
343
344 jd = -1 ;
345 if( tp[nn] != '#' ){ /* count is a plain number */
346 isdim = 0 ;
347 sscanf( tp+nn , "%d" , &jd ) ;
348 if( jd <= 0 ){
349 delete_rowtype(rt); NI_delete_str_array(sar); ERREX("bad repeat number");
350 }
351 } else { /* count is a #reference */
352 isdim = 1 ;
353 sscanf( tp+nn+1 , "%d" , &jd ) ; /* ref must be to index */
354 if( jd <= 0 || jd > ii ){ /* before this component */
355 delete_rowtype(rt); NI_delete_str_array(sar); ERREX("bad #index");
356 }
357 if( rt->comp_typ[jd-1] != NI_INT || /* ref must be to an int */
358 rt->comp_dim[jd-1] >= 0 ){ /* of fixed dim (1 int) */
359 delete_rowtype(rt); NI_delete_str_array(sar); ERREX("non-int #index");
360 }
361 }
362 } else {
363 isdim = 0 ; jd = 1 ; /* default count of 1 */
364 }
365
366 /* get the type of this component from its name */
367
368 if( kd-id < 1 || kd-id > 255 ){
369 delete_rowtype(rt); NI_delete_str_array(sar); ERREX("toolong component name");
370 }
371
372 NI_strncpy( str , tp+id , kd-id+1 ) ; /* copy component name into str */
373 qt = NI_rowtype_find_name( str ) ; /* look it up in the table */
374 if( qt == NULL ){
375 delete_rowtype(rt); NI_delete_str_array(sar); ERREX("bad component type");
376 }
377
378 if( !isdim ){ /*** fixed count: add jd copies of this component type ***/
379
380 rt->comp_typ = NI_realloc( rt->comp_typ, int, sizeof(int)*(rt->comp_num+jd) );
381 rt->comp_dim = NI_realloc( rt->comp_dim, int, sizeof(int)*(rt->comp_num+jd) );
382
383 for( jj=0 ; jj < jd ; jj++ ){
384 rt->comp_typ[rt->comp_num + jj] = qt->code ;
385 rt->comp_dim[rt->comp_num + jj] = -1 ; /* fixed dim part */
386 }
387
388 rt->comp_num += jd ; /* have more components now */
389 rt->part_num += jd * qt->part_num ; /* have more parts now */
390
391 if( ROWTYPE_is_varsize(qt) ) /* if component is variable dim, */
392 rt->flag |= ROWTYPE_VARSIZE_MASK ; /* mark rowtype as variable dim */
393
394 } else { /*** variable count: add 1 component that is a pointer */
395 /*** to an array of fixed dim elements, */
396 /*** dimension given in component #jd */
397
398 /* but can't have a var dim array of var dim arrays! */
399
400 if( ROWTYPE_is_varsize(qt) ){
401 delete_rowtype(rt); NI_delete_str_array(sar);
402 ERREX("variable dim array must have fixed dim type");
403 }
404
405 rt->comp_typ = NI_realloc( rt->comp_typ, int, sizeof(int)*(rt->comp_num+1) );
406 rt->comp_dim = NI_realloc( rt->comp_dim, int, sizeof(int)*(rt->comp_num+1) );
407
408 rt->comp_typ[rt->comp_num] = qt->code ; /* type this points to */
409 rt->comp_dim[rt->comp_num] = jd-1 ; /* which component has */
410 /* array dimension count */
411 rt->comp_num ++ ; /* 1 more component */
412 rt->part_num ++ ; /* and 1 more part */
413
414 rt->flag |= ROWTYPE_VARSIZE_MASK ; /* mark rowtype as variable dim */
415
416 }
417
418 } /* end of loop over components */
419
420 NI_delete_str_array(sar) ; /* done with this string array */
421
422 if( rt->part_num == 0 ){ delete_rowtype(rt); ERREX("no components?"); }
423
424 /*** now loop over components, breaking them down into their parts,
425 storing the part types and their offsets into the C struct ***/
426
427 rt->part_off = NI_malloc(int, sizeof(int) * rt->part_num ) ;
428 rt->part_typ = NI_malloc(int, sizeof(int) * rt->part_num ) ;
429 rt->part_dim = NI_malloc(int, sizeof(int) * rt->part_num ) ;
430 rt->part_siz = NI_malloc(int, sizeof(int) * rt->part_num ) ;
431 rt->part_rtp = NI_malloc(NI_rowtype*, sizeof(NI_rowtype *) * rt->part_num ) ;
432
433 almax = 1 ; /* will be largest type_alignment of any part */
434 cbase = 0 ; /* base offset into struct for next component */
435 id = 0 ; /* part number we are about to work on */
436
437 for( ii=0 ; ii < rt->comp_num ; ii++ ){
438
439 /*** component is a ***/
440 if( rt->comp_dim[ii] >= 0 ){ /*** variable dim array ***/
441 /*** ==> store 1 pointer ***/
442
443 if( pointer_alignment > 1 ){ /* make sure cbase */
444 jd = cbase % pointer_alignment ; /* is aligned OK */
445 if( jd > 0 ) cbase += (pointer_alignment-jd) ;
446 }
447
448 /* Note that this is the only case where a part_typ
449 might end up as a derived type - normally, part_typ
450 will be a builtin type code (NI_BYTE .. NI_STRING).
451 Note the limitation that the type of variable dim
452 arrays be a fixed dim type. */
453
454 rt->part_typ[id] = rt->comp_typ[ii] ;
455 rt->part_off[id] = cbase ;
456 rt->part_siz[id] = pointer_size ;
457 rt->part_rtp[id] = NI_rowtype_find_code( rt->part_typ[id] ) ;
458
459 /* count number of parts before the dimension component into kd */
460 /* so we can store the part index of this dimension component */
461
462 for( jd=kd=0 ; jd < rt->comp_dim[ii] ; jd++ ){
463 if( rt->comp_dim[jd] >= 0 ){ /* this component is a pointer itself */
464 kd++ ;
465 } else { /* this component has fixed dim parts */
466 qt = NI_rowtype_find_code( rt->comp_typ[jd] ) ;
467 kd += qt->part_num ;
468 }
469 }
470 rt->part_dim[id] = kd ; /* which part is the dimension of this part */
471
472 kd = pointer_alignment ;
473 if( kd > almax ) almax = kd ;
474
475 id++ ; cbase += pointer_size ;
476
477 } else { /*** fixed dim type, possibly with multiple parts ***/
478
479 qt = NI_rowtype_find_code( rt->comp_typ[ii] ) ; /* component type */
480
481 /* adjust cbase upward if this component isn't properly aligned */
482
483 if( qt->algn > 1 ){
484 jd = cbase % qt->algn ;
485 if( jd > 0 ) cbase += (qt->algn-jd) ;
486 }
487
488 pb = id ; /* part base index for this component */
489 np = qt->part_num ; /* number of parts to add here */
490
491 rt->part_typ[id] = qt->part_typ[0] ; /* first part from component */
492 rt->part_off[id] = cbase ; /* goes at the current base */
493 rt->part_dim[id] = -1 ; /* 1st part cannot be variable dim array */
494 rt->part_rtp[id] = NI_rowtype_find_code( rt->part_typ[id] ) ;
495
496 kd = rt->part_rtp[id]->algn ; /* alignment of part */
497 if( kd > almax ) almax = kd ; /* keep track of largest alignment */
498
499 last_size = rt->part_rtp[id]->size ; /* size of 1st part */
500 rt->part_siz[id] = last_size ;
501
502 id++ ; /* prepare to add next part */
503
504 /* loop over rest of parts from this component */
505
506 for( jj=1 ; jj < np ; jj++,id++ ){
507
508 rt->part_typ[id] = qt->part_typ[jj] ; /* type of new part */
509 rt->part_rtp[id] = NI_rowtype_find_code( rt->part_typ[id] ) ;
510
511 if( qt->part_dim[jj] < 0 ){ /******* fixed dim part **/
512
513 nn = last_size ; /* # bytes in last part */
514 jd = rt->part_off[id-1] ; /* offset of last part */
515 kd = rt->part_rtp[id]->algn ; /* how to align new part */
516 if( kd > almax ) almax = kd ; /* keep track of largest alignment */
517
518 nn += jd ; /* next available byte = sum of last offset and size */
519 if( kd > 1 ){ /* must move nn up if */
520 jd = nn % kd ; /* not on exact multiple */
521 if( jd > 0 ) nn += (kd-jd) ; /* of jj bytes alignment */
522 }
523 rt->part_off[id] = nn ;
524 rt->part_dim[id] = -1 ; /* mark as fixed dim part */
525
526 last_size = rt->part_rtp[id]->size ; /* size of this part */
527 rt->part_siz[id] = last_size ;
528
529 } else { /***** variable dim array part **/
530
531 nn = last_size ;
532 jd = rt->part_off[id-1] ;
533 kd = pointer_alignment ; /* we are storing a pointer here */
534 if( kd > almax ) almax = kd ;
535 nn += jd ;
536 if( kd > 1 ){
537 jd = nn % kd ;
538 if( jd > 0 ) nn += (kd-jd) ;
539 }
540 rt->part_off[id] = nn ;
541 last_size = pointer_size ;
542 rt->part_siz[id] = last_size ;
543
544 /* qt->part_dim[jj] is the part index in qt
545 of the dimension for this variable dim array part;
546 we must convert that to a part index in the new rowtype */
547
548 rt->part_dim[id] = pb + qt->part_dim[jj] ;
549
550 }
551
552 } /* end of loop over parts within this component */
553
554 /* now move the base offset up by the size of the current
555 component (which may be bigger than the sum of its parts) */
556
557 cbase += qt->size ;
558
559 } /* end of fixed dim component part-izing */
560
561 } /* end of loop over components */
562
563 /* now compute the overall size of this new rowtype:
564 at this point,
565 cbase = next byte offset available after last part;
566 this would be the size, but may have to be pushed
567 up to allow for byte alignment of this rowtype */
568
569 rt->algn = almax ;
570 if( rt->algn > 1 ){
571 jd = cbase % rt->algn ;
572 if( jd > 0 ) cbase += (rt->algn-jd) ;
573 }
574 rt->size = cbase ; /* this size is the sizeof(struct),
575 and doesn't include var dim arrays or
576 Strings, just the pointers to those things */
577
578 /* 26 Dec 2002: Compute the sum of the part sizes
579 (zero if this has variable dim arrays).
580 If rt->psiz == rt->size, then
581 struct is stored without padding bytes. */
582
583 rt->psiz = 0 ;
584 if( !ROWTYPE_is_varsize(rt) ){
585 for( ii=0 ; ii < rt->part_num ; ii++ )
586 rt->psiz += rt->part_siz[ii] ;
587 }
588
589 /* 28 Oct 2004: Move assignment of the new rowtype code to the end,
590 since a recursive call via NI_rowtype_find_name()
591 might have created a new rowtype before this one.
592 An example definition: "int,VECTOR_float_32,int". */
593
594 rt->code = ROWTYPE_BASE_CODE + rowtype_num ;
595
596 /** debugging printouts **/
597
598 if( ROWTYPE_debug ){
599 fprintf(stderr,"\n") ;
600 fprintf(stderr,"NI_rowtype_define: '%s' = '%s'\n",tname,tdef) ;
601 fprintf(stderr," code = %d\n",rt->code) ;
602 fprintf(stderr," size = %d\n",rt->size) ;
603 fprintf(stderr," psiz = %d\n",rt->psiz) ;
604 fprintf(stderr," algn = %d\n",rt->algn) ;
605 fprintf(stderr," flag = %d\n",rt->flag) ;
606
607 fprintf(stderr," comp_num = %d\n",rt->part_num) ;
608
609 fprintf(stderr," comp_typ = " ) ;
610 for( ii=0 ; ii < rt->comp_num ; ii++ ) fprintf(stderr,"%4d ",rt->comp_typ[ii]) ;
611 fprintf(stderr,"\n") ;
612
613 fprintf(stderr," comp_dim = " ) ;
614 for( ii=0 ; ii < rt->comp_num ; ii++ ) fprintf(stderr,"%4d ",rt->comp_dim[ii]) ;
615 fprintf(stderr,"\n") ;
616
617 fprintf(stderr," part_num = %d\n",rt->part_num) ;
618
619 fprintf(stderr," part_typ = " ) ;
620 for( ii=0 ; ii < rt->part_num ; ii++ ) fprintf(stderr,"%4d ",rt->part_typ[ii]) ;
621 fprintf(stderr,"\n") ;
622
623 fprintf(stderr," part_off = " ) ;
624 for( ii=0 ; ii < rt->part_num ; ii++ ) fprintf(stderr,"%4d ",rt->part_off[ii]) ;
625 fprintf(stderr,"\n") ;
626
627 fprintf(stderr," part_siz = " ) ;
628 for( ii=0 ; ii < rt->part_num ; ii++ ) fprintf(stderr,"%4d ",rt->part_siz[ii]) ;
629 fprintf(stderr,"\n") ;
630
631 fprintf(stderr," part_dim = " ) ;
632 for( ii=0 ; ii < rt->part_num ; ii++ ) fprintf(stderr,"%4d ",rt->part_dim[ii]) ;
633 fprintf(stderr,"\n") ;
634 }
635
636 /* save this in the table of rowtypes,
637 and return the numerical code for this new type */
638
639 ROWTYPE_register(rt) ;
640 return rt->code ;
641 }
642
643 /*--------------------------------------------------------------------*/
644 /*! Make an 'ni_do' element that defines a given rowtype. */
645
NI_rowtype_procins(NI_rowtype * rt)646 NI_procins * NI_rowtype_procins( NI_rowtype *rt ) /* 19 Apr 2005 */
647 {
648 NI_procins *npi ;
649 char *rhs ;
650
651 if( rt == NULL ) return NULL ;
652
653 npi = NI_new_processing_instruction( "ni_do" ) ;
654 NI_set_attribute( npi , "ni_verb" , "typedef" ) ;
655
656 rhs = NI_malloc(char,strlen(rt->name)+strlen(rt->userdef)+4) ;
657 sprintf( rhs , "%s %s" , rt->name , rt->userdef ) ;
658 NI_set_attribute( npi , "ni_object" , rhs ) ;
659 NI_free( rhs ) ;
660 return npi ;
661 }
662
663 /*--------------------------------------------------------------------*/
664 /*! Find a rowtype by its name.
665 19 Feb 2003: or its alias.
666 28 Oct 2004: If name is of form VECTOR_basictype_length,
667 then a new rowtype is created on the spot;
668 e.g., "VECTOR_float_32" is like "float[32]". */
669
NI_rowtype_find_name(char * nn)670 NI_rowtype * NI_rowtype_find_name( char *nn )
671 {
672 NI_rowtype *rt ; int ii ;
673 static int busy=0 ; /* 28 Oct 2004: prevent recursion */
674
675 if( nn == NULL || *nn == '\0' ) return NULL ;
676 if( rowtype_table == NULL ) setup_basic_types() ;
677 rt = (NI_rowtype *) findin_Htable(nn,rowtype_table) ;
678 if( rt != NULL ) return rt ;
679
680 /* 19 Feb 2003: linear search for basic type alias */
681
682 for( ii=0 ; ii <= NI_NUM_BASIC_TYPES ; ii++ )
683 if( strcmp(type_alias[ii],nn) == 0 ) return rowtype_array[ii] ;
684
685 /*-- 28 Oct 2004: Define fixed size vector types here and now:
686 format of nn must be VECTOR_basictype_length --*/
687
688 if( busy ) return NULL ; /* cannot allow re-entry below here! */
689
690 ii = strlen(nn) ;
691 if( ii < 12 || strncmp(nn,"VECTOR_",7) != 0 || strchr(nn+7,'_') == NULL )
692 return NULL ;
693
694 { char bt[32] , rt[64] ; int tt , dd ;
695
696 /* extract basic type name (after "VECTOR_") into bt array */
697
698 for( ii=7 ; ii < 32 && nn[ii] != '\0' && nn[ii] != '_' ; ii++ )
699 bt[ii-7] = nn[ii] ;
700 if( nn[ii] != '_' ) return NULL ; /* bad end of basic type name */
701 bt[ii-7] = '\0' ; /* terminate with NUL byte */
702
703 /* find bt name in basic type name list (or alias list) */
704
705 for( tt=0 ; tt <= NI_NUM_BASIC_TYPES ; tt++ )
706 if( strcmp(type_name[tt],bt) == 0 ) break ;
707
708 if( tt > NI_NUM_BASIC_TYPES ){
709 for( tt=0 ; tt <= NI_NUM_BASIC_TYPES ; tt++ )
710 if( strcmp(type_alias[tt],bt) == 0 ) break ;
711 if( tt > NI_NUM_BASIC_TYPES ) return NULL ;
712 }
713
714 /* find dimension after the nn[ii] character, which is '_' */
715
716 dd = 0 ; sscanf( nn+ii+1 , "%d" , &dd ) ;
717 if( dd <= 0 ) return NULL ;
718
719 /* ready to create a new rowtype now */
720
721 sprintf(rt,"%s[%d]",type_name[tt],dd) ;
722
723 busy = 1 ; /* prevent recursion!!! */
724 tt = NI_rowtype_define( nn , rt ) ;
725 busy = 0 ;
726 if( tt >= ROWTYPE_OFFSET ) return rowtype_array[tt-ROWTYPE_BASE_CODE] ;
727 }
728
729 return NULL ;
730 }
731
732 /*--------------------------------------------------------------------*/
733 /*! Find a rowtype by its integer code. */
734
NI_rowtype_find_code(int nn)735 NI_rowtype * NI_rowtype_find_code( int nn )
736 {
737 if( nn < 0 ) return NULL ;
738 if( rowtype_table == NULL ) setup_basic_types() ;
739 if( nn >= ROWTYPE_OFFSET ) nn = nn - ROWTYPE_BASE_CODE ;
740 if( nn < 0 || nn >= rowtype_num ) return NULL ;
741 return rowtype_array[nn] ;
742 }
743
744 /*--------------------------------------------------------------------*/
745 /*! Given a rowtype name, find its integer code.
746 Returns -1 if the name isn't found in the rowtype table.
747 ----------------------------------------------------------------------*/
748
NI_rowtype_name_to_code(char * nn)749 int NI_rowtype_name_to_code( char *nn )
750 {
751 NI_rowtype *rt = NI_rowtype_find_name( nn ) ;
752 if( rt != NULL ) return rt->code ;
753 return -1 ;
754 }
755
756 /*--------------------------------------------------------------------*/
757 /*! Given a rowtype code, find its string name.
758 Returns NULL if the code isn't found in the rowtype table,
759 otherwise returns the pointer to the name inside the table
760 (i.e., don't free this string!).
761 ----------------------------------------------------------------------*/
762
NI_rowtype_code_to_name(int nn)763 char * NI_rowtype_code_to_name( int nn )
764 {
765 NI_rowtype *rt = NI_rowtype_find_code( nn ) ;
766 if( rt != NULL ) return rt->name ;
767 return NULL ;
768 }
769
770 /*--------------------------------------------------------------------*/
771 /*! Given a rowtype code, find its alias name. This is only valid
772 for builtin types; for user-defined types, the return value is
773 the user-supplied type name string. Don't free this string!
774 ----------------------------------------------------------------------*/
775
NI_rowtype_code_to_alias(int nn)776 char * NI_rowtype_code_to_alias( int nn ) /* 19 Feb 2003 */
777 {
778 if( rowtype_table == NULL ) setup_basic_types() ;
779 if( nn <= NI_NUM_BASIC_TYPES ) return type_alias[nn] ;
780 return NI_rowtype_code_to_name( nn ) ;
781 }
782
783 /*--------------------------------------------------------------------*/
784 /*! Given a rowtype name, find its struct size in bytes.
785 - Returns -1 if rowtype not found.
786 - Note that if the rowtype contains variable dim arrays, this
787 size returned here is just the size of the storage for
788 the basic struct with pointers, not including the variable
789 arrays.
790 - See NI_rowtype_vsize() to get the size of a rowtype instance
791 including its variable dim arrays.
792 ----------------------------------------------------------------------*/
793
NI_rowtype_name_to_size(char * nn)794 int NI_rowtype_name_to_size( char *nn )
795 {
796 NI_rowtype *rt = NI_rowtype_find_name( nn ) ;
797 if( rt != NULL ) return rt->size ;
798 return -1 ;
799 }
800
801 /*-----------------------------------------------------------*/
802 /*! Given a rowtype code, find its struct size in bytes.
803 See also NI_rowtype_name_to_size().
804 -------------------------------------------------------------*/
805
NI_rowtype_code_to_size(int dtyp)806 int NI_rowtype_code_to_size( int dtyp )
807 {
808 static int last_dtyp=-1 , last_size=-1 ; /* 12 Dec 2002 */
809 NI_rowtype *rt ;
810
811 if( rowtype_table == NULL ) setup_basic_types() ;
812 if( dtyp < 0 ) return -1 ;
813 if( dtyp < ROWTYPE_OFFSET ) return type_size[dtyp] ;
814 if( dtyp == last_dtyp ) return last_size ;
815
816 rt = NI_rowtype_find_code(dtyp) ;
817 if( rt != NULL ){
818 last_dtyp = dtyp; last_size = rt->size; return last_size;
819 }
820 return -1 ; /* bad */
821 }
822
823 /*-----------------------------------------------------------------------*/
824 /*! Compute the size of all the data in a struct defined in a NI_rowtype
825 (not including padding), for this instance of the struct,
826 allowing for variable array parts. Zero is returned if something
827 bad happens.
828 -------------------------------------------------------------------------*/
829
NI_rowtype_vsize(NI_rowtype * rt,void * dpt)830 int NI_rowtype_vsize( NI_rowtype *rt , void *dpt )
831 {
832 int ii,jj , ss ;
833 char *dat = (char *)dpt ;
834
835 if( rt == NULL ) return 0; /* nonsense input */
836 if( !ROWTYPE_is_varsize(rt) ) return rt->psiz; /* fixed dim struct */
837 if( dat == NULL ) return 0; /* var size with no data? */
838
839 /* loop over parts, adding up part sizes,
840 including var dim arrays and String parts */
841
842 for( ii=ss=0 ; ii < rt->part_num ; ii++ ){
843 if( rt->part_typ[ii] == NI_STRING ){ /* String is special */
844 char *str = *((char **)((dat) + (rt)->part_off[ii])) ;
845 ss += NI_strlen(str) ;
846 } else if( rt->part_dim[ii] < 0 ){ /* 1 fixed dim type */
847 ss += rt->part_siz[ii] ;
848 } else { /* var dim array */
849 jj = ROWTYPE_part_dimen(rt,dat,ii) ; /* array size */
850 ss += jj * rt->part_rtp[ii]->psiz ; /* size of all parts */
851 } /* in var dim array */
852 }
853
854 return ss ;
855 }
856
857 /*-------------------------------------------------------------------------*/
858 /*! Encode 1 type value at the end of the text string wbuf (which is
859 assumed to be plenty long). typ must be a fixed dim type code,
860 or NI_STRING. Structs with var dim arrays must be handled separately.
861 ---------------------------------------------------------------------------*/
862
863 static int do_raw = 0 ;
864
NI_set_raw_val_to_text(int ii)865 void NI_set_raw_val_to_text( int ii ){ do_raw = ii ; }
866
NI_val_to_text(NI_rowtype * rt,char * dpt,char * wbuf)867 void NI_val_to_text( NI_rowtype *rt , char *dpt , char *wbuf )
868 {
869 int jj = strlen(wbuf) ;
870
871 switch( rt->code ){
872
873 /*-- a derived type (will not contain var dim arrays) --*/
874
875 default:{
876 if( rt != NULL ){
877 int ii ;
878 for( ii=0 ; ii < rt->part_num ; ii++ ) /* recursion */
879 NI_val_to_text( rt->part_rtp[ii] , dpt + rt->part_off[ii] , wbuf ) ;
880 }
881 }
882 break ;
883
884 /*-- integer types --*/
885
886 case NI_BYTE:{
887 byte *vpt = (byte *)dpt ;
888 sprintf(wbuf+jj," %u",(unsigned int)vpt[0]) ;
889 }
890 break ;
891
892 case NI_SHORT:{
893 short *vpt = (short *)dpt ;
894 sprintf(wbuf+jj," %d",(int)vpt[0]) ;
895 }
896 break ;
897
898 case NI_INT:{
899 int *vpt = (int *)dpt ;
900 sprintf(wbuf+jj," %d",vpt[0]) ;
901 }
902 break ;
903
904 /* multiple byte structs */
905
906 case NI_RGB:{
907 rgb *vpt = (rgb *)dpt ;
908 sprintf(wbuf+jj," %u %u %u",vpt[0].r,vpt[0].g,vpt[0].b) ;
909 }
910 break ;
911
912 case NI_RGBA:{
913 rgba *vpt = (rgba *)dpt ;
914 sprintf(wbuf+jj," %u %u %u %u",
915 vpt[0].r,vpt[0].g,vpt[0].b,vpt[0].a) ;
916 }
917 break ;
918
919 /* for floating point outputs,
920 first print to a temp string, then clip trailing and leading blanks */
921
922 case NI_FLOAT:{
923 float *vpt = (float *)dpt ;
924 char fbuf[32] ; int ff ;
925 sprintf(fbuf,"%14.7g",vpt[0]) ;
926 for( ff=strlen(fbuf) ; fbuf[ff]==' ' ; ff-- ) fbuf[ff] = '\0' ;
927 for( ff=0 ; fbuf[ff] == ' ' ; ff++ ) ;
928 sprintf(wbuf+jj," %s",fbuf+ff) ;
929 }
930 break ;
931
932 case NI_DOUBLE:{
933 double *vpt = (double *)dpt ;
934 char fbuf[32] ; int ff ;
935 sprintf(fbuf,"%20.14g",vpt[0]) ;
936 for( ff=strlen(fbuf) ; fbuf[ff]==' ' ; ff-- ) fbuf[ff] = '\0' ;
937 for( ff=0 ; fbuf[ff] == ' ' ; ff++ ) ;
938 sprintf(wbuf+jj," %s",fbuf+ff) ;
939 }
940 break ;
941
942 case NI_COMPLEX:{
943 complex *vpt = (complex *)dpt ;
944 char fbuf[32],gbuf[32] ; int ff,gg ;
945 sprintf(fbuf,"%14.7g",vpt[0].r) ;
946 for( ff=strlen(fbuf) ; fbuf[ff]==' ' ; ff-- ) fbuf[ff] = '\0' ;
947 for( ff=0 ; fbuf[ff] == ' ' ; ff++ ) ;
948 sprintf(gbuf,"%14.7g",vpt[0].i) ;
949 for( gg=strlen(gbuf) ; gbuf[gg]==' ' ; gg-- ) gbuf[gg] = '\0' ;
950 for( gg=0 ; gbuf[gg] == ' ' ; gg++ ) ;
951 sprintf(wbuf+jj," %s %s",fbuf+ff,gbuf+gg) ;
952 }
953 break ;
954
955 case NI_STRING:{ /* 30 Dec 2002 */
956 char **vpt = (char **)dpt , *str ;
957 if( !do_raw ){
958 str = quotize_string( *vpt ) ;
959 sprintf(wbuf+jj," %s",str) ;
960 NI_free(str) ;
961 } else {
962 sprintf(wbuf+jj," %s",*vpt) ;
963 }
964 }
965 break ;
966
967 } /* end of switch on part type */
968 }
969
970 /*-------------------------------------------------------------------------*/
971 /*! Encode nv type values at the end of the text string wbuf.
972 typ must be a fixed dim type code, or NI_STRING.
973 ---------------------------------------------------------------------------*/
974
NI_multival_to_text(NI_rowtype * rt,int nv,char * dpt,char * wbuf)975 void NI_multival_to_text( NI_rowtype *rt , int nv , char *dpt , char *wbuf )
976 {
977 int ii , jj=rt->size ;
978
979 for( ii=0 ; ii < nv ; ii++ )
980 NI_val_to_text( rt , dpt+ii*jj , wbuf ) ;
981 }
982
983 /*-------------------------------------------------------------------------*/
984 /*! Copy 1 fixed dim type (no String or var dim array parts here) value
985 in binary format to the wbuf.
986 - Return value is number of bytes written.
987 - Note that only data bytes are written, not any padding between parts.
988 ---------------------------------------------------------------------------*/
989
NI_val_to_binary(NI_rowtype * rt,char * dpt,char * wbuf)990 int NI_val_to_binary( NI_rowtype *rt , char *dpt , char *wbuf )
991 {
992 int jj=0 ; /* will be return value */
993
994 if( rt->size == rt->psiz ){ /* fixed dim, unpadded struct */
995
996 jj = rt->size ;
997 memcpy(wbuf,dpt,jj) ;
998
999 } else if( !ROWTYPE_is_varsize(rt) ){ /* derived fixed dim type */
1000 /* ==> write each part separately */
1001 int ii ;
1002 for( ii=0 ; ii < rt->part_num ; ii++ ){
1003 memcpy(wbuf+jj,dpt+rt->part_off[ii],rt->part_siz[ii]) ;
1004 jj += rt->part_siz[ii] ;
1005 }
1006
1007 }
1008
1009 return jj ;
1010 }
1011
1012 /*-------------------------------------------------------------------------*/
1013 /*! Copy nv fixed dim type values in binary format to the wbuf.
1014 - Return value is number of bytes written.
1015 - wbuf is assumed big enough to take the load
1016 ---------------------------------------------------------------------------*/
1017
NI_multival_to_binary(NI_rowtype * rt,int nv,char * dpt,char * wbuf)1018 int NI_multival_to_binary( NI_rowtype *rt , int nv , char *dpt , char *wbuf )
1019 {
1020 int jj=0 ;
1021
1022 if( rt->size == rt->psiz ){ /* fixed dim, unpadded structs */
1023 /* ==> Write all data at once */
1024 jj = nv * rt->size ;
1025 memcpy(wbuf,dpt,jj);
1026
1027 } else if( rt->psiz > 0 ){ /* Derived type is harder: */
1028 /* Write each struct separately */
1029 int ii ;
1030 for( ii=0 ; ii < nv ; ii++ )
1031 jj += NI_val_to_binary( rt , dpt+(ii*rt->size) , wbuf+jj ) ;
1032
1033 }
1034 return jj ;
1035 }
1036
1037 /*------------------------------------------------------------------------*/
1038 /*! Return 1 if the type contains a String part, 0 if not.
1039 --------------------------------------------------------------------------*/
1040
NI_has_String(NI_rowtype * rt)1041 int NI_has_String( NI_rowtype *rt )
1042 {
1043 int ii , jj ;
1044
1045 if( rt == NULL ) return 0 ;
1046
1047 /* test #1: if a NIML builtin type, test if it is String */
1048
1049 if( ROWTYPE_is_builtin_code(rt->code) ) return (rt->code == NI_STRING) ;
1050
1051 /* test the parts */
1052
1053 for( ii=0 ; ii < rt->part_num ; ii++ ){
1054 if( ROWTYPE_is_builtin_code(rt->part_rtp[ii]->code) ){ /* builtin part */
1055 if( rt->part_rtp[ii]->code == NI_STRING ) return 1;
1056 } else { /* derived part */
1057 if( NI_has_String( rt->part_rtp[ii] ) ) return 1; /* recursion */
1058 }
1059 }
1060 return 0 ;
1061 }
1062
1063 /*------------------------------------------------------------------------*/
1064 /*! Write one column of structs to the output stream. Now superseded
1065 by NI_write_columns(). This function is not used anywhere (I think).
1066 --------------------------------------------------------------------------*/
1067
NI_write_rowtype(NI_stream_type * ns,NI_rowtype * rt,int ndat,void * dat,int tmode)1068 int64_t NI_write_rowtype( NI_stream_type *ns , NI_rowtype *rt ,
1069 int ndat , void *dat , int tmode )
1070 {
1071 void *dpt = dat ;
1072 if( rt == NULL ) return -1 ;
1073 return NI_write_columns( ns , 1 , &(rt->code) , ndat , &dpt , tmode ) ;
1074 }
1075
1076 /*------------------------------------------------------------------------*/
1077
1078 #undef WCERR
1079 #define WCERR(x) fprintf(stderr,"NIML write data error %s\n",x)
1080
1081 /*------------------------------------------------------------------------*/
1082 /*! Write "columns" of data to a NI_stream. Each column is an array of
1083 structs of some NI_rowtype (including the builtin types):
1084 - ns = stream to write to
1085 - col_num = number of columns to write (1,2,...)
1086 - col_typ[i] = type code for column #i (i=0..col_num-1)
1087 - col_len = number of elements in each column
1088 - col_dpt[i] = pointer to data in column #i
1089 - tmode is one of
1090 - NI_TEXT_MODE ==> ASCII output
1091 - text mode is required if any data component is a String
1092 - text mode is required to "str:" streams
1093 - NI_BINARY_MODE ==> binary output (endian-ness of this CPU)
1094 - NI_BASE64_MODE ==> binary/base64 output (ditto)
1095 - return value is number of bytes written to stream
1096 (-1 if something bad happened, 0 if can't write to stream yet)
1097
1098 Only the data is written to the stream - no header or footer.
1099 This function is adapted from the 1st edition of NI_write_element().
1100 --------------------------------------------------------------------------*/
1101
NI_write_columns(NI_stream_type * ns,int col_num,int * col_typ,int col_len,void ** col_dpt,int tmode)1102 int64_t NI_write_columns( NI_stream_type *ns,
1103 int col_num , int *col_typ ,
1104 int col_len , void **col_dpt , int tmode )
1105 {
1106 int ii,jj , row , dim , col ;
1107 int64_t ntot , nout ; /* 28 Jul 2021 */
1108 char *ptr , **col_dat=(char **)col_dpt ;
1109 int nwbuf,bb=0,cc=0;
1110 char *wbuf=NULL ; /* write buffer */
1111 char *bbuf=NULL ; /* copy of write buffer */
1112 char *cbuf=NULL ; /* Base64 buffer */
1113
1114 NI_rowtype **rt=NULL ; /* array of NI_rowtype, 1 per column */
1115 int *vsiz=NULL , vsiz_tot=0 ;
1116 int *fsiz=NULL , fsiz_tot=0 ;
1117
1118 # undef FREEUP
1119 # define FREEUP do{ NI_free(wbuf); NI_free(bbuf); NI_free(cbuf); \
1120 NI_free(rt) ; NI_free(vsiz); NI_free(fsiz); \
1121 } while(0)
1122
1123 /*-- check inputs --*/
1124
1125 if( col_num <= 0 || col_len <= 0 ) return 0;
1126 if( col_typ == NULL || col_dat == NULL ){ WCERR("a"); return -1; }
1127 if( !NI_stream_writeable(ns) ){ WCERR("b"); return -1; }
1128
1129 #if 0
1130 fprintf(stderr,"NI_write_columns: col_num=%d col_len=%d tmode=%d\n",col_num,col_len,tmode) ;
1131 #endif
1132
1133 /*-- check stream --*/
1134
1135 if( ns->bad ){ /* not connected yet? */
1136 jj = NI_stream_goodcheck(ns,666) ; /* try to connect it */
1137 if( jj < 0 ) WCERR("c") ;
1138 if( jj < 1 ) return jj ; /* 0 is nothing yet, -1 is death */
1139 }
1140 #if 1
1141 jj = NI_stream_writecheck(ns,666) ;
1142 if( jj < 0 ){ WCERR("d"); return jj; } /* only exit if stream is actually bad */
1143 #endif
1144
1145 if( ns->type == NI_STRING_TYPE ) /* output to string buffer ==> text mode */
1146 tmode = NI_TEXT_MODE ;
1147
1148 /* create array of NI_rowtype for columns, etc. */
1149
1150 rt = NI_malloc(NI_rowtype*, sizeof(NI_rowtype *) * col_num ) ;
1151 vsiz = NI_malloc(int, sizeof(int) * col_num ) ;
1152 fsiz = NI_malloc(int, sizeof(int) * col_num ) ;
1153 for( col=0 ; col < col_num ; col++ ){
1154
1155 /* convert column type code to rowtype pointer */
1156
1157 rt[col] = NI_rowtype_find_code( col_typ[col] ) ;
1158
1159 /* can't find type, or no data in column? take this job and shove it */
1160
1161 if( rt[col] == NULL ){ FREEUP; WCERR("e") ; return -1; }
1162 if( col_dat[col] == NULL ){ FREEUP; WCERR("e'"); return -1; }
1163
1164 vsiz[col] = ROWTYPE_is_varsize(rt[col]) ; /* variable dim type? */
1165 fsiz[col] = rt[col]->size ; /* fixed size of struct (w/padding) */
1166 vsiz_tot += vsiz[col] ;
1167 fsiz_tot += fsiz[col] ;
1168
1169 /* can only write String parts in text mode */
1170
1171 if( tmode != NI_TEXT_MODE && NI_has_String(rt[col]) ) tmode = NI_TEXT_MODE;
1172 }
1173
1174 /*-- Special (and fast) case:
1175 one compact (no padding) fixed-size rowtype,
1176 and binary output ==> can write all data direct to stream at once --*/
1177
1178 if( col_num == 1 && tmode == NI_BINARY_MODE && fsiz[0] == rt[0]->psiz ){
1179 #if 0
1180 int ct = NI_clock_time() ;
1181 #endif
1182 nout = NI_stream_write( ns , col_dat[0] , fsiz[0]*col_len ) ;
1183 #if 0
1184 ct = NI_clock_time()-ct ;
1185 fprintf(stderr,"NI_write_columns FAST case: %d bytes in %d ms\n",fsiz[0]*col_len,ct) ;
1186 #endif
1187 FREEUP ; if( nout < 0 ) WCERR("f") ;
1188 return nout ;
1189 }
1190
1191 /*-- allocate space for the write buffer (1 row at a time) --*/
1192
1193 switch( tmode ){
1194 default: tmode = NI_TEXT_MODE ; /* fall through */
1195 case NI_TEXT_MODE: nwbuf = 6*fsiz_tot ; break ;
1196
1197 case NI_BASE64_MODE:
1198 case NI_BINARY_MODE: nwbuf = fsiz_tot ; break ;
1199 }
1200 wbuf = NI_malloc(char, nwbuf+128) ; /* 128 for the hell of it */
1201
1202 /* create buffers for Base64 output, if needed */
1203
1204 if( tmode == NI_BASE64_MODE ){
1205 bbuf = NI_malloc(char, nwbuf+128) ; bb = 0 ; /* binary buffer */
1206 cbuf = NI_malloc(char, 2*nwbuf+128) ; cc = 0 ; /* base64 buffer */
1207 load_encode_table() ;
1208 }
1209
1210 /* this macro take the 'nout' number of output bytes
1211 and adds into the running total ntot if all was well;
1212 if all was not well with the write, then it aborts the output */
1213
1214 # undef ADDOUT
1215 # define ADDOUT(x) \
1216 if( nout < 0 ){ \
1217 fprintf(stderr,"NIML:: write abort!\n"); \
1218 FREEUP ; WCERR(x) ; return -1 ; \
1219 } else ntot+=nout
1220
1221 /*-- loop over output rows,
1222 format for output into wbuf, and then send to output stream --*/
1223
1224 ntot = 0 ; /* total number of bytes output to stream */
1225
1226 for( row=0 ; row < col_len ; row++ ){
1227
1228 /* expand write buffer if any type contains variable dim array(s) */
1229
1230 if( vsiz_tot ){
1231 for( jj=col=0 ; col < col_num ; col++ ){
1232 ptr = col_dat[col] + fsiz[col]*row ; /* ptr to row-th element */
1233 jj += NI_rowtype_vsize( rt[col] , ptr ); /* size of data, w/var arrays */
1234 }
1235 if( tmode == NI_TEXT_MODE ) jj *= 6 ;
1236 if( jj > nwbuf ){ /* did it get bigger? */
1237 nwbuf = jj ;
1238 wbuf = NI_realloc(wbuf, char,nwbuf+128) ;
1239 if( tmode == NI_BASE64_MODE ){ /* expand Base64 stuff, too */
1240 bbuf = NI_realloc(bbuf, char, nwbuf+128) ;
1241 cbuf = NI_realloc(cbuf, char,2*nwbuf+128) ;
1242 }
1243 }
1244 }
1245
1246 /* initialize write buffer for this row */
1247
1248 switch( tmode ){
1249 case NI_TEXT_MODE: wbuf[0] = '\0'; break; /* clear buffer */
1250 case NI_BASE64_MODE:
1251 case NI_BINARY_MODE: jj = 0 ; break; /* clear byte count */
1252 }
1253
1254 /* loop over columns, write each into the buffer */
1255
1256 for( col=0 ; col < col_num ; col++ ){
1257 ptr = col_dat[col] + fsiz[col]*row ; /* ptr to row-th struct */
1258 /* in this columns */
1259
1260 /* write each part of this struct into the buffer */
1261
1262 /* in text mode, strlen(wbuf) keeps track of number of bytes;
1263 in binary mode, jj keeps track of number of bytes written */
1264
1265 for( ii=0 ; ii < rt[col]->part_num ; ii++ ){ /*-- loop over parts --*/
1266
1267 if( rt[col]->part_dim[ii] < 0 ){ /*-- a single value --*/
1268 switch( tmode ){ /*-- output method (text or binary) --*/
1269
1270 case NI_TEXT_MODE: /*-- sprintf value to output --*/
1271 NI_val_to_text( rt[col]->part_rtp[ii],
1272 ptr+rt[col]->part_off[ii], wbuf ) ;
1273 break ;
1274
1275 case NI_BASE64_MODE: /*-- memcpy values to output --*/
1276 case NI_BINARY_MODE:
1277 jj += NI_val_to_binary( rt[col]->part_rtp[ii],
1278 ptr+rt[col]->part_off[ii], wbuf+jj ) ;
1279 break ;
1280 }
1281
1282 } else { /*-- variable dimension array --*/
1283
1284 char **apt = (char **)(ptr+rt[col]->part_off[ii]); /* data in struct */
1285 /* is ptr to array */
1286
1287 dim = ROWTYPE_part_dimen(rt[col],ptr,ii) ; /* dimension of part */
1288 if( dim > 0 && *apt != NULL ){
1289 switch( tmode ){
1290 case NI_TEXT_MODE:
1291 NI_multival_to_text( rt[col]->part_rtp[ii] , dim ,
1292 *apt , wbuf ) ;
1293 break ;
1294 case NI_BASE64_MODE:
1295 case NI_BINARY_MODE:
1296 jj += NI_multival_to_binary( rt[col]->part_rtp[ii] , dim ,
1297 *apt , wbuf+jj ) ;
1298 break ;
1299 }
1300 }
1301 }
1302
1303 } /* end of loop over parts in this column struct */
1304 } /* end of loop over columns */
1305
1306 /*- actually write the row data in wbuf out -*/
1307
1308 switch( tmode ){
1309
1310 case NI_TEXT_MODE: /* each row is on a separate line */
1311 strcat(wbuf,"\n") ;
1312 nout = NI_stream_writestring( ns , wbuf ) ;
1313 ADDOUT("A") ;
1314 break ;
1315
1316 case NI_BINARY_MODE: /* jj bytes of binary in wbuf */
1317 nout = NI_stream_write( ns , wbuf , jj ) ;
1318 #ifdef NIML_DEBUG
1319 if( nout != jj ) NI_dpr("NI_write_columns: col#%d sends %d bytes; nout=%d\n",col,jj,nout) ;
1320 #endif
1321 ADDOUT("B") ;
1322 break ;
1323
1324 case NI_BASE64_MODE:{ /* convert binary triples into base64 quads */
1325 int nb , nb3 , nb64 , pp,qq ;
1326 byte a,b,c,w,x,y,z ;
1327
1328 /* bbuf = bb bytes of unprocessed data from last struct
1329 plus jj bytes of data from new struct
1330 (bb will be 0 or 1 or 2) */
1331
1332 memcpy(bbuf+bb,wbuf,jj) ; /* add wbuf to tail of bbuf */
1333 nb = jj+bb ; /* number of bytes in bb */
1334 if( nb < 3 ){ bb = nb; break; } /* need at least 3 bytes */
1335 nb3 = 3*(nb/3) ; /* will encode nb3 bytes */
1336
1337 /* cbuf = base64 output buffer */
1338 /* cc = # bytes written since last EOL */
1339
1340 for( qq=pp=0 ; pp < nb3 ; ){
1341 a = bbuf[pp++] ; b = bbuf[pp++] ; c = bbuf[pp++] ;
1342 B64_encode3(a,b,c,w,x,y,z) ;
1343 cbuf[qq++] = w ; cbuf[qq++] = x ;
1344 cbuf[qq++] = y ; cbuf[qq++] = z ;
1345 cc += 4; if( cc > 64 ){ cbuf[qq++]=B64_EOL2; cc=0; }
1346 }
1347
1348 /* write base64 bytes to output */
1349
1350 nout = NI_stream_write( ns , cbuf , qq ) ;
1351 ADDOUT("C") ;
1352
1353 /* deal with leftover bytes in bbuf */
1354
1355 bb = nb - nb3 ; /* num leftover bytes = 0, 1, or 2 */
1356 if( bb > 0 ){
1357 bbuf[0] = bbuf[nb3] ; /* copy leftovers */
1358 if( bb > 1 ) bbuf[1] = bbuf[nb3+1] ; /* to front of bbuf */
1359 }
1360 }
1361 break ;
1362 }
1363
1364 } /* end of loop over output structs (row) */
1365
1366 /* in Base64 mode, we might have to clean
1367 up if there are any leftover bytes in bbuf,
1368 or at least write an end of line */
1369
1370 if( tmode == NI_BASE64_MODE ){
1371 if( bb > 0 ){ /* num leftover bytes of data */
1372 byte w,x,y,z , a=bbuf[0],b=bbuf[1] ;
1373 if( bb == 2 ) B64_encode2(a,b,w,x,y,z) ;
1374 else B64_encode1(a,w,x,y,z) ;
1375 cbuf[0] = w ; cbuf[1] = x ;
1376 cbuf[2] = y ; cbuf[3] = z ; cbuf[4] = B64_EOL2 ;
1377 nout = NI_stream_write( ns , cbuf , 5 ) ;
1378 ADDOUT("D") ;
1379 } else if( cc > 0 ){ /* just write an end of line */
1380 cbuf[0] = B64_EOL2 ;
1381 nout = NI_stream_write( ns , cbuf , 1 ) ;
1382 ADDOUT("E") ;
1383 }
1384 }
1385
1386 /*-- cleanup and return --*/
1387
1388 FREEUP ; if( ntot < 0 ) WCERR("Z") ;
1389 return ntot ;
1390 }
1391
1392 /*------------------------------------------------------------------------*/
1393 /*! Read "columns" of data from a NI_stream. Each column is an array of
1394 structs of some NI_rowtype (including the builtin types):
1395 - ns = stream to read from
1396 - col_num = number of columns to read (1,2,...)
1397 - col_typ[i] = type code for column #i (i=0..col_num-1)
1398 - col_len = number of elements in each column
1399 - col_len can be 0, which means read data until the end-of-input
1400 - end-of-input is end-of-stream, or '<' in NI_TEXT_MODE
1401 - col_dpt[i] = pointer to data in column #i
1402 - col_dpt can't be NULL
1403 - but if col_dpt[i] is NULL, it will be NI_malloc()-ed
1404 - if col_dpt[i] isn't NULL, it must point to space big
1405 enough to hold the input (col_num * fixed size of rowtype #i)
1406 - if col_len==0 on input:
1407 - then col_dpt[i] should be NULL for i=0..col_num-1
1408 - this function will NI_malloc() to fit the amount of data scanned
1409 - if col_dpt[i]!=NULL with col_len==0, then function returns -1
1410 - tmode is one of
1411 - NI_TEXT_MODE ==> ASCII input
1412 - text mode is required if any rowtype component is a String
1413 - text mode is required from "str:" streams
1414 - NI_BINARY_MODE ==> binary input
1415 - NI_BASE64_MODE ==> binary/base64 input
1416 - flags is the OR of various bit masks
1417 - NI_SWAP_MASK ==> binary input must be byte-swapped after input
1418 - NI_LTEND_MASK ==> text input stops at a '<' in the input
1419 - return value is:
1420 - number of complete rows actually read (<= col_len)
1421 - zero if stream isn't ready to read
1422 - -1 if something bad happened
1423
1424 Only the data is read from the stream - no header or footer.
1425 This function is adapted from the 1st edition of NI_read_element().
1426 --------------------------------------------------------------------------*/
1427
NI_read_columns(NI_stream_type * ns,int col_num,int * col_typ,int col_len,void ** col_dpt,int tmode,int flags)1428 int NI_read_columns( NI_stream_type *ns,
1429 int col_num, int *col_typ,
1430 int col_len, void **col_dpt, int tmode, int flags )
1431 {
1432 int ii,jj , row , dim , nin , col , nn=0 ;
1433 char *ptr , **col_dat=(char **)col_dpt ;
1434
1435 NI_rowtype **rt=NULL ; /* array of NI_rowtype, 1 per column */
1436 int *vsiz=NULL , vsiz_tot=0 ;
1437 int *fsiz=NULL , fsiz_tot=0 ;
1438
1439 int (*ReadFun)( NI_stream_type *, NI_rowtype *, void *, int ) ;
1440 int ltend = (flags & NI_LTEND_MASK) != 0 ;
1441 int swap = (flags & NI_SWAP_MASK) != 0 ;
1442 int ReadFlag ;
1443 int open_ended = (col_len==0) , row_top ; /* 27 Mar 2003 */
1444
1445 # undef FREEUP
1446 # define FREEUP do{ NI_free(rt); NI_free(vsiz); NI_free(fsiz); } while(0)
1447
1448 /*-- check inputs --*/
1449
1450 if( col_num <= 0 || col_len < 0 ) return 0 ;
1451 if( col_typ == NULL || col_dat == NULL ) return -1 ;
1452 if( !NI_stream_readable(ns) ) return -1 ;
1453
1454 #ifdef NIML_DEBUG
1455 NI_dpr("ENTER NI_read_columns\n") ;
1456 #endif
1457
1458 /*-- check stream --*/
1459
1460 if( ns->bad ){ /* not connected yet? */
1461 jj = NI_stream_goodcheck(ns,666) ; /* try to connect it */
1462 if( jj < 1 ) return jj ; /* 0 is nothing yet, -1 is death */
1463 }
1464 jj = NI_stream_hasinput(ns,666) ; /* any data to be had? */
1465 if( jj < 0 ) return jj ; /* only exit if stream is actually bad */
1466
1467 /* create array of NI_rowtype for columns, etc. */
1468
1469 rt = NI_malloc(NI_rowtype*, sizeof(NI_rowtype *) * col_num ) ;
1470 vsiz = NI_malloc(int, sizeof(int) * col_num ) ;
1471 fsiz = NI_malloc(int, sizeof(int) * col_num ) ;
1472 if( open_ended ) col_len = 1 ;
1473 for( col=0 ; col < col_num ; col++ ){
1474
1475 rt[col] = NI_rowtype_find_code( col_typ[col] ) ;
1476 if( rt[col] == NULL ){ FREEUP; return -1; }
1477 if( tmode != NI_TEXT_MODE && NI_has_String(rt[col]) ){ FREEUP; return -1; }
1478
1479 vsiz[col] = ROWTYPE_is_varsize(rt[col]) ; /* variable dim type? */
1480 fsiz[col] = rt[col]->size ; /* fixed size of struct (w/padding) */
1481 vsiz_tot += vsiz[col] ;
1482 fsiz_tot += fsiz[col] ;
1483
1484 /* setup data array for this column */
1485
1486 if( col_dat[col] == NULL ){
1487 col_dat[col] = NI_malloc(char, fsiz[col]*col_len ) ; /* make space */
1488 } else {
1489 if( open_ended ){ FREEUP; return -1; }
1490 memset( col_dat[col], 0 , fsiz[col]*col_len ) ; /* set space to 0 */
1491 }
1492 }
1493
1494 /*-- Special (and fast) case:
1495 one compact (no padding) fixed-size rowtype,
1496 and binary input ==> can read all data direct from stream at once --*/
1497
1498 if( col_num == 1 &&
1499 fsiz[0] == rt[0]->psiz && /* struct size == data size */
1500 tmode == NI_BINARY_MODE &&
1501 !open_ended ){
1502
1503 nin = NI_stream_readbuf( ns , col_dat[0] , fsiz[0]*col_len ) ;
1504 if( nin < fsiz[0] ){ FREEUP; return (nin >= 0) ? 0 : -1 ; } /* bad */
1505 nin = nin / fsiz[0] ; /* number of rows finished */
1506 goto ReadFinality ; /* post-process input down below */
1507 }
1508
1509 /*-- 21 Apr 2005: repeat above for Base64 input --*/
1510
1511 if( col_num == 1 &&
1512 fsiz[0] == rt[0]->psiz && /* struct size == data size */
1513 tmode == NI_BASE64_MODE &&
1514 !open_ended ){
1515
1516 nin = NI_stream_readbuf64( ns , col_dat[0] , fsiz[0]*col_len ) ;
1517 if( nin < fsiz[0] ){ FREEUP; return (nin >= 0) ? 0 : -1 ; } /* bad */
1518 nin = nin / fsiz[0] ; /* number of rows finished */
1519 goto ReadFinality ; /* post-process input down below */
1520 }
1521
1522 /*-- Choose function to read from stream and fill one struct --*/
1523
1524 switch( tmode ){
1525 case NI_TEXT_MODE: ReadFun = NI_text_to_val ; ReadFlag = ltend; break;
1526 case NI_BINARY_MODE: ReadFun = NI_binary_to_val; ReadFlag = swap ; break;
1527 case NI_BASE64_MODE: ReadFun = NI_base64_to_val; ReadFlag = swap ; break;
1528 default:
1529 fprintf(stderr,"\n** NI_read_columns: unknown input tmode=%d\n",tmode);
1530 FREEUP ; return -1 ;
1531 }
1532
1533 /*-- OK, have to read the hard ways --*/
1534
1535 row_top = (open_ended) ? 1999999999 : col_len ; /* 28 Mar 2003 */
1536
1537 for( row=0 ; row < row_top ; row++ ){ /* loop over rows */
1538 /* until all done */
1539
1540 #ifdef NIML_DEBUG
1541 NI_dpr(" Starting row #%d\n",row) ;
1542 #endif
1543
1544 /* 27 Mar 2003: maybe need to extend length of columns */
1545
1546 if( open_ended && row >= col_len ){
1547 #ifdef NIML_DEBUG
1548 NI_dpr(" Extending column lengths!\n") ;
1549 #endif
1550 jj = (int)(1.2*col_len+32) ;
1551 for( col=0 ; col < col_num ; col++ ){
1552 col_dat[col] = NI_realloc( col_dat[col] , char, fsiz[col]*jj ) ;
1553 memset( col_dat[col]+fsiz[col]*col_len, 0 , fsiz[col]*(jj-col_len) ) ;
1554 }
1555 col_len = jj ;
1556 }
1557
1558 /* loop over columns, read into struct */
1559
1560 for( col=0 ; col < col_num ; col++ ){
1561 ptr = col_dat[col] + fsiz[col]*row ; /* ptr to row-th struct */
1562 nn = ReadFun( ns, rt[col], ptr, ReadFlag ) ; /* read data to struct */
1563 if( !nn ) break ;
1564 }
1565 if( !nn ) break ; /* some ReadFun() failed */
1566 }
1567
1568 if( row == 0 ){ /* didn't finish any rows */
1569 if( open_ended ){
1570 for( col=0 ; col < col_num ; col++ ) NI_free(col_dat[col]) ;
1571 }
1572 FREEUP; return -1;
1573 }
1574
1575 nin = row ; /* number of rows finished */
1576
1577 if( open_ended && nin < col_len ){ /* truncate columns */
1578 for( col=0 ; col < col_num ; col++ )
1579 col_dat[col] = NI_realloc( col_dat[col] , char, fsiz[col]*nin ) ;
1580 }
1581
1582 /*-- Have read all data; byte swap if needed, then get outta here --*/
1583
1584 ReadFinality:
1585
1586 if( tmode != NI_TEXT_MODE && swap ){
1587 for( col=0 ; col < col_num ; col++ )
1588 NI_swap_column( rt[col] , nin , col_dat[col] ) ;
1589 }
1590
1591 #ifdef NIML_DEBUG
1592 NI_dpr("Leaving NI_read_columns\n") ;
1593 #endif
1594
1595 FREEUP ; return nin ;
1596 }
1597
1598 /*-------------------------------------------------------------------------*/
1599 /*! Decode binary data from the NI_stream ns into a rowtype struct *dpt.
1600 - Note that String (aka NI_STRING) parts are illegal here.
1601 - Return value is 1 if all was OK, 0 if something bad happened.
1602 - Parameter swap indicates that the data coming in needs to be
1603 byte-swapped.
1604 - This is ONLY used to byte-swap the dimension for var-dimen arrays.
1605 - Actual byte-swapping of the data is done in NI_swap_column().
1606 ---------------------------------------------------------------------------*/
1607
NI_binary_to_val(NI_stream_type * ns,NI_rowtype * rt,void * dpt,int swap)1608 int NI_binary_to_val( NI_stream_type *ns, NI_rowtype *rt, void *dpt, int swap )
1609 {
1610 int nn , jj ;
1611
1612 if( rt->code == NI_STRING ) return 0 ; /* shouldn't happen */
1613
1614 if( rt->size == rt->psiz ){ /* fixed-size type with no padding */
1615 /* ==> can read directly into data struct */
1616
1617 jj = NI_stream_readbuf( ns , (char *)dpt , rt->size ) ;
1618 return (jj == rt->size) ;
1619
1620 } else { /* derived type */
1621
1622 char *dat = (char *)dpt , **aaa = NULL ;
1623 int ii , naaa = 0 , iaaa = 0 ;
1624
1625 if( ROWTYPE_is_varsize(rt) ){ /* variable dim arrays inside */
1626 for( naaa=ii=0 ; ii < rt->part_num ; ii++ )
1627 if( rt->part_dim[ii] >= 0 ) naaa++ ; /* count var dim arrays */
1628 if( naaa > 0 )
1629 aaa = NI_malloc(char*, sizeof(char *)*naaa) ; /* save their addresses */
1630 } /* for possible deletion later */
1631
1632 /* loop over parts and load them;
1633 set nn=0 if read fails at any part (and break out of read loop) */
1634
1635 for( nn=1,ii=0 ; ii < rt->part_num ; ii++ ){
1636
1637 if( rt->part_dim[ii] < 0 ){ /* read one fixed dim part */
1638
1639 nn = NI_binary_to_val( ns, rt->part_rtp[ii], dat+rt->part_off[ii], 0 );
1640
1641 } else { /* read var dim array */
1642
1643 char **apt = (char **)(dat+rt->part_off[ii]); /* data in struct */
1644 /* will be ptr to array */
1645 int dim = ROWTYPE_part_dimen(rt,dat,ii) ; /* dimension of part */
1646 int siz = rt->part_rtp[ii]->size ; /* size of one part */
1647
1648 if( swap ) NI_swap4( 1 , &dim ) ; /* byte-swap dim, which was */
1649 /* just read in a moment ago */
1650
1651 if( dim > 0 ){ /* need to get some data */
1652 *apt = NI_malloc(char, siz * dim ); /* make array */
1653
1654 if( siz != rt->part_rtp[ii]->psiz ){ /* padded values ==> */
1655 for( jj=0 ; jj < dim ; jj++ ){ /* read 1 val at a time */
1656 nn = NI_binary_to_val( ns, rt->part_rtp[ii],
1657 *apt + siz * jj , 0 ) ;
1658 if( !nn ) break ; /* bad read */
1659 }
1660
1661 } else { /* unpadded values ==> read all at once */
1662 jj = NI_stream_readbuf( ns , *apt , siz*dim ) ;
1663 nn = ( jj == siz*dim ) ;
1664 }
1665
1666 } else {
1667 *apt = NULL ; /* dim=0 ==> no array needed */
1668 }
1669 aaa[iaaa++] = *apt ; /* save for possible deletion */
1670 /* if read fails later in loop */
1671 }
1672
1673 if( !nn ) break ; /* some read was bad */
1674 } /* end of loop over parts */
1675
1676 /* bad news ==> delete any allocated var dim arrays */
1677
1678 if( !nn ){
1679 for( ii=0 ; ii < iaaa ; ii++ ) NI_free( aaa[ii] ) ;
1680 }
1681 NI_free( aaa ) ; /* don't need list of var dim arrays no more */
1682 }
1683
1684 return nn ;
1685 }
1686
1687 /*-------------------------------------------------------------------------*/
1688 /*! Decode Base64 data from the NI_stream ns into a rowtype struct *dpt.
1689 - Note that String (aka NI_STRING) parts are illegal here.
1690 - Return value is 1 if all was OK, 0 if something bad happened.
1691 - Parameter swap indicates that the data coming in needs to be
1692 byte-swapped.
1693 - This is ONLY used to byte-swap the dimension for var-dimen arrays.
1694 - Actual byte-swapping of the data is done in NI_swap_column().
1695 ---------------------------------------------------------------------------*/
1696
NI_base64_to_val(NI_stream_type * ns,NI_rowtype * rt,void * dpt,int swap)1697 int NI_base64_to_val( NI_stream_type *ns, NI_rowtype *rt, void *dpt, int swap )
1698 {
1699 int nn , jj ;
1700
1701 if( rt->code == NI_STRING ) return 0 ; /* shouldn't happen */
1702
1703 if( rt->size == rt->psiz ){ /* fixed-size type with no padding */
1704 /* ==> can read directly into data struct */
1705
1706 jj = NI_stream_readbuf64( ns , (char *)dpt , rt->size ) ;
1707 return (jj == rt->size) ;
1708
1709 } else { /* derived type */
1710
1711 char *dat = (char *)dpt , **aaa = NULL ;
1712 int ii , naaa = 0 , iaaa = 0 ;
1713
1714 if( ROWTYPE_is_varsize(rt) ){ /* variable dim arrays inside */
1715 for( naaa=ii=0 ; ii < rt->part_num ; ii++ )
1716 if( rt->part_dim[ii] >= 0 ) naaa++ ; /* count var dim arrays */
1717 if( naaa > 0 )
1718 aaa = NI_malloc(char*, sizeof(char *)*naaa) ; /* save their addresses */
1719 } /* for possible deletion later */
1720
1721 /* loop over parts and load them;
1722 set nn=0 if read fails at any part (and break out of read loop) */
1723
1724 for( nn=1,ii=0 ; ii < rt->part_num ; ii++ ){
1725
1726 if( rt->part_dim[ii] < 0 ){ /* read one fixed dim part */
1727
1728 nn = NI_base64_to_val( ns, rt->part_rtp[ii], dat+rt->part_off[ii], 0 );
1729
1730 } else { /* read var dim array */
1731
1732 char **apt = (char **)(dat+rt->part_off[ii]); /* data in struct */
1733 /* will be ptr to array */
1734 int dim = ROWTYPE_part_dimen(rt,dat,ii) ; /* dimension of part */
1735 int siz = rt->part_rtp[ii]->size ; /* size of one part */
1736
1737 if( swap ) NI_swap4( 1 , &dim ) ; /* byte-swap dim, which was */
1738 /* just read in a moment ago */
1739
1740 if( dim > 0 ){ /* need to get some data */
1741 *apt = NI_malloc(char, siz * dim ); /* make array */
1742
1743 if( siz != rt->part_rtp[ii]->psiz ){ /* padded values ==> */
1744 for( jj=0 ; jj < dim ; jj++ ){ /* read 1 val at a time */
1745 nn = NI_base64_to_val( ns, rt->part_rtp[ii],
1746 *apt + siz * jj , 0 ) ;
1747 if( !nn ) break ; /* bad read */
1748 }
1749
1750 } else { /* unpadded values ==> read all at once */
1751 jj = NI_stream_readbuf64( ns , *apt , siz*dim ) ;
1752 nn = ( jj == siz*dim ) ;
1753 }
1754
1755 } else {
1756 *apt = NULL ; /* dim=0 ==> no array needed */
1757 }
1758 aaa[iaaa++] = *apt ; /* save for possible deletion */
1759 /* if read fails later in loop */
1760 }
1761
1762 if( !nn ) break ; /* some read was bad */
1763 } /* end of loop over parts */
1764
1765 /* bad news ==> delete any allocated var dim arrays */
1766
1767 if( !nn ){
1768 for( ii=0 ; ii < iaaa ; ii++ ) NI_free( aaa[ii] ) ;
1769 }
1770 NI_free( aaa ) ; /* don't need list of var dim arrays no more */
1771 }
1772
1773 return nn ;
1774 }
1775
1776 /*-------------------------------------------------------------------------*/
1777 /*! Decode text from the NI_stream into a rowtype struct.
1778 - Parameter ltend != 0 means stop at '<' character.
1779 - Return value is 1 if it works, 0 if it fails.
1780 - If it works, *dpt will be filled with values.
1781 - Note that dpt must be pre-allocated rt->size bytes long.
1782 ---------------------------------------------------------------------------*/
1783
NI_text_to_val(NI_stream_type * ns,NI_rowtype * rt,void * dpt,int ltend)1784 int NI_text_to_val( NI_stream_type *ns, NI_rowtype *rt, void *dpt, int ltend )
1785 {
1786 int nn ;
1787
1788 switch( rt->code ){
1789
1790 /*-- a derived type: fill the parts by recursion --*/
1791
1792 default:{
1793 char *dat = (char *)dpt , **aaa = NULL ;
1794 int ii , jj , naaa = 0 , iaaa = 0 ;
1795
1796 if( ROWTYPE_is_varsize(rt) ){ /* variable dim arrays inside */
1797 for( naaa=ii=0 ; ii < rt->part_num ; ii++ )
1798 if( rt->part_dim[ii] >= 0 ) naaa++ ; /* count var dim arrays */
1799 if( naaa > 0 )
1800 aaa = NI_malloc(char*, sizeof(char *)*naaa) ; /* save their addresses */
1801 } /* for possible deletion later */
1802
1803 /* loop over parts and load them */
1804
1805 for( nn=1,ii=0 ; ii < rt->part_num ; ii++ ){
1806
1807 if( rt->part_dim[ii] < 0 ){ /* one fixed dim part */
1808
1809 nn = NI_text_to_val( ns, rt->part_rtp[ii],
1810 dat+rt->part_off[ii], ltend );
1811
1812 } else { /* var dim array */
1813
1814 char **apt = (char **)(dat+rt->part_off[ii]); /* data in struct */
1815 /* will be ptr to array */
1816 int dim = ROWTYPE_part_dimen(rt,dat,ii) ; /* dimension of part */
1817 int siz = rt->part_rtp[ii]->size ; /* size of one part struct */
1818 if( dim > 0 ){
1819 *apt = NI_malloc(char, siz * dim ); /* make array */
1820 for( jj=0 ; jj < dim ; jj++ ){ /* get values for array */
1821 nn = NI_text_to_val( ns, rt->part_rtp[ii],
1822 *apt + siz * jj , ltend ) ;
1823 if( !nn ) break ;
1824 }
1825 } else {
1826 *apt = NULL ; /* dim=0 ==> no array needed */
1827 }
1828 aaa[iaaa++] = *apt ; /* save for possible deletion */
1829
1830 }
1831
1832 if( !nn ) break ; /* some read was bad */
1833 } /* end of loop over parts */
1834
1835 /* bad news ==> delete any allocated var dim arrays */
1836
1837 if( !nn ){
1838 for( ii=0 ; ii < iaaa ; ii++ ) NI_free( aaa[ii] ) ;
1839 NI_free( aaa ) ;
1840 return 0 ;
1841 }
1842 NI_free( aaa ) ; /* in any case, dump this */
1843 }
1844 break ;
1845
1846 /*-- the 9 builtin types below here; first up: String! --*/
1847
1848 case NI_STRING:{
1849 char *val=NULL ;
1850 char **vpt = (char **) dpt ;
1851 nn = NI_decode_one_string( ns , &val , ltend ) ;
1852 if( !nn || val == NULL ) return 0 ;
1853 unescape_inplace(val) ;
1854 *vpt = val ;
1855 }
1856 break ;
1857
1858 /*-- numeric types below here --*/
1859
1860 case NI_BYTE:{
1861 double val ;
1862 byte *vpt = (byte *) dpt ;
1863 nn = NI_decode_one_double( ns , &val , ltend ) ;
1864 if( !nn ) return 0 ;
1865 *vpt = (byte) val ;
1866 }
1867 break ;
1868
1869 case NI_SHORT:{
1870 double val ;
1871 short *vpt = (short *) dpt ;
1872 nn = NI_decode_one_double( ns , &val , ltend ) ;
1873 if( !nn ) return 0 ;
1874 *vpt = (short) val ;
1875 }
1876 break ;
1877
1878 case NI_INT:{
1879 double val ;
1880 int *vpt = (int *) dpt ;
1881 nn = NI_decode_one_double( ns , &val , ltend ) ;
1882 if( !nn ) return 0 ;
1883 *vpt = (int) val ;
1884 }
1885 break ;
1886
1887 case NI_FLOAT:{
1888 double val ;
1889 float *vpt = (float *) dpt ;
1890 nn = NI_decode_one_double( ns , &val , ltend ) ;
1891 if( !nn ) return 0 ;
1892 *vpt = (float) val ;
1893 }
1894 break ;
1895
1896 case NI_DOUBLE:{
1897 double val ;
1898 double *vpt = (double *) dpt ;
1899 nn = NI_decode_one_double( ns , &val , ltend ) ;
1900 if( !nn ) return 0 ;
1901 *vpt = (double) val ;
1902 }
1903 break ;
1904
1905 case NI_COMPLEX:{
1906 double v1,v2 ;
1907 complex *vpt = (complex *) dpt ;
1908 nn = NI_decode_one_double( ns , &v1 , ltend ) ;
1909 if( !nn ) return 0 ;
1910 nn = NI_decode_one_double( ns , &v2 , ltend ) ;
1911 if( !nn ) return 0 ;
1912 vpt->r = (float) v1 ;
1913 vpt->i = (float) v2 ;
1914 }
1915 break ;
1916
1917 case NI_RGB:{
1918 double v1,v2,v3 ;
1919 rgb *vpt = (rgb *) dpt ;
1920 nn = NI_decode_one_double( ns , &v1 , ltend ) ;
1921 if( !nn ) return 0 ;
1922 nn = NI_decode_one_double( ns , &v2 , ltend ) ;
1923 if( !nn ) return 0 ;
1924 nn = NI_decode_one_double( ns , &v3 , ltend ) ;
1925 if( !nn ) return 0 ;
1926 vpt->r = (byte) v1 ;
1927 vpt->g = (byte) v2 ;
1928 vpt->b = (byte) v3 ;
1929 }
1930 break ;
1931
1932 case NI_RGBA:{
1933 double v1,v2,v3,v4 ;
1934 rgba *vpt = (rgba *) dpt ;
1935 nn = NI_decode_one_double( ns , &v1 , ltend ) ;
1936 if( !nn ) return 0 ;
1937 nn = NI_decode_one_double( ns , &v2 , ltend ) ;
1938 if( !nn ) return 0 ;
1939 nn = NI_decode_one_double( ns , &v3 , ltend ) ;
1940 if( !nn ) return 0 ;
1941 nn = NI_decode_one_double( ns , &v4 , ltend ) ;
1942 if( !nn ) return 0 ;
1943 vpt->r = (byte) v1 ;
1944 vpt->g = (byte) v2 ;
1945 vpt->b = (byte) v3 ;
1946 vpt->a = (byte) v4 ;
1947 }
1948 break ;
1949
1950 } /* end of switch on type */
1951
1952 return 1 ; /* good */
1953 }
1954
1955 /*-------------------------------------------------------------------------*/
1956 /*! Swap bytes in a bunch of rowtype structs.
1957 ---------------------------------------------------------------------------*/
1958
NI_swap_column(NI_rowtype * rt,int nrow,char * dat)1959 void NI_swap_column( NI_rowtype *rt , int nrow , char *dat )
1960 {
1961 if( rt == NULL || nrow <= 0 || dat == NULL ) return ; /* stupid inputs */
1962
1963 switch( rt->code ){
1964
1965 case NI_RGB:
1966 case NI_RGBA:
1967 case NI_STRING:
1968 case NI_BYTE: return ; /* nothing to do */
1969
1970 /*-- basic types --*/
1971
1972 case NI_SHORT:
1973 NI_swap2( nrow , dat ) ;
1974 return ;
1975
1976 case NI_INT:
1977 case NI_FLOAT:
1978 NI_swap4( nrow , dat ) ;
1979 return ;
1980
1981 case NI_DOUBLE:
1982 NI_swap8( nrow , dat ) ;
1983 return ;
1984
1985 case NI_COMPLEX:
1986 NI_swap4( 2*nrow , dat ) ;
1987 return ;
1988
1989 /* a derived type (use recursion) */
1990
1991 default:{
1992 int ii , row , fsiz = rt->size ;
1993 char *ptr ;
1994
1995 for( row=0 ; row < nrow ; row++ ){
1996 ptr = dat + fsiz*row ; /* ptr to row-th element */
1997
1998 /* loop over parts and swap them, 1 at a time */
1999
2000 for( ii=0 ; ii < rt->part_num ; ii++ ){
2001
2002 if( rt->part_dim[ii] < 0 ){ /* fixed dim part */
2003
2004 NI_swap_column( rt->part_rtp[ii] , 1 , ptr+rt->part_off[ii] ) ;
2005
2006 } else { /* var dim array */
2007
2008 char **apt = (char **)(ptr+rt->part_off[ii]); /* data in struct */
2009 /* is ptr to array */
2010 int dim = ROWTYPE_part_dimen(rt,dat,ii) ; /* dimension of part */
2011 NI_swap_column( rt->part_rtp[ii] , dim , *apt ) ;
2012
2013 }
2014 } /* end of loop over parts */
2015 } /* end of loop over rows */
2016 }
2017 return ;
2018 }
2019 }
2020
2021 /*--------------------------------------------------------------------------*/
2022 /*! Delete a column of rowtype structs, including any var dim arrays.
2023 Assumes everything was allocated with NI_malloc().
2024 After this is called, the cpt argument should be set to NULL.
2025 ----------------------------------------------------------------------------*/
2026
NI_free_column(NI_rowtype * rt,int col_len,void * cpt)2027 void NI_free_column( NI_rowtype *rt , int col_len , void *cpt )
2028 {
2029 char *dat=(char *)cpt , *ptr ;
2030 int ii , jj ;
2031
2032 if( rt == NULL || dat == NULL || col_len < 1 ) return ; /* nothing to do */
2033
2034 /* if has variable dim arrays inside, free them */
2035
2036 if( ROWTYPE_is_varsize(rt) ){
2037 for( ii=0 ; ii < col_len ; ii++ ){ /* loop over structs */
2038 ptr = dat + rt->size * ii ; /* pointer to this struct */
2039 for( jj=0 ; jj < rt->part_num ; jj++ ){ /* loop over parts */
2040 if( rt->part_typ[jj] == NI_STRING ||
2041 rt->part_dim[jj] >= 0 ){
2042 char **apt = (char **)(ptr+rt->part_off[jj]) ;
2043 NI_free(*apt) ; *apt = NULL ;
2044 }
2045 }
2046 }
2047 }
2048
2049 /* free the column array itself */
2050
2051 NI_free(cpt) ; return ;
2052 }
2053
2054 /*----------------------------------------------------------------------------*/
2055 /*! Copy a column of rowtype structs, including var dim arrays. Return
2056 is the pointer to the copy.
2057 ------------------------------------------------------------------------------*/
2058
NI_copy_column(NI_rowtype * rt,int col_len,void * cpt)2059 void * NI_copy_column( NI_rowtype *rt , int col_len , void *cpt )
2060 {
2061 char *dat=(char *)cpt , *ndat , *nptr , *qpt ;
2062 int ii , jj , kk ;
2063
2064 if( rt == NULL || dat == NULL || col_len < 1 ) return NULL ;
2065
2066 /* make a quick (surface) copy */
2067
2068 ndat = NI_malloc(char, rt->size * col_len ) ; /* new data column */
2069 memcpy( ndat , dat , rt->size * col_len ) ; /* the quick copying */
2070
2071 /* copy any var dim arrays inside, since the pointers
2072 in ndat right now still point to data in dat,
2073 but we want ndat to be entirely self-contained! */
2074
2075 if( ROWTYPE_is_varsize(rt) ){
2076 for( ii=0 ; ii < col_len ; ii++ ){ /* loop over structs */
2077 nptr = ndat + rt->size * ii ; /* ptr to this struct */
2078 for( jj=0 ; jj < rt->part_num ; jj++ ){ /* loop over parts */
2079
2080 if( rt->part_typ[jj] == NI_STRING ){ /* a string part */
2081 char **apt = (char **)(nptr+rt->part_off[jj]) ; /* *apt => data */
2082 qpt = NI_strdup(*apt) ; *apt = qpt ;
2083 } else if( rt->part_dim[jj] >= 0 ){
2084 char **apt = (char **)(nptr+rt->part_off[jj]) ; /* *apt => data */
2085 if( *apt != NULL ){
2086 kk = ROWTYPE_part_dimen(rt,nptr,jj) * rt->part_rtp[jj]->size ;
2087 qpt = NI_malloc(char, kk) ; memcpy(qpt,*apt,kk) ; *apt = qpt ;
2088 }
2089 }
2090 }
2091 }
2092 }
2093
2094 return ndat ;
2095 }
2096
2097 /*--------------------------------------------------------------------------*/
2098 /*! Return the length in bytes of a column of data (not counting padding).
2099 The pointer to the data is needed since it might contain variable
2100 size data (String or vardim arrays).
2101 ----------------------------------------------------------------------------*/
2102
NI_size_column(NI_rowtype * rt,int col_len,void * cpt)2103 int NI_size_column( NI_rowtype *rt , int col_len , void *cpt )
2104 {
2105 char *dat = (char *)cpt ;
2106 int ii , ndat ;
2107
2108 if( rt == NULL || col_len <= 0 )
2109 return 0; /* nonsense input */
2110 if( !ROWTYPE_is_varsize(rt) || dat == NULL )
2111 return (col_len*rt->psiz); /* fixed dim struct */
2112
2113 /* must loop through elements and add up their variable sizes */
2114
2115 ndat = 0 ;
2116 for( ii=0 ; ii < col_len ; ii++ )
2117 ndat += NI_rowtype_vsize( rt , dat + ii*rt->size ) ;
2118
2119 return ndat ;
2120 }
2121