Loading [MathJax]/extensions/tex2jax.js
Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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  862 void mhdf_api_begin_internal( void ) 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  */ 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 }