1
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
60 file_ptr = mhdf_alloc_FileHandle( 0, id_type, status );
61 if( !file_ptr ) return NULL;
62
63
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
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
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
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
150 int mhdf_countOpenHandles( mhdf_FileHandle file_handle )
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
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
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
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
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
296
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
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
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
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
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
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
368 void mhdf_getElemName( mhdf_FileHandle file_handle,
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
409 int mhdf_checkOpenHandles( mhdf_FileHandle handle, mhdf_Status* status )
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
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
438 void mhdf_closeFile( mhdf_FileHandle handle, mhdf_Status* status )
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
453
454
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
655 void mhdf_getElemTypeName( mhdf_FileHandle file_handle,
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
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
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 }