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