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