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