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