1 /* Copyright 2005, University Corporation for Atmospheric Research. See
2  * the COPYRIGHT file for copying and redistribution conditions. */
3 /**
4  * @file
5  * @internal This file is part of netcdf-4, a netCDF-like interface
6  * for HDF5, or a HDF5 backend for netCDF, depending on your point of
7  * view.
8  *
9  * This file handles the nc4 user-defined type functions
10  * (i.e. compound and opaque types).
11  *
12  * @author Ed Hartnett
13  */
14 #include "nc4internal.h"
15 #include "nc4dispatch.h"
16 
17 /** @internal Names of atomic types. */
18 char* nc4_atomic_name[NUM_ATOMIC_TYPES] = {"none", "byte", "char",
19                                            "short", "int", "float",
20                                            "double", "ubyte",
21                                            "ushort", "uint",
22                                            "int64", "uint64", "string"};
23 
24 /* The sizes of types may vary from platform to platform, but within
25  * netCDF files, type sizes are fixed. */
26 #define NC_CHAR_LEN sizeof(char)      /**< @internal Size of char. */
27 #define NC_STRING_LEN sizeof(char *)  /**< @internal Size of char *. */
28 #define NC_BYTE_LEN 1     /**< @internal Size of byte. */
29 #define NC_SHORT_LEN 2    /**< @internal Size of short. */
30 #define NC_INT_LEN 4      /**< @internal Size of int. */
31 #define NC_FLOAT_LEN 4    /**< @internal Size of float. */
32 #define NC_DOUBLE_LEN 8   /**< @internal Size of double. */
33 #define NC_INT64_LEN 8    /**< @internal Size of int64. */
34 
35 /**
36  * @internal Find all user-defined types for a location. This finds
37  * all user-defined types in a group.
38  *
39  * @param ncid File and group ID.
40  * @param ntypes Pointer that gets the number of user-defined
41  * types. Ignored if NULL
42  * @param typeids Array that gets the typeids. Ignored if NULL.
43  *
44  * @return ::NC_NOERR No error.
45  * @return ::NC_EBADID Bad ncid.
46  * @author Ed Hartnett
47  */
48 int
NC4_inq_typeids(int ncid,int * ntypes,int * typeids)49 NC4_inq_typeids(int ncid, int *ntypes, int *typeids)
50 {
51    NC_GRP_INFO_T *grp;
52    NC_FILE_INFO_T *h5;
53    NC_TYPE_INFO_T *type;
54    int num = 0;
55    int retval;
56 
57    LOG((2, "nc_inq_typeids: ncid 0x%x", ncid));
58 
59    /* Find info for this file and group, and set pointer to each. */
60    if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
61       return retval;
62    assert(h5 && grp);
63 
64    /* Count types. */
65    if (grp->type) {
66       int i;
67       for(i=0;i<ncindexsize(grp->type);i++)
68       {
69 	 if((type = (NC_TYPE_INFO_T*)ncindexith(grp->type,i)) == NULL) continue;
70 	 if (typeids)
71 	    typeids[num] = type->hdr.id;
72 	 num++;
73       }
74    }
75 
76    /* Give the count to the user. */
77    if (ntypes)
78       *ntypes = num;
79 
80    return NC_NOERR;
81 }
82 
83 /**
84  * @internal Get the name and size of a type. For strings, 1 is
85  * returned. For VLEN the base type len is returned.
86  *
87  * @param ncid File and group ID.
88  * @param typeid1 Type ID.
89  * @param name Gets the name of the type.
90  * @param size Gets the size of one element of the type in bytes.
91  *
92  * @return ::NC_NOERR No error.
93  * @return ::NC_EBADID Bad ncid.
94  * @return ::NC_EBADTYPE Type not found.
95  * @author Ed Hartnett
96 */
97 int
NC4_inq_type(int ncid,nc_type typeid1,char * name,size_t * size)98 NC4_inq_type(int ncid, nc_type typeid1, char *name, size_t *size)
99 {
100    NC_GRP_INFO_T *grp;
101    NC_TYPE_INFO_T *type;
102    static const int atomic_size[NUM_ATOMIC_TYPES] = {0, NC_BYTE_LEN, NC_CHAR_LEN, NC_SHORT_LEN,
103 					NC_INT_LEN, NC_FLOAT_LEN, NC_DOUBLE_LEN,
104 					NC_BYTE_LEN, NC_SHORT_LEN, NC_INT_LEN, NC_INT64_LEN,
105 					NC_INT64_LEN, NC_STRING_LEN};
106 
107    int retval;
108 
109    LOG((2, "nc_inq_type: ncid 0x%x typeid %d", ncid, typeid1));
110 
111    /* If this is an atomic type, the answer is easy. */
112    if (typeid1 < NUM_ATOMIC_TYPES)
113    {
114       if (name)
115 	strcpy(name, nc4_atomic_name[typeid1]);
116       if (size)
117 	*size = atomic_size[typeid1];
118       return NC_NOERR;
119    }
120 
121    /* Not an atomic type - so find group. */
122    if ((retval = nc4_find_nc4_grp(ncid, &grp)))
123       return retval;
124 
125    /* Find this type. */
126    if (!(type = nclistget(grp->nc4_info->alltypes, typeid1)))
127       return NC_EBADTYPE;
128 
129    if (name)
130       strcpy(name, type->hdr.name);
131 
132    if (size)
133    {
134       if (type->nc_type_class == NC_VLEN)
135 	 *size = sizeof(nc_vlen_t);
136       else if (type->nc_type_class == NC_STRING)
137 	 *size = 1;
138       else
139 	 *size = type->size;
140    }
141 
142    return NC_NOERR;
143 }
144 
145 /**
146  * @internal Find info about any user defined type.
147  *
148  * @param ncid File and group ID.
149  * @param typeid1 Type ID.
150  * @param name Gets name of the type.
151  * @param size Gets size in bytes of one element of type.
152  * @param base_nc_typep Gets the base nc_type.
153  * @param nfieldsp Gets the number of fields.
154  * @param classp Gets the type class (NC_COMPOUND, NC_ENUM, NC_VLEN).
155  *
156  * @return ::NC_NOERR No error.
157  * @return ::NC_EBADID Bad ncid.
158  * @return ::NC_EBADTYPE Type not found.
159  * @author Ed Hartnett
160 */
161 int
NC4_inq_user_type(int ncid,nc_type typeid1,char * name,size_t * size,nc_type * base_nc_typep,size_t * nfieldsp,int * classp)162 NC4_inq_user_type(int ncid, nc_type typeid1, char *name, size_t *size,
163 		 nc_type *base_nc_typep, size_t *nfieldsp, int *classp)
164 {
165    NC_GRP_INFO_T *grp;
166    NC_TYPE_INFO_T *type;
167    int retval;
168 
169    LOG((2, "nc_inq_user_type: ncid 0x%x typeid %d", ncid, typeid1));
170 
171    /* Find group metadata. */
172    if ((retval = nc4_find_nc4_grp(ncid, &grp)))
173       return retval;
174 
175    /* Find this type. */
176    if (!(type = nclistget(grp->nc4_info->alltypes, typeid1)))
177       return NC_EBADTYPE;
178 
179    /* Count the number of fields. */
180    if (nfieldsp)
181    {
182       if (type->nc_type_class == NC_COMPOUND)
183          *nfieldsp = nclistlength(type->u.c.field);
184       else if (type->nc_type_class == NC_ENUM)
185 	 *nfieldsp = nclistlength(type->u.e.enum_member);
186       else
187 	 *nfieldsp = 0;
188    }
189 
190    /* Fill in size and name info, if desired. */
191    if (size)
192    {
193       if (type->nc_type_class == NC_VLEN)
194 	 *size = sizeof(nc_vlen_t);
195       else if (type->nc_type_class == NC_STRING)
196 	 *size = 1;
197       else
198 	 *size = type->size;
199    }
200    if (name)
201       strcpy(name, type->hdr.name);
202 
203    /* VLENS and ENUMs have a base type - that is, they type they are
204     * arrays of or enums of. */
205    if (base_nc_typep)
206    {
207       if (type->nc_type_class == NC_ENUM)
208          *base_nc_typep = type->u.e.base_nc_typeid;
209       else if (type->nc_type_class == NC_VLEN)
210          *base_nc_typep = type->u.v.base_nc_typeid;
211       else
212          *base_nc_typep = NC_NAT;
213    }
214 
215    /* If the user wants it, tell whether this is a compound, opaque,
216     * vlen, enum, or string class of type. */
217    if (classp)
218       *classp = type->nc_type_class;
219 
220    return NC_NOERR;
221 }
222 
223 /**
224  * @internal Given the ncid, typeid and fieldid, get info about the
225  * field.
226  *
227  * @param ncid File and group ID.
228  * @param typeid1 Type ID.
229  * @param fieldid Field ID.
230  * @param name Gets name of field.
231  * @param offsetp Gets offset of field.
232  * @param field_typeidp Gets field type ID.
233  * @param ndimsp Gets number of dims for this field.
234  * @param dim_sizesp Gets the dim sizes for this field.
235  *
236  * @return ::NC_NOERR No error.
237  * @return ::NC_EBADID Bad ncid.
238  * @author Ed Hartnett
239 */
240 int
NC4_inq_compound_field(int ncid,nc_type typeid1,int fieldid,char * name,size_t * offsetp,nc_type * field_typeidp,int * ndimsp,int * dim_sizesp)241 NC4_inq_compound_field(int ncid, nc_type typeid1, int fieldid, char *name,
242 		      size_t *offsetp, nc_type *field_typeidp, int *ndimsp,
243 		      int *dim_sizesp)
244 {
245    NC_GRP_INFO_T *grp;
246    NC_TYPE_INFO_T *type;
247    NC_FIELD_INFO_T *field;
248    int d, retval;
249 
250    /* Find file metadata. */
251    if ((retval = nc4_find_nc4_grp(ncid, &grp)))
252       return retval;
253 
254    /* Find this type. */
255    if (!(type = nclistget(grp->nc4_info->alltypes, typeid1)))
256       return NC_EBADTYPE;
257 
258    /* Find the field. */
259    if (!(field = nclistget(type->u.c.field,fieldid)))
260       return NC_EBADFIELD;
261 
262    if (name)
263       strcpy(name, field->hdr.name);
264    if (offsetp)
265       *offsetp = field->offset;
266    if (field_typeidp)
267       *field_typeidp = field->nc_typeid;
268    if (ndimsp)
269       *ndimsp = field->ndims;
270    if (dim_sizesp)
271       for (d = 0; d < field->ndims; d++)
272          dim_sizesp[d] = field->dim_size[d];
273 
274    return NC_NOERR;
275 }
276 
277 /**
278  * @internal Given the typeid and the name, get the fieldid.
279  *
280  * @param ncid File and group ID.
281  * @param typeid1 Type ID.
282  * @param name Name of field.
283  * @param fieldidp Pointer that gets new field ID.
284  *
285  * @return ::NC_NOERR No error.
286  * @return ::NC_EBADID Bad ncid.
287  * @return ::NC_EBADTYPE Type not found.
288  * @return ::NC_EBADFIELD Field not found.
289  * @author Ed Hartnett
290 */
291 int
NC4_inq_compound_fieldindex(int ncid,nc_type typeid1,const char * name,int * fieldidp)292 NC4_inq_compound_fieldindex(int ncid, nc_type typeid1, const char *name, int *fieldidp)
293 {
294    NC_FILE_INFO_T *h5;
295    NC_TYPE_INFO_T *type;
296    NC_FIELD_INFO_T *field;
297    char norm_name[NC_MAX_NAME + 1];
298    int retval;
299    int i;
300 
301    LOG((2, "nc_inq_compound_fieldindex: ncid 0x%x typeid %d name %s",
302 	ncid, typeid1, name));
303 
304    /* Find file metadata. */
305    if ((retval = nc4_find_grp_h5(ncid, NULL, &h5)))
306       return retval;
307 
308    /* Find the type. */
309    if ((retval = nc4_find_type(h5, typeid1, &type)))
310       return retval;
311 
312    /* Did the user give us a good compound type typeid? */
313    if (!type || type->nc_type_class != NC_COMPOUND)
314       return NC_EBADTYPE;
315 
316    /* Normalize name. */
317    if ((retval = nc4_normalize_name(name, norm_name)))
318       return retval;
319 
320    /* Find the field with this name. */
321    for (i = 0; i < nclistlength(type->u.c.field); i++)
322    {
323       field = nclistget(type->u.c.field, i);
324       assert(field);
325       if (!strcmp(field->hdr.name, norm_name))
326 	 break;
327       field = NULL; /* because this is the indicator of not found */
328    }
329 
330    if (!field)
331       return NC_EBADFIELD;
332 
333    if (fieldidp)
334       *fieldidp = field->hdr.id;
335    return NC_NOERR;
336 }
337 
338 /**
339  * @internal Get enum name from enum value. Name size will be <=
340  * NC_MAX_NAME.
341  *
342  * @param ncid File and group ID.
343  * @param xtype Type ID.
344  * @param value Value of enum.
345  * @param identifier Gets the identifier for this enum value.
346  *
347  * @return ::NC_NOERR No error.
348  * @return ::NC_EBADID Bad ncid.
349  * @return ::NC_EBADTYPE Type not found.
350  * @return ::NC_EINVAL Invalid type data.
351  * @author Ed Hartnett
352 */
353 int
NC4_inq_enum_ident(int ncid,nc_type xtype,long long value,char * identifier)354 NC4_inq_enum_ident(int ncid, nc_type xtype, long long value, char *identifier)
355 {
356    NC_GRP_INFO_T *grp;
357    NC_TYPE_INFO_T *type;
358    NC_ENUM_MEMBER_INFO_T *enum_member;
359    long long ll_val;
360    int i;
361    int retval;
362    int found;
363 
364    LOG((3, "nc_inq_enum_ident: xtype %d value %d\n", xtype, value));
365 
366    /* Find group metadata. */
367    if ((retval = nc4_find_nc4_grp(ncid, &grp)))
368       return retval;
369 
370    /* Find this type. */
371    if (!(type = nclistget(grp->nc4_info->alltypes, xtype)))
372       return NC_EBADTYPE;
373 
374    /* Complain if they are confused about the type. */
375    if (type->nc_type_class != NC_ENUM)
376       return NC_EBADTYPE;
377 
378    /* Move to the desired enum member in the list. */
379    for (found = 0, i = 0; i < nclistlength(type->u.e.enum_member); i++)
380    {
381       enum_member = nclistget(type->u.e.enum_member, i);
382       assert(enum_member);
383       switch (type->u.e.base_nc_typeid)
384       {
385 	 case NC_BYTE:
386 	    ll_val = *(char *)enum_member->value;
387 	    break;
388 	 case NC_UBYTE:
389 	    ll_val = *(unsigned char *)enum_member->value;
390 	    break;
391 	 case NC_SHORT:
392 	    ll_val = *(short *)enum_member->value;
393 	    break;
394 	 case NC_USHORT:
395 	    ll_val = *(unsigned short *)enum_member->value;
396 	    break;
397 	 case NC_INT:
398 	    ll_val = *(int *)enum_member->value;
399 	    break;
400 	 case NC_UINT:
401 	    ll_val = *(unsigned int *)enum_member->value;
402 	    break;
403 	 case NC_INT64:
404 	 case NC_UINT64:
405 	    ll_val = *(long long *)enum_member->value;
406 	    break;
407 	 default:
408 	    return NC_EINVAL;
409       }
410       LOG((4, "ll_val=%d", ll_val));
411       if (ll_val == value)
412       {
413 	 if (identifier)
414 	    strcpy(identifier, enum_member->name);
415 	 found = 1;
416 	 break;
417       }
418    }
419 
420    /* If we didn't find it, life sucks for us. :-( */
421    if (!found)
422       return NC_EINVAL;
423 
424    return NC_NOERR;
425 }
426 
427 /**
428  * @internal Get information about an enum member: an identifier and
429  * value. Identifier size will be <= NC_MAX_NAME.
430  *
431  * @param ncid File and group ID.
432  * @param typeid1 Type ID.
433  * @param idx Enum member index.
434  * @param identifier Gets the identifier.
435  * @param value Gets the enum value.
436  *
437  * @return ::NC_NOERR No error.
438  * @return ::NC_EBADID Bad ncid.
439  * @return ::NC_EBADTYPE Type not found.
440  * @return ::NC_EINVAL Bad idx.
441  * @author Ed Hartnett
442 */
443 int
NC4_inq_enum_member(int ncid,nc_type typeid1,int idx,char * identifier,void * value)444 NC4_inq_enum_member(int ncid, nc_type typeid1, int idx, char *identifier,
445 		   void *value)
446 {
447    NC_GRP_INFO_T *grp;
448    NC_TYPE_INFO_T *type;
449    NC_ENUM_MEMBER_INFO_T *enum_member;
450    int retval;
451 
452    LOG((2, "nc_inq_enum_member: ncid 0x%x typeid %d", ncid, typeid1));
453 
454    /* Find group metadata. */
455    if ((retval = nc4_find_nc4_grp(ncid, &grp)))
456       return retval;
457 
458    /* Find this type. */
459    if (!(type = nclistget(grp->nc4_info->alltypes, typeid1)))
460       return NC_EBADTYPE;
461 
462    /* Complain if they are confused about the type. */
463    if (type->nc_type_class != NC_ENUM)
464       return NC_EBADTYPE;
465 
466    /* Move to the desired enum member in the list. */
467    if (!(enum_member = nclistget(type->u.e.enum_member, idx)))
468       return NC_EINVAL;
469 
470    /* Give the people what they want. */
471    if (identifier)
472       strcpy(identifier, enum_member->name);
473    if (value)
474       memcpy(value, enum_member->value, type->size);
475 
476    return NC_NOERR;
477 }
478 
479