1 /****************************************************************************
2  * NCSA HDF                                                                 *
3  * Scientific Data Technologies                                             *
4  * National Center for Supercomputing Applications                          *
5  * University of Illinois at Urbana-Champaign                               *
6  * 605 E. Springfield, Champaign IL 61820                                   *
7  *                                                                          *
8  * For conditions of distribution and use, see the accompanying             *
9  * hdf/COPYING file.                                                        *
10  *                                                                          *
11  * Modified versions of H5LT for getting and setting attributes for open
12  * groups and leaves.
13  * F. Alted 2005/09/29
14  *                                                                          *
15  ****************************************************************************/
16 
17 #include <string.h>
18 #include <stdlib.h>
19 
20 #include "H5ATTR.h"
21 
22 
23 /*-------------------------------------------------------------------------
24  *
25  * Set & get attribute functions
26  *
27  *-------------------------------------------------------------------------
28  */
29 
30 /*-------------------------------------------------------------------------
31  * Function: H5ATTRset_attribute
32  *
33  * Purpose: Create an attribute named attr_name and attach it to the
34  * object specified by the name obj_name. This supports general
35  * n-dimensional types (rank > 0), but if rank == 0, an H5T_SCALAR is
36  * chosen.
37  *
38  * Return: Success: 0, Failure: -1
39  *
40  * Programmer: Francesc Alted
41  *
42  * Date: October 18, 2006
43  *
44  * Comments:
45  *
46  * Modifications:
47  *
48  *-------------------------------------------------------------------------
49  */
50 
H5ATTRset_attribute(hid_t obj_id,const char * attr_name,hid_t type_id,size_t rank,hsize_t * dims,const char * attr_data)51 herr_t H5ATTRset_attribute( hid_t obj_id,
52                             const char *attr_name,
53                             hid_t type_id,
54                             size_t rank,
55                             hsize_t *dims,
56                             const char *attr_data )
57 {
58  hid_t      space_id;
59  hid_t      attr_id;
60  int        has_attr;
61 
62  /* Create the data space for the attribute. */
63  if (rank == 0)
64    space_id = H5Screate( H5S_SCALAR );
65  else
66    space_id = H5Screate_simple( rank, dims, NULL );
67 
68  /* Verify whether the attribute already exists */
69  has_attr = H5ATTRfind_attribute( obj_id, attr_name );
70 
71  /* The attribute already exists, delete it */
72  if ( has_attr == 1 )
73  {
74   if ( H5Adelete( obj_id, attr_name ) < 0 )
75     goto out;
76  }
77 
78  /* Create and write the attribute */
79  attr_id = H5Acreate( obj_id, attr_name, type_id, space_id, H5P_DEFAULT,
80                       H5P_DEFAULT );
81 
82  if ( H5Awrite( attr_id, type_id, attr_data ) < 0 )
83   goto out;
84 
85  H5Aclose( attr_id );
86 
87  H5Sclose( space_id );
88 
89  return 0;
90 
91 out:
92  return -1;
93 }
94 
95 
96 /*-------------------------------------------------------------------------
97  * Function: H5ATTRset_attribute_string
98  *
99  * Purpose: Creates and writes a string attribute named attr_name and attaches
100  *          it to the object specified by the name obj_name.
101  *
102  * Return: Success: 0, Failure: -1
103  *
104  * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
105  *
106  * Date: July 23, 2001
107  *
108  * Comments: If the attribute already exists, it is overwritten
109  *
110  * Modifications:
111  *
112  *-------------------------------------------------------------------------
113  */
114 
H5ATTRset_attribute_string(hid_t obj_id,const char * attr_name,const char * attr_data,hsize_t attr_size,int cset)115 herr_t H5ATTRset_attribute_string( hid_t obj_id,
116                                    const char *attr_name,
117                                    const char *attr_data,
118                                    hsize_t attr_size,
119                                    int cset )
120 {
121  hid_t      attr_type;
122  /*size_t     attr_size;*/
123  hid_t      attr_space_id;
124  hid_t      attr_id;
125  int        has_attr;
126 
127  /* Create the attribute */
128  if ( (attr_type = H5Tcopy( H5T_C_S1 )) < 0 )
129   goto out;
130 
131  if ( ( ( cset == H5T_CSET_ASCII ) || ( cset == H5T_CSET_UTF8 ) ) &&
132       ( H5Tset_cset( attr_type, cset ) < 0 ) )
133   goto out;
134 
135  if ( H5Tset_strpad( attr_type, H5T_STR_NULLTERM ) < 0 )
136   goto out;
137 
138  if ( attr_size > 0 )
139  {
140   if (H5Tset_size( attr_type, attr_size) < 0 )
141    goto out;
142   if ( (attr_space_id = H5Screate( H5S_SCALAR )) < 0 )
143    goto out;
144  }
145  else
146  {
147   if ( (attr_space_id = H5Screate( H5S_NULL )) < 0 )
148    goto out;
149  }
150 
151  /* Verify if the attribute already exists */
152  has_attr = H5ATTRfind_attribute( obj_id, attr_name );
153 
154  /* The attribute already exists, delete it */
155  if ( has_attr == 1 )
156  {
157   if ( H5Adelete( obj_id, attr_name ) < 0 )
158     goto out;
159  }
160 
161  /* Create and write the attribute */
162 
163  if ( (attr_id = H5Acreate( obj_id, attr_name, attr_type, attr_space_id,
164                             H5P_DEFAULT, H5P_DEFAULT )) < 0 )
165   goto out;
166 
167  if ( H5Awrite( attr_id, attr_type, attr_data ) < 0 )
168   goto out;
169 
170  if ( H5Aclose( attr_id ) < 0 )
171   goto out;
172 
173  if ( H5Sclose( attr_space_id ) < 0 )
174   goto out;
175 
176  if ( H5Tclose(attr_type) < 0 )
177   goto out;
178 
179  return 0;
180 
181 out:
182  return -1;
183 }
184 
185 
186 /*-------------------------------------------------------------------------
187  * Function: H5ATTRget_attribute
188  *
189  * Purpose: Reads an attribute named attr_name with the memory type type_id
190  *
191  * Return: Success: 0, Failure: -1
192  *
193  * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
194  *
195  * Date: September 19, 2002
196  *
197  * Comments:
198  *
199  * Modifications:
200  *
201  *-------------------------------------------------------------------------
202  */
203 
H5ATTRget_attribute(hid_t obj_id,const char * attr_name,hid_t type_id,void * data)204 herr_t H5ATTRget_attribute( hid_t obj_id,
205                             const char *attr_name,
206                             hid_t type_id,
207                             void *data )
208 {
209 
210  /* identifiers */
211  hid_t attr_id;
212 
213  if ( ( attr_id = H5Aopen_by_name(obj_id, ".", attr_name,
214                                   H5P_DEFAULT, H5P_DEFAULT) ) < 0 )
215   return -1;
216 
217  if ( H5Aread( attr_id, type_id, data ) < 0 )
218   goto out;
219 
220  if ( H5Aclose( attr_id ) < 0 )
221   return -1;
222 
223  return 0;
224 
225 out:
226  H5Aclose( attr_id );
227  return -1;
228 }
229 
230 
231 /*-------------------------------------------------------------------------
232  * Function: H5ATTRget_attribute_string
233  *
234  * Purpose: Reads an string attribute named attr_name.
235  *
236  * Return: Success: 0, Failure: -1
237  *
238  * Programmer: Francesc Alted, faltet@pytables.com
239  *
240  * Date: February 23, 2005
241  *
242  * Comments:
243  *
244  * Modifications:
245  *
246  *-------------------------------------------------------------------------
247  */
248 
H5ATTRget_attribute_string(hid_t obj_id,const char * attr_name,char ** data,int * cset)249 hsize_t H5ATTRget_attribute_string( hid_t obj_id,
250                                     const char *attr_name,
251                                     char **data,
252                                     int *cset )
253 {
254  /* identifiers */
255  hid_t      attr_id;
256  hid_t      attr_type;
257  hid_t      space_id;
258  hsize_t    type_size = 0;
259  htri_t     is_vlstr = 0;
260 
261  *data = NULL;
262  if ( ( attr_id = H5Aopen_by_name(obj_id, ".", attr_name,
263                                   H5P_DEFAULT, H5P_DEFAULT) ) < 0 )
264   return -1;
265 
266  if ( (attr_type = H5Aget_type( attr_id )) < 0 )
267   goto out;
268 
269  if ( ( cset != NULL ) && ( ( *cset = H5Tget_cset( attr_type ) ) < 0 ) )
270   goto out;
271 
272  is_vlstr = H5Tis_variable_str( attr_type );
273  if ( is_vlstr == 0 )
274  {
275   /* Get the size */
276   if ( (type_size = H5Tget_size( attr_type )) < 0 )
277    goto out;
278 
279   if ( (space_id = H5Aget_space( attr_id )) < 0 )
280    goto out;
281 
282   if ( H5Sget_simple_extent_type( space_id ) == H5S_NULL )
283    type_size = 0;
284 
285   H5Sclose( space_id );
286 
287   /* Malloc space enough for the string, plus 1 for the trailing '\0' */
288   *data = (char *)malloc(type_size + 1);
289 
290   if ( type_size > 0)
291   {
292    if ( H5Aread( attr_id, attr_type, *data ) < 0 )
293     goto out;
294   }
295 
296   /* Set the last character to \0 in case we are dealing with space
297      padded strings */
298   (*data)[type_size] = '\0';
299  }
300  else
301  {
302   /* is_vlstr */
303   if ( H5Aread( attr_id, attr_type, data ) < 0 )
304    goto out;
305 
306   type_size = strlen( *data );
307  }
308 
309  if ( H5Tclose( attr_type ) < 0 )
310   goto out;
311 
312  if ( H5Aclose( attr_id ) < 0 )
313   return -1;
314 
315  return type_size;
316 
317 out:
318  H5Tclose( attr_type );
319  H5Aclose( attr_id );
320  if ( (is_vlstr == 0) && (*data != NULL) )
321   free(*data);
322  *data = NULL;
323  return -1;
324 }
325 
326 
327 /*-------------------------------------------------------------------------
328  * Function: H5ATTRget_attribute_vlen_string_array
329  *
330  * Purpose: Reads a variable length string attribute named attr_name.
331  *
332  * Return: Success: number of elements of the array, Failure: -1
333  *
334  * Programmer: Antonio Valentino <antonio.valentino@tiscali.it>
335  *
336  * Date: November 27, 2011
337  *
338  * Comments: only rank 1 attributes of 8bit strings are supported
339  *
340  * Modifications:
341  *
342  *-------------------------------------------------------------------------
343  */
344 
H5ATTRget_attribute_vlen_string_array(hid_t obj_id,const char * attr_name,char *** data,int * cset)345 hsize_t H5ATTRget_attribute_vlen_string_array( hid_t obj_id,
346                                                const char *attr_name,
347                                                char ***data,
348                                                int *cset )
349 {
350  /* identifiers */
351  hid_t attr_id = -1, attr_type = -1, space_id = -1;
352  hsize_t nelements = 0, *dims = NULL;
353  int ndims = 0, i;
354 
355  *data = NULL;
356  if ( ( attr_id = H5Aopen_by_name( obj_id, ".", attr_name,
357                                    H5P_DEFAULT, H5P_DEFAULT ) ) < 0 )
358   return -1;
359 
360  if ( (attr_type = H5Aget_type( attr_id )) < 0 )
361   goto out;
362 
363  if ( ( cset != NULL ) && ( ( *cset = H5Tget_cset( attr_type ) ) < 0 ) )
364   goto out;
365 
366  if ( (space_id = H5Aget_space( attr_id )) < 0 )
367   goto out;
368 
369  if ( (ndims = H5Sget_simple_extent_ndims( space_id )) < 1 )
370   goto out;
371 
372  if ( (dims = (hsize_t *)malloc(ndims * sizeof(hsize_t))) == NULL )
373   goto out;
374 
375  if ( H5Sget_simple_extent_dims( space_id, dims, NULL ) < 0 )
376   goto out;
377 
378  nelements = 1;
379  for ( i = 0; i < ndims; ++i )
380   nelements *= dims[i];
381 
382  free( dims );
383  dims = NULL;
384 
385  if ((*data = (char **)malloc( nelements * sizeof(char*))) == NULL )
386   goto out;
387 
388  if ( H5Aread( attr_id, attr_type, *data ) < 0 )
389   goto out;
390 
391  if ( H5Tclose( attr_type ) < 0 )
392   goto out;
393 
394  if ( H5Sclose( space_id ) < 0 )
395   goto out;
396 
397  if ( H5Aclose( attr_id ) < 0 )
398   return -1;
399 
400  return nelements;
401 
402 out:
403  if ( *data != NULL )
404   free( *data );
405  *data = NULL;
406  if ( dims != NULL )
407   free( dims );
408  H5Tclose( attr_type );
409  H5Sclose( space_id );
410  H5Aclose( attr_id );
411  return -1;
412 }
413 
414 
415 /*-------------------------------------------------------------------------
416  *
417  * Helper functions
418  *
419  *-------------------------------------------------------------------------
420  */
421 
422 /*-------------------------------------------------------------------------
423  * Function: find_attr
424  *
425  * Purpose: operator function used by H5ATTRfind_attribute
426  *
427  * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
428  *
429  * Date: June 21, 2001
430  *
431  * Comments:
432  *
433  * Modifications:
434  *
435  *-------------------------------------------------------------------------
436  */
437 
find_attr(hid_t loc_id,const char * name,const H5A_info_t * ainfo,void * op_data)438 static herr_t find_attr( hid_t loc_id,
439                          const char *name,
440                          const H5A_info_t *ainfo,
441                          void *op_data)
442 {
443 
444  /* Define a default zero value for return. This will cause the
445   * iterator to continue if the palette attribute is not found yet.
446   */
447 
448  int ret = 0;
449 
450  char *attr_name = (char*)op_data;
451 
452  /* Shut the compiler up */
453  loc_id=loc_id;
454 
455  /* Define a positive value for return value if the attribute was
456   * found. This will cause the iterator to immediately return that
457   * positive value, indicating short-circuit success
458   */
459 
460  if( strcmp( name, attr_name ) == 0 )
461   ret = 1;
462 
463  return ret;
464 }
465 
466 
467 /*-------------------------------------------------------------------------
468  * Function: H5ATTRfind_attribute
469  *
470  * Purpose: Inquires if an attribute named attr_name exists attached
471  * to the object loc_id.
472  *
473  * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
474  *
475  * Date: June 21, 2001
476  *
477  * Comments:
478  *  The function uses H5Aiterate with the operator function find_attr
479  *
480  * Return:
481  *  Success: The return value of the first operator that
482  *              returns non-zero, or zero if all members were
483  *              processed with no operator returning non-zero.
484  *
485  *  Failure: Negative if something goes wrong within the
486  *              library, or the negative value returned by one
487  *              of the operators.
488  *
489  *-------------------------------------------------------------------------
490  */
491 
H5ATTRfind_attribute(hid_t loc_id,const char * attr_name)492 herr_t H5ATTRfind_attribute( hid_t loc_id,
493                              const char* attr_name )
494 {
495 
496  hsize_t attr_num;
497  herr_t  ret;
498 
499  attr_num = 0;
500  ret = H5Aiterate( loc_id, H5_INDEX_CRT_ORDER, H5_ITER_NATIVE, &attr_num,
501                    find_attr, (void *)attr_name );
502 
503  return ret;
504 }
505 
506 
507 
508 /*-------------------------------------------------------------------------
509  * Function: H5ATTRget_attribute_ndims
510  *
511  * Purpose: Gets the dimensionality of an attribute.
512  *
513  * Return: Success: 0, Failure: -1
514  *
515  * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
516  *
517  * Date: September 4, 2001
518  *
519  *-------------------------------------------------------------------------
520  */
521 
H5ATTRget_type_ndims(hid_t obj_id,const char * attr_name,hid_t * type_id,H5T_class_t * class_id,size_t * type_size,int * rank)522 herr_t H5ATTRget_type_ndims( hid_t obj_id,
523                              const char *attr_name,
524                              hid_t *type_id,
525                              H5T_class_t *class_id,
526                              size_t *type_size,
527                              int *rank )
528 {
529  hid_t       attr_id;
530  hid_t       space_id;
531 
532  /* Open the attribute. */
533  if ( ( attr_id = H5Aopen_by_name(obj_id, ".", attr_name,
534                                   H5P_DEFAULT, H5P_DEFAULT) ) < 0 )
535  {
536   return -1;
537  }
538 
539  /* Get an identifier for the datatype. */
540  *type_id = H5Aget_type( attr_id );
541 
542  /* Get the class. */
543  *class_id = H5Tget_class( *type_id );
544 
545  /* Get the size. */
546  *type_size = H5Tget_size( *type_id );
547 
548  /* Get the dataspace handle */
549  if ( (space_id = H5Aget_space( attr_id )) < 0 )
550   goto out;
551 
552  /* Get rank */
553  if ( (*rank = H5Sget_simple_extent_ndims( space_id )) < 0 )
554   goto out;
555 
556  /* Terminate access to the attribute */
557  if ( H5Sclose( space_id ) < 0 )
558   goto out;
559 
560  /* End access to the attribute */
561  if ( H5Aclose( attr_id ) )
562   goto out;;
563 
564  return 0;
565 
566 out:
567  H5Tclose( *type_id );
568  H5Aclose( attr_id );
569  return -1;
570 }
571 
572 
573 /*-------------------------------------------------------------------------
574  * Function: H5ATTRget_dims
575  *
576  * Purpose: Gets information about an attribute.
577  *
578  * Return: Success: 0, Failure: -1
579  *
580  * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
581  *
582  * Date: September 4, 2001
583  *
584  *-------------------------------------------------------------------------
585  */
586 
H5ATTRget_dims(hid_t obj_id,const char * attr_name,hsize_t * dims)587 herr_t H5ATTRget_dims( hid_t obj_id,
588                        const char *attr_name,
589                        hsize_t *dims)
590 {
591  hid_t       attr_id;
592  hid_t       space_id;
593 
594  /* Open the attribute. */
595  if ( ( attr_id = H5Aopen_by_name(obj_id, ".", attr_name,
596                                   H5P_DEFAULT, H5P_DEFAULT) ) < 0 )
597  {
598   return -1;
599  }
600 
601   /* Get the dataspace handle */
602  if ( (space_id = H5Aget_space( attr_id )) < 0 )
603   goto out;
604 
605  /* Get dimensions */
606  if ( H5Sget_simple_extent_dims( space_id, dims, NULL) < 0 )
607   goto out;
608 
609  /* Terminate access to the dataspace */
610  if ( H5Sclose( space_id ) < 0 )
611   goto out;
612 
613   /* End access to the attribute */
614  if ( H5Aclose( attr_id ) )
615   goto out;
616 
617  return 0;
618 
619 out:
620  H5Aclose( attr_id );
621  return -1;
622 }
623