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