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