Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
file.c
Go to the documentation of this file.
1 /**
2  * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3  * storing and accessing finite element mesh data.
4  *
5  * Copyright 2004 Sandia Corporation. Under the terms of Contract
6  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7  * retains certain rights in this software.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  */
15 
16 #include <stdlib.h>
17 #include <string.h>
18 #include <assert.h>
19 #include <H5Fpublic.h>
20 #include <H5Ppublic.h>
21 #include <H5Gpublic.h>
22 #include <H5Spublic.h>
23 #include <H5Tpublic.h>
24 #include <H5Apublic.h>
25 #ifdef MOAB_HAVE_HDF5_PARALLEL
26 #include <H5FDmpi.h>
27 #include <H5FDmpio.h>
28 #endif
29 #include "mhdf.h"
30 #include "status.h"
31 #include "names-and-paths.h"
32 #include "util.h"
33 #include "file-handle.h"
34 
35 static int make_hdf_group( const char* path, hid_t file, size_t size, mhdf_Status* status );
36 
37 mhdf_FileHandle mhdf_createFile( const char* filename,
38  int overwrite,
39  const char** elem_type_list,
40  size_t elem_list_len,
41  hid_t id_type,
42  mhdf_Status* status )
43 {
44  FileHandle* file_ptr;
45  unsigned int flags;
46  unsigned char idx;
47  size_t i;
48  hid_t enum_id, group_id;
49  int rval;
50  API_BEGIN;
51 
52  if( elem_list_len > 255 )
53  {
54  mhdf_setFail( status, "Element type list too long." );
55  return NULL;
56  }
57  mhdf_setOkay( status );
58 
59  /* Create struct to hold working data */
60  file_ptr = mhdf_alloc_FileHandle( 0, id_type, status );
61  if( !file_ptr ) return NULL;
62 
63  /* Create the file */
64  flags = overwrite ? H5F_ACC_TRUNC : H5F_ACC_EXCL;
65  file_ptr->hdf_handle = H5Fcreate( filename, flags, H5P_DEFAULT, H5P_DEFAULT );
66  if( file_ptr->hdf_handle < 0 )
67  {
68  mhdf_setFail( status, "Failed to create file \"%s\"", filename );
69  free( file_ptr );
70  return NULL;
71  }
72 
73  /* Create file structure */
74  if( !make_hdf_group( ROOT_GROUP, file_ptr->hdf_handle, 6, status ) ||
75  !make_hdf_group( TAG_GROUP, file_ptr->hdf_handle, 0, status ) ||
76  !make_hdf_group( ELEMENT_GROUP, file_ptr->hdf_handle, 8, status ) ||
77  !make_hdf_group( NODE_GROUP, file_ptr->hdf_handle, 3, status ) ||
78  !make_hdf_group( SET_GROUP, file_ptr->hdf_handle, 5, status ) ||
79  !make_hdf_group( NODE_TAG_GROUP, file_ptr->hdf_handle, 0, status ) ||
80  !make_hdf_group( SET_TAG_GROUP, file_ptr->hdf_handle, 0, status ) )
81  {
82  H5Fclose( file_ptr->hdf_handle );
83  free( file_ptr );
84  return NULL;
85  }
86 
87  /* Store the max ID as an attribite on the /tstt/ group */
88 #if defined( H5Gopen_vers ) && H5Gopen_vers > 1
89  group_id = H5Gopen2( file_ptr->hdf_handle, ROOT_GROUP, H5P_DEFAULT );
90 #else
91  group_id = H5Gopen( file_ptr->hdf_handle, ROOT_GROUP );
92 #endif
93  rval = mhdf_create_scalar_attrib( group_id, MAX_ID_ATTRIB, H5T_NATIVE_ULONG, &file_ptr->max_id, status );
94  H5Gclose( group_id );
95  if( !rval )
96  {
97  H5Fclose( file_ptr->hdf_handle );
98  free( file_ptr );
99  return NULL;
100  }
101 
102  /* Create the type name list in file */
103  enum_id = H5Tenum_create( H5T_NATIVE_UCHAR );
104  if( enum_id < 0 )
105  {
106  mhdf_setFail( status, "Failed to store elem type list." );
107  H5Fclose( file_ptr->hdf_handle );
108  free( file_ptr );
109  return NULL;
110  }
111  for( i = 0; i < elem_list_len; ++i )
112  {
113  if( !elem_type_list[i] || !*elem_type_list[i] ) continue;
114 
115  idx = (unsigned char)i;
116  if( H5Tenum_insert( enum_id, elem_type_list[i], &idx ) < 0 )
117  {
118  mhdf_setFail( status, "Failed to store elem type list." );
119  H5Fclose( file_ptr->hdf_handle );
120  free( file_ptr );
121  return NULL;
122  }
123  }
124 #if defined( H5Tcommit_vers ) && H5Tcommit_vers > 1
125  if( H5Tcommit2( file_ptr->hdf_handle, TYPE_ENUM_PATH, enum_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT ) < 0 )
126 #else
127  if( H5Tcommit( file_ptr->hdf_handle, TYPE_ENUM_PATH, enum_id ) < 0 )
128 #endif
129  {
130  mhdf_setFail( status, "Failed to store elem type list." );
131  H5Fclose( file_ptr->hdf_handle );
132  free( file_ptr );
133  return NULL;
134  }
135  H5Tclose( enum_id );
136 
137  API_END_H( 1 );
138  return file_ptr;
139 }
140 
141 mhdf_FileHandle mhdf_openFile( const char* filename,
142  int writeable,
143  unsigned long* max_id_out,
144  hid_t id_type,
145  mhdf_Status* status )
146 {
147  return mhdf_openFileWithOpt( filename, writeable, max_id_out, id_type, H5P_DEFAULT, status );
148 }
149 
151 {
152  return H5Fget_obj_count( ( (FileHandle*)file_handle )->hdf_handle, H5F_OBJ_ALL );
153 }
154 
155 static herr_t get_max_id( hid_t group_id, const char* subgroup, const char* datatable, unsigned long* data )
156 {
157  unsigned long id;
158  hid_t elem_id, conn_id, attr_id, space_id;
159  herr_t rval;
160  int rank;
161  hsize_t dims[2];
162 
163 #if defined( H5Gopen_vers ) && H5Gopen_vers > 1
164  elem_id = H5Gopen2( group_id, subgroup, H5P_DEFAULT );
165 #else
166  elem_id = H5Gopen( group_id, subgroup );
167 #endif
168  if( elem_id < 0 ) return (herr_t)-1;
169 
170 #if defined( H5Dopen_vers ) && H5Dopen_vers > 1
171  conn_id = H5Dopen2( elem_id, datatable, H5P_DEFAULT );
172 #else
173  conn_id = H5Dopen( elem_id, datatable );
174 #endif
175  H5Gclose( elem_id );
176  if( conn_id < 0 ) return (herr_t)-1;
177 
178  space_id = H5Dget_space( conn_id );
179  if( space_id < 0 )
180  {
181  H5Dclose( conn_id );
182  return -1;
183  }
184 
185  rank = H5Sget_simple_extent_ndims( space_id );
186  if( rank <= 0 || rank > 2 )
187  {
188  H5Dclose( conn_id );
189  H5Sclose( space_id );
190  return -1;
191  }
192 
193  rval = H5Sget_simple_extent_dims( space_id, dims, NULL );
194  H5Sclose( space_id );
195  if( rval < 0 )
196  {
197  H5Dclose( conn_id );
198  return -1;
199  }
200 
201  attr_id = H5Aopen_name( conn_id, START_ID_ATTRIB );
202  H5Dclose( conn_id );
203  if( attr_id < 0 ) return (herr_t)-1;
204 
205  rval = H5Aread( attr_id, H5T_NATIVE_ULONG, &id );
206  H5Aclose( attr_id );
207  if( rval < 0 ) return rval;
208 
209  id += dims[0];
210  if( id > *data ) *data = id;
211  return 0;
212 }
213 
214 static herr_t max_id_iter( hid_t group_id, const char* name, void* data )
215 {
216  return get_max_id( group_id, name, CONNECTIVITY_NAME, (unsigned long*)data );
217 }
218 
219 static int scan_for_max_id( FileHandle* file_ptr, mhdf_Status* status )
220 {
221  hid_t group_id;
222  herr_t rval;
223 
224  /* Check for new format, with max_id as attrib of root group */
225 #if defined( H5Gopen_vers ) && H5Gopen_vers > 1
226  group_id = H5Gopen2( file_ptr->hdf_handle, ROOT_GROUP, H5P_DEFAULT );
227 #else
228  group_id = H5Gopen( file_ptr->hdf_handle, ROOT_GROUP );
229 #endif
230  if( group_id < 0 )
231  {
232  mhdf_setFail( status, "Internal error - invalid file." );
233  return 0;
234  }
235  if( mhdf_read_scalar_attrib( group_id, MAX_ID_ATTRIB, H5T_NATIVE_ULONG, &file_ptr->max_id, status ) )
236  {
237  H5Gclose( group_id );
238  return 1;
239  }
240 
241  /* Didn't find it, scan the elements group */
242  rval = H5Giterate( group_id, ELEMENT_GROUP_NAME, 0, &max_id_iter, &file_ptr->max_id );
243  if( rval )
244  {
245  H5Gclose( group_id );
246  mhdf_setFail( status, "Internal error -- invalid file." );
247  return 0;
248  }
249 
250  /* Check node table too */
251  rval = get_max_id( group_id, NODE_GROUP_NAME, "coordinates", (unsigned long*)( &file_ptr->max_id ) );
252  if( rval )
253  {
254  H5Gclose( group_id );
255  mhdf_setFail( status, "Internal error -- invalid file." );
256  return 0;
257  }
258 
259  /* Check set table, if it exists */
260  rval = mhdf_is_in_group( group_id, SET_GROUP_NAME, status );
261  if( rval < 1 )
262  {
263  H5Gclose( group_id );
264  return !rval;
265  }
266  rval = get_max_id( group_id, SET_GROUP_NAME, SET_META_NAME, (unsigned long*)( &file_ptr->max_id ) );
267  H5Gclose( group_id );
268  if( rval )
269  {
270  mhdf_setFail( status, "Internal error -- invalid file." );
271  return 0;
272  }
273 
274  return 1;
275 }
276 
277 mhdf_FileHandle mhdf_openFileWithOpt( const char* filename,
278  int writable,
279  unsigned long* max_id_out,
280  hid_t id_type,
281  hid_t access_prop,
282  mhdf_Status* status )
283 {
284  FileHandle* file_ptr;
285  unsigned int flags;
286  hid_t group_id;
287  int check_is_hdf5 = 1;
288 #ifdef MOAB_HAVE_HDF5_PARALLEL
289  herr_t err;
290  MPI_Comm comm;
291  MPI_Info info;
292 #endif
293  API_BEGIN;
294 
295  /* Check if file is HDF5 */
296  /* Don't do this because it can't handle MPI-IO driver code that
297  passes options via prefixes on the file name. */
298 #ifdef MOAB_HAVE_HDF5_PARALLEL
299  if( access_prop != H5P_DEFAULT )
300  {
301  err = H5Pget_fapl_mpio( access_prop, &comm, &info );
302  if( err >= 0 )
303  {
304  check_is_hdf5 = 0;
305  /* MPI Documentation is inconsistent with regards to whether
306  or not the above call dup's these, but my testing with 1.8.3
307  indicates that at least for that version they are not.
308  MPI_Comm_free(&comm);
309  MPI_Info_free(&info); */
310  }
311  }
312 #endif
313  if( check_is_hdf5 && H5Fis_hdf5( filename ) <= 0 )
314  {
315  mhdf_setFail( status, "%s: File is not HDF5", filename );
316  return NULL;
317  }
318 
319  /* Create struct to hold working data */
320  file_ptr = mhdf_alloc_FileHandle( 0, id_type, status );
321  if( !file_ptr )
322  {
323  mhdf_setFail( status, "Memory allocation failed" );
324  return NULL;
325  }
326 
327  /* Create the file */
328  flags = writable ? H5F_ACC_RDWR : H5F_ACC_RDONLY;
329  file_ptr->hdf_handle = H5Fopen( filename, flags, access_prop );
330  if( file_ptr->hdf_handle < 0 )
331  {
332  mhdf_setFail( status, "Failed to open file \"%s\"", filename );
333  free( file_ptr );
334  return NULL;
335  }
336 
337  /* Check for TSTT data in file */
338 #if defined( H5Gopen_vers ) && H5Gopen_vers > 1
339  group_id = H5Gopen2( file_ptr->hdf_handle, ROOT_GROUP, H5P_DEFAULT );
340 #else
341  group_id = H5Gopen( file_ptr->hdf_handle, ROOT_GROUP );
342 #endif
343  if( group_id < 0 )
344  {
345  mhdf_setFail( status, "Invalid file \"%s\"\n", filename );
346  H5Fclose( file_ptr->hdf_handle );
347  free( file_ptr );
348  return NULL;
349  }
350  H5Gclose( group_id );
351 
352  /* Get max id */
353  if( !scan_for_max_id( file_ptr, status ) )
354  {
355  H5Fclose( file_ptr->hdf_handle );
356  mhdf_setFail( status, "Internal error reading file" );
357  free( file_ptr );
358  return NULL;
359  }
360 
361  if( max_id_out ) *max_id_out = file_ptr->max_id;
362 
363  mhdf_setOkay( status );
364  API_END_H( 1 );
365  return file_ptr;
366 }
367 
369  unsigned int type_index,
370  char* buffer,
371  size_t buf_size,
372  mhdf_Status* status )
373 {
374  FileHandle* file_ptr;
375  herr_t rval;
376  hid_t enum_id;
377  API_BEGIN;
378 
379  if( type_index > 255 )
380  {
381  mhdf_setFail( status, "Type index out of bounds." );
382  return;
383  }
384 
385  file_ptr = (FileHandle*)( file_handle );
386  if( !mhdf_check_valid_file( file_ptr, status ) ) return;
387 
388  enum_id = get_elem_type_enum( file_ptr, status );
389  if( enum_id < 0 ) return;
390 
391  rval = H5Tconvert( H5T_NATIVE_UINT, H5Tget_super( enum_id ), 1, &type_index, NULL, H5P_DEFAULT );
392  if( rval < 0 )
393  {
394  H5Tclose( enum_id );
395  mhdf_setFail( status, "Internal error converting to enum type." );
396  return;
397  }
398 
399  rval = H5Tenum_nameof( enum_id, &type_index, buffer, buf_size );
400  H5Tclose( enum_id );
401  if( rval < 0 )
402  mhdf_setFail( status, "H5Tenum_nameof failed. Invalid type index?" );
403  else
404  mhdf_setOkay( status );
405 
406  API_END;
407 }
408 
410 {
411  FileHandle* file_ptr;
412  int result;
413  API_BEGIN;
414 
415  file_ptr = (FileHandle*)( handle );
416  if( !mhdf_check_valid_file( file_ptr, status ) ) return -1;
417 
418  /* Check for open handles. HDF5 will not actually close the
419  file until all handles are closed. */
420  result = H5Fget_obj_count( file_ptr->hdf_handle, H5F_OBJ_ALL );
421  if( result != 1 )
422  {
423  mhdf_setFail( status,
424  "Cannot close file with open handles: "
425  "%d file, %d data, %d group, %d type, %d attr\n",
426  H5Fget_obj_count( file_ptr->hdf_handle, H5F_OBJ_FILE ) - 1,
427  H5Fget_obj_count( file_ptr->hdf_handle, H5F_OBJ_DATASET ),
428  H5Fget_obj_count( file_ptr->hdf_handle, H5F_OBJ_GROUP ),
429  H5Fget_obj_count( file_ptr->hdf_handle, H5F_OBJ_DATATYPE ),
430  H5Fget_obj_count( file_ptr->hdf_handle, H5F_OBJ_ATTR ) );
431  return result - 1;
432  }
433 
434  API_END_H( 0 );
435  return 0;
436 }
437 
439 {
440  FileHandle* file_ptr;
441  API_BEGIN;
442 
443  file_ptr = (FileHandle*)( handle );
444  if( !mhdf_check_valid_file( file_ptr, status ) ) return;
445  /*
446  if (file_ptr->open_handle_count)
447  {
448  mhdf_setError( status, "Cannot close file with %d open data handles.",
449  file_ptr->open_handle_count );
450  return;
451  }
452  */
453 
454  /* Check for open handles. HDF5 will not actually close the
455  file until all handles are closed. */
456  if( mhdf_checkOpenHandles( handle, status ) ) return;
457 
458  if( 0 > H5Fclose( file_ptr->hdf_handle ) )
459  {
460  mhdf_setFail( status, "H5FClose failed. Invalid handle?" );
461  return;
462  }
463 
464  memset( file_ptr, 0, sizeof( FileHandle ) );
465  free( file_ptr );
466  mhdf_setOkay( status );
467  API_END_H( -1 );
468 }
469 
470 void mhdf_closeData( mhdf_FileHandle file, hid_t handle, mhdf_Status* status )
471 {
472  FileHandle* file_ptr;
473  herr_t rval = -1;
474 
475  file_ptr = (FileHandle*)( file );
476  if( !mhdf_check_valid_file( file_ptr, status ) ) return;
477 
478  switch( H5Iget_type( handle ) )
479  {
480  case H5I_GROUP:
481  rval = H5Gclose( handle );
482  break;
483  case H5I_DATATYPE:
484  rval = H5Tclose( handle );
485  break;
486  case H5I_DATASPACE:
487  rval = H5Sclose( handle );
488  break;
489  case H5I_DATASET:
490  rval = H5Dclose( handle );
491  break;
492  default:
493  rval = -1;
494  }
495 
496  if( rval < 0 )
497  {
498  mhdf_setFail( status, "H5Xclose failed. Invalid handle?\n" );
499  }
500  else
501  {
502  file_ptr->open_handle_count--;
503  mhdf_setOkay( status );
504  }
505 }
506 
507 void mhdf_addElement( mhdf_FileHandle file_handle, const char* name, unsigned int elem_type, mhdf_Status* status )
508 {
509  FileHandle* file_ptr = (FileHandle*)file_handle;
510  hid_t group_id, tag_id, enum_id;
511  char *path, *ptr;
512  size_t name_len;
513  herr_t rval;
514  API_BEGIN;
515 
516  if( !mhdf_check_valid_file( file_ptr, status ) ) return;
517 
518  name_len = mhdf_name_to_path( name, NULL, 0 );
519  name_len += strlen( ELEMENT_GROUP ) + 1;
520  path = (char*)mhdf_malloc( name_len, status );
521  if( !path ) return;
522 
523  strcpy( path, ELEMENT_GROUP );
524  ptr = path + strlen( ELEMENT_GROUP );
525  if( !mhdf_path_to_name( name, ptr ) )
526  {
527  mhdf_setFail( status, "Invalid character string in internal file path: \"%s\"\n", name );
528  return;
529  }
530 
531 #if defined( H5Gcreate_vers ) && H5Gcreate_vers > 1
532  group_id = H5Gcreate2( file_ptr->hdf_handle, path, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
533 #else
534  group_id = H5Gcreate( file_ptr->hdf_handle, path, 3 );
535 #endif
536  if( group_id < 0 )
537  {
538  mhdf_setFail( status, "Creation of \"%s\" group failed.\n", path );
539  free( path );
540  return;
541  }
542  free( path );
543 
544 #if defined( H5Gcreate_vers ) && H5Gcreate_vers > 1
545  tag_id = H5Gcreate2( group_id, DENSE_TAG_SUBGROUP, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
546 #else
547  tag_id = H5Gcreate( group_id, DENSE_TAG_SUBGROUP, 0 );
548 #endif
549  if( tag_id < 0 )
550  {
551  H5Gclose( group_id );
552  mhdf_setFail( status, "Creation of tag subgroup failed.\n" );
553  return;
554  }
555  H5Gclose( tag_id );
556 
557  enum_id = get_elem_type_enum( file_ptr, status );
558  if( enum_id < 0 )
559  {
560  H5Gclose( group_id );
561  return;
562  }
563 
564  rval = H5Tconvert( H5T_NATIVE_UINT, H5Tget_super( enum_id ), 1, &elem_type, NULL, H5P_DEFAULT );
565  if( rval < 0 )
566  {
567  H5Gclose( group_id );
568  H5Tclose( enum_id );
569  mhdf_setFail( status, "Internal error converting to enum type." );
570  return;
571  }
572 
573  rval = mhdf_create_scalar_attrib( group_id, ELEM_TYPE_ATTRIB, enum_id, &elem_type, status );
574  H5Tclose( enum_id );
575  if( rval < 0 )
576  {
577  H5Gclose( group_id );
578  return;
579  }
580 
581  H5Gclose( group_id );
582  mhdf_setOkay( status );
583  API_END;
584 }
585 
586 char** mhdf_getElemHandles( mhdf_FileHandle file_handle, unsigned int* count_out, mhdf_Status* status )
587 {
588  hsize_t count, length, i;
589  char** buffer;
590  char* current;
591  hid_t group_id;
592  herr_t rval;
593  ssize_t rlen = 0;
594  size_t remaining;
595  FileHandle* file_ptr = (FileHandle*)file_handle;
596  if( !mhdf_check_valid_file( file_ptr, status ) ) return NULL;
597 
598 #if defined( H5Gopen_vers ) && H5Gopen_vers > 1
599  group_id = H5Gopen2( file_ptr->hdf_handle, ELEMENT_GROUP, H5P_DEFAULT );
600 #else
601  group_id = H5Gopen( file_ptr->hdf_handle, ELEMENT_GROUP );
602 #endif
603  if( group_id < 0 )
604  {
605  mhdf_setFail( status, "Invalid file -- element group does not exist." );
606  return NULL;
607  }
608 
609  rval = H5Gget_num_objs( group_id, &count );
610  if( rval < 0 )
611  {
612  H5Gclose( group_id );
613  mhdf_setFail( status, "Internal error calling H5Gget_num_objs." );
614  return NULL;
615  }
616  *count_out = count;
617 
618  for( i = 0; i < count; ++i )
619  {
620  rlen += H5Gget_objname_by_idx( group_id, i, NULL, 0 ) + 1;
621  }
622 
623  length = count * sizeof( char* ) + rlen;
624  buffer = (char**)mhdf_malloc( length, status );
625  if( !buffer )
626  {
627  H5Gclose( group_id );
628  return NULL;
629  }
630  current = (char*)( buffer + count );
631  remaining = rlen;
632 
633  for( i = 0; i < count; ++i )
634  {
635  buffer[i] = current;
636  rlen = H5Gget_objname_by_idx( group_id, i, current, remaining ) + 1;
637  if( rlen < 0 )
638  {
639  H5Gclose( group_id );
640  free( buffer );
641  mhdf_setFail( status, "Internal error calling H5Gget_objname_by_idx." );
642  return NULL;
643  }
644 
645  mhdf_path_to_name( current, current );
646  remaining -= rlen;
647  current += rlen;
648  }
649 
650  H5Gclose( group_id );
651  mhdf_setOkay( status );
652  return buffer;
653 }
654 
656  const char* elem_handle,
657  char* buffer,
658  size_t buf_len,
659  mhdf_Status* status )
660 {
661  FileHandle* file_ptr;
662  hid_t elem_id, type_id, attr_id;
663  char bytes[16];
664  herr_t rval;
665  API_BEGIN;
666 
667  if( NULL == buffer || buf_len < 2 )
668  {
669  mhdf_setFail( status, "invalid input" );
670  return;
671  }
672  buffer[0] = '\0';
673 
674  file_ptr = (FileHandle*)( file_handle );
675  if( !mhdf_check_valid_file( file_ptr, status ) ) return;
676 
677  elem_id = mhdf_elem_group_from_handle( file_ptr, elem_handle, status );
678  if( elem_id < 0 ) return;
679 
680  attr_id = H5Aopen_name( elem_id, ELEM_TYPE_ATTRIB );
681  H5Gclose( elem_id );
682  if( attr_id < 0 )
683  {
684  mhdf_setFail( status, "Missing element type attribute. Invalid file." );
685  return;
686  }
687 
688  type_id = H5Aget_type( attr_id );
689  assert( type_id > 0 );
690 
691  rval = H5Aread( attr_id, type_id, bytes );
692  H5Aclose( attr_id );
693  if( rval < 0 )
694  {
695  H5Tclose( type_id );
696  mhdf_setFail( status, "Failed to read element type attribute. Invalid file." );
697  return;
698  }
699 
700  rval = H5Tenum_nameof( type_id, bytes, buffer, buf_len );
701  H5Tclose( type_id );
702  if( rval < 0 )
703  {
704  mhdf_setFail( status, "Invalid datatype for element type attribute. Invalid file." );
705  return;
706  }
707 
708  mhdf_setOkay( status );
709  API_END;
710  return;
711 }
712 
713 static int make_hdf_group( const char* path, hid_t file, size_t sz, mhdf_Status* status )
714 {
715 #if defined( H5Gcreate_vers ) && H5Gcreate_vers > 1
716  hid_t handle = H5Gcreate2( file, path, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
717  /* empty statement to avoid compiler warning */
718  if( sz )
719  {
720  }
721 #else
722  hid_t handle = H5Gcreate( file, path, sz );
723 #endif
724  if( handle < 0 )
725  {
726  mhdf_setFail( status, "Failed to create \"%s\" group.", path );
727  return 0;
728  }
729  else
730  {
731  H5Gclose( handle );
732  return 1;
733  }
734 }
735 
736 const char* mhdf_node_type_handle( void )
737 {
738  static const char rval[] = "nodes";
739  return rval;
740 }
741 
742 const char* mhdf_set_type_handle( void )
743 {
744  static const char rval[] = "sets";
745  return rval;
746 }
747 
748 int mhdf_isPolyElement( mhdf_FileHandle file_handle, const char* elem_handle, mhdf_Status* status )
749 {
750  FileHandle* file_ptr;
751  hid_t elem_id;
752  int rval;
753  API_BEGIN;
754 
755  file_ptr = (FileHandle*)( file_handle );
756  if( !mhdf_check_valid_file( file_ptr, status ) ) return -1;
757 
758  elem_id = mhdf_elem_group_from_handle( file_ptr, elem_handle, status );
759  if( elem_id < 0 ) return -1;
760 
761  mhdf_setOkay( status );
762  rval = mhdf_is_in_group( elem_id, POLY_INDEX_NAME, status );
763  H5Gclose( elem_id );
764  API_END;
765  return rval;
766 }
767 
768 void mhdf_writeHistory( mhdf_FileHandle file_handle, const char** strings, int num_strings, mhdf_Status* status )
769 {
770  FileHandle* file_ptr;
771  hid_t data_id, type_id, space_id;
772  hsize_t dim = (hsize_t)num_strings;
773  herr_t rval;
774  API_BEGIN;
775 
776  file_ptr = (FileHandle*)( file_handle );
777  if( !mhdf_check_valid_file( file_ptr, status ) ) return;
778 
779  type_id = H5Tcopy( H5T_C_S1 );
780  if( type_id < 0 || H5Tset_size( type_id, H5T_VARIABLE ) < 0 )
781  {
782  if( type_id >= 0 ) H5Tclose( type_id );
783  mhdf_setFail( status, "Could not create variable length string type." );
784  return;
785  }
786 
787  space_id = H5Screate_simple( 1, &dim, NULL );
788  if( space_id < 0 )
789  {
790  H5Tclose( type_id );
791  mhdf_setFail( status, "H5Screate_simple failed." );
792  return;
793  }
794 
795 #if defined( H5Dcreate_vers ) && H5Dcreate_vers > 1
796  data_id =
797  H5Dcreate2( file_ptr->hdf_handle, HISTORY_PATH, type_id, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
798 #else
799  data_id = H5Dcreate( file_ptr->hdf_handle, HISTORY_PATH, type_id, space_id, H5P_DEFAULT );
800 #endif
801  H5Sclose( space_id );
802  if( data_id < 0 )
803  {
804  H5Tclose( type_id );
805  mhdf_setFail( status, "Failed to create \"%s\".", HISTORY_PATH );
806  return;
807  }
808 
809  rval = H5Dwrite( data_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, strings );
810  H5Dclose( data_id );
811  H5Tclose( type_id );
812  if( rval < 0 )
813  {
814  H5Gunlink( file_ptr->hdf_handle, HISTORY_PATH );
815  mhdf_setFail( status, "Failed to write history data." );
816  return;
817  }
818 
819  mhdf_setOkay( status );
820  API_END;
821 }
822 
823 char** mhdf_readHistory( mhdf_FileHandle file_handle, int* num_strings, mhdf_Status* status )
824 {
825  FileHandle* file_ptr;
826  hid_t data_id, type_id, space_id, group_id;
827  hsize_t dim;
828  herr_t rval;
829  char** array;
830  API_BEGIN;
831 
832  file_ptr = (FileHandle*)( file_handle );
833  if( !mhdf_check_valid_file( file_ptr, status ) ) return NULL;
834 
835  /* check if file contains history data */
836 #if defined( H5Gopen_vers ) && H5Gopen_vers > 1
837  group_id = H5Gopen2( file_ptr->hdf_handle, ROOT_GROUP, H5P_DEFAULT );
838 #else
839  group_id = H5Gopen( file_ptr->hdf_handle, ROOT_GROUP );
840 #endif
841  if( group_id < 0 )
842  {
843  mhdf_setFail( status, "Could not open root group. Invalid file." );
844  return NULL;
845  }
846 
847  rval = mhdf_is_in_group( group_id, HISTORY_NAME, status );
848  if( rval < 1 )
849  {
850  H5Gclose( group_id );
851  *num_strings = 0;
852  if( 0 == rval ) mhdf_setOkay( status );
853  return NULL;
854  }
855 
856 #if defined( H5Dopen_vers ) && H5Dopen_vers > 1
857  data_id = H5Dopen2( group_id, HISTORY_NAME, H5P_DEFAULT );
858 #else
859  data_id = H5Dopen( group_id, HISTORY_NAME );
860 #endif
861  H5Gclose( group_id );
862  if( data_id < 0 )
863  {
864  mhdf_setFail( status, "Failed to open \"%s\".", HISTORY_PATH );
865  return NULL;
866  }
867 
868  space_id = H5Dget_space( data_id );
869  if( space_id < 0 )
870  {
871  H5Dclose( data_id );
872  mhdf_setFail( status, "Internal error calling H5Dget_space." );
873  return NULL;
874  }
875 
876  if( 1 != H5Sget_simple_extent_ndims( space_id ) || 1 != H5Sget_simple_extent_dims( space_id, &dim, NULL ) )
877  {
878  H5Dclose( data_id );
879  mhdf_setFail( status, "Invalid dimension for \"%s\".", HISTORY_PATH );
880  return NULL;
881  }
882  H5Sclose( space_id );
883 
884  if( 0 == dim )
885  {
886  H5Dclose( data_id );
887  *num_strings = 0;
888  mhdf_setOkay( status );
889  return NULL;
890  }
891 
892  array = (char**)mhdf_malloc( dim * sizeof( char* ), status );
893  if( !array )
894  {
895  H5Dclose( data_id );
896  return NULL;
897  }
898 
899  type_id = H5Tcopy( H5T_C_S1 );
900  if( type_id < 0 || H5Tset_size( type_id, H5T_VARIABLE ) < 0 )
901  {
902  H5Dclose( data_id );
903  if( type_id >= 0 ) H5Tclose( type_id );
904  mhdf_setFail( status, "Could not create variable length string type." );
905  free( array );
906  return NULL;
907  }
908 
909  rval = H5Dread( data_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, array );
910  H5Tclose( type_id );
911  H5Dclose( data_id );
912  if( rval < 0 )
913  {
914  free( array );
915  mhdf_setFail( status, "H5Dread failed." );
916  return NULL;
917  }
918 
919  *num_strings = dim;
920  mhdf_setOkay( status );
921  API_END;
922  return array;
923 }
924 
925 void mhdf_getNextStartId( mhdf_FileHandle file, mhdf_index_t* start_id_out, mhdf_Status* status )
926 {
927  FileHandle* file_ptr = (FileHandle*)file;
928  API_BEGIN;
929 
930  mhdf_setOkay( status );
931  if( mhdf_check_valid_file( file_ptr, status ) ) *start_id_out = file_ptr->max_id + 1;
932 
933  API_END;
934 }