1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group.                                               *
3 * Copyright by the Board of Trustees of the University of Illinois.         *
4 * All rights reserved.                                                      *
5 *                                                                           *
6 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7 * terms governing use, modification, and redistribution, is contained in    *
8 * the files COPYING and Copyright.html.  COPYING can be found at the root   *
9 * of the source code distribution tree; Copyright.html can be found at the  *
10 * root level of an installed copy of the electronic HDF5 document set and   *
11 * is linked from the top-level documents page.  It can also be found at     *
12 * http://hdfgroup.org/HDF5/doc/Copyright.html.  If you do not have          *
13 * access to either file, you may request a copy from help@hdfgroup.org.     *
14 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16/*
17This code is a variant of the H5detect.c code from HDF5.
18Author: D. Heimbigner 10/7/2008
19*/
20
21#include <stdlib.h>
22#include <string.h>
23#include <assert.h>
24#include <netcdf.h>
25#include "config.h"
26#include "ncaux.h"
27
28struct NCAUX_FIELD {
29    char* name;
30    nc_type fieldtype;
31    size_t ndims;
32    int dimsizes[NC_MAX_VAR_DIMS];
33    size_t size;
34    size_t offset;
35    size_t alignment;
36};
37
38struct NCAUX_CMPD {
39    int ncid;
40    int mode;
41    char* name;
42    size_t nfields;
43    struct NCAUX_FIELDfields;
44    size_t size;
45    size_t offset; /* cumulative as fields are added */
46    size_t alignment;
47};
48
49static int ncaux_initialized = 0;
50
51static void compute_alignments(void);
52static int computefieldinfo(struct NCAUX_CMPDcmpd);
53
54int
55ncaux_begin_compound(int ncid, const char *name, int alignmode, void** tagp)
56{
57    int status = NC_NOERR;
58    struct NCAUX_CMPDcmpd = NULL;
59
60    if(!ncaux_initialized) {
61 compute_alignments();
62 ncaux_initialized = 1;
63    }
64
65    if(tagp) *tagp = NULL;
66
67    cmpd = (struct NCAUX_CMPD*)calloc(1,sizeof(struct NCAUX_CMPD));
68    if(cmpd == NULL) {status = NC_ENOMEM; goto fail;}
69    cmpd->ncid = ncid;
70    cmpd->mode = alignmode;
71    cmpd->nfields = 0;
72    cmpd->name = strdup(name);
73    if(cmpd->name == NULL) {status = NC_ENOMEM; goto fail;}
74
75    if(tagp) {
76      *tagp = (void*)cmpd;
77    } else { /* Error, free cmpd to avoid memory leak. */
78      free(cmpd);
79    }
80    return status;
81
82fail:
83    ncaux_abort_compound((void*)cmpd);
84    return status;
85}
86
87int
88ncaux_abort_compound(void* tag)
89{
90    int i;
91    struct NCAUX_CMPDcmpd = (struct NCAUX_CMPD*)tag;
92    if(cmpd == NULL) goto done;
93    if(cmpd->name) free(cmpd->name);
94    for(i=0;i<cmpd->nfields;i++) {
95 struct NCAUX_FIELDfield = &cmpd->fields[i];
96 if(field->name) free(field->name);
97    }
98    if(cmpd->fields) free(cmpd->fields);
99    free(cmpd);
100
101done:
102    return NC_NOERR;
103}
104
105int
106ncaux_add_field(void* tag,  const char *namenc_type field_type,
107    int ndims, const int* dimsizes)
108{
109    int i;
110    int status = NC_NOERR;
111    struct NCAUX_CMPDcmpd = (struct NCAUX_CMPD*)tag;
112    struct NCAUX_FIELDnewfields = NULL;
113    struct NCAUX_FIELDfield = NULL;
114
115    if(cmpd == NULL) goto done;
116    if(ndims < 0) {status = NC_EINVAL; goto done;}
117    for(i=0;i<ndims;i++) {
118 if(dimsizes[i] <= 0) {status = NC_EINVAL; goto done;}
119    }
120    if(cmpd->fields == NULL) {
121        newfields = (struct NCAUX_FIELD*)calloc(1,sizeof(struct NCAUX_FIELD));
122    } else {
123        newfields = (struct NCAUX_FIELD*)realloc(cmpd->fields,cmpd->nfields+1*sizeof(struct NCAUX_FIELD));
124    }
125    if(cmpd->fields == NULL) {status = NC_ENOMEM; goto done;}
126    cmpd->fields = newfields;
127    field = &cmpd->fields[cmpd->nfields+1];
128    field->name = strdup(name);
129    field->fieldtype = field_type;
130    if(field->name == NULL) {status = NC_ENOMEM; goto done;}
131    field->ndims = (size_t)ndims;
132    memcpy(field->dimsizes,dimsizes,sizeof(int)*field->ndims);
133    cmpd->nfields++;
134
135done:
136    if(newfields)
137      free(newfields);
138    return status;
139}
140
141static size_t
142dimproduct(size_t ndims, int* dimsizes)
143{
144    int i;
145    size_t product = 1;
146    for(i=0;i<ndims;i++) product *= (size_t)dimsizes[i];
147    return product;
148}
149
150int
151ncaux_end_compound(void* tagnc_typeidp)
152{
153    int i;
154    int status = NC_NOERR;
155    struct NCAUX_CMPDcmpd = (struct NCAUX_CMPD*)tag;
156
157    if(cmpd == NULL) {status = NC_EINVAL; goto done;}
158
159    /* Compute field and compound info */
160    status = computefieldinfo(cmpd);
161    if(status != NC_NOERR) goto done;
162
163    status = nc_def_compound(cmpd->ncidcmpd->sizecmpd->nameidp);
164    if(status != NC_NOERR) goto done;
165
166    for(i=0;i<cmpd->nfields;i++) {
167 struct NCAUX_FIELDfield = &cmpd->fields[i];
168 if(field->ndims > 0) {
169            status = nc_insert_compound(cmpd->ncid, *idpfield->name,
170 field->offsetfield->fieldtype);
171 } else {
172            status = nc_insert_array_compound(cmpd->ncid, *idpfield->name,
173 field->offsetfield->fieldtype,
174 (int)field->ndims,field->dimsizes);
175 }
176        if(status != NC_NOERR) goto done;
177    }
178
179done:
180    return status;
181}
182
183/**************************************************/
184
185/*
186The heart of this is the following macro,
187which computes the offset of a field x
188when preceded by a char field.
189The assumptions appear to be as follows:
1901. the offset produced in this situation indicates
191   the alignment for x relative in such a way that it
192   depends only on the types that precede it in the struct.
1932. the compiler does not reorder fields.
1943. arrays are tightly packed.
1954. nested structs are alignd according to their first member
196   (this actually follows from C language requirement that
197    a struct can legally be cast to an instance of its first member).
198Given the alignments for the various common primitive types,
199it is assumed that one can use them anywhere to construct
200the layout of a struct of such types.
201It seems to work for HDF5 for a wide variety of machines.
202*/
203
204#define COMP_ALIGNMENT(DST,TYPE)  {\
205    struct {char f1TYPE x;} tmp; \
206    DST.typename = #TYPE ;        \
207    DST.alignment = (size_t)((char*)(&(tmp.x)) - (char*)(&tmp));}
208
209/* Define indices for every primitive C type */
210/* NAT => NOT-A-TYPE*/
211#define NATINDEX       0
212#define CHARINDEX      1
213#define UCHARINDEX     2
214#define SHORTINDEX     3
215#define USHORTINDEX    4
216#define INTINDEX       5
217#define UINTINDEX      6
218#define LONGINDEX      7
219#define ULONGINDEX     8
220#define LONGLONGINDEX  9
221#define ULONGLONGINDEX 10
222#define FLOATINDEX     11
223#define DOUBLEINDEX    12
224#define PTRINDEX       13
225#define NCVLENINDEX    14
226
227#define NCTYPES        15
228
229typedef struct Alignment {
230    char* typename;
231    size_t alignment;
232Alignment;
233
234typedef Alignment Typealignvec;
235
236/* Capture in struct and in a vector*/
237typedef struct Typealignset {
238    Alignment charalign; /* char*/
239    Alignment ucharalign; /* unsigned char*/
240    Alignment shortalign; /* short*/
241    Alignment ushortalign; /* unsigned short*/
242    Alignment intalign; /* int*/
243    Alignment uintalign; /* unsigned int*/
244    Alignment longalign; /* long*/
245    Alignment ulongalign; /* unsigned long*/
246    Alignment longlongalign; /* long long*/
247    Alignment ulonglongalign; /* unsigned long long*/
248    Alignment floatalign; /* float*/
249    Alignment doublealign; /* double*/
250    Alignment ptralign; /* void**/
251    Alignment ncvlenalign; /* nc_vlen_t*/
252Typealignset;
253
254static Typealignvec vec[NCTYPES];
255static Typealignset set;
256
257static void
258compute_alignments(void)
259{
260    /* Compute the alignments for all the common C data types*/
261    /* First for the struct*/
262    /* initialize*/
263    memset((void*)&set,0,sizeof(set));
264    memset((void*)vec,0,sizeof(vec));
265
266    COMP_ALIGNMENT(set.charalign,char);
267    COMP_ALIGNMENT(set.ucharalign,unsigned char);
268    COMP_ALIGNMENT(set.shortalign,short);
269    COMP_ALIGNMENT(set.ushortalign,unsigned short);
270    COMP_ALIGNMENT(set.intalign,int);
271    COMP_ALIGNMENT(set.uintalign,unsigned int);
272    COMP_ALIGNMENT(set.longalign,long);
273    COMP_ALIGNMENT(set.ulongalign,unsigned long);
274    COMP_ALIGNMENT(set.longlongalign,long long);
275    COMP_ALIGNMENT(set.ulonglongalign,unsigned long long);
276    COMP_ALIGNMENT(set.floatalign,float);
277    COMP_ALIGNMENT(set.doublealign,double);
278    COMP_ALIGNMENT(set.ptralign,void*);
279    COMP_ALIGNMENT(set.ncvlenalign,nc_vlen_t);
280
281    /* Then the vector*/
282    COMP_ALIGNMENT(vec[CHARINDEX],char);
283    COMP_ALIGNMENT(vec[UCHARINDEX],unsigned char);
284    COMP_ALIGNMENT(vec[SHORTINDEX],short);
285    COMP_ALIGNMENT(vec[USHORTINDEX],unsigned short);
286    COMP_ALIGNMENT(vec[INTINDEX],int);
287    COMP_ALIGNMENT(vec[UINTINDEX],unsigned int);
288    COMP_ALIGNMENT(vec[LONGINDEX],long);
289    COMP_ALIGNMENT(vec[ULONGINDEX],unsigned long);
290    COMP_ALIGNMENT(vec[LONGLONGINDEX],long long);
291    COMP_ALIGNMENT(vec[ULONGLONGINDEX],unsigned long long);
292    COMP_ALIGNMENT(vec[FLOATINDEX],float);
293    COMP_ALIGNMENT(vec[DOUBLEINDEX],double);
294    COMP_ALIGNMENT(vec[PTRINDEX],void*);
295    COMP_ALIGNMENT(vec[NCVLENINDEX],nc_vlen_t);
296}
297
298static size_t
299nctypealignment(nc_type nctype)
300{
301    Alignmentalign = NULL;
302    int index = 0;
303    switch (nctype) {
304      case NC_BYTEindex = UCHARINDEX; break;
305      case NC_CHARindex = CHARINDEX; break;
306      case NC_SHORTindex = SHORTINDEX; break;
307      case NC_INTindex = INTINDEX; break;
308      case NC_FLOATindex = FLOATINDEX; break;
309      case NC_DOUBLEindex = DOUBLEINDEX; break;
310      case NC_UBYTEindex = UCHARINDEX; break;
311      case NC_USHORTindex = USHORTINDEX; break;
312      case NC_UINTindex = UINTINDEX; break;
313      case NC_INT64index = LONGLONGINDEX; break;
314      case NC_UINT64index = ULONGLONGINDEX; break;
315      case NC_STRINGindex = PTRINDEX; break;
316      case NC_VLENindex = NCVLENINDEX; break;
317      case NC_OPAQUEindex = UCHARINDEX; break;
318      default: assert(0);
319    }
320    align = &vec[index];
321    return align->alignment;
322}
323
324static size_t
325getpadding(size_t offset, size_t alignment)
326{
327    size_t rem = (alignment==0?0:(offset % alignment));
328    size_t pad = (rem==0?0:(alignment - rem));
329    return pad;
330}
331
332/* Find first primitive field of a possibly nested sequence of compounds */
333static nc_type
334findfirstfield(int ncidnc_type xtype)
335{
336    int status = NC_NOERR;
337    nc_type fieldtype = xtype;
338    if(xtype <= NC_MAX_ATOMIC_TYPE) goto done;
339
340    status = nc_inq_compound_fieldtype(ncidxtype, 0, &fieldtype);
341    if(status != NC_NOERR) goto done;
342    fieldtype = findfirstfield(ncid,fieldtype);
343
344done:
345    return (status == NC_NOERR?fieldtype:NC_NAT);
346}
347
348static int
349computefieldinfo(struct NCAUX_CMPDcmpd)
350{
351    int i;
352    int status = NC_NOERR;
353    size_t offset = 0;
354    size_t totaldimsize;
355
356    /* Assign the sizes for the fields */
357    for(i=0;i<cmpd->nfields;i++) {
358 struct NCAUX_FIELDfield = &cmpd->fields[i];
359 status = nc_inq_type(cmpd->ncid,field->fieldtype,NULL,&field->size);
360        if(status != NC_NOERR) goto done;
361 totaldimsize = dimproduct(field->ndims,field->dimsizes);
362 field->size *= totaldimsize;
363    }
364
365    for(offset=0,i=0;i<cmpd->nfields;i++) {
366        struct NCAUX_FIELDfield = &cmpd->fields[i];
367 int alignment = 0;
368 nc_type firsttype = findfirstfield(cmpd->ncid,field->fieldtype);
369
370        /* only support 'c' alignment for now*/
371 switch (field->fieldtype) {
372 case NC_OPAQUE:
373     field->alignment = 1;
374     break;
375 case NC_ENUM:
376            field->alignment = nctypealignment(firsttype);
377     break;
378 case NC_VLEN: /*fall thru*/
379 case NC_COMPOUND:
380            field->alignment = nctypealignment(firsttype);
381     break;
382 default:
383            field->alignment = nctypealignment(field->fieldtype);
384     break;
385 }
386        offset += getpadding(offset,alignment);
387        field->offset = offset;
388        offset += field->size;
389    }
390    cmpd->size = offset;
391    cmpd->alignment = cmpd->fields[0].alignment;
392
393done:
394    return status;
395}
396
397


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed