LAL  7.5.0.1-08ee4f4
H5FileIOLowLevel.c
Go to the documentation of this file.
1 #include <config.h>
2 
3 #ifdef HAVE_HDF5
4 /* FIXME: should really update interface */
5 #define H5_USE_110_API
6 #include <hdf5.h>
7 #include <hdf5_hl.h>
8 #endif
9 
10 #include <stdio.h>
11 #include <string.h>
12 #include <limits.h>
13 #include <lal/LALStdio.h>
14 #include <lal/LALStdlib.h>
15 #include <lal/LALString.h>
16 #include <lal/AVFactories.h>
17 #include <lal/H5FileIO.h>
18 
19 /* INTERNAL */
20 
21 #ifdef __GNUC__
22 #define UNUSED __attribute__ ((unused))
23 #else
24 #define UNUSED
25 #endif
26 
27 #ifndef HAVE_HDF5
28 #pragma GCC diagnostic ignored "-Wunused-parameter"
29 #else
30 
31 /* replace HDF5 routines with threadsafe versions, if necessary */
32 #include "H5ThreadSafe.c"
33 
34 #define LAL_H5_FILE_MODE_READ H5F_ACC_RDONLY
35 #define LAL_H5_FILE_MODE_WRITE H5F_ACC_TRUNC
36 
37 struct tagLALH5Object {
38  hid_t object_id; /* this object's id must be first */
39 };
40 
41 struct tagLALH5File {
42  hid_t file_id; /* this object's id must be first */
43  unsigned int mode;
44  int is_a_group;
45  char fname[FILENAME_MAX];
46 };
47 
48 struct tagLALH5Dataset {
49  hid_t dataset_id; /* this object's id must be first */
50  hid_t parent_id;
51  hid_t space_id;
52  hid_t dtype_id; /* note: this is the in-memory type */
53  char name[]; /* flexible array member must be last */
54 };
55 
56 /* creates HDF5 enum data type; use H5Tclose() to free */
57 static hid_t XLALH5TypeEnum(const char *names[], const int values[], size_t length)
58 {
59  hid_t dtype_id;
60  size_t i;
61  dtype_id = threadsafe_H5Tenum_create(H5T_NATIVE_INT);
62  if (dtype_id < 0)
64  for (i = 0; i < length; ++i) {
65  herr_t status = threadsafe_H5Tenum_insert(dtype_id, names[i], values + i);
66  if (status < 0) {
67  threadsafe_H5Tclose(dtype_id);
69  }
70  }
71  return dtype_id;
72 }
73 
74 /* creates HDF5 float complex data type; use H5Tclose() to free */
75 typedef struct { float re; float im; } internal_float_complex_type;
76 static hid_t XLALH5TypeNativeFloatComplex(void)
77 {
78  hid_t dtype_id;
79  dtype_id = threadsafe_H5Tcreate(H5T_COMPOUND, sizeof(internal_float_complex_type));
80  threadsafe_H5Tinsert(dtype_id, "r", HOFFSET(internal_float_complex_type, re), H5T_NATIVE_FLOAT);
81  threadsafe_H5Tinsert(dtype_id, "i", HOFFSET(internal_float_complex_type, im), H5T_NATIVE_FLOAT);
82  return dtype_id;
83 }
84 
85 /* creates HDF5 double complex data type; use H5Tclose() to free */
86 typedef struct { double re; double im; } internal_double_complex_type;
87 static hid_t XLALH5TypeNativeDoubleComplex(void)
88 {
89  hid_t dtype_id;
90  dtype_id = threadsafe_H5Tcreate(H5T_COMPOUND, sizeof(internal_double_complex_type));
91  threadsafe_H5Tinsert(dtype_id, "r", HOFFSET(internal_double_complex_type, re), H5T_NATIVE_DOUBLE);
92  threadsafe_H5Tinsert(dtype_id, "i", HOFFSET(internal_double_complex_type, im), H5T_NATIVE_DOUBLE);
93  return dtype_id;
94 }
95 
96 /* creates HDF5 LIGOTimeGPS type; use H5Tclose() to free */
97 static hid_t XLALH5TypeNativeLIGOTimeGPS(void)
98 {
99  hid_t dtype_id;
100  hid_t int32_dtype_id;
101  int32_dtype_id = threadsafe_H5Tcopy(H5T_NATIVE_INT);
102  threadsafe_H5Tset_size(int32_dtype_id, 4); // 4 bytes = 32 bits
103  dtype_id = threadsafe_H5Tcreate(H5T_COMPOUND, sizeof(LIGOTimeGPS));
104  threadsafe_H5Tinsert(dtype_id, "gpsSeconds", HOFFSET(LIGOTimeGPS, gpsSeconds), int32_dtype_id);
105  threadsafe_H5Tinsert(dtype_id, "gpsNanoSeconds", HOFFSET(LIGOTimeGPS, gpsNanoSeconds), int32_dtype_id);
106  threadsafe_H5Tclose(int32_dtype_id);
107  return dtype_id;
108 }
109 
110 /* converts LALTYPECODE to HDF5 type; use H5Tclose() to free */
111 static hid_t XLALH5TypeFromLALType(LALTYPECODE dtype)
112 {
113  hid_t dtype_id;
114  size_t size = 1U << (dtype & LAL_TYPE_SIZE_MASK);
115 
116  /* allow only supported data types */
117  switch (dtype) {
118  case LAL_CHAR_TYPE_CODE:
119  case LAL_I2_TYPE_CODE:
120  case LAL_I4_TYPE_CODE:
121  case LAL_I8_TYPE_CODE:
122  case LAL_UCHAR_TYPE_CODE:
123  case LAL_U2_TYPE_CODE:
124  case LAL_U4_TYPE_CODE:
125  case LAL_U8_TYPE_CODE:
126  case LAL_S_TYPE_CODE:
127  case LAL_D_TYPE_CODE:
128  case LAL_C_TYPE_CODE:
129  case LAL_Z_TYPE_CODE:
130  /* these are all supported */
131  break;
132  default:
133  /* anything else is not */
134  XLAL_ERROR(XLAL_ETYPE, "Unsupported LALTYPECODE value 0%o", (unsigned int)dtype);
135  }
136 
137  if ((dtype & LAL_CMPLX_TYPE_FLAG)) {
138  /* complex numbers are treated as compound types */
139  switch (size) {
140  case 8:
141  dtype_id = XLALH5TypeNativeFloatComplex();
142  break;
143  case 16:
144  dtype_id = XLALH5TypeNativeDoubleComplex();
145  break;
146  default:
147  /* it should be impossible to get here */
148  XLAL_ERROR(XLAL_ETYPE, "Not reached");
149  }
150  } else if ((dtype & LAL_FLTPT_TYPE_FLAG)) {
151  /* floating point number */
152  switch (size) {
153  case 4:
154  dtype_id = threadsafe_H5Tcopy(H5T_NATIVE_FLOAT);
155  break;
156  case 8:
157  dtype_id = threadsafe_H5Tcopy(H5T_NATIVE_DOUBLE);
158  break;
159  default:
160  /* it should be impossible to get here */
161  XLAL_ERROR(XLAL_ETYPE, "Not reached");
162  }
163  } else if ((dtype & LAL_UNSGN_TYPE_FLAG)) {
164  /* unsigned integer */
165  switch (size) {
166  case 1:
167  dtype_id = threadsafe_H5Tcopy(H5T_NATIVE_UCHAR);
168  break;
169  case 2:
170  dtype_id = threadsafe_H5Tcopy(H5T_NATIVE_UINT16);
171  break;
172  case 4:
173  dtype_id = threadsafe_H5Tcopy(H5T_NATIVE_UINT32);
174  break;
175  case 8:
176  dtype_id = threadsafe_H5Tcopy(H5T_NATIVE_UINT64);
177  break;
178  default:
179  /* it should be impossible to get here */
180  XLAL_ERROR(XLAL_ETYPE, "Not reached");
181  }
182  } else {
183  switch (size) {
184  case 1:
185  dtype_id = threadsafe_H5Tcopy(H5T_NATIVE_SCHAR);
186  break;
187  case 2:
188  dtype_id = threadsafe_H5Tcopy(H5T_NATIVE_INT16);
189  break;
190  case 4:
191  dtype_id = threadsafe_H5Tcopy(H5T_NATIVE_INT32);
192  break;
193  case 8:
194  dtype_id = threadsafe_H5Tcopy(H5T_NATIVE_INT64);
195  break;
196  default:
197  /* it should be impossible to get here */
198  XLAL_ERROR(XLAL_ETYPE, "Not reached");
199  }
200  }
201 
202  return dtype_id;
203 }
204 
205 /* converts HDF5 type to LALTYPECODE */
206 static LALTYPECODE XLALTypeFromH5Type(hid_t dtype_id)
207 {
208  LALTYPECODE dtype = 0;
209  switch (threadsafe_H5Tget_class(dtype_id)) {
210  case H5T_INTEGER:
211  switch (threadsafe_H5Tget_sign(dtype_id)) {
212  case H5T_SGN_NONE:
213  dtype |= LAL_UNSGN_TYPE_FLAG;
214  break;
215  default:
216  /* do nothing */
217  break;
218  }
219  switch (threadsafe_H5Tget_size(dtype_id)) {
220  case 1:
221  dtype |= LAL_1_BYTE_TYPE_SIZE;
222  break;
223  case 2:
224  dtype |= LAL_2_BYTE_TYPE_SIZE;
225  break;
226  case 4:
227  dtype |= LAL_4_BYTE_TYPE_SIZE;
228  break;
229  case 8:
230  dtype |= LAL_8_BYTE_TYPE_SIZE;
231  break;
232  default:
233  XLAL_ERROR(XLAL_ETYPE, "Unsupported data type\n");
234  break;
235  }
236  break;
237  case H5T_FLOAT:
238  dtype |= LAL_FLTPT_TYPE_FLAG;
239  switch (threadsafe_H5Tget_size(dtype_id)) {
240  case 4:
241  dtype |= LAL_4_BYTE_TYPE_SIZE;
242  break;
243  case 8:
244  dtype |= LAL_8_BYTE_TYPE_SIZE;
245  break;
246  default:
247  XLAL_ERROR(XLAL_ETYPE, "Unsupported data type\n");
248  break;
249  }
250  break;
251  case H5T_COMPOUND: {
252  /* note: complex numbers are the only compound type supported */
253  char *s;
254 
255  /* sanity check the dtype_id */
256 
257  /* must have 2 members ... */
258  if (threadsafe_H5Tget_nmembers(dtype_id) != 2)
259  XLAL_ERROR(XLAL_ETYPE, "Unsupported data type\n");
260 
261  /* both members must be floating-point type ... */
262  if (threadsafe_H5Tget_member_class(dtype_id, 0) != H5T_FLOAT)
263  XLAL_ERROR(XLAL_ETYPE, "Unsupported data type\n");
264  if (threadsafe_H5Tget_member_class(dtype_id, 1) != H5T_FLOAT)
265  XLAL_ERROR(XLAL_ETYPE, "Unsupported data type\n");
266 
267  /* first member name must be something like "real" ... */
268  s = threadsafe_H5Tget_member_name(dtype_id, 0);
269  if (XLALStringNCaseCompare(s, "real", strlen(s)) != 0) {
270  free(s);
271  XLAL_ERROR(XLAL_ETYPE, "Unsupported data type\n");
272  }
273  free(s);
274 
275  /* second member name must be something like "imaginary" ... */
276  s = threadsafe_H5Tget_member_name(dtype_id, 1);
277  if (XLALStringNCaseCompare(s, "imaginary", strlen(s)) != 0) {
278  free(s);
279  XLAL_ERROR(XLAL_ETYPE, "Unsupported data type\n");
280  }
281  free(s);
282 
284  switch (threadsafe_H5Tget_size(dtype_id)) {
285  case 8:
286  dtype |= LAL_8_BYTE_TYPE_SIZE;
287  break;
288  case 16:
289  dtype |= LAL_16_BYTE_TYPE_SIZE;
290  break;
291  default:
292  XLAL_ERROR(XLAL_ETYPE, "Unsupported data type\n");
293  break;
294  }
295  break;
296  }
297  case H5T_STRING:
298  /* overload CHAR type */
299  return LAL_CHAR_TYPE_CODE;
300  default:
301  XLAL_ERROR(XLAL_ETYPE, "Unsupported data type\n");
302  break;
303  }
304  return dtype;
305 }
306 
307 /* creates a HDF5 file for writing */
308 static LALH5File * XLALH5FileCreate(const char *path)
309 {
310  char tmpfname[FILENAME_MAX];
311  LALH5File *file;
312  if (snprintf(tmpfname, sizeof(tmpfname), "%s.tmp", path) < 0)
314  file = LALCalloc(1, sizeof(*file));
315  if (!file)
317  XLALStringCopy(file->fname, path, sizeof(file->fname));
318  file->file_id = threadsafe_H5Fcreate(tmpfname, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
319  if (file->file_id < 0) {
320  LALFree(file);
321  XLAL_ERROR_NULL(XLAL_EIO, "Could not create HDF5 file `%s'", path);
322  }
323  file->mode = LAL_H5_FILE_MODE_WRITE;
324  return file;
325 }
326 
327 /* opens a HDF5 file for reading */
328 static LALH5File * XLALH5FileOpenRead(const char *path)
329 {
330  LALH5File *file;
331  file = LALCalloc(1, sizeof(*file));
332  if (!file)
334  file->file_id = threadsafe_H5Fopen(path, H5F_ACC_RDONLY, H5P_DEFAULT);
335  if (file->file_id < 0) {
336  LALFree(file);
337  XLAL_ERROR_NULL(XLAL_EIO, "Could not open HDF5 file `%s'", path);
338  }
339  file->mode = LAL_H5_FILE_MODE_READ;
340  return file;
341 }
342 
343 #if 0
344 static hid_t XLALGetObjectIdentifier(const void *ptr)
345 {
346  /*
347  * use type punning to get the identifier
348  * note that the identifier is always the
349  * first member of the LALH5 types
350  */
351  union { const void *ptr; const hid_t *hid; } id = {ptr};
352  if (ptr == NULL)
354  return *id.hid;
355 }
356 #endif
357 
358 #endif /* HAVE_HDF5 */
359 
360 /* EXPORTED ROUTINES */
361 
362 /**
363  * @addtogroup H5FileIOLowLevel_c
364  * @brief Low-level routines for reading/writing HDF5 files.
365  * @details
366  * These routines are basic routines for accessing HDF5 files.
367  * The mid-level and high-level routines, which are based on
368  * these routines, are typically more convenient routines to use.
369  * @{
370  */
371 
372 /**
373  * @name File/Group Routines
374  * @{
375  */
376 
377 /**
378  * @brief Closes a ::LALH5File
379  * @details
380  * This routine closes a ::LALH5File and deallocates resources
381  * associated with it. If the file was opened for writing, this
382  * routine also renames the temporary file as the actual file.
383  *
384  * @param file A pointer to a ::LALH5File structure to close.
385  */
387 {
388 #ifndef HAVE_HDF5
389  XLAL_ERROR_VOID(XLAL_EFAILED, "HDF5 support not implemented");
390 #else
391  if (file) {
392  if (file->is_a_group)
393  threadsafe_H5Gclose(file->file_id);
394  else {
395  if (file->mode == LAL_H5_FILE_MODE_WRITE) {
396  char tmpfname[FILENAME_MAX];
397  size_t namelen;
398  namelen = threadsafe_H5Fget_name(file->file_id, NULL, 0);
399  if (sizeof(tmpfname) <= namelen) {
400  threadsafe_H5Fclose(file->file_id);
401  LALFree(file);
402  XLAL_ERROR_VOID(XLAL_EIO, "Failed to move temporary file");
403  }
404  threadsafe_H5Fget_name(file->file_id, tmpfname, sizeof(tmpfname));
405  threadsafe_H5Fflush(file->file_id , H5F_SCOPE_GLOBAL);
406  if (rename(tmpfname, file->fname) < 0) {
407  threadsafe_H5Fclose(file->file_id);
408  LALFree(file);
409  XLAL_ERROR_VOID(XLAL_EIO, "Failed to move temporary file");
410  }
411  }
412  threadsafe_H5Fclose(file->file_id);
413  }
414  LALFree(file);
415  }
416  return;
417 #endif
418 }
419 
420 /**
421  * @brief Opens a ::LALH5File
422  * @details
423  * Opens a HDF5 file with pathname @p path and creates a ::LALH5File structure
424  * associated with it.
425  *
426  * The @p mode parameter points to a string that determines whether the
427  * file is being opened for reading and writing. Allowed strings are:
428  *
429  * <dl>
430  * <dt>r</dt><dd>Open file for reading.</dd>
431  * <dt>w</dt><dd>Truncate to zero length or create file for writing.</dd>
432  * </dl>
433  *
434  * If a file is opened for writing then data is initially written to a
435  * temporary file, and this file is renamed once the ::LALH5File structure
436  * is closed with XLALH5FileClose().
437  *
438  * @param path Pointer to a string containing the path of the file to open.
439  * @param mode Mode to open the file, either "r" or "w".
440  * @returns A pointer to a ::LALH5File structure associated with the
441  * specified HDF5 file.
442  * @retval NULL An error occurred opening the file.
443  */
444 LALH5File * XLALH5FileOpen(const char UNUSED *path, const char UNUSED *mode)
445 {
446 #ifndef HAVE_HDF5
447  XLAL_ERROR_NULL(XLAL_EFAILED, "HDF5 support not implemented");
448 #else
449  if (path == NULL || mode == NULL)
451  if (strcmp(mode, "r") == 0)
452  return XLALH5FileOpenRead(path);
453  else if (strcmp(mode, "w") == 0)
454  return XLALH5FileCreate(path);
455  XLAL_ERROR_NULL(XLAL_EINVAL, "Invalid mode \"%s\": must be either \"r\" or \"w\"", mode);
456 #endif
457 }
458 
459 /**
460  * @brief Opens a group in a ::LALH5File
461  * @details
462  * Opens a HDF5 group with name @p name contained in the HDF5 file
463  * associated with the ::LALH5File @p file. If the HDF5 file is
464  * being read, the specified group must exist in that file. If
465  * the HDF5 file is being written, the specified group is created
466  * within the file.
467  *
468  * @param file Pointer to a ::LALH5File structure in which to open the group.
469  * @param name Pointer to a string with the name of the group to open.
470  * @returns A pointer to a ::LALH5File structure associated with the
471  * specified group within a HDF5 file.
472  * @retval NULL An error occurred opening the group.
473  */
474 LALH5File * XLALH5GroupOpen(LALH5File UNUSED *file, const char UNUSED *name)
475 {
476 #ifndef HAVE_HDF5
477  XLAL_ERROR_NULL(XLAL_EFAILED, "HDF5 support not implemented");
478 #else
479  LALH5File *group;
480  if (file == NULL)
482  group = LALCalloc(1, sizeof(*group));
483  if (!group)
485  group->is_a_group = 1;
486  group->mode = file->mode;
487  if (!name) /* this is the same as the file */
488  group->file_id = file->file_id;
489  else if (group->mode == LAL_H5_FILE_MODE_READ)
490  group->file_id = threadsafe_H5Gopen2(file->file_id, name, H5P_DEFAULT);
491  else if (group->mode == LAL_H5_FILE_MODE_WRITE) {
492  hid_t gcpl; /* property list to allow intermediate groups to be created */
493  gcpl = threadsafe_H5Pcreate(H5P_LINK_CREATE);
494  if (gcpl < 0 || threadsafe_H5Pset_create_intermediate_group(gcpl, 1) < 0) {
495  LALFree(group);
497  }
498  group->file_id = threadsafe_H5Gcreate2(file->file_id, name, gcpl, H5P_DEFAULT, H5P_DEFAULT);
499  threadsafe_H5Pclose(gcpl);
500  } else
501  XLAL_ERROR_NULL(XLAL_EINVAL, "Corrupted file structure");
502  if (group->file_id < 0) {
503  LALFree(group);
504  XLAL_ERROR_NULL(XLAL_EIO, "Failed to open group `%s'", name ? name : "(null)");
505  }
506  return group;
507 #endif
508 }
509 
510 /**
511  * @brief Checks for existence of a group in a ::LALH5File
512  * @details
513  * Checks if group with name @p name exists in the HDF5 file associated with the
514  * ::LALH5File file @p file. If the group exists the return code is 1.
515  * If the group does not exist a return code value of 0 is used.
516  *
517  * @attention Read failure results in a returned value of 0.
518  *
519  * @param file Pointer to a ::LALH5File structure to check for group.
520  * @param name Pointer to a string with the name of the group to check.
521  * @retval 0 Group does not exist or failure.
522  * @retval 1 Group exists.
523  */
524 int XLALH5FileCheckGroupExists(const LALH5File UNUSED *file, const char UNUSED *name)
525 {
526 #ifndef HAVE_HDF5
527  XLAL_ERROR_VAL(0, XLAL_EFAILED, "HDF5 support not implemented");
528 #else
529  if (file == NULL || name == NULL)
531  H5G_info_t info;
532  if (threadsafe_H5Gget_info_by_name(file->file_id, name, &info, H5P_DEFAULT) < 0)
533  return 0;
534  return 1;
535 #endif
536 }
537 
538 /**
539  * @brief Checks for existence of a dataset in a ::LALH5File
540  * @details
541  * Checks if dataset with name @p name exists in the HDF5 file associated with the
542  * ::LALH5File file @p file. If the dataset exists the return code is 1.
543  * If the dataset does not exist a return code value of 0 is used.
544  *
545  * @attention Read failure results in a returned value of 0.
546  *
547  * @param file Pointer to a ::LALH5File structure to check for dataset.
548  * @param name Pointer to a string with the name of the dataset to check.
549  * @retval 0 Dataset does not exist or failure.
550  * @retval 1 Dataset exists.
551  */
552 int XLALH5FileCheckDatasetExists(const LALH5File UNUSED *file, const char UNUSED *name)
553 {
554 #ifndef HAVE_HDF5
555  XLAL_ERROR_VAL(0, XLAL_EFAILED, "HDF5 support not implemented");
556 #else
557  H5G_info_t group_info;
558  hsize_t i;
559 
560  if (file == NULL || name == NULL)
562 
563  if (threadsafe_H5Gget_info(file->file_id, &group_info) < 0)
564  XLAL_ERROR_VAL(0, XLAL_EIO, "Could not read group info");
565 
566  for (i = 0; i < group_info.nlinks; ++i) {
567  H5O_info_t obj_info;
568  if (threadsafe_H5Oget_info_by_idx(file->file_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &obj_info, H5P_DEFAULT) < 0)
569  XLAL_ERROR_VAL(0, XLAL_EIO, "Could not read object info");
570  if (obj_info.type == H5O_TYPE_DATASET) {
571  char *base;
572  hid_t obj_id;
573  int n;
574  obj_id = threadsafe_H5Oopen_by_addr(file->file_id, obj_info.addr);
575  if (obj_id < 0)
576  XLAL_ERROR_VAL(0, XLAL_EIO, "Could not open object");
577  n = threadsafe_H5Iget_name(obj_id, NULL, 0);
578  if (n < 0) {
579  threadsafe_H5Oclose(obj_id);
580  XLAL_ERROR_VAL(0, XLAL_EIO, "Could not read object");
581  }
582  char dset_name[n + 1];
583  n = threadsafe_H5Iget_name(obj_id, dset_name, n + 1);
584  threadsafe_H5Oclose(obj_id);
585  if (n < 0)
586  XLAL_ERROR_VAL(0, XLAL_EIO, "Could not read object");
587  /* get basename */
588  if ((base = strrchr(dset_name, '/')))
589  ++base;
590  else
591  base = dset_name;
592 
593  if (strcmp(name, base) == 0)
594  return 1; /* found it */
595  }
596  }
597 
598  /* no matching dataset found */
599  return 0;
600 #endif
601 }
602 
603 /**
604  * @brief DEPRECATED: Checks for existence of a Group in a LALH5File object ::LALH5File
605  * @details
606  * Checks if group with name @p exists in the HDF5 files associated with the
607  * ::LALH5File file. If the group exists the return code is 1
608  * if the group does not exist a return code value of 0 is used.
609  *
610  * @deprecated
611  * Use XLALH5FileCheckGroupExists instead.
612  *
613  * @param file Pointer to a ::LALH5File structure to check for group in
614  * @param name Pointer to a string with the name of the group to check.
615  * @returns int, 1 if group exists. 0 if not.
616  */
617 int XLALH5CheckGroupExists(LALH5File UNUSED *file, const char UNUSED *name)
618 {
619 #ifndef HAVE_HDF5
620  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
621 #else
622  XLAL_PRINT_DEPRECATION_WARNING("XLALH5FileCheckGroupExists");
623  if (threadsafe_H5Gget_objinfo(file->file_id, name, 0, NULL))
624  {
625  return 0;
626  }
627  else
628  {
629  return 1;
630  }
631 #endif
632 }
633 
634 /**
635  * @brief Gets the number of groups contained in a ::LALH5File
636  * @details
637  * This routines returns the number of groups contained in a
638  * an ::LALH5File @p file which can be either a file or a group.
639  * This routine does not recursively count subgroups of the
640  * groups found.
641  *
642  * @param file Pointer to a ::LALH5File file or group to be queried.
643  * @returns The number of groups contained in the file or group.
644  * @retval -1 Failure.
645  */
646 size_t XLALH5FileQueryNGroups(const LALH5File UNUSED *file)
647 {
648 #ifndef HAVE_HDF5
649  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
650 #else
651  H5G_info_t group_info;
652  size_t num = 0;
653  hsize_t i;
654 
655  if (file == NULL)
657 
658  if (threadsafe_H5Gget_info(file->file_id, &group_info) < 0)
659  XLAL_ERROR(XLAL_EIO, "Could not read group info");
660 
661  for (i = 0; i < group_info.nlinks; ++i) {
662  H5O_info_t obj_info;
663  if (threadsafe_H5Oget_info_by_idx(file->file_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &obj_info, H5P_DEFAULT) < 0)
664  XLAL_ERROR(XLAL_EIO, "Could not read object info");
665  if (obj_info.type == H5O_TYPE_GROUP)
666  ++num;
667  }
668 
669  return num;
670 #endif
671 }
672 
673 /**
674  * @brief Gets the name of a group contained in a ::LALH5File
675  * @details
676  * This routines gets the name of a group contained in a ::LALH5File
677  * @p file which can be either a file or a group.
678  * The index @p pos identifies which group's name is returned.
679  * The result is written into the buffer pointed to by @p name, the size
680  * of which is @p size bytes. If @p name is NULL, no data is copied but
681  * the routine returns the length of the string. Therefore, this routine
682  * can be called once to determine the amount of memory required, the
683  * memory can be allocated, and then it can be called a second time to
684  * read the string. If the parameter @p size is less than or equal to
685  * the string length then only $p size-1 bytes of the string are copied
686  * to the buffer @p name.
687  * @note The return value is the length of the string, not including the
688  * terminating NUL character; thus the buffer @p name should be allocated
689  * to be one byte larger.
690  * @param name Pointer to a buffer into which the string will be written.
691  * @param size Size in bytes of the buffer into which the string will be
692  * written.
693  * @param file Pointer to a ::LALH5File file or group to be queried.
694  * @param pos The index identifying which group contained in the file.
695  * @retval 0 Success.
696  * @retval -1 Failure.
697  */
698 int XLALH5FileQueryGroupName(char UNUSED *name, size_t UNUSED size, const LALH5File UNUSED *file, int UNUSED pos)
699 {
700 #ifndef HAVE_HDF5
701  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
702 #else
703  H5G_info_t group_info;
704  size_t num = 0;
705  hsize_t i;
706 
707  if (file == NULL)
709 
710  if (threadsafe_H5Gget_info(file->file_id, &group_info) < 0)
711  XLAL_ERROR(XLAL_EIO, "Could not read group info");
712 
713  for (i = 0; i < group_info.nlinks; ++i) {
714  H5O_info_t obj_info;
715  if (threadsafe_H5Oget_info_by_idx(file->file_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &obj_info, H5P_DEFAULT) < 0)
716  XLAL_ERROR(XLAL_EIO, "Could not read object info");
717  if (obj_info.type == H5O_TYPE_GROUP) {
718  if (num == (size_t)pos) { /* found it */
719  hid_t obj_id;
720  int n;
721  obj_id = threadsafe_H5Oopen_by_addr(file->file_id, obj_info.addr);
722  if (obj_id < 0)
723  XLAL_ERROR(XLAL_EIO, "Could not open object");
724  n = threadsafe_H5Iget_name(obj_id, name, size);
725  threadsafe_H5Oclose(obj_id);
726  if (n < 0)
727  XLAL_ERROR(XLAL_EIO, "Could not read object name");
728  return n;
729  } else
730  ++num;
731  }
732  }
733 
734  /* failed to find position */
735  XLAL_ERROR(XLAL_EINVAL, "No group associated with given position");
736 #endif
737 }
738 
739 /**
740  * @brief Gets the number of datasets contained in a ::LALH5File
741  * @details
742  * This routines returns the number of datasets contained in a
743  * an ::LALH5File @p file which can be either a file or a group.
744  *
745  * @param file Pointer to a ::LALH5File file or group to be queried.
746  * @returns The number of datasets contained in the file or group.
747  * @retval -1 Failure.
748  */
750 {
751 #ifndef HAVE_HDF5
752  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
753 #else
754  H5G_info_t group_info;
755  size_t num = 0;
756  hsize_t i;
757 
758  if (file == NULL)
760 
761  if (threadsafe_H5Gget_info(file->file_id, &group_info) < 0)
762  XLAL_ERROR(XLAL_EIO, "Could not read group info");
763 
764  for (i = 0; i < group_info.nlinks; ++i) {
765  H5O_info_t obj_info;
766  if (threadsafe_H5Oget_info_by_idx(file->file_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &obj_info, H5P_DEFAULT) < 0)
767  XLAL_ERROR(XLAL_EIO, "Could not read object info");
768  if (obj_info.type == H5O_TYPE_DATASET)
769  ++num;
770  }
771 
772  return num;
773 #endif
774 }
775 
776 /**
777  * @brief Gets the name of a dataset contained in a ::LALH5File
778  * @details
779  * This routines gets the name of a dataset contained in a ::LALH5File
780  * @p file which can be either a file or a group.
781  * The index @p pos identifies which dataset's name is returned.
782  * The result is written into the buffer pointed to by @p name, the size
783  * of which is @p size bytes. If @p name is NULL, no data is copied but
784  * the routine returns the length of the string. Therefore, this routine
785  * can be called once to determine the amount of memory required, the
786  * memory can be allocated, and then it can be called a second time to
787  * read the string. If the parameter @p size is less than or equal to
788  * the string length then only $p size-1 bytes of the string are copied
789  * to the buffer @p name.
790  * @note The return value is the length of the string, not including the
791  * terminating NUL character; thus the buffer @p name should be allocated
792  * to be one byte larger.
793  * @param name Pointer to a buffer into which the string will be written.
794  * @param size Size in bytes of the buffer into which the string will be
795  * written.
796  * @param file Pointer to a ::LALH5File file or group to be queried.
797  * @param pos The index identifying which dataset contained in the file.
798  * @retval 0 Success.
799  * @retval -1 Failure.
800  */
801 int XLALH5FileQueryDatasetName(char UNUSED *name, size_t UNUSED size, const LALH5File UNUSED *file, int UNUSED pos)
802 {
803 #ifndef HAVE_HDF5
804  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
805 #else
806  H5G_info_t group_info;
807  size_t num = 0;
808  hsize_t i;
809 
810  if (file == NULL)
812 
813  if (threadsafe_H5Gget_info(file->file_id, &group_info) < 0)
814  XLAL_ERROR(XLAL_EIO, "Could not read group info");
815 
816  for (i = 0; i < group_info.nlinks; ++i) {
817  H5O_info_t obj_info;
818  if (threadsafe_H5Oget_info_by_idx(file->file_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &obj_info, H5P_DEFAULT) < 0)
819  XLAL_ERROR(XLAL_EIO, "Could not read object info");
820  if (obj_info.type == H5O_TYPE_DATASET) {
821  if (num == (size_t)pos) { /* found it */
822  hid_t obj_id;
823  int n;
824  obj_id = threadsafe_H5Oopen_by_addr(file->file_id, obj_info.addr);
825  if (obj_id < 0)
826  XLAL_ERROR(XLAL_EIO, "Could not open object");
827  n = threadsafe_H5Iget_name(obj_id, name, size);
828  threadsafe_H5Oclose(obj_id);
829  if (n < 0)
830  XLAL_ERROR(XLAL_EIO, "Could not read object name");
831  return n;
832  } else
833  ++num;
834  }
835  }
836 
837  /* failed to find position */
838  XLAL_ERROR(XLAL_EINVAL, "No dataset associated with given position");
839 #endif
840 }
841 
842 /**
843  * @brief DEPRECATED: Gets dataset names from a ::LALH5File
844  * @details
845  * This routine returns the names of all datasets in a ::LALH5File.
846  *
847  * @deprecated
848  * Use XLALH5AttributeQueryN() and XLALH5AttributeQueryName() instead.
849  *
850  * @param names Pointer a list of strings to be returned to the user. Memory
851  * should be freed by the caller.
852  * @param N Pointer to a UINT4 where the number of datasets will be recorded
853  * @param file ::LALH5File from which to read datasets
854  * @retval 0 Success.
855  * @retval -1 Failure.
856  */
857 int XLALH5FileGetDatasetNames(LALH5File UNUSED *file, char UNUSED *** names, UINT4 UNUSED *N)
858 {
859 #ifndef HAVE_HDF5
860  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
861 #else
862  hsize_t ng;
863  int ns;
864  int otype;
865  int i;
866 
867  XLAL_PRINT_DEPRECATION_WARNING("XLALH5FileQueryNDatasets() and XLALH5FileQueryDatasetName");
868 
869  if (file == NULL)
871  if (names == NULL)
873 
874  threadsafe_H5Gget_num_objs(file->file_id, &ng);
875  *N = ng;
876 
877  /*
878  * Filter objects that don't meet our requirements
879  */
880  for (i = 0; i < (int)ng; i++) {
881  otype = threadsafe_H5Gget_objtype_by_idx(file->file_id, (size_t)i);
882  if (otype != H5G_DATASET) {
883  (*N)--;
884  }
885  }
886  char ** namelist = (char**) XLALMalloc((*N) * sizeof(*names));
887 
888  for (i = 0; i < (int)ng; i++) {
889  otype = threadsafe_H5Gget_objtype_by_idx(file->file_id, (size_t)i);
890  if (otype != H5G_DATASET) {
891  continue;
892  }
893 
894  ns = threadsafe_H5Gget_objname_by_idx(file->file_id, (size_t)i, NULL, 0) + 1;
895  namelist[i] = (char*) XLALMalloc(ns * sizeof(namelist[i]));
896  threadsafe_H5Gget_objname_by_idx(file->file_id, (size_t)i, namelist[i], ns);
897  }
898 
899  *names = namelist;
900  return(XLAL_SUCCESS);
901 #endif
902 }
903 
904 /** @} */
905 
906 /**
907  * @name Dataset Routines
908  * @{
909  */
910 
911 /**
912  * @brief Frees a ::LALH5Dataset
913  * @details
914  * Closes a HDF5 dataset associated with the ::LALH5Dataset @p dset
915  * and deallocates memory of the ::LALH5Dataset structure.
916  * @param dset Pointer to a ::LALH5Dataset structure to close.
917  */
918 void XLALH5DatasetFree(LALH5Dataset UNUSED *dset)
919 {
920 #ifndef HAVE_HDF5
921  XLAL_ERROR_VOID(XLAL_EFAILED, "HDF5 support not implemented");
922 #else
923  if (dset) {
924  threadsafe_H5Tclose(dset->dtype_id);
925  threadsafe_H5Sclose(dset->space_id);
926  threadsafe_H5Dclose(dset->dataset_id);
927  LALFree(dset);
928  }
929  return;
930 #endif
931 }
932 
933 /**
934  * @brief Allocates a multi-dimensional ::LALH5Dataset
935  * @details
936  * Creates a new HDF5 dataset with name @p name within a HDF5 file
937  * associated with the ::LALH5File @p file structure and allocates a
938  * ::LALH5Dataset structure associated with the dataset. The type
939  * of data to be stored in the dataset is given by the \c LALTYPECODE
940  * @p dtype and the rank array dimensions of the dataset is given by
941  * the UINT4Vector @p dimLength.
942  *
943  * The ::LALH5File @p file passed to this routine must be a file
944  * opened for writing.
945  *
946  * @param file Pointer to a ::LALH5File structure in which to create the dataset.
947  * @param name Pointer to a string with the name of the dataset to create.
948  * @param dtype \c LALTYPECODE value specifying the data type.
949  * @param dimLength Pointer to a UINT4Vector specifying the dataspace
950  * dimensions.
951  * @returns A pointer to a ::LALH5Dataset structure associated with the
952  * specified dataset within a HDF5 file.
953  * @retval NULL An error occurred creating the dataset.
954  */
955 LALH5Dataset * XLALH5DatasetAlloc(LALH5File UNUSED *file, const char UNUSED *name, LALTYPECODE UNUSED dtype, UINT4Vector UNUSED *dimLength)
956 {
957 #ifndef HAVE_HDF5
958  XLAL_ERROR_NULL(XLAL_EFAILED, "HDF5 support not implemented");
959 #else
960  LALH5Dataset *dset;
961  hsize_t *dims;
962  UINT4 dim;
963  size_t namelen;
964 
965  if (name == NULL || file == NULL || dimLength == NULL)
967  if (file->mode != LAL_H5_FILE_MODE_WRITE)
968  XLAL_ERROR_NULL(XLAL_EINVAL, "Attempting to write to a read-only HDF5 file");
969 
970  namelen = strlen(name);
971  dset = LALCalloc(1, sizeof(*dset) + namelen + 1); /* use flexible array member to record name */
972  if (!dset)
974 
975  /* create datatype */
976  dset->dtype_id = XLALH5TypeFromLALType(dtype);
977  if (dset->dtype_id < 0) {
978  LALFree(dset);
980  }
981 
982  /* copy dimensions to HDF5 type */
983  dims = LALCalloc(dimLength->length, sizeof(*dims));
984  if (!dims) {
985  threadsafe_H5Tclose(dset->dtype_id);
986  LALFree(dset);
988  }
989  for (dim = 0; dim < dimLength->length; ++dim)
990  dims[dim] = dimLength->data[dim];
991 
992  /* create dataspace */
993  dset->space_id = threadsafe_H5Screate_simple(dimLength->length, dims, NULL);
994  LALFree(dims);
995  if (dset->space_id < 0) {
996  threadsafe_H5Tclose(dset->dtype_id);
997  LALFree(dset);
998  XLAL_ERROR_NULL(XLAL_EIO, "Could not create dataspace for dataset `%s'", name);
999  }
1000 
1001  /* create dataset */
1002  dset->dataset_id = threadsafe_H5Dcreate2(file->file_id, name, dset->dtype_id, dset->space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1003  if (dset->dataset_id < 0) {
1004  threadsafe_H5Tclose(dset->dtype_id);
1005  threadsafe_H5Sclose(dset->space_id);
1006  LALFree(dset);
1007  XLAL_ERROR_NULL(XLAL_EIO, "Could not create dataset `%s'", name);
1008  }
1009 
1010  /* record name of dataset and parent id */
1011  snprintf(dset->name, namelen + 1, "%s", name);
1012  dset->parent_id = file->file_id;
1013 
1014  return dset;
1015 #endif
1016 }
1017 
1018 /**
1019  * @brief Allocates a 1-dimensional ::LALH5Dataset
1020  * @details
1021  * Creates a new HDF5 dataset with name @p name within a HDF5 file
1022  * associated with the ::LALH5File @p file structure and allocates a
1023  * ::LALH5Dataset structure associated with the dataset. The type
1024  * of data to be stored in the dataset is given by the \c LALTYPECODE
1025  * @p dtype and the number of points in the dataset is given by
1026  * the @p length parameter.
1027  *
1028  * The ::LALH5File @p file passed to this routine must be a file
1029  * opened for writing.
1030  *
1031  * @param file Pointer to a ::LALH5File structure in which to create the dataset.
1032  * @param name Pointer to a string with the name of the dataset to create.
1033  * @param dtype \c LALTYPECODE value specifying the data type.
1034  * @param length The number of points of data in the dataset.
1035  * @returns A pointer to a ::LALH5Dataset structure associated with the
1036  * specified dataset within a HDF5 file.
1037  * @retval NULL An error occurred creating the dataset.
1038  */
1039 LALH5Dataset * XLALH5DatasetAlloc1D(LALH5File UNUSED *file, const char UNUSED *name, LALTYPECODE UNUSED dtype, size_t UNUSED length)
1040 {
1041 #ifndef HAVE_HDF5
1042  XLAL_ERROR_NULL(XLAL_EFAILED, "HDF5 support not implemented");
1043 #else
1044  LALH5Dataset *dset;
1045  hsize_t npoints = length;
1046  size_t namelen;
1047 
1048  if (name == NULL || file == NULL)
1050  if (file->mode != LAL_H5_FILE_MODE_WRITE)
1051  XLAL_ERROR_NULL(XLAL_EINVAL, "Attempting to write to a read-only HDF5 file");
1052 
1053  namelen = strlen(name);
1054  dset = LALCalloc(1, sizeof(*dset) + namelen + 1); /* use flexible array member to record name */
1055  if (!dset)
1057 
1058  /* create datatype */
1059  dset->dtype_id = XLALH5TypeFromLALType(dtype);
1060  if (dset->dtype_id < 0) {
1061  LALFree(dset);
1063  }
1064 
1065  /* create dataspace */
1066  dset->space_id = threadsafe_H5Screate_simple(1, &npoints, NULL);
1067  if (dset->space_id < 0) {
1068  threadsafe_H5Tclose(dset->dtype_id);
1069  LALFree(dset);
1070  XLAL_ERROR_NULL(XLAL_EIO, "Could not create dataspace for dataset `%s'", name);
1071  }
1072 
1073  /* create dataset */
1074  dset->dataset_id = threadsafe_H5Dcreate2(file->file_id, name, dset->dtype_id, dset->space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1075  if (dset->dataset_id < 0) {
1076  threadsafe_H5Tclose(dset->dtype_id);
1077  threadsafe_H5Sclose(dset->space_id);
1078  LALFree(dset);
1079  XLAL_ERROR_NULL(XLAL_EIO, "Could not create dataset `%s'", name);
1080  }
1081 
1082  /* record name of dataset and parent id */
1083  snprintf(dset->name, namelen + 1, "%s", name);
1084  dset->parent_id = file->file_id;
1085 
1086  return dset;
1087 #endif
1088 }
1089 
1090 /**
1091  * @brief Allocates a variable-length string ::LALH5Dataset
1092  * @details
1093  * Creates a new HDF5 dataset with name @p name within a HDF5 file
1094  * associated with the ::LALH5File @p file structure and allocates a
1095  * ::LALH5Dataset structure associated with the dataset. The type
1096  * of data to be stored in the dataset is variable length strings
1097  * and the number of strings in the dataset is given by the @p length
1098  * parameter.
1099  *
1100  * The ::LALH5File @p file passed to this routine must be a file
1101  * opened for writing.
1102  *
1103  * @param file Pointer to a ::LALH5File structure in which to create the dataset.
1104  * @param name Pointer to a string with the name of the dataset to create.
1105  * @param length The number of variable length strings in the dataset.
1106  * @returns A pointer to a ::LALH5Dataset structure associated with the
1107  * specified dataset within a HDF5 file.
1108  * @retval NULL An error occurred creating the dataset.
1109  */
1110 LALH5Dataset * XLALH5DatasetAllocStringData(LALH5File UNUSED *file, const char UNUSED *name, size_t UNUSED length)
1111 {
1112 #ifndef HAVE_HDF5
1113  XLAL_ERROR_NULL(XLAL_EFAILED, "HDF5 support not implemented");
1114 #else
1115  LALH5Dataset *dset;
1116  hsize_t npoints = length;
1117  size_t namelen;
1118 
1119  if (name == NULL || file == NULL)
1121  if (file->mode != LAL_H5_FILE_MODE_WRITE)
1122  XLAL_ERROR_NULL(XLAL_EINVAL, "Attempting to write to a read-only HDF5 file");
1123 
1124  namelen = strlen(name);
1125  dset = LALCalloc(1, sizeof(*dset) + namelen + 1); /* use flexible array member to record name */
1126  if (!dset)
1128 
1129  /* create datatype; here we use ASCII encoding */
1130  dset->dtype_id = threadsafe_H5Tcopy(H5T_C_S1);
1131  if (dset->dtype_id < 0) {
1132  LALFree(dset);
1133  XLAL_ERROR_NULL(XLAL_EIO, "Could not copy datatype");
1134  }
1135  if (threadsafe_H5Tset_size(dset->dtype_id, H5T_VARIABLE) < 0) {
1136  threadsafe_H5Tclose(dset->dtype_id);
1137  LALFree(dset);
1138  XLAL_ERROR_NULL(XLAL_EIO, "Could not set datatype size");
1139  }
1140 
1141  /* create dataspace */
1142  dset->space_id = threadsafe_H5Screate_simple(1, &npoints, NULL);
1143  if (dset->space_id < 0) {
1144  threadsafe_H5Tclose(dset->dtype_id);
1145  LALFree(dset);
1146  XLAL_ERROR_NULL(XLAL_EIO, "Could not create dataspace for dataset `%s'", name);
1147  }
1148 
1149  /* create dataset */
1150  dset->dataset_id = threadsafe_H5Dcreate2(file->file_id, name, dset->dtype_id, dset->space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1151  if (dset->dataset_id < 0) {
1152  threadsafe_H5Tclose(dset->dtype_id);
1153  threadsafe_H5Sclose(dset->space_id);
1154  LALFree(dset);
1155  XLAL_ERROR_NULL(XLAL_EIO, "Could not create dataset `%s'", name);
1156  }
1157 
1158  /* record name of dataset and parent id */
1159  snprintf(dset->name, namelen + 1, "%s", name);
1160  dset->parent_id = file->file_id;
1161 
1162  return dset;
1163 #endif
1164 }
1165 
1166 /**
1167  * @brief Writes data to a ::LALH5Dataset
1168  * @details
1169  * Writes the data contained in @p data to a HDF5 dataset associated
1170  * with the ::LALH5Dataset @p dset structure.
1171  * @param dset Pointer to a ::LALH5Dataset structure to which to write the data.
1172  * @param data Pointer to the data buffer to be written.
1173  * @retval 0 Success.
1174  * @retval -1 Failure.
1175  */
1176 int XLALH5DatasetWrite(LALH5Dataset UNUSED *dset, void UNUSED *data)
1177 {
1178 #ifndef HAVE_HDF5
1179  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1180 #else
1181  if (dset == NULL || data == NULL)
1183  if (threadsafe_H5Dwrite(dset->dataset_id, dset->dtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0)
1184  XLAL_ERROR(XLAL_EIO, "Could not write data to dataset");
1185  return 0;
1186 #endif
1187 }
1188 
1189 /**
1190  * @brief Reads a ::LALH5Dataset
1191  * @details
1192  * Opens an existing HDF5 dataset with name @p name within a HDF5 file
1193  * associated with the ::LALH5File @p file structure and allocates a
1194  * ::LALH5Dataset structure associated with the dataset.
1195  *
1196  * The ::LALH5File @p file passed to this routine must be a file
1197  * opened for reading.
1198  *
1199  * @param file Pointer to a ::LALH5File structure containing the dataset
1200  * to be opened.
1201  * @param name Pointer to a string with the name of the dataset to open.
1202  * @returns A pointer to a ::LALH5Dataset structure associated with the
1203  * specified dataset within a HDF5 file.
1204  * @retval NULL An error occurred creating the dataset.
1205  */
1206 LALH5Dataset * XLALH5DatasetRead(LALH5File UNUSED *file, const char UNUSED *name)
1207 {
1208 #ifndef HAVE_HDF5
1209  XLAL_ERROR_NULL(XLAL_EFAILED, "HDF5 support not implemented");
1210 #else
1211  hid_t dtype_id;
1212  LALH5Dataset *dset;
1213  size_t namelen;
1214  if (name == NULL || file == NULL)
1216  if (file->mode != LAL_H5_FILE_MODE_READ)
1217  XLAL_ERROR_NULL(XLAL_EINVAL, "Attempting to read a write-only HDF5 file");
1218 
1219  namelen = strlen(name);
1220  dset = LALCalloc(1, sizeof(*dset) + namelen + 1); /* use flexible array member to record name */
1221  if (!dset)
1223 
1224  dset->dataset_id = threadsafe_H5Dopen2(file->file_id, name, H5P_DEFAULT);
1225  if (dset->dataset_id < 0) {
1226  LALFree(dset);
1227  XLAL_ERROR_NULL(XLAL_EIO, "Could not read dataset `%s'", name);
1228  }
1229 
1230  dset->space_id = threadsafe_H5Dget_space(dset->dataset_id);
1231  if (dset->space_id < 0) {
1232  LALFree(dset);
1233  XLAL_ERROR_NULL(XLAL_EIO, "Could not read dataspace of dataset `%s'", name);
1234  }
1235 
1236  dtype_id = threadsafe_H5Dget_type(dset->dataset_id);
1237  if (dtype_id < 0) {
1238  threadsafe_H5Sclose(dset->space_id);
1239  LALFree(dset);
1240  XLAL_ERROR_NULL(XLAL_EIO, "Could not read datatype of dataset `%s'", name);
1241  }
1242 
1243  /* convert type to native type */
1244  dset->dtype_id = threadsafe_H5Tget_native_type(dtype_id, H5T_DIR_ASCEND);
1245  threadsafe_H5Tclose(dtype_id);
1246  if (dset->dtype_id < 0) {
1247  threadsafe_H5Sclose(dset->space_id);
1248  LALFree(dset);
1249  XLAL_ERROR_NULL(XLAL_EIO, "Could not get native type for dataset `%s'", name);
1250  }
1251 
1252  /* record name of dataset and parent id */
1253  snprintf(dset->name, namelen + 1, "%s", name);
1254  dset->parent_id = file->file_id;
1255  return dset;
1256 #endif
1257 }
1258 
1259 /**
1260  * @brief Checks if a ::LALH5Dataset contains variable length string data
1261  * @param dset Pointer to a ::LALH5Dataset to be checked.
1262  * @retval 1 ::LALH5Dataset is of variable length string type
1263  * @retval 0 ::LALH5Dataset is not of variable length string type
1264  * @retval -1 Failure.
1265  */
1267 {
1268 #ifndef HAVE_HDF5
1269  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1270 #else
1271  return threadsafe_H5Tget_class(dset->dtype_id) == H5T_STRING;
1272 #endif
1273 }
1274 
1275 /**
1276  * @brief Gets the number of points in a ::LALH5Dataset
1277  * @param dset Pointer to a ::LALH5Dataset to be queried.
1278  * @returns The number of points in the HDF5 dataset associated
1279  * with the specified ::LALH5Dataset.
1280  * @retval (size_t)(-1) Failure.
1281  */
1283 {
1284 #ifndef HAVE_HDF5
1285  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1286 #else
1287  hssize_t npoints;
1288  if (dset == NULL)
1290  npoints = threadsafe_H5Sget_simple_extent_npoints(dset->space_id);
1291  if (npoints < 0)
1292  XLAL_ERROR(XLAL_EIO, "Could not read number of points in dataspace");
1293  return npoints;
1294 #endif
1295 }
1296 
1297 /**
1298  * @brief Gets the number of bytes in a ::LALH5Dataset
1299  * @param dset Pointer to a ::LALH5Dataset to be queried.
1300  * @returns The number of bytes in the HDF5 dataset associated
1301  * with the specified ::LALH5Dataset. This is the number of
1302  * bytes required to hold the data in that dataset.
1303  * @retval (size_t)(-1) Failure.
1304  */
1306 {
1307 #ifndef HAVE_HDF5
1308  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1309 #else
1310  size_t size;
1311  size_t npoints;
1312  if (dset == NULL)
1314  size = threadsafe_H5Tget_size(dset->dtype_id);
1315  if (size == 0)
1316  XLAL_ERROR(XLAL_EIO, "Could not read size of datatype");
1317  npoints = XLALH5DatasetQueryNPoints(dset);
1318  if (npoints == (size_t)(-1))
1320  return size * npoints;
1321 #endif
1322 }
1323 
1324 /**
1325  * @brief Gets the type of data in a ::LALH5Dataset
1326  * @param dset Pointer to a ::LALH5Dataset to be queried.
1327  * @returns The \c LALTYPECODE of the datatype in the
1328  * HDF5 dataset associated with the specified ::LALH5Dataset.
1329  * @retval -1 Failure.
1330  */
1332 {
1333 #ifndef HAVE_HDF5
1334  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1335 #else
1336  LALTYPECODE dtype;
1337  if (dset == NULL)
1339  dtype = XLALTypeFromH5Type(dset->dtype_id);
1340  if ((int)dtype < 0)
1342  return dtype;
1343 #endif
1344 }
1345 
1346 /**
1347  * @brief Gets the number of dimensions of the dataspace in a ::LALH5Dataset
1348  * @param dset Pointer to a ::LALH5Dataset to be queried.
1349  * @returns The number of dimensions in the dataspace in the
1350  * HDF5 dataset associated with the specified ::LALH5Dataset.
1351  * @retval -1 Failure.
1352  */
1354 {
1355 #ifndef HAVE_HDF5
1356  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1357 #else
1358  int rank;
1359  if (dset == NULL)
1361  rank = threadsafe_H5Sget_simple_extent_ndims(dset->space_id);
1362  if (rank < 0)
1363  XLAL_ERROR(XLAL_EIO, "Could not read rank of dataset");
1364  return rank;
1365 #endif
1366 }
1367 
1368 /**
1369  * @brief Gets the dimensions of the dataspace in a ::LALH5Dataset
1370  * @param dset Pointer to a ::LALH5Dataset to be queried.
1371  * @returns A pointer to a newly-allocated UINT4Vector containing
1372  * the dimensions of the dataspace in the HDF5 dataset associated
1373  * with the * specified ::LALH5Dataset.
1374  * @retval NULL Failure.
1375  */
1377 {
1378 #ifndef HAVE_HDF5
1379  XLAL_ERROR_NULL(XLAL_EFAILED, "HDF5 support not implemented");
1380 #else
1381  UINT4Vector *dimLength;
1382  hsize_t *dims;
1383  int rank;
1384  int dim;
1385 
1386  if (dset == NULL)
1388 
1389  rank = XLALH5DatasetQueryNDim(dset);
1390  if (rank < 0)
1392 
1393  dims = LALCalloc(rank, sizeof(*dims));
1394  if (threadsafe_H5Sget_simple_extent_dims(dset->space_id, dims, NULL) < 0) {
1395  LALFree(dims);
1396  XLAL_ERROR_NULL(XLAL_EIO, "Could not read dimensions of dataspace");
1397  }
1398 
1399  dimLength = XLALCreateUINT4Vector(rank);
1400  if (dimLength == NULL) {
1401  LALFree(dims);
1403  }
1404 
1405  for (dim = 0; dim < rank; ++dim)
1406  dimLength->data[dim] = dims[dim];
1407  LALFree(dims);
1408 
1409  return dimLength;
1410 #endif
1411 }
1412 
1413 /* LALMalloc and LALFree hooks to give to HDF5 library for memory allocation */
1414 #ifdef HAVE_HDF5
1415 static void *lal_malloc_hook(size_t size, void UNUSED *alloc_info)
1416 {
1417  return XLALMalloc(size);
1418 }
1419 static void lal_free_hook(void *mem, void UNUSED *free_info)
1420 {
1421  XLALFree(mem);
1422  return;
1423 }
1424 #endif
1425 
1426 /**
1427  * @brief Gets the data contained in a ::LALH5Dataset
1428  * @details
1429  * This routine reads data from a HDF5 dataset associated with
1430  * the ::LALH5Dataset @p dset and stores the data in the buffer
1431  * @p data. This buffer should be sufficiently large to hold
1432  * the entire contents of the dataset; this size can be determined
1433  * with the routine XLALH5DatasetQueryNBytes().
1434  * If the dataset contains variable-length string data, @p data
1435  * should instead be a pointer to an array of length npoints of
1436  * char* pointers where npoints can be determined with the
1437  * routine XLALH5DatasetQueryNPoints(). In this case, each of the npoints
1438  * strings will be allocated using LALMalloc().
1439  * @param data Pointer to a memory in which to store the data.
1440  * @param dset Pointer to a ::LALH5Dataset from which to extract the data.
1441  * @retval 0 Success.
1442  * @retval -1 Failure.
1443  */
1444 int XLALH5DatasetQueryData(void UNUSED *data, LALH5Dataset UNUSED *dset)
1445 {
1446 #ifndef HAVE_HDF5
1447  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1448 #else
1449  int isstrdata;
1450  hid_t plist;
1451  if (data == NULL || dset == NULL)
1453  isstrdata = XLALH5DatasetCheckStringData(dset);
1454  if (isstrdata < 0)
1456  if (isstrdata) {
1457  /* string data: tell HDF5 library to use LALMalloc */
1458  plist = threadsafe_H5Pcreate(H5P_DATASET_XFER);
1459  if (plist < 0)
1460  XLAL_ERROR(XLAL_EIO, "Could not create property list");
1461  if (threadsafe_H5Pset_vlen_mem_manager(plist, lal_malloc_hook, NULL, lal_free_hook, NULL) < 0) {
1462  threadsafe_H5Pclose(plist);
1463  XLAL_ERROR(XLAL_EIO, "Could not set memory manager");
1464  }
1465  } else { /* not string data */
1466  plist = threadsafe_H5Pcopy(H5P_DEFAULT);
1467  if (plist < 0)
1468  XLAL_ERROR(XLAL_EIO, "Could not create property list");
1469  }
1470  if (threadsafe_H5Dread(dset->dataset_id, dset->dtype_id, H5S_ALL, H5S_ALL, plist, data) < 0) {
1471  threadsafe_H5Pclose(plist);
1472  XLAL_ERROR(XLAL_EIO, "Could not read data from dataset");
1473  }
1474  threadsafe_H5Pclose(plist);
1475  return 0;
1476 #endif
1477 }
1478 
1479 /** @} */
1480 
1481 /**
1482  * @name Attribute Routines
1483  * @anchor attribute_routines
1484  * @details
1485  * These routines allow for reading or writing attributes to ::LALH5File
1486  * or ::LALH5Dataset objects. To use these, the pointer to the object
1487  * should be cast to a \c LALH5Generic type as in the following example.
1488  * @code
1489  * LALH5File *file = XLALH5FileOpen("example.h5", "r");
1490  * LALH5Dataset *dset = XLALH5DatasetRead(file, "example_dataset");
1491  * size_t num_file_attrs;
1492  * size_t num_dset_attrs;
1493  * num_file_attrs = XLALH5AttributeQueryN((LALH5Generic)file);
1494  * num_dset_attrs = XLALH5AttributeQueryN((LALH5Generic)dset);
1495  * @endcode
1496  * @{
1497  */
1498 
1499 
1500 /**
1501  * @brief Checks for existence of an attribute associated with a ::LALH5File
1502  * or ::LALH5Dataset
1503  * @details
1504  * Checks if there is an attribute with name @p name associated with
1505  * an HDF5 object @p object that is either a ::LALH5File or
1506  * ::LALH5Dataset.
1507  * If the attribute exists the return code is 1;
1508  * if the dataset does not exist a return code value of 0 is used.
1509  *
1510  * @attention Read failure results in a returned value of 0.
1511  *
1512  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to check for
1513  * attribute.
1514  * @param name Pointer to a string with the name of the attribute to check.
1515  * @retval 0 Attribute does not exist or failure.
1516  * @retval 1 Attribute exists.
1517  */
1518 size_t XLALH5AttributeCheckExists(const LALH5Generic UNUSED object, const char UNUSED *name)
1519 {
1520 #ifndef HAVE_HDF5
1521  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1522 #else
1523  hid_t obj_id;
1524  H5O_info_t obj_info;
1525  hsize_t i;
1526 
1527  obj_id = object.generic->object_id;
1528  if (obj_id < 0)
1530 
1531  if (threadsafe_H5Oget_info(obj_id, &obj_info) < 0)
1532  XLAL_ERROR_VAL(0, XLAL_EIO, "Could not get HDF5 object info");
1533 
1534  for (i = 0; i < obj_info.num_attrs; ++i) {
1535  hid_t attr_id;
1536  int n;
1537 
1538  attr_id = threadsafe_H5Aopen_idx(obj_id, i);
1539  if (attr_id < 0)
1540  XLAL_ERROR_VAL(0, XLAL_EIO, "Could not read attribute");
1541 
1542  n = threadsafe_H5Aget_name(attr_id, 0, NULL);
1543  if (n < 0) {
1544  threadsafe_H5Aclose(attr_id);
1545  XLAL_ERROR_VAL(0, XLAL_EIO, "Could not read attribute name");
1546  }
1547  char attr_name[n + 1];
1548  n = threadsafe_H5Aget_name(attr_id, n + 1, attr_name);
1549  threadsafe_H5Aclose(attr_id);
1550  if (n < 0)
1551  XLAL_ERROR_VAL(0, XLAL_EIO, "Could not read attribute name");
1552  if (strcmp(name, attr_name) == 0)
1553  return 1; /* found it */
1554  }
1555 
1556  /* no matching attribute found */
1557  return 0;
1558 #endif
1559 }
1560 
1561 /**
1562  * @brief Gets the number of attributes associated with a ::LALH5File
1563  * or ::LALH5Dataset
1564  * @details
1565  * This routines returns the number of attributes associated with
1566  * an HDF5 object @p object that is either a ::LALH5File or
1567  * ::LALH5Dataset.
1568  *
1569  * @param object Pointer to a ::LALH5File or ::LALH5Dataset that will be
1570  * queried.
1571  * @returns The number of attributes associated with the object.
1572  * @retval -1 Failure.
1573  */
1574 size_t XLALH5AttributeQueryN(const LALH5Generic UNUSED object)
1575 {
1576 #ifndef HAVE_HDF5
1577  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1578 #else
1579  hid_t obj_id;
1580  H5O_info_t obj_info;
1581 
1582  obj_id = object.generic->object_id;
1583  if (obj_id < 0)
1585 
1586  if (threadsafe_H5Oget_info(obj_id, &obj_info) < 0)
1587  XLAL_ERROR(XLAL_EIO, "Could not get HDF5 object info");
1588 
1589  return obj_info.num_attrs;
1590 #endif
1591 }
1592 
1593 /**
1594  * @brief Gets the name of an attribute associated with a ::LALH5File
1595  * or ::LALH5Dataset
1596  * @details
1597  * This routines gets the name of an attributes associated with
1598  * an HDF5 object @p object that is either a ::LALH5File or
1599  * ::LALH5Dataset.
1600  * The index @p pos identifies which attribute's name is returned.
1601  * The result is written into the buffer pointed to by @p name, the size
1602  * of which is @p size bytes. If @p name is NULL, no data is copied but
1603  * the routine returns the length of the string. Therefore, this routine
1604  * can be called once to determine the amount of memory required, the
1605  * memory can be allocated, and then it can be called a second time to
1606  * read the string. If the parameter @p size is less than or equal to
1607  * the string length then only $p size-1 bytes of the string are copied
1608  * to the buffer @p name.
1609  * @note The return value is the length of the string, not including the
1610  * terminating NUL character; thus the buffer @p name should be allocated
1611  * to be one byte larger.
1612  * @param name Pointer to a buffer into which the string will be written.
1613  * @param size Size in bytes of the buffer into which the string will be
1614  * written.
1615  * @param object Pointer to a ::LALH5File or ::LALH5Dataset that will be
1616  * queried.
1617  * @param pos The index identifying which attribute associated with the object.
1618  * @retval 0 Success.
1619  * @retval -1 Failure.
1620  */
1621 int XLALH5AttributeQueryName(char UNUSED *name, size_t UNUSED size, const LALH5Generic UNUSED object, int UNUSED pos)
1622 {
1623 #ifndef HAVE_HDF5
1624  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1625 #else
1626  hid_t obj_id;
1627  hid_t attr_id;
1628  H5O_info_t obj_info;
1629  int n;
1630 
1631  obj_id = object.generic->object_id;
1632  if (obj_id < 0)
1634 
1635  if (threadsafe_H5Oget_info(obj_id, &obj_info) < 0)
1636  XLAL_ERROR(XLAL_EIO, "Could not get HDF5 object info");
1637 
1638  if ((hsize_t)pos >= obj_info.num_attrs)
1639  XLAL_ERROR(XLAL_EINVAL, "No attribute associated with given position");
1640 
1641  attr_id = threadsafe_H5Aopen_idx(obj_id, pos);
1642  if (attr_id < 0)
1643  XLAL_ERROR(XLAL_EIO, "Could not read attribute");
1644 
1645  n = threadsafe_H5Aget_name(attr_id, size, name);
1646  threadsafe_H5Aclose(attr_id);
1647  if (n < 0)
1648  XLAL_ERROR(XLAL_EIO, "Could not read attribute name");
1649 
1650  return n;
1651 #endif
1652 }
1653 
1654 /**
1655  * @brief Adds a scalar attribute to a ::LALH5File or ::LALH5Dataset
1656  * @details
1657  * This routine adds a scalar-valued attribute with name @p key
1658  * and value given by the memory addressed by @p value to a
1659  * HDF5 object associated with the ::LALH5File or ::LALH5Dataset
1660  * @p object.
1661  * The data type of the scalar value is given by the \c LALTYPECODE
1662  * @p dtype.
1663  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to which the attribute
1664  * will be added.
1665  * @param key Pointer to a string with the name of the new attribute.
1666  * @param value Pointer to the value of the scalar attribute to be added.
1667  * @param dtype \c LALTYPECODE value specifying the data type of the attribute.
1668  * @retval 0 Success.
1669  * @retval -1 Failure.
1670  */
1671 int XLALH5AttributeAddScalar(LALH5Generic UNUSED object, const char UNUSED *key, const void UNUSED *value, LALTYPECODE UNUSED dtype)
1672 {
1673 #ifndef HAVE_HDF5
1674  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1675 #else
1676  hid_t obj_id;
1677  hid_t attr_id;
1678  hid_t space_id;
1679  hid_t dtype_id;
1680 
1681  obj_id = object.generic->object_id;
1682  if (obj_id < 0)
1684 
1685  dtype_id = XLALH5TypeFromLALType(dtype);
1686  if (dtype_id < 0)
1688 
1689  space_id = threadsafe_H5Screate(H5S_SCALAR);
1690  if (space_id < 0) {
1691  threadsafe_H5Tclose(dtype_id);
1692  XLAL_ERROR(XLAL_EIO, "Could not create dataspace for attribute `%s'", key);
1693  }
1694 
1695  attr_id = threadsafe_H5Acreate2(obj_id, key, dtype_id, space_id, H5P_DEFAULT, H5P_DEFAULT);
1696  threadsafe_H5Sclose(space_id);
1697  if (attr_id < 0) {
1698  threadsafe_H5Tclose(dtype_id);
1699  XLAL_ERROR(XLAL_EIO, "Could not create attribute `%s'", key);
1700  }
1701 
1702  if (threadsafe_H5Awrite(attr_id, dtype_id, value) < 0) {
1703  threadsafe_H5Aclose(attr_id);
1704  threadsafe_H5Tclose(dtype_id);
1705  XLAL_ERROR(XLAL_EIO, "Could not write attribute `%s'", key);
1706  }
1707 
1708  threadsafe_H5Aclose(attr_id);
1709  threadsafe_H5Tclose(dtype_id);
1710  return 0;
1711 #endif
1712 }
1713 
1714 /**
1715  * @brief Adds a string attribute to a ::LALH5File or ::LALH5Dataset
1716  * @details
1717  * This routine adds a NUL-terminated variable-length string @p value
1718  * attribute with name @p key to a HDF5 object associated with the
1719  * ::LALH5File or ::LALH5Dataset @p object.
1720  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to which the
1721  * attribute will be added.
1722  * @param key Pointer to a string with the name of the new attribute.
1723  * @param value Pointer to a string with the value of the new attribute.
1724  * @retval 0 Success.
1725  * @retval -1 Failure.
1726  */
1727 int XLALH5AttributeAddString(LALH5Generic UNUSED object, const char UNUSED *key, const char UNUSED *value)
1728 {
1729 #ifndef HAVE_HDF5
1730  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1731 #else
1732  hid_t obj_id;
1733  hid_t attr_id;
1734  hid_t space_id;
1735  hid_t dtype_id;
1736 
1737  obj_id = object.generic->object_id;
1738  if (obj_id < 0)
1740 
1741  dtype_id = threadsafe_H5Tcopy(H5T_C_S1);
1742  if (dtype_id < 0)
1743  XLAL_ERROR(XLAL_EIO, "Could not create datatype for attribure `%s'", key);
1744  if (threadsafe_H5Tset_size(dtype_id, H5T_VARIABLE) < 0)
1745  {
1746  threadsafe_H5Tclose(dtype_id);
1747  XLAL_ERROR(XLAL_EIO, "Could not create datatype for attribure `%s'", key);
1748  }
1749 
1750  space_id = threadsafe_H5Screate(H5S_SCALAR);
1751  if (space_id < 0) {
1752  threadsafe_H5Tclose(dtype_id);
1753  XLAL_ERROR(XLAL_EIO, "Could not create dataspace for attribute `%s'", key);
1754  }
1755 
1756  attr_id = threadsafe_H5Acreate2(obj_id, key, dtype_id, space_id, H5P_DEFAULT, H5P_DEFAULT);
1757  threadsafe_H5Sclose(space_id);
1758  if (attr_id < 0) {
1759  threadsafe_H5Tclose(dtype_id);
1760  XLAL_ERROR(XLAL_EIO, "Could not create attribute `%s'", key);
1761  }
1762 
1763  if (threadsafe_H5Awrite(attr_id, dtype_id, &value) < 0) {
1764  threadsafe_H5Aclose(attr_id);
1765  threadsafe_H5Tclose(dtype_id);
1766  XLAL_ERROR(XLAL_EIO, "Could not write attribute `%s'", key);
1767  }
1768 
1769  threadsafe_H5Aclose(attr_id);
1770  threadsafe_H5Tclose(dtype_id);
1771  return 0;
1772 #endif
1773 }
1774 
1775 /**
1776  * @brief Adds a LIGOTimeGPS attribute to a ::LALH5File or ::LALH5Dataset
1777  * @details
1778  * This routine adds a LIGOTimeGPS @p value attribute with name @p key to a
1779  * HDF5 object associated with the ::LALH5File or ::LALH5Dataset @p object.
1780  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to which the
1781  * attribute will be added.
1782  * @param key Pointer to a string with the name of the new attribute.
1783  * @param value Pointer to a LIGOTimeGPS structure with the value of the new
1784  * attribute.
1785  * @retval 0 Success.
1786  * @retval -1 Failure.
1787  */
1788 int XLALH5AttributeAddLIGOTimeGPS(LALH5Generic UNUSED object, const char UNUSED *key, const LIGOTimeGPS UNUSED *value)
1789 {
1790 #ifndef HAVE_HDF5
1791  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1792 #else
1793  hid_t obj_id;
1794  hid_t attr_id;
1795  hid_t space_id;
1796  hid_t dtype_id;
1797 
1798  obj_id = object.generic->object_id;
1799  if (obj_id < 0)
1801 
1802  dtype_id = XLALH5TypeNativeLIGOTimeGPS();
1803  if (dtype_id < 0)
1805 
1806  space_id = threadsafe_H5Screate(H5S_SCALAR);
1807  if (space_id < 0) {
1808  threadsafe_H5Tclose(dtype_id);
1809  XLAL_ERROR(XLAL_EIO, "Could not create dataspace for attribute `%s'", key);
1810  }
1811 
1812  attr_id = threadsafe_H5Acreate2(obj_id, key, dtype_id, space_id, H5P_DEFAULT, H5P_DEFAULT);
1813  threadsafe_H5Sclose(space_id);
1814  if (attr_id < 0) {
1815  threadsafe_H5Tclose(dtype_id);
1816  XLAL_ERROR(XLAL_EIO, "Could not create attribute `%s'", key);
1817  }
1818 
1819  if (threadsafe_H5Awrite(attr_id, dtype_id, value) < 0) {
1820  threadsafe_H5Aclose(attr_id);
1821  threadsafe_H5Tclose(dtype_id);
1822  XLAL_ERROR(XLAL_EIO, "Could not write attribute `%s'", key);
1823  }
1824 
1825  threadsafe_H5Aclose(attr_id);
1826  threadsafe_H5Tclose(dtype_id);
1827  return 0;
1828 #endif
1829 }
1830 
1831 /**
1832  * @brief Adds a 1d enum array attribute to a ::LALH5File or ::LALH5Dataset
1833  * @details
1834  * This routine adds the 1d enum array @p value of length @p length attribute
1835  * with name @p key to a HDF5 object associated with the ::LALH5File or
1836  * ::LALH5Dataset @p object.
1837  * The names and values of the @p nenum enumeration constants are provided
1838  * in the arrays @p enumnames and @p enumvals respectively.
1839  *
1840  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to which the
1841  * attribute will be added.
1842  * @param enumnames Pointer to an array of names of the enum constants.
1843  * @param enumvals Pointer to an array of values of the enum constants.
1844  * @param nenum Number of enum constants.
1845  * @param key Pointer to a string with the name of the new attribute.
1846  * @param value Pointer to an array of enum values.
1847  * @param length Length of the array of enum values.
1848  * @retval 0 Success.
1849  * @retval -1 Failure.
1850  */
1851 int XLALH5AttributeAddEnumArray1D(LALH5Generic UNUSED object, const char UNUSED *enumnames[], const int UNUSED enumvals[], size_t UNUSED nenum, const char UNUSED *key, const int UNUSED value[], size_t UNUSED length)
1852 {
1853 #ifndef HAVE_HDF5
1854  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1855 #else
1856  hsize_t dims[] = {length};
1857  hid_t obj_id;
1858  hid_t attr_id;
1859  hid_t space_id;
1860  hid_t edtype_id;
1861  hid_t adtype_id;
1862 
1863  obj_id = object.generic->object_id;
1864  if (obj_id < 0)
1866 
1867  edtype_id = XLALH5TypeEnum(enumnames, enumvals, nenum);
1868  if (edtype_id < 0)
1869  XLAL_ERROR(XLAL_EFUNC, "Could not create enum type for attribute `%s'", key);
1870 
1871  adtype_id = threadsafe_H5Tarray_create2(edtype_id, 1, dims);
1872  threadsafe_H5Tclose(edtype_id);
1873  if (adtype_id < 0)
1874  XLAL_ERROR(XLAL_EIO, "Could not create array type for attribute `%s'", key);
1875 
1876  space_id = threadsafe_H5Screate(H5S_SCALAR);
1877  if (space_id < 0) {
1878  threadsafe_H5Tclose(adtype_id);
1879  XLAL_ERROR(XLAL_EIO, "Could not create dataspace for attribute `%s'", key);
1880  }
1881 
1882  attr_id = threadsafe_H5Acreate2(obj_id, key, adtype_id, space_id, H5P_DEFAULT, H5P_DEFAULT);
1883  threadsafe_H5Sclose(space_id);
1884  if (attr_id < 0) {
1885  threadsafe_H5Tclose(adtype_id);
1886  XLAL_ERROR(XLAL_EIO, "Could not create attribute `%s'", key);
1887  }
1888 
1889  if (threadsafe_H5Awrite(attr_id, adtype_id, value) < 0) {
1890  threadsafe_H5Aclose(attr_id);
1891  threadsafe_H5Tclose(adtype_id);
1892  XLAL_ERROR(XLAL_EIO, "Could not write attribute `%s'", key);
1893  }
1894 
1895  threadsafe_H5Aclose(attr_id);
1896  threadsafe_H5Tclose(adtype_id);
1897  return 0;
1898 #endif
1899 }
1900 
1901 /**
1902  * @brief Gets the datatype of an attribute in a ::LALH5File or ::LALH5Dataset
1903  * @details
1904  * This routine queries the datatype of a scalar attribute with
1905  * name @p key in a HDF5 object associated with the ::LALH5File or ::LALH5Dataset
1906  * @p object.
1907  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to be queried.
1908  * @param key Pointer to a string with the name of the attribute to query.
1909  * @returns \c LALTYPECODE value of the datatype of the scalar attribute.
1910  * @retval -1 Failure.
1911  */
1912 LALTYPECODE XLALH5AttributeQueryScalarType(const LALH5Generic UNUSED object, const char UNUSED *key)
1913 {
1914 #ifndef HAVE_HDF5
1915  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1916 #else
1917  LALTYPECODE dtype;
1918  hid_t obj_id;
1919  hid_t attr_id;
1920  hid_t space_id;
1921  hid_t dtype_id;
1922  hid_t memtype_id;
1923 
1924  obj_id = object.generic->object_id;
1925  if (obj_id < 0)
1927 
1928  attr_id = threadsafe_H5Aopen(obj_id, key, H5P_DEFAULT);
1929  if (attr_id < 0)
1930  XLAL_ERROR(XLAL_EIO, "Could not read attribute `%s'", key);
1931 
1932  /* sanity check: make sure this is a scalar attribute */
1933  space_id = threadsafe_H5Aget_space(attr_id);
1934  if (space_id < 0) {
1935  threadsafe_H5Aclose(attr_id);
1936  XLAL_ERROR(XLAL_EIO, "Could not read dataspace of attribute `%s'", key);
1937  }
1938  if (threadsafe_H5Sget_simple_extent_ndims(space_id) != 0 || threadsafe_H5Sget_simple_extent_npoints(space_id) != 1) {
1939  threadsafe_H5Sclose(space_id);
1940  threadsafe_H5Aclose(attr_id);
1941  XLAL_ERROR(XLAL_EIO, "Attribute `%s' is not a scalar attribute", key);
1942  }
1943 
1944  dtype_id = threadsafe_H5Aget_type(attr_id);
1945  threadsafe_H5Aclose(attr_id);
1946  if (attr_id < 0)
1947  XLAL_ERROR(XLAL_EIO, "Could not read type of attribute `%s'", key);
1948 
1949  memtype_id = threadsafe_H5Tget_native_type(dtype_id, H5T_DIR_ASCEND);
1950  threadsafe_H5Tclose(dtype_id);
1951  if (memtype_id < 0)
1952  XLAL_ERROR(XLAL_EIO, "Could not get native type of attribute `%s'", key);
1953 
1954  dtype = XLALTypeFromH5Type(memtype_id);
1955  threadsafe_H5Tclose(memtype_id);
1956  if ((int)dtype < 0)
1958 
1959  return dtype;
1960 #endif
1961 }
1962 
1963 /**
1964  * @brief Gets the value of a scalar attribute in a ::LALH5File or ::LALH5Dataset
1965  * @details
1966  * This routine queries the value of a scalar attribute with
1967  * name @p key in a HDF5 object associated with the ::LALH5File or ::LALH5Dataset
1968  * @p object.
1969  * The value is stored in memory pointed to by the pointer @p value.
1970  *
1971  * @attention
1972  * This routine does not allocate memory for @p value. The calling
1973  * routine must ensure that the memory addressed by the pointer @p value
1974  * is sufficient to hold the value in the attribute.
1975  *
1976  * @param value Pointer to memory in which the value will be stored.
1977  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to be queried.
1978  * @param key Pointer to a string with the name of the attribute to query.
1979  * @retval 0 Success.
1980  * @retval -1 Failure.
1981  */
1982 int XLALH5AttributeQueryScalarValue(void UNUSED *value, const LALH5Generic UNUSED object, const char UNUSED *key)
1983 {
1984 #ifndef HAVE_HDF5
1985  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
1986 #else
1987  hid_t obj_id;
1988  hid_t attr_id;
1989  hid_t space_id;
1990  hid_t dtype_id;
1991  hid_t memtype_id;
1992 
1993  obj_id = object.generic->object_id;
1994  if (obj_id < 0)
1996 
1997  attr_id = threadsafe_H5Aopen(obj_id, key, H5P_DEFAULT);
1998  if (attr_id < 0)
1999  XLAL_ERROR(XLAL_EIO, "Could not read attribute `%s'", key);
2000 
2001  /* sanity check: make sure this is a scalar attribute */
2002  space_id = threadsafe_H5Aget_space(attr_id);
2003  if (space_id < 0) {
2004  threadsafe_H5Aclose(attr_id);
2005  XLAL_ERROR(XLAL_EIO, "Could not read dataspace of attribute `%s'", key);
2006  }
2007  if (threadsafe_H5Sget_simple_extent_ndims(space_id) != 0 || threadsafe_H5Sget_simple_extent_npoints(space_id) != 1) {
2008  threadsafe_H5Sclose(space_id);
2009  threadsafe_H5Aclose(attr_id);
2010  XLAL_ERROR(XLAL_EIO, "Attribute `%s' is not a scalar attribute", key);
2011  }
2012  threadsafe_H5Sclose(space_id);
2013 
2014  dtype_id = threadsafe_H5Aget_type(attr_id);
2015  if (dtype_id < 0) {
2016  threadsafe_H5Aclose(attr_id);
2017  XLAL_ERROR(XLAL_EIO, "Could not read type of attribute `%s'", key);
2018  }
2019 
2020  memtype_id = threadsafe_H5Tget_native_type(dtype_id, H5T_DIR_ASCEND);
2021  threadsafe_H5Tclose(dtype_id);
2022  if (memtype_id < 0) {
2023  threadsafe_H5Aclose(attr_id);
2024  XLAL_ERROR(XLAL_EIO, "Could not get native type of attribute `%s'", key);
2025  }
2026 
2027  if (threadsafe_H5Aread(attr_id, memtype_id, value) < 0) {
2028  threadsafe_H5Tclose(memtype_id);
2029  threadsafe_H5Aclose(attr_id);
2030  XLAL_ERROR(XLAL_EIO, "Could not read data from attribute `%s'", key);
2031  }
2032 
2033  threadsafe_H5Tclose(memtype_id);
2034  threadsafe_H5Aclose(attr_id);
2035  return 0;
2036 #endif
2037 }
2038 
2039 /**
2040  * @brief Gets the value of a string attribute in a ::LALH5File or ::LALH5Dataset
2041  * @details
2042  * This routine queries the value of a string attribute with
2043  * name @p key in a HDF5 object associated with the ::LALH5File or ::LALH5Dataset
2044  * @p object.
2045  * The result is written into the buffer pointed to by @p value, the size
2046  * of which is @p size bytes. If @p value is NULL, no data is copied but
2047  * the routine returns the length of the string. Therefore, this routine
2048  * can be called once to determine the amount of memory required, the
2049  * memory can be allocated, and then it can be called a second time to
2050  * read the string. If the parameter @p size is less than or equal to
2051  * the string length then only $p size-1 bytes of the string are copied
2052  * to the buffer @p value.
2053  * @note The return value is the length of the string, not including the
2054  * terminating NUL character; thus the buffer @p value should be allocated
2055  * to be one byte larger.
2056  * @param value Pointer to a buffer into which the string will be written.
2057  * @param size Size in bytes of the buffer into which the string will be
2058  * written.
2059  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to be queried.
2060  * @param key Pointer to a string with the name of the attribute to query.
2061  * @returns The number of bytes that would be written to @p value had @p size
2062  * been sufficiently large excluding the terminating NUL byte.
2063  * @retval -1 Failure.
2064  */
2065 int XLALH5AttributeQueryStringValue(char UNUSED *value, size_t UNUSED size, const LALH5Generic UNUSED object, const char UNUSED *key)
2066 {
2067 #ifndef HAVE_HDF5
2068  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2069 #else
2070  char *str;
2071  hid_t obj_id;
2072  hid_t attr_id;
2073  hid_t space_id;
2074  hid_t dtype_id;
2075  hid_t memtype_id;
2076  int n;
2077 
2078  obj_id = object.generic->object_id;
2079  if (obj_id < 0)
2081 
2082  attr_id = threadsafe_H5Aopen(obj_id, key, H5P_DEFAULT);
2083  if (attr_id < 0)
2084  XLAL_ERROR(XLAL_EIO, "Could not read attribute `%s'", key);
2085 
2086  /* sanity check: make sure this is just one variable-length string */
2087  space_id = threadsafe_H5Aget_space(attr_id);
2088  if (space_id < 0) {
2089  threadsafe_H5Aclose(attr_id);
2090  XLAL_ERROR(XLAL_EIO, "Could not read dataspace of attribute `%s'", key);
2091  }
2092  if (threadsafe_H5Sget_simple_extent_ndims(space_id) != 0) {
2093  threadsafe_H5Sclose(space_id);
2094  threadsafe_H5Aclose(attr_id);
2095  XLAL_ERROR(XLAL_EIO, "Attribute `%s' is not a string", key);
2096  }
2097 
2098  dtype_id = threadsafe_H5Aget_type(attr_id);
2099  if (dtype_id < 0) {
2100  threadsafe_H5Sclose(space_id);
2101  threadsafe_H5Aclose(attr_id);
2102  XLAL_ERROR(XLAL_EIO, "Could not read type of attribute `%s'", key);
2103  }
2104  threadsafe_H5Tclose(dtype_id);
2105 
2106  memtype_id = threadsafe_H5Tcopy(H5T_C_S1);
2107  if (memtype_id < 0 || threadsafe_H5Tset_size(memtype_id, H5T_VARIABLE)) {
2108  threadsafe_H5Sclose(space_id);
2109  threadsafe_H5Aclose(attr_id);
2111  }
2112 
2113  if (threadsafe_H5Aread(attr_id, memtype_id, &str) < 0) {
2114  threadsafe_H5Tclose(memtype_id);
2115  threadsafe_H5Sclose(space_id);
2116  threadsafe_H5Aclose(attr_id);
2117  XLAL_ERROR(XLAL_EIO, "Could not read data from attribute `%s'", key);
2118  }
2119 
2120  n = snprintf(value, value == NULL ? 0 : size, "%s", str);
2121 
2122  threadsafe_H5Dvlen_reclaim(memtype_id, space_id, H5P_DEFAULT, &str);
2123 
2124  threadsafe_H5Tclose(memtype_id);
2125  threadsafe_H5Sclose(space_id);
2126  threadsafe_H5Aclose(attr_id);
2127  return n;
2128 #endif
2129 }
2130 
2131 /**
2132  * @brief Gets the value of a LIGOTimeGPS attribute in a ::LALH5File or ::LALH5Dataset
2133  * @details
2134  * This routine queries the value of a LIGOTimeGPS attribute with
2135  * name @p key in a HDF5 object associated with the ::LALH5File or ::LALH5Dataset
2136  * @p object.
2137  * The value is stored in memory pointed to by the pointer @p value.
2138  * @param value Pointer to a LIGOTimeGPS structure in which the attribute
2139  * value will be stored.
2140  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to be queried.
2141  * @param key Pointer to a string with the name of the attribute to query.
2142  * @returns Pointer to the LIGOTimeGPS structure passed to this routine.
2143  * @retval NULL Failure.
2144  */
2145 LIGOTimeGPS * XLALH5AttributeQueryLIGOTimeGPSValue(LIGOTimeGPS UNUSED *value, const LALH5Generic UNUSED object, const char UNUSED *key)
2146 {
2147 #ifndef HAVE_HDF5
2148  XLAL_ERROR_NULL(XLAL_EFAILED, "HDF5 support not implemented");
2149 #else
2150  char *s;
2151  hid_t obj_id;
2152  hid_t attr_id;
2153  hid_t space_id;
2154  hid_t dtype_id;
2155  hid_t memtype_id;
2156 
2157  obj_id = object.generic->object_id;
2158  if (obj_id < 0)
2160 
2161  attr_id = threadsafe_H5Aopen(obj_id, key, H5P_DEFAULT);
2162  if (attr_id < 0)
2163  XLAL_ERROR_NULL(XLAL_EIO, "Could not read attribute `%s'", key);
2164 
2165  /* sanity check: make sure this is a scalar attribute */
2166  space_id = threadsafe_H5Aget_space(attr_id);
2167  if (space_id < 0) {
2168  threadsafe_H5Aclose(attr_id);
2169  XLAL_ERROR_NULL(XLAL_EIO, "Could not read dataspace of attribute `%s'", key);
2170  }
2171  if (threadsafe_H5Sget_simple_extent_ndims(space_id) != 0 || threadsafe_H5Sget_simple_extent_npoints(space_id) != 1) {
2172  threadsafe_H5Sclose(space_id);
2173  threadsafe_H5Aclose(attr_id);
2174  XLAL_ERROR_NULL(XLAL_EIO, "Attribute `%s' is not a scalar attribute", key);
2175  }
2176  threadsafe_H5Sclose(space_id);
2177 
2178  /* sanity check the dtype_id */
2179 
2180  dtype_id = threadsafe_H5Aget_type(attr_id);
2181  if (dtype_id < 0) {
2182  threadsafe_H5Aclose(attr_id);
2183  XLAL_ERROR_NULL(XLAL_EIO, "Could not read type of attribute `%s'", key);
2184  }
2185 
2186  /* must be compound data type ... */
2187  if (threadsafe_H5Tget_class(dtype_id) != H5T_COMPOUND) {
2188  threadsafe_H5Tclose(dtype_id);
2189  threadsafe_H5Aclose(attr_id);
2190  XLAL_ERROR_NULL(XLAL_ETYPE, "Incorrect data type for attribute `%s'", key);
2191  }
2192 
2193  /* must have 2 members ... */
2194  if (threadsafe_H5Tget_nmembers(dtype_id) != 2) {
2195  threadsafe_H5Tclose(dtype_id);
2196  threadsafe_H5Aclose(attr_id);
2197  XLAL_ERROR_NULL(XLAL_ETYPE, "Incorrect data type for attribute `%s'", key);
2198  }
2199 
2200  /* both members must be integer type ... */
2201  if (threadsafe_H5Tget_member_class(dtype_id, 0) != H5T_INTEGER) {
2202  threadsafe_H5Tclose(dtype_id);
2203  threadsafe_H5Aclose(attr_id);
2204  XLAL_ERROR_NULL(XLAL_ETYPE, "Incorrect data type for attribute `%s'", key);
2205  }
2206  if (threadsafe_H5Tget_member_class(dtype_id, 1) != H5T_INTEGER) {
2207  threadsafe_H5Tclose(dtype_id);
2208  threadsafe_H5Aclose(attr_id);
2209  XLAL_ERROR_NULL(XLAL_ETYPE, "Incorrect data type for attribute `%s'", key);
2210  }
2211 
2212  /* FIXME: should also check member sizes? */
2213 
2214  /* first member name must be "gpsSeconds" ... */
2215  s = threadsafe_H5Tget_member_name(dtype_id, 0);
2216  if (strcmp(s, "gpsSeconds") != 0) {
2217  free(s);
2218  threadsafe_H5Tclose(dtype_id);
2219  threadsafe_H5Aclose(attr_id);
2220  XLAL_ERROR_NULL(XLAL_ETYPE, "Incorrect data type for attribute `%s'", key);
2221  }
2222  free(s);
2223 
2224  /* second member name must be "gpsNanoSeconds" ... */
2225  s = threadsafe_H5Tget_member_name(dtype_id, 1);
2226  if (strcmp(s, "gpsNanoSeconds") != 0) {
2227  free(s);
2228  threadsafe_H5Tclose(dtype_id);
2229  threadsafe_H5Aclose(attr_id);
2230  XLAL_ERROR_NULL(XLAL_ETYPE, "Incorrect data type for attribute `%s'", key);
2231  }
2232  free(s);
2233 
2234  threadsafe_H5Tclose(dtype_id);
2235 
2236  memtype_id = XLALH5TypeNativeLIGOTimeGPS();
2237  if (memtype_id < 0) {
2238  threadsafe_H5Aclose(attr_id);
2239  XLAL_ERROR_NULL(XLAL_EIO, "Could not get native type of attribute `%s'", key);
2240  }
2241 
2242  if (threadsafe_H5Aread(attr_id, memtype_id, value) < 0) {
2243  threadsafe_H5Tclose(memtype_id);
2244  threadsafe_H5Aclose(attr_id);
2245  XLAL_ERROR_NULL(XLAL_EIO, "Could not read data from attribute `%s'", key);
2246  }
2247 
2248  threadsafe_H5Tclose(memtype_id);
2249  threadsafe_H5Aclose(attr_id);
2250  return value;
2251 #endif
2252 }
2253 
2254 /**
2255  * @brief Gets the length of a 1D enum array attribute in a ::LALH5File or
2256  * ::LALH5Dataset
2257  * @details
2258  * This routine queries the length of a 1D enum array with name @p key in a
2259  * HDF5 object associated with the ::LALH5File or ::LALH5Dataset @p object.
2260  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to be queried.
2261  * @param key Pointer to a string with the name of the attribute to query.
2262  * @returns Length of the 1D enum array.
2263  * @retval -1 Failure.
2264  */
2265 size_t XLALH5AttributeQueryEnumArray1DLength(const LALH5Generic UNUSED object, const char UNUSED *key)
2266 {
2267 #ifndef HAVE_HDF5
2268  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2269 #else
2270  hsize_t dims[] = {-1};
2271  hid_t obj_id;
2272  hid_t attr_id;
2273  hid_t dtype_id;
2274 
2275  obj_id = object.generic->object_id;
2276  if (obj_id < 0)
2278 
2279  attr_id = threadsafe_H5Aopen(obj_id, key, H5P_DEFAULT);
2280  if (attr_id < 0)
2281  XLAL_ERROR(XLAL_EIO, "Could not read attribute `%s'", key);
2282 
2283  dtype_id = threadsafe_H5Aget_type(attr_id);
2284  if (dtype_id < 0) {
2285  threadsafe_H5Aclose(attr_id);
2286  XLAL_ERROR(XLAL_EIO, "Could not read type of attribute `%s'", key);
2287  }
2288 
2289  /* must be array data type ... */
2290  if (threadsafe_H5Tget_class(dtype_id) != H5T_ARRAY) {
2291  threadsafe_H5Tclose(dtype_id);
2292  threadsafe_H5Aclose(attr_id);
2293  XLAL_ERROR(XLAL_ETYPE, "Incorrect data type for attribute `%s'", key);
2294  }
2295 
2296  /* must be a 1d array data type ... */
2297  if (threadsafe_H5Tget_array_ndims(dtype_id) != 1) {
2298  threadsafe_H5Tclose(dtype_id);
2299  threadsafe_H5Aclose(attr_id);
2300  XLAL_ERROR(XLAL_ETYPE, "Incorrect data type for attribute `%s'", key);
2301  }
2302 
2303  if (threadsafe_H5Tget_array_dims2(dtype_id, dims) < 0) {
2304  threadsafe_H5Tclose(dtype_id);
2305  threadsafe_H5Aclose(attr_id);
2306  XLAL_ERROR(XLAL_ETYPE, "Could not get array length of attribute `%s'", key);
2307  }
2308 
2309  threadsafe_H5Tclose(dtype_id);
2310  threadsafe_H5Aclose(attr_id);
2311  return dims[0];
2312 #endif
2313 }
2314 
2315 /**
2316  * @brief Gets the values in a 1D enum array attribute in a ::LALH5File or
2317  * ::LALH5Dataset
2318  * @details
2319  * This routine reads the values of a 1D enum array with name @p key in a
2320  * HDF5 object associated with the ::LALH5File or ::LALH5Dataset @p object
2321  * into the array @p value.
2322  *
2323  * @attention
2324  * This routine does not allocate memory for @p value. The calling
2325  * routine must ensure that the memory addressed by the pointer @p value
2326  * is sufficient to hold the value in the attribute.
2327  * The routine XLALH5AttributeQueryEnumArray1DLength() will yield the
2328  * length that this array must have.
2329  *
2330  * @param value Pointer to an array where then enum values will be stored.
2331  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to be queried.
2332  * @param key Pointer to a string with the name of the attribute to query.
2333  * @retval 0 Success.
2334  * @retval -1 Failure.
2335  */
2336 int XLALH5AttributeQueryEnumArray1DValue(int UNUSED value[], const LALH5Generic UNUSED object, const char UNUSED *key)
2337 {
2338 #ifndef HAVE_HDF5
2339  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2340 #else
2341  hid_t obj_id;
2342  hid_t attr_id;
2343  hid_t dtype_id;
2344 
2345  obj_id = object.generic->object_id;
2346  if (obj_id < 0)
2348 
2349  attr_id = threadsafe_H5Aopen(obj_id, key, H5P_DEFAULT);
2350  if (attr_id < 0)
2351  XLAL_ERROR(XLAL_EIO, "Could not read attribute `%s'", key);
2352 
2353  dtype_id = threadsafe_H5Aget_type(attr_id);
2354  if (dtype_id < 0) {
2355  threadsafe_H5Aclose(attr_id);
2356  XLAL_ERROR(XLAL_EIO, "Could not read type of attribute `%s'", key);
2357  }
2358 
2359  /* must be array data type ... */
2360  if (threadsafe_H5Tget_class(dtype_id) != H5T_ARRAY) {
2361  threadsafe_H5Tclose(dtype_id);
2362  threadsafe_H5Aclose(attr_id);
2363  XLAL_ERROR(XLAL_ETYPE, "Incorrect data type for attribute `%s'", key);
2364  }
2365 
2366  /* must be a 1d array data type ... */
2367  if (threadsafe_H5Tget_array_ndims(dtype_id) != 1) {
2368  threadsafe_H5Tclose(dtype_id);
2369  threadsafe_H5Aclose(attr_id);
2370  XLAL_ERROR(XLAL_ETYPE, "Incorrect data type for attribute `%s'", key);
2371  }
2372 
2373  if (threadsafe_H5Aread(attr_id, dtype_id, value) < 0) {
2374  threadsafe_H5Tclose(dtype_id);
2375  threadsafe_H5Aclose(attr_id);
2376  XLAL_ERROR(XLAL_ETYPE, "Could not read data from attribute `%s'", key);
2377  }
2378 
2379  threadsafe_H5Tclose(dtype_id);
2380  threadsafe_H5Aclose(attr_id);
2381  return 0;
2382 #endif
2383 }
2384 
2385 /**
2386  * @brief Gets the number of constants in an enum type associated with an
2387  * attribute in a ::LALH5File or ::LALH5Dataset
2388  * @details
2389  * This routine queries the number constants in an enum type associated
2390  * with the attribute with name @p key in a
2391  * HDF5 object associated with the ::LALH5File or ::LALH5Dataset @p object.
2392  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to be queried.
2393  * @param key Pointer to a string with the name of the attribute to query.
2394  * @returns Number of constants in enum type.
2395  * @retval -1 Failure.
2396  */
2397 size_t XLALH5AttributeQueryNEnum(const LALH5Generic UNUSED object, const char UNUSED *key)
2398 {
2399 #ifndef HAVE_HDF5
2400  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2401 #else
2402  hid_t obj_id;
2403  hid_t attr_id;
2404  hid_t dtype_id;
2405  H5T_class_t dtype_class;
2406  int nenum;
2407 
2408  obj_id = object.generic->object_id;
2409  if (obj_id < 0)
2411 
2412  attr_id = threadsafe_H5Aopen(obj_id, key, H5P_DEFAULT);
2413  if (attr_id < 0)
2414  XLAL_ERROR(XLAL_EIO, "Could not read attribute `%s'", key);
2415 
2416  dtype_id = threadsafe_H5Aget_type(attr_id);
2417  if (dtype_id < 0) {
2418  threadsafe_H5Aclose(attr_id);
2419  XLAL_ERROR(XLAL_EIO, "Could not read type of attribute `%s'", key);
2420  }
2421 
2422  dtype_class = threadsafe_H5Tget_class(dtype_id);
2423  if (dtype_class == H5T_ARRAY) {
2424  /* get base data type */
2425  hid_t super_id;
2426  super_id = threadsafe_H5Tget_super(dtype_id);
2427  threadsafe_H5Tclose(dtype_id);
2428  dtype_id = super_id;
2429  dtype_class = threadsafe_H5Tget_class(dtype_id);
2430  }
2431  if (dtype_class == H5T_NO_CLASS) {
2432  threadsafe_H5Tclose(dtype_id);
2433  threadsafe_H5Aclose(attr_id);
2434  XLAL_ERROR(XLAL_EIO, "Could not read type class of attribute `%s'", key);
2435  }
2436  if (dtype_class != H5T_ENUM) {
2437  threadsafe_H5Tclose(dtype_id);
2438  threadsafe_H5Aclose(attr_id);
2439  XLAL_ERROR(XLAL_EIO, "Attribute `%s' is not an enum type", key);
2440  }
2441 
2442  nenum = threadsafe_H5Tget_nmembers(dtype_id);
2443  if (nenum < 0) {
2444  threadsafe_H5Tclose(dtype_id);
2445  threadsafe_H5Aclose(attr_id);
2446  XLAL_ERROR(XLAL_EIO, "Could not read number of enum constants of attribute `%s'", key);
2447  }
2448 
2449  threadsafe_H5Tclose(dtype_id);
2450  threadsafe_H5Aclose(attr_id);
2451  return nenum;
2452 #endif
2453 }
2454 
2455 /**
2456  * @brief Gets the name of a constants in an enum type associated with an
2457  * attribute in a ::LALH5File or ::LALH5Dataset
2458  * @details
2459  * This routine queries the name of a constant in an enum type associated
2460  * with the attribute with name @p key in a
2461  * HDF5 object associated with the ::LALH5File or ::LALH5Dataset @p object.
2462  * The index @p pos identifies which constant's name is returned.
2463  * The result is written into the buffer pointed to by @p name, the size
2464  * of which is @p size bytes. If @p name is NULL, no data is copied but
2465  * the routine returns the length of the string. Therefore, this routine
2466  * can be called once to determine the amount of memory required, the
2467  * memory can be allocated, and then it can be called a second time to
2468  * read the string. If the parameter @p size is less than or equal to
2469  * the string length then only $p size-1 bytes of the string are copied
2470  * to the buffer @p name.
2471  * @note The return value is the length of the string, not including the
2472  * terminating NUL character; thus the buffer @p name should be allocated
2473  * to be one byte larger.
2474  * @param name Pointer to a buffer into which the string will be written.
2475  * @param size Size in bytes of the buffer into which the string will be
2476  * written.
2477  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to be queried.
2478  * @param key Pointer to a string with the name of the attribute to query.
2479  * @param pos The index identifying which enum constant.
2480  * @returns The number of bytes that would be written to @p name had @p size
2481  * been sufficiently large excluding the terminating NUL byte.
2482  * @retval -1 Failure.
2483  */
2484 int XLALH5AttributeQueryEnumName(char UNUSED *name, size_t UNUSED size, const LALH5Generic UNUSED object, const char UNUSED *key, int UNUSED pos)
2485 {
2486 #ifndef HAVE_HDF5
2487  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2488 #else
2489  hid_t obj_id;
2490  hid_t attr_id;
2491  hid_t dtype_id;
2492  H5T_class_t dtype_class;
2493  int nenum;
2494  int n;
2495  char *s;
2496 
2497  obj_id = object.generic->object_id;
2498  if (obj_id < 0)
2500 
2501  attr_id = threadsafe_H5Aopen(obj_id, key, H5P_DEFAULT);
2502  if (attr_id < 0)
2503  XLAL_ERROR(XLAL_EIO, "Could not read attribute `%s'", key);
2504 
2505  dtype_id = threadsafe_H5Aget_type(attr_id);
2506  if (dtype_id < 0) {
2507  threadsafe_H5Aclose(attr_id);
2508  XLAL_ERROR(XLAL_EIO, "Could not read type of attribute `%s'", key);
2509  }
2510 
2511  dtype_class = threadsafe_H5Tget_class(dtype_id);
2512  if (dtype_class == H5T_ARRAY) {
2513  /* get base data type */
2514  hid_t super_id;
2515  super_id = threadsafe_H5Tget_super(dtype_id);
2516  threadsafe_H5Tclose(dtype_id);
2517  dtype_id = super_id;
2518  dtype_class = threadsafe_H5Tget_class(dtype_id);
2519  }
2520  if (dtype_class == H5T_NO_CLASS) {
2521  threadsafe_H5Tclose(dtype_id);
2522  threadsafe_H5Aclose(attr_id);
2523  XLAL_ERROR(XLAL_EIO, "Could not read type class of attribute `%s'", key);
2524  }
2525  if (dtype_class != H5T_ENUM) {
2526  threadsafe_H5Tclose(dtype_id);
2527  threadsafe_H5Aclose(attr_id);
2528  XLAL_ERROR(XLAL_EIO, "Attribute `%s' is not an enum type", key);
2529  }
2530 
2531  nenum = threadsafe_H5Tget_nmembers(dtype_id);
2532  if (nenum < 0) {
2533  threadsafe_H5Tclose(dtype_id);
2534  threadsafe_H5Aclose(attr_id);
2535  XLAL_ERROR(XLAL_EIO, "Could not read number of enum constants of attribute `%s'", key);
2536  }
2537  if (pos >= nenum) {
2538  threadsafe_H5Tclose(dtype_id);
2539  threadsafe_H5Aclose(attr_id);
2540  XLAL_ERROR(XLAL_EINVAL, "Requested enum constant of attribute `%s' does not exist", key);
2541  }
2542 
2543  s = threadsafe_H5Tget_member_name(dtype_id, pos);
2544  if (s == NULL) {
2545  threadsafe_H5Tclose(dtype_id);
2546  threadsafe_H5Aclose(attr_id);
2547  XLAL_ERROR(XLAL_EIO, "Could not read enum constant name of attribute `%s'", key);
2548  }
2549 
2550  n = snprintf(name, name == NULL ? 0 : size, "%s", s);
2551 
2552  free(s);
2553  threadsafe_H5Tclose(dtype_id);
2554  threadsafe_H5Aclose(attr_id);
2555  return n;
2556 #endif
2557 }
2558 
2559 /**
2560  * @brief Gets the value of a constants in an enum type associated with an
2561  * attribute in a ::LALH5File or ::LALH5Dataset
2562  * @details
2563  * This routine queries the value of a constant in an enum type associated
2564  * with the attribute with name @p key in a
2565  * HDF5 object associated with the ::LALH5File or ::LALH5Dataset @p object.
2566  * The index @p pos identifies which constant's name is returned.
2567  * @param object Pointer to a ::LALH5File or ::LALH5Dataset to be queried.
2568  * @param key Pointer to a string with the name of the attribute to query.
2569  * @param pos The index identifying which enum constant.
2570  * @returns The value of the enum constant.
2571  * @retval -1 Failure. Note that -1 might also be a valid enum constant!
2572  */
2573 int XLALH5AttributeQueryEnumValue(const LALH5Generic UNUSED object, const char UNUSED *key, int UNUSED pos)
2574 {
2575 #ifndef HAVE_HDF5
2576  XLAL_ERROR_VAL(INT_MAX, XLAL_EFAILED, "HDF5 support not implemented");
2577 #else
2578  hid_t obj_id;
2579  hid_t attr_id;
2580  hid_t dtype_id;
2581  H5T_class_t dtype_class;
2582  int nenum;
2583  int val;
2584 
2585  obj_id = object.generic->object_id;
2586  if (obj_id < 0)
2588 
2589  attr_id = threadsafe_H5Aopen(obj_id, key, H5P_DEFAULT);
2590  if (attr_id < 0)
2591  XLAL_ERROR(XLAL_EIO, "Could not read attribute `%s'", key);
2592 
2593  dtype_id = threadsafe_H5Aget_type(attr_id);
2594  if (dtype_id < 0) {
2595  threadsafe_H5Aclose(attr_id);
2596  XLAL_ERROR(XLAL_EIO, "Could not read type of attribute `%s'", key);
2597  }
2598 
2599  dtype_class = threadsafe_H5Tget_class(dtype_id);
2600  if (dtype_class == H5T_ARRAY) {
2601  /* get base data type */
2602  hid_t super_id;
2603  super_id = threadsafe_H5Tget_super(dtype_id);
2604  threadsafe_H5Tclose(dtype_id);
2605  dtype_id = super_id;
2606  dtype_class = threadsafe_H5Tget_class(dtype_id);
2607  }
2608  if (dtype_class == H5T_NO_CLASS) {
2609  threadsafe_H5Tclose(dtype_id);
2610  threadsafe_H5Aclose(attr_id);
2611  XLAL_ERROR(XLAL_EIO, "Could not read type class of attribute `%s'", key);
2612  }
2613  if (dtype_class != H5T_ENUM) {
2614  threadsafe_H5Tclose(dtype_id);
2615  threadsafe_H5Aclose(attr_id);
2616  XLAL_ERROR(XLAL_EIO, "Attribute `%s' is not an enum type", key);
2617  }
2618 
2619  nenum = threadsafe_H5Tget_nmembers(dtype_id);
2620  if (nenum < 0) {
2621  threadsafe_H5Tclose(dtype_id);
2622  threadsafe_H5Aclose(attr_id);
2623  XLAL_ERROR(XLAL_EIO, "Could not read number of enum constants of attribute `%s'", key);
2624  }
2625  if (pos >= nenum) {
2626  threadsafe_H5Tclose(dtype_id);
2627  threadsafe_H5Aclose(attr_id);
2628  XLAL_ERROR(XLAL_EINVAL, "Requested enum constant of attribute `%s' does not exist", key);
2629  }
2630 
2631  if (threadsafe_H5Tget_member_value(dtype_id, pos, &val) < 0)
2632  {
2633  threadsafe_H5Tclose(dtype_id);
2634  threadsafe_H5Aclose(attr_id);
2635  XLAL_ERROR(XLAL_EIO, "Could not read enum constant value of attribute `%s'", key);
2636  }
2637 
2638  threadsafe_H5Tclose(dtype_id);
2639  threadsafe_H5Aclose(attr_id);
2640  return val;
2641 #endif
2642 }
2643 
2644 /** @} */
2645 
2646 /**
2647  * @name File Attribute Routines
2648  *
2649  * @deprecated
2650  * Use the general @ref attribute_routines "Attribute Routines"
2651  * instead.
2652  *
2653  * @{
2654  */
2655 
2656 /**
2657  * @brief DEPRECATED: Adds a scalar attribute to a ::LALH5File
2658  * @details
2659  * This routine adds a scalar-valued attribute with name @p key
2660  * and value given by the memory addressed by @p value to a
2661  * HDF5 file associated with the ::LALH5File @p file.
2662  * The data type of the scalar value is given by the \c LALTYPECODE
2663  * @p dtype.
2664  *
2665  * @deprecated
2666  * Use XLALH5AttributeAddScalar() instead.
2667  *
2668  * @param file Pointer to a ::LALH5File to which the attribute will be added.
2669  * @param key Pointer to a string with the name of the new attribute.
2670  * @param value Pointer to the value of the scalar attribute to be added.
2671  * @param dtype \c LALTYPECODE value specifying the data type of the attribute.
2672  * @retval 0 Success.
2673  * @retval -1 Failure.
2674  */
2675 int XLALH5FileAddScalarAttribute(LALH5File UNUSED *file, const char UNUSED *key, const void UNUSED *value, LALTYPECODE UNUSED dtype)
2676 {
2677 #ifndef HAVE_HDF5
2678  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2679 #else
2680  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeAddScalar");
2681  if (XLALH5AttributeAddScalar((LALH5Generic)file, key, value, dtype) < 0)
2683  return 0;
2684 #endif
2685 }
2686 
2687 /**
2688  * @brief DEPRECATED: Gets attribute names from a ::LALH5File
2689  * @details
2690  * This routine returns the names of all attributes from a HDF5 Dataset
2691  *
2692  * @deprecated
2693  * Use XLALH5AttributeQueryN() and XLALH5AttributeQueryName() instead.
2694  *
2695  * @param names Pointer a list of strings to be returned to the user. Memory
2696  * should be freed by the caller.
2697  * @param file Pointer to a ::LALH5File from which the attributes will be added.
2698  * @param N Pointer to a UINT4 where the number of datasets will be recorded
2699  * @retval 0 Success.
2700  * @retval -1 Failure.
2701  */
2702 int XLALH5FileGetAttributeNames(LALH5File UNUSED *file, char UNUSED *** names, UINT4 UNUSED *N)
2703 {
2704 #ifndef HAVE_HDF5
2705  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2706 #else
2707  int na;
2708  int ns;
2709  int i;
2710  hid_t aid;
2711 
2712  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeQueryN() and XLALH5AttributeQueryName");
2713  if (file == NULL)
2715  if (names == NULL)
2717 
2718  na = threadsafe_H5Aget_num_attrs(file->file_id);
2719  char ** namelist = (char**) XLALMalloc(na * sizeof(*names));
2720 
2721  for (i = 0; i <na; i++) {
2722  aid = threadsafe_H5Aopen_idx(file->file_id, (unsigned int)i);
2723  ns = threadsafe_H5Aget_name(aid, 0, NULL) + 1;
2724  namelist[i] = (char*) XLALMalloc(ns * sizeof(namelist[i]));
2725  threadsafe_H5Aget_name(aid, ns, namelist[i]);
2726  threadsafe_H5Aclose(aid);
2727  }
2728 
2729  *N=na;
2730  *names = namelist;
2731  return(XLAL_SUCCESS);
2732 #endif
2733 }
2734 
2735 
2736 /**
2737  * @brief DEPRECATED: Adds a string attribute to a ::LALH5File
2738  * @details
2739  * This routine adds a NUL-terminated variable-length string @p value
2740  * attribute with name @p key to a HDF5 file associated with the
2741  * ::LALH5File @p file.
2742  *
2743  * @deprecated
2744  * Use XLALH5AttributeAddString() instead.
2745  *
2746  * @param file Pointer to a ::LALH5File to which the attribute will be added.
2747  * @param key Pointer to a string with the name of the new attribute.
2748  * @param value Pointer to a string with the value of the new attribute.
2749  * @retval 0 Success.
2750  * @retval -1 Failure.
2751  */
2752 int XLALH5FileAddStringAttribute(LALH5File UNUSED *file, const char UNUSED *key, const char UNUSED *value)
2753 {
2754 #ifndef HAVE_HDF5
2755  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2756 #else
2757  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeAddString");
2758  if (XLALH5AttributeAddString((LALH5Generic)file, key, value) < 0)
2760  return 0;
2761 #endif
2762 }
2763 
2764 /**
2765  * @brief DEPRECATED: Adds a LIGOTimeGPS attribute to a ::LALH5File
2766  * @details
2767  * This routine adds a LIGOTimeGPS @p value attribute with name @p key to a
2768  * HDF5 file associated with the ::LALH5File @p file.
2769  *
2770  * @deprecated
2771  * Use XLALH5AttributeAddLIGOTimeGPS() instead.
2772  *
2773  * @param file Pointer to a ::LALH5File to which the attribute will be added.
2774  * @param key Pointer to a string with the name of the new attribute.
2775  * @param value Pointer to a LIGOTimeGPS structure with the value of the new
2776  * attribute.
2777  * @retval 0 Success.
2778  * @retval -1 Failure.
2779  */
2780 int XLALH5FileAddLIGOTimeGPSAttribute(LALH5File UNUSED *file, const char UNUSED *key, const LIGOTimeGPS UNUSED *value)
2781 {
2782 #ifndef HAVE_HDF5
2783  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2784 #else
2785  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeAddLIGOTimeGPS");
2786  if (XLALH5AttributeAddLIGOTimeGPS((LALH5Generic)file, key, value) < 0)
2788  return 0;
2789 #endif
2790 }
2791 
2792 /**
2793  * @brief DEPRECATED: Gets the datatype of an attribute in a ::LALH5File
2794  * @details
2795  * This routine queries the datatype of a scalar attribute with
2796  * name @p key in a HDF5 file associated with the ::LALH5File @p file.
2797  *
2798  * @deprecated
2799  * Use XLALH5AttributeQueryScalarType() instead.
2800  *
2801  * @param file Pointer to a ::LALH5File to be queried.
2802  * @param key Pointer to a string with the name of the attribute to query.
2803  * @returns \c LALTYPECODE value of the datatype of the scalar attribute.
2804  * @retval -1 Failure.
2805  */
2807 {
2808 #ifndef HAVE_HDF5
2809  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2810 #else
2811  LALTYPECODE dtype;
2812 
2813  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeQueryScalarType");
2815  if ((int)(dtype) < 0)
2817 
2818  return dtype;
2819 #endif
2820 }
2821 
2822 /**
2823  * @brief DEPRECATED: Gets the value of a scalar attribute in a ::LALH5File
2824  * @details
2825  * This routine queries the value of a scalar attribute with
2826  * name @p key in a HDF5 file associated with the ::LALH5File @p file.
2827  * The value is stored in memory pointed to by the pointer @p value.
2828  *
2829  * @attention
2830  * This routine does not allocate memory for @p value. The calling
2831  * routine must ensure that the memory addressed by the pointer @p value
2832  * is sufficient to hold the value in the attribute.
2833  *
2834  * @deprecated
2835  * Use XLALH5AttributeQueryScalarValue() instead.
2836  *
2837  * @param value Pointer to memory in which the value will be stored.
2838  * @param file Pointer to a ::LALH5File to be queried.
2839  * @param key Pointer to a string with the name of the attribute to query.
2840  * @retval 0 Success.
2841  * @retval -1 Failure.
2842  */
2843 int XLALH5FileQueryScalarAttributeValue(void UNUSED *value, LALH5File UNUSED *file, const char UNUSED *key)
2844 {
2845 #ifndef HAVE_HDF5
2846  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2847 #else
2848  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeQueryScalarValue");
2849  if (XLALH5AttributeQueryScalarValue(value, (LALH5Generic)file, key) < 0)
2851  return 0;
2852 #endif
2853 }
2854 
2855 /**
2856  * @brief DEPRECATED: Gets the value of a string attribute in a ::LALH5File
2857  * @details
2858  * This routine queries the value of a string attribute with
2859  * name @p key in a HDF5 file associated with the ::LALH5File @p file.
2860  * The result is written into the buffer pointed to by @p value, the size
2861  * of which is @p size bytes. If @p value is NULL, no data is copied but
2862  * the routine returns the length of the string. Therefore, this routine
2863  * can be called once to determine the amount of memory required, the
2864  * memory can be allocated, and then it can be called a second time to
2865  * read the string. If the parameter @p size is less than or equal to
2866  * the string length then only $p size-1 bytes of the string are copied
2867  * to the buffer @p value.
2868  * @note The return value is the length of the string, not including the
2869  * terminating NUL character; thus the buffer @p value should be allocated
2870  * to be one byte larger.
2871  *
2872  * @deprecated
2873  * Use XLALH5AttributeQueryStringValue() instead.
2874  *
2875  * @param value Pointer to a buffer into which the string will be written.
2876  * @param size Size in bytes of the buffer into which the string will be
2877  * written.
2878  * @param file Pointer to a ::LALH5File to be queried.
2879  * @param key Pointer to a string with the name of the attribute to query.
2880  * @returns The number of bytes that would be written to @p value had @p size
2881  * been sufficiently large excluding the terminating NUL byte.
2882  * @retval -1 Failure.
2883  */
2884 int XLALH5FileQueryStringAttributeValue(char UNUSED *value, size_t UNUSED size, LALH5File UNUSED *file, const char UNUSED *key)
2885 {
2886 #ifndef HAVE_HDF5
2887  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2888 #else
2889  int n;
2890 
2891  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeQueryStringValue");
2892  n = XLALH5AttributeQueryStringValue(value, size, (LALH5Generic)file, key);
2893  if (n < 0)
2895 
2896  return n;
2897 #endif
2898 }
2899 
2900 /**
2901  * @brief DEPRECATED: Gets the value of a LIGOTimeGPS attribute in a ::LALH5File
2902  * @details
2903  * This routine queries the value of a LIGOTimeGPS attribute with
2904  * name @p key in a HDF5 file associated with the ::LALH5File @p file.
2905  * The value is stored in memory pointed to by the pointer @p value.
2906  *
2907  * @deprecated
2908  * Use XLALH5AttributeQueryLIGOTimeGPSValue() instead.
2909  *
2910  * @param value Pointer to a LIGOTimeGPS structure in which the attribute
2911  * value will be stored.
2912  * @param file Pointer to a ::LALH5File to be queried.
2913  * @param key Pointer to a string with the name of the attribute to query.
2914  * @returns Pointer to the LIGOTimeGPS structure passed to this routine.
2915  * @retval NULL Failure.
2916  */
2917 LIGOTimeGPS * XLALH5FileQueryLIGOTimeGPSAttributeValue(LIGOTimeGPS UNUSED *value, LALH5File UNUSED *file, const char UNUSED *key)
2918 {
2919 #ifndef HAVE_HDF5
2920  XLAL_ERROR_NULL(XLAL_EFAILED, "HDF5 support not implemented");
2921 #else
2922  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeQueryLIGOTimeGPSValue");
2923  if (XLALH5AttributeQueryLIGOTimeGPSValue(value, (LALH5Generic)file, key) == NULL)
2925  return value;
2926 #endif
2927 }
2928 
2929 /** @} */
2930 
2931 /**
2932  * @name Dataset Attribute Routines
2933  *
2934  * @deprecated
2935  * Use the general @ref attribute_routines "Attribute Routines"
2936  * instead.
2937  *
2938  * @{
2939  */
2940 
2941 /**
2942  * @brief DEPRECATED: Adds a scalar attribute to a ::LALH5Dataset
2943  * @details
2944  * This routine adds a scalar-valued attribute with name @p key
2945  * and value given by the memory addressed by @p value to a
2946  * HDF5 dataset associated with the ::LALH5Dataset @p dset.
2947  * The data type of the scalar value is given by the \c LALTYPECODE
2948  * @p dtype.
2949  *
2950  * @deprecated
2951  * Use XLALH5AttributeAddScalar() instead.
2952  *
2953  * @param dset Pointer to a ::LALH5Dataset to which the attribute will be added.
2954  * @param key Pointer to a string with the name of the new attribute.
2955  * @param value Pointer to the value of the scalar attribute to be added.
2956  * @param dtype \c LALTYPECODE value specifying the data type of the attribute.
2957  * @retval 0 Success.
2958  * @retval -1 Failure.
2959  */
2960 int XLALH5DatasetAddScalarAttribute(LALH5Dataset UNUSED *dset, const char UNUSED *key, const void UNUSED *value, LALTYPECODE UNUSED dtype)
2961 {
2962 #ifndef HAVE_HDF5
2963  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2964 #else
2965  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeAddScalar");
2966  if (XLALH5AttributeAddScalar((LALH5Generic)dset, key, value, dtype) < 0)
2968  return 0;
2969 #endif
2970 }
2971 
2972 /**
2973  * @brief DEPRECATED: Adds a string attribute to a ::LALH5Dataset
2974  * @details
2975  * This routine adds a NUL-terminated variable-length string @p value
2976  * attribute with name @p key to a HDF5 dataset associated with the
2977  * ::LALH5Dataset @p dset.
2978  *
2979  * @deprecated
2980  * Use XLALH5AttributeAddString() instead.
2981  *
2982  * @param dset Pointer to a ::LALH5Dataset to which the attribute will be added.
2983  * @param key Pointer to a string with the name of the new attribute.
2984  * @param value Pointer to a string with the value of the new attribute.
2985  * @retval 0 Success.
2986  * @retval -1 Failure.
2987  */
2988 int XLALH5DatasetAddStringAttribute(LALH5Dataset UNUSED *dset, const char UNUSED *key, const char UNUSED *value)
2989 {
2990 #ifndef HAVE_HDF5
2991  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
2992 #else
2993  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeAddString");
2994  if (XLALH5AttributeAddString((LALH5Generic)dset, key, value) < 0)
2996  return 0;
2997 #endif
2998 }
2999 
3000 /**
3001  * @brief DEPRECATED: Adds a LIGOTimeGPS attribute to a ::LALH5Dataset
3002  * @details
3003  * This routine adds a LIGOTimeGPS @p value attribute with name @p key to a
3004  * HDF5 dataset associated with the ::LALH5Dataset @p dset.
3005  *
3006  * @deprecated
3007  * Use XLALH5AttributeAddLIGOTimeGPS() instead.
3008  *
3009  * @param dset Pointer to a ::LALH5Dataset to which the attribute will be added.
3010  * @param key Pointer to a string with the name of the new attribute.
3011  * @param value Pointer to a LIGOTimeGPS structure with the value of the new
3012  * attribute.
3013  * @retval 0 Success.
3014  * @retval -1 Failure.
3015  */
3016 int XLALH5DatasetAddLIGOTimeGPSAttribute(LALH5Dataset UNUSED *dset, const char UNUSED *key, const LIGOTimeGPS UNUSED *value)
3017 {
3018 #ifndef HAVE_HDF5
3019  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3020 #else
3021  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeAddLIGOTimeGPS");
3022  if (XLALH5AttributeAddLIGOTimeGPS((LALH5Generic)dset, key, value) < 0)
3024  return 0;
3025 #endif
3026 }
3027 
3028 /**
3029  * @brief DEPRECATED: Gets the datatype of an attribute in a ::LALH5Dataset
3030  * @details
3031  * This routine queries the datatype of a scalar attribute with
3032  * name @p key in a HDF5 dataset associated with the ::LALH5Dataset @p dset.
3033  *
3034  * @deprecated
3035  * Use XLALH5AttributeQueryScalarType() instead.
3036  *
3037  * @param dset Pointer to a ::LALH5Dataset to be queried.
3038  * @param key Pointer to a string with the name of the attribute to query.
3039  * @returns \c LALTYPECODE value of the datatype of the scalar attribute.
3040  * @retval -1 Failure.
3041  */
3043 {
3044 #ifndef HAVE_HDF5
3045  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3046 #else
3047  LALTYPECODE dtype;
3048 
3049  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeQueryScalarType");
3050  dtype = XLALH5AttributeQueryScalarType((LALH5Generic)dset, key);
3051  if ((int)(dtype) < 0)
3053 
3054  return dtype;
3055 #endif
3056 }
3057 
3058 /**
3059  * @brief DEPRECATED: Gets the value of a scalar attribute in a ::LALH5Dataset
3060  * @details
3061  * This routine queries the value of a scalar attribute with
3062  * name @p key in a HDF5 dataset associated with the ::LALH5Dataset @p dset.
3063  * The value is stored in memory pointed to by the pointer @p value.
3064  *
3065  * @attention
3066  * This routine does not allocate memory for @p value. The calling
3067  * routine must ensure that the memory addressed by the pointer @p value
3068  * is sufficient to hold the value in the attribute.
3069  *
3070  * @deprecated
3071  * Use XLALH5AttributeQueryScalarValue() instead.
3072  *
3073  * @param value Pointer to memory in which the value will be stored.
3074  * @param dset Pointer to a ::LALH5Dataset to be queried.
3075  * @param key Pointer to a string with the name of the attribute to query.
3076  * @retval 0 Success.
3077  * @retval -1 Failure.
3078  */
3079 int XLALH5DatasetQueryScalarAttributeValue(void UNUSED *value, LALH5Dataset UNUSED *dset, const char UNUSED *key)
3080 {
3081 #ifndef HAVE_HDF5
3082  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3083 #else
3084  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeQueryScalarValue");
3085  if (XLALH5AttributeQueryScalarValue(value, (LALH5Generic)dset, key) < 0)
3087  return 0;
3088 #endif
3089 }
3090 
3091 /**
3092  * @brief DEPRECATED: Gets the value of a string attribute in a ::LALH5Dataset
3093  * @details
3094  * This routine queries the value of a string attribute with
3095  * name @p key in a HDF5 dataset associated with the ::LALH5Dataset @p dset.
3096  * The result is written into the buffer pointed to by @p value, the size
3097  * of which is @p size bytes. If @p value is NULL, no data is copied but
3098  * the routine returns the length of the string. Therefore, this routine
3099  * can be called once to determine the amount of memory required, the
3100  * memory can be allocated, and then it can be called a second time to
3101  * read the string. If the parameter @p size is less than or equal to
3102  * the string length then only $p size-1 bytes of the string are copied
3103  * to the buffer @p value.
3104  * @note The return value is the length of the string, not including the
3105  * terminating NUL character; thus the buffer @p value should be allocated
3106  * to be one byte larger.
3107  *
3108  * @deprecated
3109  * Use XLALH5AttributeQueryStringValue() instead.
3110  *
3111  * @param value Pointer to a buffer into which the string will be written.
3112  * @param size Size in bytes of the buffer into which the string will be
3113  * written.
3114  * @param dset Pointer to a ::LALH5Dataset to be queried.
3115  * @param key Pointer to a string with the name of the attribute to query.
3116  * @returns The number of bytes that would be written to @p value had @p size
3117  * been sufficiently large excluding the terminating NUL byte.
3118  * @retval NULL Failure.
3119  */
3120 int XLALH5DatasetQueryStringAttributeValue(char UNUSED *value, size_t UNUSED size, LALH5Dataset UNUSED *dset, const char UNUSED *key)
3121 {
3122 #ifndef HAVE_HDF5
3123  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3124 #else
3125  int n;
3126 
3127  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeQueryStringValue");
3128  n = XLALH5AttributeQueryStringValue(value, size, (LALH5Generic)dset, key);
3129  if (n < 0)
3131 
3132  return n;
3133 #endif
3134 }
3135 
3136 /**
3137  * @brief DEPRECATED: Gets the value of a LIGOTimeGPS attribute in a ::LALH5Dataset
3138  * @details
3139  * This routine queries the value of a LIGOTimeGPS attribute with
3140  * name @p key in a HDF5 dataset associated with the ::LALH5Dataset @p dset.
3141  * The value is stored in memory pointed to by the pointer @p value.
3142  *
3143  * @deprecated
3144  * Use XLALH5AttributeQueryLIGOTimeGPSValue() instead.
3145  *
3146  * @param value Pointer to a LIGOTimeGPS structure in which the attribute
3147  * value will be stored.
3148  * @param dset Pointer to a ::LALH5Dataset to be queried.
3149  * @param key Pointer to a string with the name of the attribute to query.
3150  * @returns Pointer to the LIGOTimeGPS structure passed to this routine.
3151  * @retval NULL Failure.
3152  */
3153 LIGOTimeGPS * XLALH5DatasetQueryLIGOTimeGPSAttributeValue(LIGOTimeGPS UNUSED *value, LALH5Dataset UNUSED *dset, const char UNUSED *key)
3154 {
3155 #ifndef HAVE_HDF5
3156  XLAL_ERROR_NULL(XLAL_EFAILED, "HDF5 support not implemented");
3157 #else
3158  XLAL_PRINT_DEPRECATION_WARNING("XLALH5AttributeQueryLIGOTimeGPSValue");
3159  if (XLALH5AttributeQueryLIGOTimeGPSValue(value, (LALH5Generic)dset, key) == NULL)
3161  return value;
3162 #endif
3163 }
3164 
3165 /** @} */
3166 
3167 /** @} */
3168 
3169 /**
3170  * @addtogroup H5Table_group
3171  * @brief Routines for reading/writing tables in HDF5 files.
3172  * @details
3173  * These routines are basic routines for reading and writing
3174  * tables in HDF5 files.
3175  * @{
3176  */
3177 
3178 /**
3179  * @brief Allocates a ::LALH5Dataset dataset to hold a table.
3180  * @details
3181  * This routine creates a dataset with name @p name within an HDF5
3182  * file associated with the ::LALH5File @p file structure and allocates
3183  * a ::LALH5Dataset structure associated with the dataset. The type
3184  * of data to be stored are table data comprised of rows of size
3185  * @p rowsz; each row having @p ncols columns with names @p cols, types @p
3186  * types, and offsets @p offsets.
3187 
3188  * with the ::LALH5Dataset @p dset and stores the data in the buffer @p data.
3189  * This buffer should be sufficiently large to hold the requested rows
3190  * of the dataset, which is comprised of a number of rows each of size
3191  * @p rowsz. Each row is comprised of a number of columns
3192  * which are named in the comma-separated list in string @p cols.
3193  * The offsets of the columns and the sizes of the columns in each row
3194  * of data is provided by the arrays @p offsets and @p colsz respectively.
3195  *
3196  * The following example shows how to create a dataset named @a particles
3197  * in which particle data can be stored.
3198  * @code
3199  * #include <stddef.h>
3200  * #include <lal/LALStdlib.h>
3201  * #include <lal/LALH5FileIO.h>
3202  *
3203  * struct body {REAL8 x; REAL8 y; REAL8 z; REAL8 vx; REAL8 vy; REAL8 vz;};
3204  * size_t ncols = 6;
3205  * size_t types[6] = {LAL_D_TYPE_CODE, LAL_D_TYPE_CODE, LAL_D_TYPE_CODE, LAL_D_TYPE_CODE, LAL_D_TYPE_CODE, LAL_D_TYPE_CODE};
3206  * size_t offsets[6] = {offsetof(struct body, x), offsetof(struct body, y), offsetof(struct body, z), offsetof(struct body, vx), offsetof(struct body, vy), offsetof(struct body, vz)};
3207  * size_t rowsz = sizeof(*data);
3208  * LALH5File *file = XLALH5FileOpen("example.h5", "w");
3209  * LALH5Dataset *dset = XLALH5TableAlloc(file, "particles", ncols, cols, types, offsets, rowsz);
3210  * @endcode
3211  *
3212  * @param file Pointer to a ::LALH5File in which to create the dataset.
3213  * @param name Pointer to a string with the name of the dataset to create (also
3214  * the table name).
3215  * @param ncols Number of columns in each row.
3216  * @param cols Pointer to an array of strings giving the column names.
3217  * @param types Pointer to an array of \c LALTYPECODE values specifying the data
3218  * type of each column.
3219  * @param offsets Pointer to an array of offsets for each column.
3220  * @param rowsz Size of each row of data.
3221  * @returns A pointer to a ::LALH5Dataset structure associated with the specified
3222  * dataset within a HDF5 file.
3223  * @retval NULL An error occurred creating the dataset.
3224  */
3225 LALH5Dataset * XLALH5TableAlloc(LALH5File UNUSED *file, const char UNUSED *name, size_t UNUSED ncols, const char UNUSED **cols, const LALTYPECODE UNUSED *types, const size_t UNUSED *offsets, size_t UNUSED rowsz)
3226 {
3227 #ifndef HAVE_HDF5
3228  XLAL_ERROR_NULL(XLAL_EFAILED, "HDF5 support not implemented");
3229 #else
3230  const size_t chunk_size = 32;
3231  hid_t dtype_id[ncols];
3232  hid_t tdtype_id;
3233  size_t col;
3234  size_t namelen;
3235  herr_t status;
3236  LALH5Dataset *dset;
3237 
3238  if (file == NULL || cols == NULL || types == NULL || offsets == NULL)
3240 
3241  if (file->mode != LAL_H5_FILE_MODE_WRITE)
3242  XLAL_ERROR_NULL(XLAL_EINVAL, "Attempting to write to a read-only HDF5 file");
3243 
3244  /* map the LAL types to HDF5 types */
3245  for (col = 0; col < ncols; ++col) {
3246  dtype_id[col] = XLALH5TypeFromLALType(types[col]);
3247  if (dtype_id[col] < 0)
3249  }
3250 
3251  /* make empty table */
3252  /* note: table title and dataset name are the same */
3253  status = threadsafe_H5TBmake_table(name, file->file_id, name, ncols, 0, rowsz, cols, offsets, dtype_id, chunk_size, NULL, 0, NULL);
3254  for (col = 0; col < ncols; ++col)
3255  threadsafe_H5Tclose(dtype_id[col]);
3256 
3257  if (status < 0)
3259 
3260  /* now read dataset from file to return */
3261 
3262  namelen = strlen(name);
3263  dset = LALCalloc(1, sizeof(*dset) + namelen + 1); /* use flexible array member to record name */
3264  if (!dset)
3266 
3267  dset->dataset_id = threadsafe_H5Dopen2(file->file_id, name, H5P_DEFAULT);
3268  if (dset->dataset_id < 0) {
3269  LALFree(dset);
3270  XLAL_ERROR_NULL(XLAL_EIO, "Could not read dataset `%s'", name);
3271  }
3272 
3273  dset->space_id = threadsafe_H5Dget_space(dset->dataset_id);
3274  if (dset->space_id < 0) {
3275  LALFree(dset);
3276  XLAL_ERROR_NULL(XLAL_EIO, "Could not read dataspace of dataset `%s'", name);
3277  }
3278 
3279  tdtype_id = threadsafe_H5Dget_type(dset->dataset_id);
3280  if (tdtype_id < 0) {
3281  threadsafe_H5Sclose(dset->space_id);
3282  LALFree(dset);
3283  XLAL_ERROR_NULL(XLAL_EIO, "Could not read datatype of dataset `%s'", name);
3284  }
3285 
3286  /* convert type to native type */
3287  dset->dtype_id = threadsafe_H5Tget_native_type(tdtype_id, H5T_DIR_ASCEND);
3288  threadsafe_H5Tclose(tdtype_id);
3289  if (dset->dtype_id < 0) {
3290  threadsafe_H5Sclose(dset->space_id);
3291  LALFree(dset);
3292  XLAL_ERROR_NULL(XLAL_EIO, "Could not get native type for dataset `%s'", name);
3293  }
3294 
3295  /* record name of dataset and parent id */
3296  snprintf(dset->name, namelen + 1, "%s", name);
3297  dset->parent_id = file->file_id;
3298  return dset;
3299 #endif
3300 }
3301 
3302 /**
3303  * @brief Appends rows of data to a ::LALH5Dataset dataset holding a table.
3304  * @details
3305  * This routine appends @p nrows rows of data each having size @p rowsz
3306  * to a HDF5 table dataset associated with the ::LALH5Dataset structure
3307  * @p dset. The data is contained in @p data and the offsets and sizes
3308  * of each column are given by the arrays @p offsets and @p colsz.
3309  *
3310  * The following example shows how to append rows to a dataset named
3311  * @a particles in which particle data is stored.
3312  * @code
3313  * #include <stddef.h>
3314  * #include <lal/LALStdlib.h>
3315  * #include <lal/LALH5FileIO.h>
3316  *
3317  * struct body {REAL8 x; REAL8 y; REAL8 z; REAL8 vx; REAL8 vy; REAL8 vz;} data[] = {
3318  * { .x = +0.83, .y = -0.13, .z = -0.24, .vx = +0.60, .vy = -0.79, .vz = -0.98 },
3319  * { .x = -0.59, .y = -0.12, .z = -0.60, .vx = +0.38, .vy = +0.61, .vz = -0.75 },
3320  * { .x = -0.48, .y = -0.78, .z = +0.83, .vx = -0.58, .vy = -0.09, .vz = +0.44 },
3321  * { .x = +0.99, .y = -0.13, .z = -0.48, .vx = +0.44, .vy = +0.06, .vz = -0.58 },
3322  * { .x = -0.26, .y = +0.92, .z = -0.98, .vx = -0.75, .vy = +0.45, .vz = +0.30 },
3323  * { .x = +0.88, .y = -0.50, .z = +0.53, .vx = -0.82, .vy = +0.50, .vz = -0.36 },
3324  * { .x = -0.20, .y = +0.55, .z = +0.85, .vx = -0.87, .vy = +0.41, .vz = +0.38 },
3325  * { .x = +0.48, .y = -0.09, .z = +0.29, .vx = -0.76, .vy = +0.27, .vz = -0.38 },
3326  * { .x = +0.11, .y = -0.13, .z = -0.02, .vx = +0.69, .vy = +0.64, .vz = +0.06 },
3327  * { .x = -0.85, .y = +0.08, .z = -0.25, .vx = -0.20, .vy = -0.69, .vz = +0.77 }
3328  * };
3329  * size_t nrows = sizeof(data)/sizeof(*data);
3330  * size_t ncols = 6;
3331  * size_t types[6] = {LAL_D_TYPE_CODE, LAL_D_TYPE_CODE, LAL_D_TYPE_CODE, LAL_D_TYPE_CODE, LAL_D_TYPE_CODE, LAL_D_TYPE_CODE};
3332  * size_t offsets[6] = {offsetof(struct body, x), offsetof(struct body, y), offsetof(struct body, z), offsetof(struct body, vx), offsetof(struct body, vy), offsetof(struct body, vz)};
3333  * size_t colsz[6] = {sizeof(data->x), sizeof(data->y), sizeof(data->z), sizeof(data->vx), sizeof(data->vy), sizeof(data->vz)};
3334  * size_t rowsz = sizeof(*data);
3335  * LALH5File *file = XLALH5FileOpen("example.h5", "w");
3336  * LALH5Dataset *dset = XLALH5TableAlloc(file, "particles", ncols, cols, types, offsets, rowsz);
3337  * XLALH5TableAppend(dset, offsets, colsz, nrows, rowsz, data);
3338  * @endcode
3339  *
3340  * @param dset Pointer to a ::LALH5Dataset containing the table into which the
3341  * rows will be appended.
3342  * @param offsets Pointer to an array of offsets for each column.
3343  * @param colsz Pointer to an array of sizes of each column.
3344  * @param nrows Number of rows of data that will be appended.
3345  * @param rowsz Size of each row of data.
3346  * @param data Pointer to a memory in which contains the data to be appended.
3347  * @retval 0 Success.
3348  * @retval -1 Failure.
3349  */
3350 int XLALH5TableAppend(LALH5Dataset UNUSED *dset, const size_t UNUSED *offsets, const size_t UNUSED *colsz, size_t UNUSED nrows, size_t UNUSED rowsz, const void UNUSED *data)
3351 {
3352 #ifndef HAVE_HDF5
3353  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3354 #else
3355  if (dset == NULL || offsets == NULL || colsz == NULL)
3357 
3358  if (threadsafe_H5TBappend_records(dset->parent_id, dset->name, nrows, rowsz, offsets, colsz, data) < 0)
3360 
3361  return 0;
3362 #endif
3363 }
3364 
3365 /**
3366  * @brief Reads table data from a ::LALH5Dataset
3367  * @details
3368  * This routine reads the table data from a HDF5 dataset associated with the
3369  * ::LALH5Dataset @p dset and stores the data in the buffer @p data.
3370  * This buffer should be sufficiently large to hold the entire contents
3371  * of the dataset, which is comprised of a number of rows each of size
3372  * @p rowsz. The number of rows can be determined with the routine
3373  * XLALH5TableQueryNRows(). Each row is comprised of a number of columns,
3374  * which can be determined with the routine XLALH5TableQueryNColumns().
3375  * The offsets of the columns and the sizes of the columns in each row
3376  * of data is provided by the arrays @p offsets and @p colsz respectively.
3377  *
3378  * The following example shows how to read the data from a table
3379  * named @a particles.
3380  * @code
3381  * #include <stddef.h>
3382  * #include <lal/LALStdlib.h>
3383  * #include <lal/LALH5FileIO.h>
3384  *
3385  * struct body {REAL8 x; REAL8 y; REAL8 z; REAL8 vx; REAL8 vy; REAL8 vz;} *data;
3386  * size_t offsets[] = {offsetof(struct body, x), offsetof(struct body, y), offsetof(struct body, z), offsetof(struct body, vx), offsetof(struct body, vy), offsetof(struct body, vz)};
3387  * size_t colsz[] = {sizeof(data->x), sizeof(data->y), sizeof(data->z), sizeof(data->vx), sizeof(data->vy), sizeof(data->vz)};
3388  * size_t rowsz = sizeof(*data);
3389  * LALH5File *file = XLALH5FileOpen("example.h5", "r");
3390  * LALH5Dataset *dset = XLALH5DatasetRead(file, "particles");
3391  * size_t nrows = XLALH5TableQueryNRows(dset);
3392  * data = LALMalloc(nrows * rowsz);
3393  * XLALH5TableRead(data, dset, offsets, colsz, rowsz);
3394  * @endcode
3395  *
3396  * @param data Pointer to a memory in which to store the data.
3397  * @param dset Pointer to a ::LALH5Dataset from which to extract the data.
3398  * @param offsets Pointer to an array of offsets for each column.
3399  * @param colsz Pointer to an array of sizes of each column.
3400  * @param rowsz Size of each row of data.
3401  * @retval 0 Success.
3402  * @retval -1 Failure.
3403  */
3404 int XLALH5TableRead(void UNUSED *data, const LALH5Dataset UNUSED *dset, const size_t UNUSED *offsets, const size_t UNUSED *colsz, size_t UNUSED rowsz)
3405 {
3406 #ifndef HAVE_HDF5
3407  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3408 #else
3409  if (data == NULL || dset == NULL || offsets == NULL || colsz == NULL)
3411 
3412  if (threadsafe_H5TBread_table(dset->parent_id, dset->name, rowsz, offsets, colsz, data) < 0)
3414 
3415  return 0;
3416 #endif
3417 }
3418 
3419 /**
3420  * @brief Reads certain rows of table data from a ::LALH5Dataset
3421  * @details
3422  * This routine reads certain rows of table data from a HDF5 dataset associated
3423  * with the ::LALH5Dataset @p dset and stores the data in the buffer @p data.
3424  * This buffer should be sufficiently large to hold the requested @p nrows rows
3425  * of the dataset, starting with row @p row0 (the first row is row 0), which is
3426  * comprised of a number of rows each of size @p rowsz. Each row is comprised
3427  * of a number of columns, which can be determined with the routine
3428  * XLALH5TableQueryNColumns(). The offsets of the columns and the sizes of the
3429  * columns in each row of data is provided by the arrays @p offsets and
3430  * @p colsz respectively.
3431  *
3432  * The following example shows how to read rows 2 to 5 inclusive
3433  * (where the first row is row 0) of data from a table named
3434  * @a particles.
3435  * @code
3436  * #include <stddef.h>
3437  * #include <lal/LALStdlib.h>
3438  * #include <lal/LALH5FileIO.h>
3439  *
3440  * struct body {REAL8 x; REAL8 y; REAL8 z; REAL8 vx; REAL8 vy; REAL8 vz;} data[4];
3441  * size_t offsets[] = {offsetof(struct body, x), offsetof(struct body, y), offsetof(struct body, z), offsetof(struct body, vx), offsetof(struct body, vy), offsetof(struct body, vz)};
3442  * size_t colsz[] = {sizeof(data->x), sizeof(data->y), sizeof(data->z), sizeof(data->vx), sizeof(data->vy), sizeof(data->vz)};
3443  * size_t rowsz = sizeof(*data);
3444  * size_t row0 = 2;
3445  * size_t nrows = sizeof(data)/sizeof(*data);
3446  * LALH5File *file = XLALH5FileOpen("example.h5", "r");
3447  * LALH5Dataset *dset = XLALH5DatasetRead(file, "particles");
3448  * XLALH5TableReadRows(data, dset, offsets, colsz, row0, nrows, rowsz);
3449  * @endcode
3450  *
3451  * @param data Pointer to a memory in which to store the data.
3452  * @param dset Pointer to a ::LALH5Dataset from which to extract the data.
3453  * @param offsets Pointer to an array of offsets for each column.
3454  * @param colsz Pointer to an array of sizes of each column.
3455  * @param row0 The first row to read.
3456  * @param nrows The Number of rows to read.
3457  * @param rowsz Size of each row of data.
3458  * @retval 0 Success.
3459  * @retval -1 Failure.
3460  */
3461 int XLALH5TableReadRows(void UNUSED *data, const LALH5Dataset UNUSED *dset, const size_t UNUSED *offsets, const size_t UNUSED *colsz, size_t UNUSED row0, size_t UNUSED nrows, size_t UNUSED rowsz)
3462 {
3463 #ifndef HAVE_HDF5
3464  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3465 #else
3466  if (data == NULL || dset == NULL || offsets == NULL || colsz == NULL)
3468 
3469  if (threadsafe_H5TBread_records(dset->parent_id, dset->name, row0, nrows, rowsz, offsets, colsz, data) < 0)
3471 
3472  return 0;
3473 #endif
3474 }
3475 
3476 /**
3477  * @brief Reads certain columns of table data from a ::LALH5Dataset
3478  * @details
3479  * This routine reads certain columns of table data from a HDF5 dataset associated
3480  * with the ::LALH5Dataset @p dset and stores the data in the buffer @p data.
3481  * This buffer should be sufficiently large to hold the requested rows
3482  * of the dataset, which is comprised of a number of rows each of size
3483  * @p rowsz. Each row is comprised of a number of columns
3484  * which are named in the comma-separated list in string @p cols.
3485  * The offsets of the columns and the sizes of the columns in each row
3486  * of data is provided by the arrays @p offsets and @p colsz respectively.
3487  *
3488  * The following example shows how to read rows 2 to 5 inclusive
3489  * (where the first row is row 0) of certain columns of data from a table named
3490  * @a particles.
3491  * @code
3492  * #include <stddef.h>
3493  * #include <lal/LALStdlib.h>
3494  * #include <lal/LALH5FileIO.h>
3495  *
3496  * struct position {REAL8 x; REAL8 y; REAL8 z;} data[4];
3497  * const char *cols = "x,y,z";
3498  * size_t offsets[] = {offsetof(struct position, x), offsetof(struct position, y), offsetof(struct position, z)};
3499  * size_t colsz[] = {sizeof(data->x), sizeof(data->y), sizeof(data->z)};
3500  * size_t rowsz = sizeof(*data);
3501  * size_t row0 = 2;
3502  * size_t nrows = sizeof(data)/sizeof(*data);
3503  * LALH5File *file = XLALH5FileOpen("example.h5", "r");
3504  * LALH5Dataset *dset = XLALH5DatasetRead(file, "particles");
3505  * XLALH5TableReadColumns(data, dset, cols, offsets, colsz, row0, nrows, rowsz);
3506  * @endcode
3507  *
3508  * @param data Pointer to a memory in which to store the data.
3509  * @param dset Pointer to a ::LALH5Dataset from which to extract the data.
3510  * @param cols Pointer to an string listing the column names separated by commas.
3511  * @param offsets Pointer to an array of offsets for each column.
3512  * @param colsz Pointer to an array of sizes of each column.
3513  * @param row0 The first row to read.
3514  * @param nrows The Number of rows to read.
3515  * @param rowsz Size of each row of data.
3516  * @retval 0 Success.
3517  * @retval -1 Failure.
3518  */
3519 int XLALH5TableReadColumns(void UNUSED *data, const LALH5Dataset UNUSED *dset, const char UNUSED *cols, const size_t UNUSED *offsets, const size_t UNUSED *colsz, size_t UNUSED row0, size_t UNUSED nrows, size_t UNUSED rowsz)
3520 {
3521 #ifndef HAVE_HDF5
3522  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3523 #else
3524  if (data == NULL || dset == NULL || offsets == NULL || colsz == NULL)
3526 
3527  if (threadsafe_H5TBread_fields_name(dset->parent_id, dset->name, cols, row0, nrows, rowsz, offsets, colsz, data) < 0)
3529 
3530  return 0;
3531 #endif
3532 }
3533 
3534 /**
3535  * @brief Gets the number of rows in a ::LALH5Dataset containing table data.
3536  * @param dset Pointer to a ::LALH5Dataset containing table data to be queried.
3537  * @returns The number of rows of table data in the HDF5 dataset associated
3538  * with the specified ::LALH5Dataset.
3539  * @retval (size_t)(-1) Failure.
3540  */
3541 size_t XLALH5TableQueryNRows(const LALH5Dataset UNUSED *dset)
3542 {
3543 #ifndef HAVE_HDF5
3544  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3545 #else
3546  hsize_t nrows;
3547 
3548  if (dset == NULL)
3550 
3551  if (threadsafe_H5TBget_table_info(dset->parent_id, dset->name, NULL, &nrows) < 0)
3553 
3554  return nrows;
3555 #endif
3556 }
3557 
3558 /**
3559  * @brief Gets the number of columns in a ::LALH5Dataset containing table data.
3560  * @param dset Pointer to a ::LALH5Dataset containing table data to be queried.
3561  * @returns The number of columns of table data in the HDF5 dataset associated
3562  * with the specified ::LALH5Dataset.
3563  * @retval (size_t)(-1) Failure.
3564  */
3565 size_t XLALH5TableQueryNColumns(const LALH5Dataset UNUSED *dset)
3566 {
3567 #ifndef HAVE_HDF5
3568  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3569 #else
3570  hsize_t ncols;
3571 
3572  if (dset == NULL)
3574 
3575  if (threadsafe_H5TBget_table_info(dset->parent_id, dset->name, &ncols, NULL) < 0)
3577 
3578  return ncols;
3579 #endif
3580 }
3581 
3582 /**
3583  * @brief Gets the number of bytes in a row in a ::LALH5Dataset containing table
3584  * data.
3585  * @param dset Pointer to a ::LALH5Dataset containing table data to be queried.
3586  * @returns The number of bytes of a row of data in the HDF5 dataset associated
3587  * with the specified ::LALH5Dataset.
3588  * @retval (size_t)(-1) Failure.
3589  */
3590 size_t XLALH5TableQueryRowSize(const LALH5Dataset UNUSED *dset)
3591 {
3592 #ifndef HAVE_HDF5
3593  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3594 #else
3595  size_t rowsz;
3596 
3597  if (dset == NULL)
3599 
3600  if (threadsafe_H5TBget_field_info(dset->parent_id, dset->name, NULL, NULL, NULL, &rowsz) < 0)
3602 
3603  return rowsz;
3604 #endif
3605 }
3606 
3607 /**
3608  * @brief Gets the name of a column in a ::LALH5Dataset containing table
3609  * data.
3610  * @details
3611  * This routines gets the name of a column of data in a ::LALH5Dataset
3612  * @p dset that contains table data.
3613  * The index @p pos identifies which column's name is returned.
3614  * The result is written into the buffer pointed to by @p name, the size
3615  * of which is @p size bytes. If @p name is NULL, no data is copied but
3616  * the routine returns the length of the string. Therefore, this routine
3617  * can be called once to determine the amount of memory required, the
3618  * memory can be allocated, and then it can be called a second time to
3619  * read the string. If the parameter @p size is less than or equal to
3620  * the string length then only $p size-1 bytes of the string are copied
3621  * to the buffer @p name.
3622  * @note The return value is the length of the string, not including the
3623  * terminating NUL character; thus the buffer @p name should be allocated
3624  * to be one byte larger.
3625  * @param name Pointer to a buffer into which the string will be written.
3626  * @param size Size in bytes of the buffer into which the string will be
3627  * written.
3628  * @param dset Pointer to a ::LALH5Dataset containing table data to be
3629  * queried.
3630  * @param pos The index identifying which column of the table.
3631  * @retval 0 Success.
3632  * @retval -1 Failure.
3633  */
3634 int XLALH5TableQueryColumnName(char UNUSED *name, size_t UNUSED size, const LALH5Dataset UNUSED *dset, int UNUSED pos)
3635 {
3636 #ifndef HAVE_HDF5
3637  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3638 #else
3639  int ncols;
3640  char *col;
3641  int n;
3642 
3643  if (dset == NULL)
3645 
3646  ncols = threadsafe_H5Tget_nmembers(dset->dtype_id);
3647  if (ncols < 0)
3648  XLAL_ERROR(XLAL_EIO, "Could not read type members");
3649 
3650  if (ncols <= pos)
3651  XLAL_ERROR(XLAL_EINVAL, "Requested column does not exist");
3652 
3653  col = threadsafe_H5Tget_member_name(dset->dtype_id, pos);
3654  if (col == NULL)
3655  XLAL_ERROR(XLAL_EIO, "Could not read column name");
3656 
3657  n = snprintf(name, name == NULL ? 0 : size, "%s", col);
3658  free(col);
3659  return n;
3660 #endif
3661 }
3662 
3663 /**
3664  * @brief Gets the size in bytes of a column in a ::LALH5Dataset containing table
3665  * data.
3666  * @param dset Pointer to a ::LALH5Dataset containing table data to be
3667  * queried.
3668  * @param pos The index identifying which column of the table.
3669  * @returns The size in bytes of the specified column entry in the HDF5 dataset
3670  * associated with the specified ::LALH5Dataset.
3671  * @retval -1 Failure.
3672  */
3673 size_t XLALH5TableQueryColumnSize(const LALH5Dataset UNUSED *dset, int UNUSED pos)
3674 {
3675 #ifndef HAVE_HDF5
3676  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3677 #else
3678  hid_t member_type_id;
3679  hid_t native_member_type_id;
3680  int ncols;
3681  size_t size;
3682 
3683  if (dset == NULL)
3685 
3686  ncols = threadsafe_H5Tget_nmembers(dset->dtype_id);
3687  if (ncols < 0)
3688  XLAL_ERROR(XLAL_EIO, "Could not read type members");
3689 
3690  if (ncols <= pos)
3691  XLAL_ERROR(XLAL_EINVAL, "Requested column does not exist");
3692 
3693  member_type_id = threadsafe_H5Tget_member_type(dset->dtype_id, pos);
3694  if (member_type_id < 0)
3695  XLAL_ERROR(XLAL_EIO, "Could not read column type");
3696 
3697  native_member_type_id = threadsafe_H5Tget_native_type(member_type_id, H5T_DIR_DEFAULT);
3698  if (native_member_type_id < 0) {
3699  threadsafe_H5Tclose(member_type_id);
3700  XLAL_ERROR(XLAL_EIO, "Could not read column native type");
3701  }
3702 
3703  size = threadsafe_H5Tget_size(native_member_type_id);
3704  if (size == 0) {
3705  threadsafe_H5Tclose(native_member_type_id);
3706  threadsafe_H5Tclose(member_type_id);
3707  XLAL_ERROR(XLAL_EIO, "Could not read column size");
3708  }
3709 
3710  threadsafe_H5Tclose(native_member_type_id);
3711  threadsafe_H5Tclose(member_type_id);
3712 
3713  return size;
3714 #endif
3715 }
3716 
3717 /**
3718  * @brief Gets the type of data stored in a column in a ::LALH5Dataset
3719  * containing table data.
3720  * @param dset Pointer to a ::LALH5Dataset containing table data to be
3721  * queried.
3722  * @param pos The index identifying which column of the table.
3723  * @returns The \c LALTYPECODE of the datatype of the specified column entry in
3724  * the HDF5 dataset associated with the specified ::LALH5Dataset.
3725  * @retval -1 Failure.
3726  */
3727 LALTYPECODE XLALH5TableQueryColumnType(const LALH5Dataset UNUSED *dset, int UNUSED pos)
3728 {
3729 #ifndef HAVE_HDF5
3730  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3731 #else
3732  hid_t member_type_id;
3733  int ncols;
3734  LALTYPECODE type;
3735 
3736  if (dset == NULL)
3738 
3739  ncols = threadsafe_H5Tget_nmembers(dset->dtype_id);
3740  if (ncols < 0)
3741  XLAL_ERROR(XLAL_EIO, "Could not read type members");
3742 
3743  if (ncols <= pos)
3744  XLAL_ERROR(XLAL_EINVAL, "Requested column does not exist");
3745 
3746  member_type_id = threadsafe_H5Tget_member_type(dset->dtype_id, pos);
3747  if (member_type_id < 0)
3748  XLAL_ERROR(XLAL_EIO, "Could not read column type");
3749 
3750  type = XLALTypeFromH5Type(member_type_id);
3751  threadsafe_H5Tclose(member_type_id);
3752 
3753  if ((int)type < 0)
3755  return type;
3756 #endif
3757 }
3758 
3759 /**
3760  * @brief Gets the offset of the data in a column in a ::LALH5Dataset
3761  * containing table data.
3762  * @param dset Pointer to a ::LALH5Dataset containing table data to be
3763  * queried.
3764  * @param pos The index identifying which column of the table.
3765  * @returns The offset of the specified column data in a row of data
3766  * in the HDF5 dataset associated with the specified ::LALH5Dataset.
3767  * @retval (size_t)(-1) Failure.
3768  */
3769 size_t XLALH5TableQueryColumnOffset(const LALH5Dataset UNUSED *dset, int UNUSED pos)
3770 {
3771 #ifndef HAVE_HDF5
3772  XLAL_ERROR(XLAL_EFAILED, "HDF5 support not implemented");
3773 #else
3774  int ncols;
3775  size_t offset;
3776 
3777  if (dset == NULL)
3779 
3780  ncols = threadsafe_H5Tget_nmembers(dset->dtype_id);
3781  if (ncols < 0)
3782  XLAL_ERROR(XLAL_EIO, "Could not read type members");
3783 
3784  if (ncols <= pos)
3785  XLAL_ERROR(XLAL_EINVAL, "Requested column does not exist");
3786 
3787  /* H5Tget_member_offset fails iff H5Tget_member_class does */
3788  if (threadsafe_H5Tget_member_class(dset->dtype_id, pos) < 0)
3789  XLAL_ERROR(XLAL_EINVAL, "Could not read offset");
3790 
3791  offset = threadsafe_H5Tget_member_offset(dset->dtype_id, pos);
3792  return offset;
3793 #endif
3794 }
3795 
3796 /** @} */
struct tagLALH5File LALH5File
Incomplete type for a HDF5 file.
Definition: H5FileIO.h:93
struct tagLALH5Dataset LALH5Dataset
Incomplete type for a HDF5 dataset.
Definition: H5FileIO.h:102
#define LALCalloc(m, n)
Definition: LALMalloc.h:94
#define LALFree(p)
Definition: LALMalloc.h:96
const char *const name
type name
Definition: UserInput.c:193
const char * names[]
Definition: WindowTest.c:34
void XLALH5FileClose(LALH5File UNUSED *file)
Closes a LALH5File.
LALTYPECODE XLALH5AttributeQueryScalarType(const LALH5Generic UNUSED object, const char UNUSED *key)
Gets the datatype of an attribute in a LALH5File or LALH5Dataset.
int XLALH5FileQueryGroupName(char UNUSED *name, size_t UNUSED size, const LALH5File UNUSED *file, int UNUSED pos)
Gets the name of a group contained in a LALH5File.
size_t XLALH5DatasetQueryNPoints(LALH5Dataset UNUSED *dset)
Gets the number of points in a LALH5Dataset.
void XLALH5DatasetFree(LALH5Dataset UNUSED *dset)
Frees a LALH5Dataset.
int XLALH5AttributeQueryName(char UNUSED *name, size_t UNUSED size, const LALH5Generic UNUSED object, int UNUSED pos)
Gets the name of an attribute associated with a LALH5File or LALH5Dataset.
int XLALH5CheckGroupExists(LALH5File UNUSED *file, const char UNUSED *name)
DEPRECATED: Checks for existence of a Group in a LALH5File object LALH5File.
size_t XLALH5FileQueryNDatasets(const LALH5File UNUSED *file)
Gets the number of datasets contained in a LALH5File.
LALH5Dataset * XLALH5DatasetAllocStringData(LALH5File UNUSED *file, const char UNUSED *name, size_t UNUSED length)
Allocates a variable-length string LALH5Dataset.
size_t XLALH5DatasetQueryNBytes(LALH5Dataset UNUSED *dset)
Gets the number of bytes in a LALH5Dataset.
LALH5Dataset * XLALH5DatasetAlloc(LALH5File UNUSED *file, const char UNUSED *name, LALTYPECODE UNUSED dtype, UINT4Vector UNUSED *dimLength)
Allocates a multi-dimensional LALH5Dataset.
int XLALH5AttributeAddString(LALH5Generic UNUSED object, const char UNUSED *key, const char UNUSED *value)
Adds a string attribute to a LALH5File or LALH5Dataset.
LALH5Dataset * XLALH5DatasetAlloc1D(LALH5File UNUSED *file, const char UNUSED *name, LALTYPECODE UNUSED dtype, size_t UNUSED length)
Allocates a 1-dimensional LALH5Dataset.
int XLALH5AttributeQueryEnumName(char UNUSED *name, size_t UNUSED size, const LALH5Generic UNUSED object, const char UNUSED *key, int UNUSED pos)
Gets the name of a constants in an enum type associated with an attribute in a LALH5File or LALH5Data...
UINT4Vector * XLALH5DatasetQueryDims(LALH5Dataset UNUSED *dset)
Gets the dimensions of the dataspace in a LALH5Dataset.
size_t XLALH5AttributeQueryEnumArray1DLength(const LALH5Generic UNUSED object, const char UNUSED *key)
Gets the length of a 1D enum array attribute in a LALH5File or LALH5Dataset.
int XLALH5DatasetQueryScalarAttributeValue(void UNUSED *value, LALH5Dataset UNUSED *dset, const char UNUSED *key)
DEPRECATED: Gets the value of a scalar attribute in a LALH5Dataset.
LIGOTimeGPS * XLALH5FileQueryLIGOTimeGPSAttributeValue(LIGOTimeGPS UNUSED *value, LALH5File UNUSED *file, const char UNUSED *key)
DEPRECATED: Gets the value of a LIGOTimeGPS attribute in a LALH5File.
LALH5File * XLALH5GroupOpen(LALH5File UNUSED *file, const char UNUSED *name)
Opens a group in a LALH5File.
int XLALH5FileQueryScalarAttributeValue(void UNUSED *value, LALH5File UNUSED *file, const char UNUSED *key)
DEPRECATED: Gets the value of a scalar attribute in a LALH5File.
int XLALH5AttributeQueryStringValue(char UNUSED *value, size_t UNUSED size, const LALH5Generic UNUSED object, const char UNUSED *key)
Gets the value of a string attribute in a LALH5File or LALH5Dataset.
int XLALH5AttributeAddLIGOTimeGPS(LALH5Generic UNUSED object, const char UNUSED *key, const LIGOTimeGPS UNUSED *value)
Adds a LIGOTimeGPS attribute to a LALH5File or LALH5Dataset.
LALTYPECODE XLALH5DatasetQueryScalarAttributeType(LALH5Dataset UNUSED *dset, const char UNUSED *key)
DEPRECATED: Gets the datatype of an attribute in a LALH5Dataset.
int XLALH5FileAddLIGOTimeGPSAttribute(LALH5File UNUSED *file, const char UNUSED *key, const LIGOTimeGPS UNUSED *value)
DEPRECATED: Adds a LIGOTimeGPS attribute to a LALH5File.
int XLALH5DatasetAddLIGOTimeGPSAttribute(LALH5Dataset UNUSED *dset, const char UNUSED *key, const LIGOTimeGPS UNUSED *value)
DEPRECATED: Adds a LIGOTimeGPS attribute to a LALH5Dataset.
int XLALH5AttributeAddEnumArray1D(LALH5Generic UNUSED object, const char UNUSED *enumnames[], const int UNUSED enumvals[], size_t UNUSED nenum, const char UNUSED *key, const int UNUSED value[], size_t UNUSED length)
Adds a 1d enum array attribute to a LALH5File or LALH5Dataset.
int XLALH5FileQueryDatasetName(char UNUSED *name, size_t UNUSED size, const LALH5File UNUSED *file, int UNUSED pos)
Gets the name of a dataset contained in a LALH5File.
LALTYPECODE XLALH5FileQueryScalarAttributeType(LALH5File UNUSED *file, const char UNUSED *key)
DEPRECATED: Gets the datatype of an attribute in a LALH5File.
int XLALH5DatasetCheckStringData(LALH5Dataset UNUSED *dset)
Checks if a LALH5Dataset contains variable length string data.
LIGOTimeGPS * XLALH5AttributeQueryLIGOTimeGPSValue(LIGOTimeGPS UNUSED *value, const LALH5Generic UNUSED object, const char UNUSED *key)
Gets the value of a LIGOTimeGPS attribute in a LALH5File or LALH5Dataset.
int XLALH5AttributeQueryEnumValue(const LALH5Generic UNUSED object, const char UNUSED *key, int UNUSED pos)
Gets the value of a constants in an enum type associated with an attribute in a LALH5File or LALH5Dat...
int XLALH5DatasetAddStringAttribute(LALH5Dataset UNUSED *dset, const char UNUSED *key, const char UNUSED *value)
DEPRECATED: Adds a string attribute to a LALH5Dataset.
LALTYPECODE XLALH5DatasetQueryType(LALH5Dataset UNUSED *dset)
Gets the type of data in a LALH5Dataset.
int XLALH5DatasetQueryStringAttributeValue(char UNUSED *value, size_t UNUSED size, LALH5Dataset UNUSED *dset, const char UNUSED *key)
DEPRECATED: Gets the value of a string attribute in a LALH5Dataset.
int XLALH5FileAddScalarAttribute(LALH5File UNUSED *file, const char UNUSED *key, const void UNUSED *value, LALTYPECODE UNUSED dtype)
DEPRECATED: Adds a scalar attribute to a LALH5File.
int XLALH5FileCheckDatasetExists(const LALH5File UNUSED *file, const char UNUSED *name)
Checks for existence of a dataset in a LALH5File.
LALH5File * XLALH5FileOpen(const char UNUSED *path, const char UNUSED *mode)
Opens a LALH5File.
int XLALH5AttributeAddScalar(LALH5Generic UNUSED object, const char UNUSED *key, const void UNUSED *value, LALTYPECODE UNUSED dtype)
Adds a scalar attribute to a LALH5File or LALH5Dataset.
int XLALH5FileGetDatasetNames(LALH5File UNUSED *file, char UNUSED ***names, UINT4 UNUSED *N)
DEPRECATED: Gets dataset names from a LALH5File.
int XLALH5FileAddStringAttribute(LALH5File UNUSED *file, const char UNUSED *key, const char UNUSED *value)
DEPRECATED: Adds a string attribute to a LALH5File.
size_t XLALH5AttributeQueryNEnum(const LALH5Generic UNUSED object, const char UNUSED *key)
Gets the number of constants in an enum type associated with an attribute in a LALH5File or LALH5Data...
size_t XLALH5AttributeCheckExists(const LALH5Generic UNUSED object, const char UNUSED *name)
Checks for existence of an attribute associated with a LALH5File or LALH5Dataset.
int XLALH5AttributeQueryScalarValue(void UNUSED *value, const LALH5Generic UNUSED object, const char UNUSED *key)
Gets the value of a scalar attribute in a LALH5File or LALH5Dataset.
LALH5Dataset * XLALH5DatasetRead(LALH5File UNUSED *file, const char UNUSED *name)
Reads a LALH5Dataset.
int XLALH5FileGetAttributeNames(LALH5File UNUSED *file, char UNUSED ***names, UINT4 UNUSED *N)
DEPRECATED: Gets attribute names from a LALH5File.
int XLALH5FileCheckGroupExists(const LALH5File UNUSED *file, const char UNUSED *name)
Checks for existence of a group in a LALH5File.
int XLALH5DatasetQueryData(void UNUSED *data, LALH5Dataset UNUSED *dset)
Gets the data contained in a LALH5Dataset.
int XLALH5DatasetWrite(LALH5Dataset UNUSED *dset, void UNUSED *data)
Writes data to a LALH5Dataset.
LIGOTimeGPS * XLALH5DatasetQueryLIGOTimeGPSAttributeValue(LIGOTimeGPS UNUSED *value, LALH5Dataset UNUSED *dset, const char UNUSED *key)
DEPRECATED: Gets the value of a LIGOTimeGPS attribute in a LALH5Dataset.
size_t XLALH5AttributeQueryN(const LALH5Generic UNUSED object)
Gets the number of attributes associated with a LALH5File or LALH5Dataset.
int XLALH5DatasetQueryNDim(LALH5Dataset UNUSED *dset)
Gets the number of dimensions of the dataspace in a LALH5Dataset.
int XLALH5FileQueryStringAttributeValue(char UNUSED *value, size_t UNUSED size, LALH5File UNUSED *file, const char UNUSED *key)
DEPRECATED: Gets the value of a string attribute in a LALH5File.
int XLALH5DatasetAddScalarAttribute(LALH5Dataset UNUSED *dset, const char UNUSED *key, const void UNUSED *value, LALTYPECODE UNUSED dtype)
DEPRECATED: Adds a scalar attribute to a LALH5Dataset.
int XLALH5AttributeQueryEnumArray1DValue(int UNUSED value[], const LALH5Generic UNUSED object, const char UNUSED *key)
Gets the values in a 1D enum array attribute in a LALH5File or LALH5Dataset.
size_t XLALH5FileQueryNGroups(const LALH5File UNUSED *file)
Gets the number of groups contained in a LALH5File.
int XLALH5TableRead(void UNUSED *data, const LALH5Dataset UNUSED *dset, const size_t UNUSED *offsets, const size_t UNUSED *colsz, size_t UNUSED rowsz)
Reads table data from a LALH5Dataset.
LALTYPECODE XLALH5TableQueryColumnType(const LALH5Dataset UNUSED *dset, int UNUSED pos)
Gets the type of data stored in a column in a LALH5Dataset containing table data.
int XLALH5TableReadColumns(void UNUSED *data, const LALH5Dataset UNUSED *dset, const char UNUSED *cols, const size_t UNUSED *offsets, const size_t UNUSED *colsz, size_t UNUSED row0, size_t UNUSED nrows, size_t UNUSED rowsz)
Reads certain columns of table data from a LALH5Dataset.
size_t XLALH5TableQueryRowSize(const LALH5Dataset UNUSED *dset)
Gets the number of bytes in a row in a LALH5Dataset containing table data.
size_t XLALH5TableQueryNColumns(const LALH5Dataset UNUSED *dset)
Gets the number of columns in a LALH5Dataset containing table data.
size_t XLALH5TableQueryNRows(const LALH5Dataset UNUSED *dset)
Gets the number of rows in a LALH5Dataset containing table data.
int XLALH5TableQueryColumnName(char UNUSED *name, size_t UNUSED size, const LALH5Dataset UNUSED *dset, int UNUSED pos)
Gets the name of a column in a LALH5Dataset containing table data.
int XLALH5TableAppend(LALH5Dataset UNUSED *dset, const size_t UNUSED *offsets, const size_t UNUSED *colsz, size_t UNUSED nrows, size_t UNUSED rowsz, const void UNUSED *data)
Appends rows of data to a LALH5Dataset dataset holding a table.
int XLALH5TableReadRows(void UNUSED *data, const LALH5Dataset UNUSED *dset, const size_t UNUSED *offsets, const size_t UNUSED *colsz, size_t UNUSED row0, size_t UNUSED nrows, size_t UNUSED rowsz)
Reads certain rows of table data from a LALH5Dataset.
LALH5Dataset * XLALH5TableAlloc(LALH5File UNUSED *file, const char UNUSED *name, size_t UNUSED ncols, const char UNUSED **cols, const LALTYPECODE UNUSED *types, const size_t UNUSED *offsets, size_t UNUSED rowsz)
Allocates a LALH5Dataset dataset to hold a table.
size_t XLALH5TableQueryColumnSize(const LALH5Dataset UNUSED *dset, int UNUSED pos)
Gets the size in bytes of a column in a LALH5Dataset containing table data.
size_t XLALH5TableQueryColumnOffset(const LALH5Dataset UNUSED *dset, int UNUSED pos)
Gets the offset of the data in a column in a LALH5Dataset containing table data.
LALTYPECODE
Type codes: use these type codes to identify a LAL atomic data type, see Headers LAL(Atomic)Datatypes...
Definition: LALDatatypes.h:49
uint32_t UINT4
Four-byte unsigned integer.
@ LAL_UNSGN_TYPE_FLAG
Unsigned (vs signed) type 0100000 = 32.
Definition: LALDatatypes.h:45
@ LAL_FLTPT_TYPE_FLAG
Floating-point (vs integer) type 01000 = 8.
Definition: LALDatatypes.h:43
@ LAL_CMPLX_TYPE_FLAG
Complex (vs real) type 010000 = 16.
Definition: LALDatatypes.h:44
@ LAL_C_TYPE_CODE
COMPLEX8 type code (27)
Definition: LALDatatypes.h:60
@ LAL_CHAR_TYPE_CODE
CHAR type code (0)
Definition: LALDatatypes.h:50
@ LAL_U2_TYPE_CODE
UINT2 type code (33)
Definition: LALDatatypes.h:55
@ LAL_Z_TYPE_CODE
COMPLEX16 type code (28)
Definition: LALDatatypes.h:61
@ LAL_S_TYPE_CODE
REAL4 type code (18)
Definition: LALDatatypes.h:58
@ LAL_I2_TYPE_CODE
INT2 type code (1)
Definition: LALDatatypes.h:51
@ LAL_I8_TYPE_CODE
INT8 type code (3)
Definition: LALDatatypes.h:53
@ LAL_D_TYPE_CODE
REAL8 type code (19)
Definition: LALDatatypes.h:59
@ LAL_I4_TYPE_CODE
INT4 type code (2)
Definition: LALDatatypes.h:52
@ LAL_UCHAR_TYPE_CODE
UCHAR type code (32)
Definition: LALDatatypes.h:54
@ LAL_U8_TYPE_CODE
UINT8 type code (35)
Definition: LALDatatypes.h:57
@ LAL_U4_TYPE_CODE
UINT4 type code (34)
Definition: LALDatatypes.h:56
@ LAL_4_BYTE_TYPE_SIZE
Four byte size 010 = 2.
Definition: LALDatatypes.h:35
@ LAL_2_BYTE_TYPE_SIZE
Two byte size 01 = 1.
Definition: LALDatatypes.h:34
@ LAL_8_BYTE_TYPE_SIZE
Eight byte size 011 = 3.
Definition: LALDatatypes.h:36
@ LAL_16_BYTE_TYPE_SIZE
Sixteen byte size 0100 = 4.
Definition: LALDatatypes.h:37
@ LAL_1_BYTE_TYPE_SIZE
One byte size 00 = 0.
Definition: LALDatatypes.h:33
@ LAL_TYPE_SIZE_MASK
Type size mask 0111 = 7.
Definition: LALDatatypes.h:38
#define XLALMalloc(n)
Definition: LALMalloc.h:44
#define XLALFree(p)
Definition: LALMalloc.h:47
size_t XLALStringCopy(char *dst, const char *src, size_t size)
Copy sources string src to destination string dst.
Definition: LALString.c:104
int XLALStringNCaseCompare(const char *s1, const char *s2, size_t n)
Compare the first N characters of two strings, ignoring case and without using locale-dependent funct...
Definition: LALString.c:219
UINT4Vector * XLALCreateUINT4Vector(UINT4 length)
#define XLAL_ERROR_VOID(...)
Macro to invoke a failure from a XLAL routine returning void.
Definition: XLALError.h:726
#define XLAL_ERROR_VAL(val,...)
Macro to invoke the XLALError() function and return with code val (it should not really be used itsel...
Definition: XLALError.h:687
#define XLAL_ERROR_NULL(...)
Macro to invoke a failure from a XLAL routine returning a pointer.
Definition: XLALError.h:713
#define XLAL_ERROR(...)
Macro to invoke a failure from a XLAL routine returning an integer.
Definition: XLALError.h:700
#define XLAL_PRINT_DEPRECATION_WARNING(replacement)
Prints a deprecation warning at the "warning" verbosity level.
Definition: XLALError.h:228
@ XLAL_ENOMEM
Memory allocation error.
Definition: XLALError.h:407
@ XLAL_SUCCESS
Success return value (not an error number)
Definition: XLALError.h:401
@ XLAL_EFAULT
Invalid pointer.
Definition: XLALError.h:408
@ XLAL_EFUNC
Internal function call failed bit: "or" this with existing error number.
Definition: XLALError.h:462
@ XLAL_ETYPE
Wrong or unknown type.
Definition: XLALError.h:422
@ XLAL_EIO
I/O error.
Definition: XLALError.h:406
@ XLAL_EINVAL
Invalid argument.
Definition: XLALError.h:409
@ XLAL_EFAILED
Generic failure.
Definition: XLALError.h:418
Epoch relative to GPS epoch, see LIGOTimeGPS type for more details.
Definition: LALDatatypes.h:458
Vector of type UINT4, see DATATYPE-Vector types for more details.
Definition: LALDatatypes.h:118
UINT4 * data
Pointer to the data array.
Definition: LALDatatypes.h:123
Incomplete type for a pointer to an HDF5 file or group or dataset.
Definition: H5FileIO.h:110