Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
util.c
Go to the documentation of this file.
1 /**
2  * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3  * storing and accessing finite element mesh data.
4  *
5  * Copyright 2004 Sandia Corporation. Under the terms of Contract
6  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7  * retains certain rights in this software.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  */
15 
16 #include <stdlib.h>
17 #include <string.h>
18 #include <assert.h>
19 #include <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  /* empty statement to remove compiler warning */
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  /* empty statement to remove compiler warning */
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  /* empty statement to remove compiler warning */
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  /*#if (1000 * H5_VERS_MAJOR + H5_VERS_MINOR) < 1008*/
302  const hsize_t one = 1;
303  /*#endif*/
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  /*#if H5_VERS_MAJOR > 1 || H5_VERS_MINOR >= 8
364  mem_id = H5Screate(H5S_NULL);
365  #else*/
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  /*#endif*/
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  /*#if (1000 * H5_VERS_MAJOR + H5_VERS_MINOR) < 1008*/
416  const hsize_t one = 1;
417  /*#endif*/
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  /*#if H5_VERS_MAJOR > 1 || H5_VERS_MINOR >= 8
479  mem_id = H5Screate(H5S_NULL);
480  #else*/
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  /*#endif*/
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 
863 {
864  /* HDF5 docs are incorrect. Passing H5F_OBJ_ALL as the first
865  arg to H5Fget_obj_count returns the total number of open
866  handles, not just those in files (i.e. temporary types and such.)
867  mhdf_api_handle_count = H5Fget_obj_count( H5F_OBJ_ALL, H5F_OBJ_ALL );
868  Need to loop to get actual file handles:
869  */
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 
885 }