1
15
16 #include <stdlib.h>
17 #include <string.h>
18 #include <assert.h>
19 #include <ctype.h>
20 #include <hdf5.h>
21 #include "util.h"
22 #include "status.h"
23 #include "names-and-paths.h"
24
25 #ifdef VALGRIND
26 #include <valgrind/memcheck.h>
27 #else
28 #define VALGRIND_CHECK_MEM_IS_DEFINED( A, B )
29 #define VALGRIND_MAKE_MEM_UNDEFINED( A, B )
30 #endif
31
32 void* mhdf_malloc( size_t size, mhdf_Status* status )
33 {
34 void* result;
35 result = malloc( size );
36 if( !result ) mhdf_setFail( status, "Allocation of %d bytes failed.\n", (int)size );
37 return result;
38 }
39
40 void* mhdf_realloc( void* ptr, size_t size, mhdf_Status* status )
41 {
42 void* result;
43 result = realloc( ptr, size );
44 if( !result ) mhdf_setFail( status, "Allocation of %d bytes failed.\n", (int)size );
45 return result;
46 }
47
48 size_t mhdf_name_to_path( const char* name, char* path, size_t path_len )
49 {
50 size_t length = 1;
51 unsigned char* iter;
52
53 if( 0 == strcmp( name, "." ) )
54 {
55 if( path_len >= 4 ) sprintf( path, "\\%02X", (int)*name );
56 return 4;
57 }
58
59 for( iter = (unsigned char*)name; *iter; ++iter )
60 {
61 if( iscntrl( *iter ) || *iter == '/' || *iter == '\\' || *iter > 127 )
62 length += 3;
63 else
64 length += 1;
65 }
66 if( path_len < length ) return length;
67
68 for( iter = (unsigned char*)name; *iter; ++iter )
69 {
70 if( iscntrl( *iter ) || *iter == '/' || *iter == '\\' || *iter > 127 )
71 {
72 sprintf( path, "\\%02X", (int)( *iter ) );
73 path += 3;
74 }
75 else
76 {
77 *( path++ ) = *iter;
78 }
79 }
80
81 *path = '\0';
82 return length;
83 }
84
85 static int mhdf_hex_char( int c )
86 {
87 if( isdigit( c ) )
88 return c - '0';
89 else
90 return toupper( c ) - ( 'A' - 10 );
91 }
92
93 int mhdf_path_to_name( const char* path, char* name )
94 {
95 const char* iter;
96 char c1, c2;
97
98 for( iter = path; *iter; ++iter, ++name )
99 {
100 if( *iter == '\\' )
101 {
102 c1 = *++iter;
103 c2 = *++iter;
104 if( !isxdigit( c1 ) || !isxdigit( c2 ) ) return 0;
105
106 *name = (char)( 16 * mhdf_hex_char( c1 ) + mhdf_hex_char( c2 ) );
107 }
108 else
109 {
110 *name = *iter;
111 }
112 }
113
114 *name = '\0';
115 return 1;
116 }
117
118 char* mhdf_name_to_path_copy( const char* name, mhdf_Status* status )
119 {
120 size_t size;
121 char* buffer;
122
123 size = mhdf_name_to_path( name, NULL, 0 );
124 buffer = (char*)mhdf_malloc( size, status );
125 if( !buffer ) return NULL;
126
127 mhdf_name_to_path( name, buffer, size );
128 return buffer;
129 }
130
131 char* mhdf_name_to_path_cat( const char* prefix, const char* name, mhdf_Status* status )
132 {
133 size_t size, plen;
134 char* buffer;
135
136 plen = strlen( prefix );
137 size = mhdf_name_to_path( name, NULL, 0 ) + 1;
138 buffer = (char*)mhdf_malloc( size + plen, status );
139 if( !buffer ) return NULL;
140
141 memcpy( buffer, prefix, plen );
142 mhdf_name_to_path( name, buffer + plen, size );
143 return buffer;
144 }
145
146 hid_t mhdf_elem_group_from_handle( FileHandle* file_ptr, const char* elem_handle, mhdf_Status* status )
147 {
148 char* path;
149 hid_t result;
150
151 path = mhdf_name_to_path_cat( ELEMENT_GROUP, elem_handle, status );
152 if( NULL == path ) return -1;
153
154 #if defined( H5Gopen_vers ) && H5Gopen_vers > 1
155 result = H5Gopen2( file_ptr->hdf_handle, path, H5P_DEFAULT );
156 #else
157 result = H5Gopen( file_ptr->hdf_handle, path );
158 #endif
159 free( path );
160 if( result < 0 ) mhdf_setFail( status, "Failed to open element group: \"%s\"", elem_handle );
161 return result;
162 }
163
164 int mhdf_create_scalar_attrib( hid_t object, const char* name, hid_t type, const void* value, mhdf_Status* status )
165 {
166 hid_t dspace_id, attr_id;
167 herr_t rval;
168
169 dspace_id = H5Screate( H5S_SCALAR );
170 if( dspace_id < 0 )
171 {
172 mhdf_setFail( status, "Internal error calling H5Screate_simple." );
173 return 0;
174 }
175
176 #if defined( H5Acreate_vers ) && H5Acreate_vers > 1
177 attr_id = H5Acreate2( object, name, type, dspace_id, H5P_DEFAULT, H5P_DEFAULT );
178 #else
179 attr_id = H5Acreate( object, name, type, dspace_id, H5P_DEFAULT );
180 #endif
181 H5Sclose( dspace_id );
182 if( attr_id < 0 )
183 {
184 mhdf_setFail( status, "Failed to create \"%s\" attrib.", name );
185 return 0;
186 }
187
188 VALGRIND_CHECK_MEM_IS_DEFINED( value, H5Tget_size( type ) );
189 rval = H5Awrite( attr_id, type, value );
190 H5Aclose( attr_id );
191 if( rval < 0 )
192 {
193 mhdf_setFail( status, "Failed to write \"%s\" attrib.", name );
194 return 0;
195 }
196
197 return 1;
198 }
199
200 int mhdf_read_scalar_attrib( hid_t object, const char* name, hid_t type, void* value, mhdf_Status* status )
201 {
202 hid_t attr_id, type_id;
203 herr_t rval;
204
205 attr_id = H5Aopen_name( object, name );
206 if( attr_id < 0 )
207 {
208 mhdf_setFail( status, "Failed to create \"%s\" attrib.", name );
209 return 0;
210 }
211
212 if( type > 0 )
213 {
214 type_id = type;
215 }
216 else
217 {
218 type_id = H5Aget_type( attr_id );
219 if( type_id < 0 )
220 {
221 H5Aclose( attr_id );
222 return 0;
223 }
224 }
225
226 rval = H5Aread( attr_id, type_id, value );
227 H5Aclose( attr_id );
228 if( type < 1 ) H5Tclose( type_id );
229 if( rval < 0 )
230 {
231 mhdf_setFail( status, "Failed to read \"%s\" attrib.", name );
232 return 0;
233 }
234
235 return 1;
236 }
237
238 #if defined( H5Aiterate_vers ) && H5Aiterate_vers > 1
239 static herr_t find_attr_by_name( hid_t handle, const char* name, const H5A_info_t* info, void* mydata )
240 {
241
242 if( info )
243 {
244 }
245 #else
246 static herr_t find_attr_by_name( hid_t handle, const char* name, void* mydata )
247 {
248 #endif
249
250 if( handle )
251 {
252 }
253 return !strcmp( name, (const char*)mydata );
254 }
255
256 int mhdf_find_attribute( hid_t object, const char* attrib_name, unsigned int* index_out, mhdf_Status* status )
257 {
258 herr_t rval;
259 #if defined( H5Aiterate_vers ) && H5Aiterate_vers > 1
260 hsize_t idx = 0;
261 rval = H5Aiterate2( object, H5_INDEX_CRT_ORDER, H5_ITER_NATIVE, &idx, &find_attr_by_name, (void*)attrib_name );
262 *index_out = (unsigned int)idx;
263 #else
264 *index_out = 0;
265 rval = H5Aiterate( object, index_out, &find_attr_by_name, (void*)attrib_name );
266 #endif
267 if( rval < 0 ) mhdf_setFail( status, "Internal error calling H5Aiterate." );
268 return (int)rval;
269 }
270
271 static herr_t find_link_by_name( hid_t handle, const char* name, void* mydata )
272 {
273
274 if( handle )
275 {
276 }
277 return !strcmp( name, (const char*)mydata );
278 }
279
280 int mhdf_is_in_group( hid_t group, const char* name, mhdf_Status* status )
281 {
282 int rval;
283 rval = H5Giterate( group, ".", NULL, &find_link_by_name, (void*)name );
284 if( rval < 0 ) mhdf_setFail( status, "Internal error in H5Giterate." );
285 return rval;
286 }
287
288 static int mhdf_readwrite( hid_t data_id,
289 int read,
290 long offset,
291 long count,
292 hid_t type,
293 void* array,
294 hid_t io_prop,
295 mhdf_Status* status )
296 {
297 hid_t slab_id, mem_id;
298 hsize_t offsets[2], counts[2] = { 1, 1 };
299 herr_t rval;
300 int dims;
301
302 const hsize_t one = 1;
303
304
305 if( offset < 0 || count < 0 )
306 {
307 mhdf_setFail( status,
308 "Invalid input for %s: "
309 "offset = %ld, count = %ld\n",
310 read ? "read" : "write", offset, count );
311 return 0;
312 }
313
314 slab_id = H5Dget_space( data_id );
315 if( slab_id < 0 )
316 {
317 mhdf_setFail( status, "Internal error calling H5Dget_space." );
318 return 0;
319 }
320
321 dims = H5Sget_simple_extent_ndims( slab_id );
322 if( dims < 1 || dims > 2 )
323 {
324 H5Sclose( slab_id );
325 mhdf_setFail( status, "Internal error: unexpected dataset rank: %d.", dims );
326 return 0;
327 }
328
329 dims = H5Sget_simple_extent_dims( slab_id, counts, NULL );
330 if( dims < 0 )
331 {
332 H5Sclose( slab_id );
333 mhdf_setFail( status, "Internal error calling H5Sget_simple_extend_dims." );
334 return 0;
335 }
336
337 if( (unsigned long)( offset + count ) > counts[0] )
338 {
339 H5Sclose( slab_id );
340 mhdf_setFail( status, "Requested %s of rows %ld to %ld of a %ld row table.\n", read ? "read" : "write", offset,
341 offset + count - 1, (long)counts[dims - 1] );
342 return 0;
343 }
344
345 counts[0] = (hsize_t)count;
346 offsets[0] = (hsize_t)offset;
347 offsets[1] = 0;
348 if( count )
349 rval = H5Sselect_hyperslab( slab_id, H5S_SELECT_SET, offsets, NULL, counts, NULL );
350 else
351 rval = H5Sselect_none( slab_id );
352 if( rval < 0 )
353 {
354 H5Sclose( slab_id );
355 mhdf_setFail( status, "Internal error calling H5Sselect_hyperslab." );
356 return 0;
357 }
358
359 if( count )
360 mem_id = H5Screate_simple( dims, counts, NULL );
361 else
362 {
363
366 mem_id = H5Screate_simple( 1, &one, NULL );
367 if( mem_id && 0 > H5Sselect_none( mem_id ) )
368 {
369 H5Sclose( mem_id );
370 mem_id = -1;
371 }
372
373 }
374
375 if( mem_id < 0 )
376 {
377 H5Sclose( slab_id );
378 mhdf_setFail( status, "Internal error calling H5Screate_simple." );
379 return 0;
380 }
381
382 if( read )
383 rval = H5Dread( data_id, type, mem_id, slab_id, io_prop, array );
384 else
385 {
386 VALGRIND_CHECK_MEM_IS_DEFINED( array, counts[0] * counts[1] * H5Tget_size( type ) );
387 rval = H5Dwrite( data_id, type, mem_id, slab_id, io_prop, array );
388 }
389 H5Sclose( slab_id );
390 H5Sclose( mem_id );
391 if( rval < 0 )
392 {
393 mhdf_setFail( status, "Internal error calling H5D%s.", read ? "read" : "write" );
394 return 0;
395 }
396
397 mhdf_setOkay( status );
398 return 1;
399 }
400
401 static int mhdf_readwrite_column( hid_t data_id,
402 int read,
403 int column,
404 long offset,
405 long count,
406 hid_t type,
407 void* array,
408 hid_t io_prop,
409 mhdf_Status* status )
410 {
411 hid_t slab_id, mem_id;
412 hsize_t offsets[2], counts[2];
413 herr_t rval;
414 int dims;
415
416 const hsize_t one = 1;
417
418
419 if( column < 0 || offset < 0 || count < 0 )
420 {
421 mhdf_setFail( status,
422 "Invalid input for %s: "
423 "column = %d, offset = %ld, count = %ld\n",
424 read ? "read" : "write", column, offset, count );
425 return 0;
426 }
427
428 slab_id = H5Dget_space( data_id );
429 if( slab_id < 0 )
430 {
431 mhdf_setFail( status, "Internal error calling H5Dget_space." );
432 return 0;
433 }
434
435 dims = H5Sget_simple_extent_ndims( slab_id );
436 if( dims < 1 || dims > 2 )
437 {
438 H5Sclose( slab_id );
439 mhdf_setFail( status, "Internal error: unexpected dataset rank: %d.", dims );
440 return 0;
441 }
442
443 dims = H5Sget_simple_extent_dims( slab_id, counts, NULL );
444 if( dims < 0 )
445 {
446 H5Sclose( slab_id );
447 mhdf_setFail( status, "Internal error calling H5Sget_simple_extend_dims." );
448 return 0;
449 }
450
451 if( (unsigned long)( offset + count ) > counts[0] || (unsigned long)column > counts[1] )
452 {
453 H5Sclose( slab_id );
454 mhdf_setFail( status, "Requested %s of (%ld,%d)->(%ld,%ld) of (%ld, %ld) table.\n", read ? "read" : "write",
455 offset, column, offset + count - 1, column, (long)counts[0], (long)counts[1] );
456 return 0;
457 }
458
459 counts[0] = (hsize_t)count;
460 offsets[0] = (hsize_t)offset;
461 counts[1] = 1;
462 offsets[1] = column;
463 if( count )
464 rval = H5Sselect_hyperslab( slab_id, H5S_SELECT_SET, offsets, NULL, counts, NULL );
465 else
466 rval = H5Sselect_none( slab_id );
467 if( rval < 0 )
468 {
469 H5Sclose( slab_id );
470 mhdf_setFail( status, "Internal error calling H5Sselect_hyperslab." );
471 return 0;
472 }
473
474 if( count )
475 mem_id = H5Screate_simple( dims, counts, NULL );
476 else
477 {
478
481 mem_id = H5Screate_simple( 1, &one, NULL );
482 if( mem_id && 0 > H5Sselect_none( mem_id ) )
483 {
484 H5Sclose( mem_id );
485 mem_id = -1;
486 }
487
488 }
489
490 if( mem_id < 0 )
491 {
492 H5Sclose( slab_id );
493 mhdf_setFail( status, "Internal error calling H5Screate_simple." );
494 return 0;
495 }
496
497 if( read )
498 rval = H5Dread( data_id, type, mem_id, slab_id, io_prop, array );
499 else
500 {
501 VALGRIND_CHECK_MEM_IS_DEFINED( array, count * H5Tget_size( type ) );
502 rval = H5Dwrite( data_id, type, mem_id, slab_id, io_prop, array );
503 VALGRIND_MAKE_MEM_UNDEFINED( array, count * H5Tget_size( type ) );
504 }
505 H5Sclose( slab_id );
506 H5Sclose( mem_id );
507 if( rval < 0 )
508 {
509 mhdf_setFail( status, "Internal error calling H5D%s.", read ? "read" : "write" );
510 return 0;
511 }
512
513 mhdf_setOkay( status );
514 return 1;
515 }
516
517 int mhdf_write_data( hid_t data_id,
518 long offset,
519 long count,
520 hid_t type_id,
521 const void* array,
522 hid_t prop,
523 mhdf_Status* status )
524 {
525 return mhdf_readwrite( data_id, 0, offset, count, type_id, (void*)array, prop, status );
526 }
527
528 int mhdf_read_data( hid_t data_id,
529 long offset,
530 long count,
531 hid_t type_id,
532 void* array,
533 hid_t prop,
534 mhdf_Status* status )
535 {
536 return mhdf_readwrite( data_id, 1, offset, count, type_id, array, prop, status );
537 }
538
539 int mhdf_read_column( hid_t data_id,
540 int column,
541 long offset,
542 long count,
543 hid_t type,
544 void* array,
545 hid_t prop,
546 mhdf_Status* status )
547 {
548 return mhdf_readwrite_column( data_id, 1, column, offset, count, type, array, prop, status );
549 }
550
551 int mhdf_write_column( hid_t data_id,
552 int column,
553 long offset,
554 long count,
555 hid_t type,
556 const void* array,
557 hid_t prop,
558 mhdf_Status* status )
559 {
560 return mhdf_readwrite_column( data_id, 0, column, offset, count, type, (void*)array, prop, status );
561 }
562
563 hid_t mhdf_create_table( hid_t group_id, const char* path, hid_t type, int rank, hsize_t* dims, mhdf_Status* status )
564 {
565 return mhdf_create_table_with_prop( group_id, path, type, rank, dims, H5P_DEFAULT, status );
566 }
567
568 hid_t mhdf_create_table_with_prop( hid_t group_id,
569 const char* path,
570 hid_t type,
571 int rank,
572 hsize_t* dims,
573 hid_t create_prop,
574 mhdf_Status* status )
575 {
576 hid_t space_id, table_id;
577
578 space_id = H5Screate_simple( rank, dims, NULL );
579 if( space_id < 0 )
580 {
581 mhdf_setFail( status, "Internal error calling H5Screate_simple." );
582 return -1;
583 }
584
585 #if defined( H5Dcreate_vers ) && H5Dcreate_vers > 1
586 table_id = H5Dcreate2( group_id, path, type, space_id, H5P_DEFAULT, create_prop, H5P_DEFAULT );
587 #else
588 table_id = H5Dcreate( group_id, path, type, space_id, create_prop );
589 #endif
590 H5Sclose( space_id );
591 if( table_id < 0 )
592 {
593 mhdf_setFail( status, "HDF5 DataSet creation failed." );
594 return -1;
595 }
596
597 mhdf_setOkay( status );
598 return table_id;
599 }
600
601 hid_t mhdf_open_table( hid_t group_id, const char* path, int columns, hsize_t* rows_out, mhdf_Status* status )
602 {
603 hid_t table_id, space_id;
604 hsize_t dims[2];
605 int rank;
606
607 #if defined( H5Dopen_vers ) && H5Dopen_vers > 1
608 table_id = H5Dopen2( group_id, path, H5P_DEFAULT );
609 #else
610 table_id = H5Dopen( group_id, path );
611 #endif
612 if( table_id < 0 )
613 {
614 mhdf_setFail( status, "HDF5 DataSet creation failed." );
615 return -1;
616 }
617
618 space_id = H5Dget_space( table_id );
619 if( space_id < 0 )
620 {
621 mhdf_setFail( status, "Internal error in H5Dget_space." );
622 H5Dclose( table_id );
623 return -1;
624 }
625
626 rank = H5Sget_simple_extent_ndims( space_id );
627 if( rank != ( columns ? 1 : 2 ) )
628 {
629 mhdf_setFail( status, "Incorrect DataSpace for DataSet." );
630 H5Sclose( space_id );
631 H5Dclose( table_id );
632 return -1;
633 }
634
635 rank = H5Sget_simple_extent_dims( space_id, dims, NULL );
636 H5Sclose( space_id );
637 if( rank < 0 )
638 {
639 mhdf_setFail( status, "Internal error calling H5Sget_simple_extent_dims." );
640 H5Dclose( table_id );
641 return -1;
642 }
643
644 *rows_out = dims[0];
645 mhdf_setOkay( status );
646 return table_id;
647 }
648
649 hid_t mhdf_open_table2( hid_t group_id,
650 const char* path,
651 int rank,
652 hsize_t* dims_out,
653 long* start_id_out,
654 mhdf_Status* status )
655 {
656 hid_t table_id, space_id;
657
658 #if defined( H5Dopen_vers ) && H5Dopen_vers > 1
659 table_id = H5Dopen2( group_id, path, H5P_DEFAULT );
660 #else
661 table_id = H5Dopen( group_id, path );
662 #endif
663 if( table_id < 0 )
664 {
665 mhdf_setFail( status, "HDF5 DataSet creation failed." );
666 return -1;
667 }
668
669 space_id = H5Dget_space( table_id );
670 if( space_id < 0 )
671 {
672 mhdf_setFail( status, "Internal error in H5Dget_space." );
673 H5Dclose( table_id );
674 return -1;
675 }
676
677 if( H5Sget_simple_extent_ndims( space_id ) != rank )
678 {
679 mhdf_setFail( status, "Incorrect DataSpace for DataSet." );
680 H5Sclose( space_id );
681 H5Dclose( table_id );
682 return -1;
683 }
684
685 rank = H5Sget_simple_extent_dims( space_id, dims_out, NULL );
686 H5Sclose( space_id );
687 if( rank < 0 )
688 {
689 mhdf_setFail( status, "Internal error calling H5Sget_simple_extent_dims." );
690 H5Dclose( table_id );
691 return -1;
692 }
693
694 if( !mhdf_read_scalar_attrib( table_id, START_ID_ATTRIB, H5T_NATIVE_LONG, start_id_out, status ) )
695 {
696 mhdf_setFail( status, "File format error. Failed to retreive ID offset." );
697 H5Dclose( table_id );
698 return -1;
699 }
700
701 mhdf_setOkay( status );
702 return table_id;
703 }
704
705 hid_t mhdf_open_table_simple( hid_t group_id, const char* path, mhdf_Status* status )
706 {
707 hid_t table_id;
708
709 #if defined( H5Dopen_vers ) && H5Dopen_vers > 1
710 table_id = H5Dopen2( group_id, path, H5P_DEFAULT );
711 #else
712 table_id = H5Dopen( group_id, path );
713 #endif
714 if( table_id < 0 )
715 {
716 mhdf_setFail( status, "HDF5 DataSet creation failed." );
717 }
718 else
719 {
720 mhdf_setOkay( status );
721 }
722
723 return table_id;
724 }
725
726 static int qs_comp_int( const void* ptr1, const void* ptr2 )
727 {
728 const int* left = (const int*)ptr1;
729 const int* right = (const int*)ptr2;
730 return *left < *right ? -1 : *left > *right ? 1 : 0;
731 }
732
733 int mhdf_compact_to_ranges( int* length, int* ids, int ordered )
734 {
735 int new_length = 0;
736 int *iter, *end;
737 int prev, count;
738 int need_copy = 0;
739 int *copy_ptr = 0, *w_iter;
740 size_t blen;
741
742 if( !ordered ) qsort( ids, *length, sizeof( int ), &qs_comp_int );
743
744 iter = ids;
745 end = ids + *length;
746 while( iter != end )
747 {
748 prev = *( iter++ );
749 while( iter < end && *( iter++ ) == ++prev )
750 ;
751 new_length += 2;
752 if( new_length > ( iter - ids ) ) need_copy = 1;
753 }
754
755 if( new_length > *length ) return 0;
756
757 if( need_copy )
758 {
759 blen = sizeof( int ) * *length;
760 copy_ptr = (int*)malloc( blen );
761 memcpy( copy_ptr, ids, blen );
762 iter = copy_ptr;
763 }
764 else
765 {
766 iter = ids;
767 }
768
769 end = iter + *length;
770 w_iter = ids;
771 while( iter != end )
772 {
773 prev = *( iter++ );
774 count = 1;
775 while( iter < end && *( iter++ ) == ++prev )
776 ;
777 *( w_iter++ ) = prev - count;
778 *( w_iter++ ) = count;
779 }
780
781 *length = new_length;
782 if( need_copy ) free( copy_ptr );
783 return 1;
784 }
785
786 hid_t get_elem_type_enum( FileHandle* file_ptr, mhdf_Status* status )
787 {
788 hid_t result;
789 #if defined( H5Topen_vers ) && H5Topen_vers > 1
790 result = H5Topen2( file_ptr->hdf_handle, TYPE_ENUM_PATH, H5P_DEFAULT );
791 #else
792 result = H5Topen( file_ptr->hdf_handle, TYPE_ENUM_PATH );
793 #endif
794 if( result < 0 ) mhdf_setFail( status, "Element type enum does not exist in file. Invalid file." );
795 return result;
796 }
797
798 int mhdf_write_max_id( FileHandle* file_ptr, mhdf_Status* status )
799 {
800 hid_t group_id, attr_id, space_id;
801 herr_t rval;
802
803 #if defined( H5Gopen_vers ) && H5Gopen_vers > 1
804 group_id = H5Gopen2( file_ptr->hdf_handle, ROOT_GROUP, H5P_DEFAULT );
805 #else
806 group_id = H5Gopen( file_ptr->hdf_handle, ROOT_GROUP );
807 #endif
808 if( group_id < 0 )
809 {
810 mhdf_setFail( status, "Internal error -- file invalid." );
811 return 0;
812 }
813
814 attr_id = H5Aopen_name( group_id, MAX_ID_ATTRIB );
815 if( attr_id < 0 )
816 {
817 space_id = H5Screate( H5S_SCALAR );
818 #if defined( H5Acreate_vers ) && H5Acreate_vers > 1
819 attr_id = H5Acreate2( group_id, MAX_ID_ATTRIB, H5T_NATIVE_ULONG, space_id, H5P_DEFAULT, H5P_DEFAULT );
820 #else
821 attr_id = H5Acreate( group_id, MAX_ID_ATTRIB, H5T_NATIVE_ULONG, space_id, H5P_DEFAULT );
822 #endif
823 H5Sclose( space_id );
824 }
825 H5Gclose( group_id );
826 if( attr_id < 0 )
827 {
828 mhdf_setFail( status, "Failed to create attribute \"%s\" on \"%s\"", MAX_ID_ATTRIB, ROOT_GROUP );
829 return 0;
830 }
831
832 rval = H5Awrite( attr_id, H5T_NATIVE_ULONG, &file_ptr->max_id );
833 H5Aclose( attr_id );
834 if( rval < 0 )
835 {
836 mhdf_setFail( status, "Failed to write \"%s\" attrib.", MAX_ID_ATTRIB );
837 return 0;
838 }
839
840 return 1;
841 }
842
843 static int mhdf_api_handle_count = 0;
844
845 static int num_open( void )
846 {
847 hid_t list[64];
848 int nf, rval, i, count = 0;
849
850 nf = H5Fget_obj_ids( H5F_OBJ_ALL, H5F_OBJ_FILE, sizeof( list ) / sizeof( hid_t ), list );
851 if( nf <= 0 || nf > 64 ) return 0;
852
853 for( i = 0; i < nf; i++ )
854 {
855 rval = H5Fget_obj_count( list[i], H5F_OBJ_ALL );
856 if( rval > 0 ) count += rval;
857 }
858
859 return count;
860 }
861
862 void mhdf_api_begin_internal( void )
863 {
864
870 mhdf_api_handle_count = num_open();
871 }
872
873 void mhdf_api_end_internal( int expected_diff, const char* filename, int linenumber )
874 {
875 if( mhdf_api_handle_count + expected_diff != num_open() )
876 {
877 fprintf( stderr, "Unclosed handles at end of mhdf API call.\n" );
878 fprintf( stderr, "Entered with %d, expected %d change, got %d.\n", mhdf_api_handle_count, expected_diff,
879 num_open() );
880 fprintf( stderr, "%s:%d\n", filename, linenumber );
881 abort();
882 }
883
884 mhdf_api_handle_count = 0;
885 }