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 COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://www.hdfgroup.org/licenses.               *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 /*
15  * Module Info: This module contains the functionality for enumerated datatypes
16  *      in the H5T interface.
17  */
18 
19 #include "H5Tmodule.h" /* This source code file is part of the H5T module */
20 
21 #include "H5private.h"   /*generic functions			  */
22 #include "H5Eprivate.h"  /*error handling			  */
23 #include "H5Iprivate.h"  /*ID functions		   		  */
24 #include "H5MMprivate.h" /*memory management			  */
25 #include "H5Tpkg.h"      /*data-type functions			  */
26 
27 /* Static local functions */
28 static char * H5T__enum_nameof(H5T_t *dt, const void *value, char *name /*out*/, size_t size);
29 static herr_t H5T__enum_valueof(H5T_t *dt, const char *name, void *value /*out*/);
30 
31 /*-------------------------------------------------------------------------
32  * Function:	H5Tenum_create
33  *
34  * Purpose:	Create a new enumeration data type based on the specified
35  *		TYPE, which must be an integer type.
36  *
37  * Return:	Success:	ID of new enumeration data type
38  *
39  *		Failure:	Negative
40  *
41  * Programmer:	Robb Matzke
42  *              Tuesday, December 22, 1998
43  *
44  *-------------------------------------------------------------------------
45  */
46 hid_t
H5Tenum_create(hid_t parent_id)47 H5Tenum_create(hid_t parent_id)
48 {
49     H5T_t *parent = NULL; /*base integer data type	*/
50     H5T_t *dt     = NULL; /*new enumeration data type	*/
51     hid_t  ret_value;     /*return value			*/
52 
53     FUNC_ENTER_API(H5I_INVALID_HID)
54     H5TRACE1("i", "i", parent_id);
55 
56     /* Check args */
57     if (NULL == (parent = (H5T_t *)H5I_object_verify(parent_id, H5I_DATATYPE)) ||
58         H5T_INTEGER != parent->shared->type)
59         HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not an integer data type")
60 
61     /* Build new type */
62     if (NULL == (dt = H5T__enum_create(parent)))
63         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, H5I_INVALID_HID, "cannot create enum type")
64 
65     /* Atomize the type */
66     if ((ret_value = H5I_register(H5I_DATATYPE, dt, TRUE)) < 0)
67         HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register data type atom")
68 
69 done:
70     FUNC_LEAVE_API(ret_value)
71 } /* end H5Tenum_create() */
72 
73 /*-------------------------------------------------------------------------
74  * Function:	H5T__enum_create
75  *
76  * Purpose:	Private function for H5Tenum_create.  Create a new
77  *              enumeration data type based on the specified
78  *		TYPE, which must be an integer type.
79  *
80  * Return:	Success:	new enumeration data type
81  *
82  *		Failure:        NULL
83  *
84  * Programmer:	Raymond Lu
85  *              October 9, 2002
86  *
87  *-------------------------------------------------------------------------
88  */
89 H5T_t *
H5T__enum_create(H5T_t * parent)90 H5T__enum_create(H5T_t *parent)
91 {
92     H5T_t *ret_value = NULL; /* New enumeration data type	*/
93 
94     FUNC_ENTER_PACKAGE
95 
96     HDassert(parent);
97 
98     /* Build new type */
99     if (NULL == (ret_value = H5T__alloc()))
100         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
101     ret_value->shared->type   = H5T_ENUM;
102     ret_value->shared->parent = H5T_copy(parent, H5T_COPY_ALL);
103     HDassert(ret_value->shared->parent);
104     ret_value->shared->size = ret_value->shared->parent->shared->size;
105 
106 done:
107     FUNC_LEAVE_NOAPI(ret_value)
108 }
109 
110 /*-------------------------------------------------------------------------
111  * Function:	H5Tenum_insert
112  *
113  * Purpose:	Insert a new enumeration data type member into an enumeration
114  *		type. TYPE is the enumeration type, NAME is the name of the
115  *		new member, and VALUE points to the value of the new member.
116  *		The NAME and VALUE must both be unique within the TYPE. VALUE
117  *		points to data which is of the data type defined when the
118  *		enumeration type was created.
119  *
120  * Return:	Success:	non-negative
121  *
122  *		Failure:	negative
123  *
124  * Programmer:	Robb Matzke
125  *              Wednesday, December 23, 1998
126  *
127  *-------------------------------------------------------------------------
128  */
129 herr_t
H5Tenum_insert(hid_t type,const char * name,const void * value)130 H5Tenum_insert(hid_t type, const char *name, const void *value)
131 {
132     H5T_t *dt        = NULL;
133     herr_t ret_value = SUCCEED; /* Return value */
134 
135     FUNC_ENTER_API(FAIL)
136     H5TRACE3("e", "i*s*x", type, name, value);
137 
138     /* Check args */
139     if (NULL == (dt = (H5T_t *)H5I_object_verify(type, H5I_DATATYPE)))
140         HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
141     if (H5T_ENUM != dt->shared->type)
142         HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an enumeration data type")
143     if (!name || !*name)
144         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified")
145     if (!value)
146         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no value specified")
147 
148     /* Do work */
149     if (H5T__enum_insert(dt, name, value) < 0)
150         HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to insert new enumeration member")
151 
152 done:
153     FUNC_LEAVE_API(ret_value)
154 }
155 
156 /*-------------------------------------------------------------------------
157  * Function:	H5T__enum_insert
158  *
159  * Purpose:	Insert a new member having a NAME and VALUE into an
160  *		enumeration data TYPE.  The NAME and VALUE must both be
161  *		unique. The VALUE points to data of the data type defined for
162  *		the enumeration base type.
163  *
164  * Return:	Success:	non-negative
165  *
166  *		Failure:	negative
167  *
168  * Programmer:	Robb Matzke
169  *              Wednesday, December 23, 1998
170  *
171  *-------------------------------------------------------------------------
172  */
173 herr_t
H5T__enum_insert(const H5T_t * dt,const char * name,const void * value)174 H5T__enum_insert(const H5T_t *dt, const char *name, const void *value)
175 {
176     unsigned i;
177     herr_t   ret_value = SUCCEED; /* Return value */
178 
179     FUNC_ENTER_PACKAGE
180 
181     HDassert(dt);
182     HDassert(name && *name);
183     HDassert(value);
184 
185     /* The name and value had better not already exist */
186     for (i = 0; i < dt->shared->u.enumer.nmembs; i++) {
187         if (!HDstrcmp(dt->shared->u.enumer.name[i], name))
188             HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "name redefinition")
189         if (!HDmemcmp((uint8_t *)dt->shared->u.enumer.value + (i * dt->shared->size), value,
190                       dt->shared->size))
191             HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "value redefinition")
192     }
193 
194     /* Increase table sizes */
195     if (dt->shared->u.enumer.nmembs >= dt->shared->u.enumer.nalloc) {
196         char **  names;
197         uint8_t *values;
198         unsigned n = MAX(32, 2 * dt->shared->u.enumer.nalloc);
199 
200         if (NULL == (names = (char **)H5MM_realloc(dt->shared->u.enumer.name, n * sizeof(char *))))
201             HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
202         dt->shared->u.enumer.name = names;
203 
204         if (NULL == (values = (uint8_t *)H5MM_realloc(dt->shared->u.enumer.value, n * dt->shared->size)))
205             HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed")
206         dt->shared->u.enumer.value  = values;
207         dt->shared->u.enumer.nalloc = n;
208     }
209 
210     /* Insert new member at end of member arrays */
211     dt->shared->u.enumer.sorted  = H5T_SORT_NONE;
212     i                            = dt->shared->u.enumer.nmembs++;
213     dt->shared->u.enumer.name[i] = H5MM_xstrdup(name);
214     H5MM_memcpy((uint8_t *)dt->shared->u.enumer.value + (i * dt->shared->size), value, dt->shared->size);
215 
216 done:
217     FUNC_LEAVE_NOAPI(ret_value)
218 }
219 
220 /*-------------------------------------------------------------------------
221  * Function:	H5Tget_member_value
222  *
223  * Purpose:	Return the value for an enumeration data type member.
224  *
225  * Return:	Success:	non-negative with the member value copied
226  *				into the memory pointed to by VALUE.
227  *
228  *		Failure:	negative, VALUE memory is undefined.
229  *
230  * Programmer:	Robb Matzke
231  *              Wednesday, December 23, 1998
232  *
233  *-------------------------------------------------------------------------
234  */
235 herr_t
H5Tget_member_value(hid_t type,unsigned membno,void * value)236 H5Tget_member_value(hid_t type, unsigned membno, void *value /*out*/)
237 {
238     H5T_t *dt        = NULL;
239     herr_t ret_value = SUCCEED; /* Return value */
240 
241     FUNC_ENTER_API(FAIL)
242     H5TRACE3("e", "iIux", type, membno, value);
243 
244     if (NULL == (dt = (H5T_t *)H5I_object_verify(type, H5I_DATATYPE)))
245         HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
246     if (H5T_ENUM != dt->shared->type)
247         HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "operation not defined for data type class")
248     if (membno >= dt->shared->u.enumer.nmembs)
249         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid member number")
250     if (!value)
251         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "null value buffer")
252 
253     if (H5T__get_member_value(dt, membno, value) < 0)
254         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get member value")
255 done:
256     FUNC_LEAVE_API(ret_value)
257 }
258 
259 /*-------------------------------------------------------------------------
260  * Function:	H5T__get_member_value
261  *
262  * Purpose:	Private function for H5T__get_member_value.  Return the
263  *              value for an enumeration data type member.
264  *
265  * Return:	Success:	non-negative with the member value copied
266  *				into the memory pointed to by VALUE.
267  *
268  *		Failure:	negative, VALUE memory is undefined.
269  *
270  * Programmer:	Raymond Lu
271  *              October 9, 2002
272  *
273  *-------------------------------------------------------------------------
274  */
275 herr_t
H5T__get_member_value(const H5T_t * dt,unsigned membno,void * value)276 H5T__get_member_value(const H5T_t *dt, unsigned membno, void *value /*out*/)
277 {
278     FUNC_ENTER_PACKAGE_NOERR
279 
280     HDassert(dt);
281     HDassert(value);
282 
283     H5MM_memcpy(value, (uint8_t *)dt->shared->u.enumer.value + (membno * dt->shared->size), dt->shared->size);
284 
285     FUNC_LEAVE_NOAPI(SUCCEED)
286 }
287 
288 /*-------------------------------------------------------------------------
289  * Function:	H5Tenum_nameof
290  *
291  * Purpose:	Finds the symbol name that corresponds to the specified VALUE
292  *		of an enumeration data type TYPE. At most SIZE characters of
293  *		the symbol name are copied into the NAME buffer. If the
294  *		entire symbol anem and null terminator do not fit in the NAME
295  *		buffer then as many characters as possible are copied (not
296  *		null terminated) and the function fails.
297  *
298  * Return:	Success:	Non-negative.
299  *
300  *		Failure:	Negative, first character of NAME is set to
301  *				null if SIZE allows it.
302  *
303  * Programmer:	Robb Matzke
304  *              Monday, January  4, 1999
305  *
306  *-------------------------------------------------------------------------
307  */
308 herr_t
H5Tenum_nameof(hid_t type,const void * value,char * name,size_t size)309 H5Tenum_nameof(hid_t type, const void *value, char *name /*out*/, size_t size)
310 {
311     H5T_t *dt        = NULL;
312     herr_t ret_value = SUCCEED; /* Return value */
313 
314     FUNC_ENTER_API(FAIL)
315     H5TRACE4("e", "i*xxz", type, value, name, size);
316 
317     /* Check args */
318     if (NULL == (dt = (H5T_t *)H5I_object_verify(type, H5I_DATATYPE)))
319         HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
320     if (H5T_ENUM != dt->shared->type)
321         HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an enumeration data type")
322     if (!value)
323         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no value supplied")
324     if (!name)
325         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name buffer supplied")
326 
327     if (NULL == H5T__enum_nameof(dt, value, name, size))
328         HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "nameof query failed")
329 
330 done:
331     FUNC_LEAVE_API(ret_value)
332 }
333 
334 /*-------------------------------------------------------------------------
335  * Function:	H5T__enum_nameof
336  *
337  * Purpose:	Finds the symbol name that corresponds the the specified
338  *		VALUE of an enumeration data type DT. At most SIZE characters
339  *		of the symbol name are copied into the NAME buffer. If the
340  *		entire symbol name and null terminator do not fit in the NAME
341  *		buffer then as many characters as possible are copied and the
342  *		function returns failure.
343  *
344  *		If NAME is the null pointer and SIZE is zero then enough
345  *		space is allocated to hold the result and a pointer to that
346  *		memory is returned.
347  *
348  * Return:	Success:	Pointer to NAME
349  *
350  *		Failure:	NULL, name[0] is set to null.
351  *
352  * Programmer:	Robb Matzke
353  *              Monday, January  4, 1999
354  *
355  *-------------------------------------------------------------------------
356  */
357 static char *
H5T__enum_nameof(H5T_t * dt,const void * value,char * name,size_t size)358 H5T__enum_nameof(H5T_t *dt, const void *value, char *name /*out*/, size_t size)
359 {
360     H5T_t *  copied_dt = NULL;   /* Do sorting in copied datatype */
361     unsigned lt, md = 0, rt;     /* Indices for binary search	*/
362     int      cmp        = (-1);  /* Comparison result		*/
363     hbool_t  alloc_name = FALSE; /* Whether name has been allocated */
364     char *   ret_value  = NULL;  /* Return value */
365 
366     FUNC_ENTER_STATIC
367 
368     /* Check args */
369     HDassert(dt && H5T_ENUM == dt->shared->type);
370     HDassert(value);
371     HDassert(name || 0 == size);
372 
373     if (name && size > 0)
374         *name = '\0';
375 
376     /* Sanity check */
377     if (dt->shared->u.enumer.nmembs == 0)
378         HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, NULL, "datatype has no members")
379 
380     /* Do a binary search over the values to find the correct one.  Do sorting
381      * and search on the copied datatype to protect the original order. */
382     if (NULL == (copied_dt = H5T_copy(dt, H5T_COPY_ALL)))
383         HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, NULL, "unable to copy data type")
384     if (H5T__sort_value(copied_dt, NULL) < 0)
385         HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOMPARE, NULL, "value sort failed")
386 
387     lt = 0;
388     rt = copied_dt->shared->u.enumer.nmembs;
389     while (lt < rt) {
390         md  = (lt + rt) / 2;
391         cmp = HDmemcmp(value, (uint8_t *)copied_dt->shared->u.enumer.value + (md * copied_dt->shared->size),
392                        copied_dt->shared->size);
393         if (cmp < 0)
394             rt = md;
395         else if (cmp > 0)
396             lt = md + 1;
397         else
398             break;
399     } /* end while */
400 
401     /* Value was not yet defined. This fixes bug # 774, 2002/06/05 EIP */
402     if (cmp != 0)
403         HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, NULL, "value is currently not defined")
404 
405     /* Save result name */
406     if (!name) {
407         if (NULL == (name = (char *)H5MM_malloc(HDstrlen(copied_dt->shared->u.enumer.name[md]) + 1)))
408             HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
409         alloc_name = TRUE;
410     } /* end if */
411     HDstrncpy(name, copied_dt->shared->u.enumer.name[md], size);
412     if (HDstrlen(copied_dt->shared->u.enumer.name[md]) >= size)
413         HGOTO_ERROR(H5E_DATATYPE, H5E_NOSPACE, NULL, "name has been truncated")
414 
415     /* Set return value */
416     ret_value = name;
417 
418 done:
419     if (copied_dt)
420         if (H5T_close_real(copied_dt) < 0)
421             HDONE_ERROR(H5E_DATATYPE, H5E_CANTCLOSEOBJ, NULL, "unable to close data type");
422     if (!ret_value && alloc_name)
423         H5MM_free(name);
424 
425     FUNC_LEAVE_NOAPI(ret_value)
426 } /* end H5T__enum_nameof() */
427 
428 /*-------------------------------------------------------------------------
429  * Function:	H5Tenum_valueof
430  *
431  * Purpose:	Finds the value that corresponds to the specified NAME f an
432  *		enumeration TYPE. The VALUE argument should be at least as
433  *		large as the value of H5Tget_size(type) in order to hold the
434  *		result.
435  *
436  * Return:	Success:	Non-negative
437  *
438  *		Failure:	Negative
439  *
440  * Programmer:	Robb Matzke
441  *              Monday, January  4, 1999
442  *
443  *-------------------------------------------------------------------------
444  */
445 herr_t
H5Tenum_valueof(hid_t type,const char * name,void * value)446 H5Tenum_valueof(hid_t type, const char *name, void *value /*out*/)
447 {
448     H5T_t *dt;
449     herr_t ret_value = SUCCEED; /* Return value */
450 
451     FUNC_ENTER_API(FAIL)
452     H5TRACE3("e", "i*sx", type, name, value);
453 
454     /* Check args */
455     if (NULL == (dt = (H5T_t *)H5I_object_verify(type, H5I_DATATYPE)))
456         HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type")
457     if (H5T_ENUM != dt->shared->type)
458         HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an enumeration data type")
459     if (!name || !*name)
460         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name")
461     if (!value)
462         HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no value buffer")
463 
464     if (H5T__enum_valueof(dt, name, value) < 0)
465         HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "valueof query failed")
466 
467 done:
468     FUNC_LEAVE_API(ret_value)
469 } /* H5Tenum_valueof() */
470 
471 /*-------------------------------------------------------------------------
472  * Function:	H5T__enum_valueof
473  *
474  * Purpose:	Finds the value that corresponds the the specified symbol
475  *		NAME of an enumeration data type DT and copy it to the VALUE
476  *		result buffer. The VALUE should be allocated by the caller to
477  *		be large enough for the result.
478  *
479  * Return:	Success:	Non-negative, value stored in VALUE.
480  *
481  *		Failure:	Negative, VALUE is undefined.
482  *
483  * Programmer:	Robb Matzke
484  *              Monday, January  4, 1999
485  *
486  *-------------------------------------------------------------------------
487  */
488 static herr_t
H5T__enum_valueof(H5T_t * dt,const char * name,void * value)489 H5T__enum_valueof(H5T_t *dt, const char *name, void *value /*out*/)
490 {
491     unsigned lt, md = 0, rt;      /*indices for binary search	*/
492     int      cmp       = (-1);    /*comparison result		*/
493     H5T_t *  copied_dt = NULL;    /*do sorting in copied datatype */
494     herr_t   ret_value = SUCCEED; /* Return value */
495 
496     FUNC_ENTER_STATIC
497 
498     /* Check args */
499     HDassert(dt && H5T_ENUM == dt->shared->type);
500     HDassert(name && *name);
501     HDassert(value);
502 
503     /* Sanity check */
504     if (dt->shared->u.enumer.nmembs == 0)
505         HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, FAIL, "datatype has no members")
506 
507     /* Do a binary search over the names to find the correct one.  Do sorting
508      * and search on the copied datatype to protect the original order. */
509     if (NULL == (copied_dt = H5T_copy(dt, H5T_COPY_ALL)))
510         HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to copy data type");
511     if (H5T__sort_name(copied_dt, NULL) < 0)
512         HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOMPARE, FAIL, "value sort failed")
513 
514     lt = 0;
515     rt = copied_dt->shared->u.enumer.nmembs;
516 
517     while (lt < rt) {
518         md  = (lt + rt) / 2;
519         cmp = HDstrcmp(name, copied_dt->shared->u.enumer.name[md]);
520         if (cmp < 0) {
521             rt = md;
522         }
523         else if (cmp > 0) {
524             lt = md + 1;
525         }
526         else {
527             break;
528         }
529     }
530     /* Value was not yet defined. This fixes bug # 774, 2002/06/05 EIP */
531     if (cmp != 0)
532         HGOTO_ERROR(H5E_DATATYPE, H5E_NOTFOUND, FAIL, "string doesn't exist in the enumeration type")
533 
534     H5MM_memcpy(value, (uint8_t *)copied_dt->shared->u.enumer.value + (md * copied_dt->shared->size),
535                 copied_dt->shared->size);
536 
537 done:
538     if (copied_dt)
539         if (H5T_close_real(copied_dt) < 0)
540             HDONE_ERROR(H5E_DATATYPE, H5E_CANTCLOSEOBJ, FAIL, "unable to close data type")
541 
542     FUNC_LEAVE_NOAPI(ret_value)
543 }
544