Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 #include "mhdf.h" 00002 #include <stdlib.h> 00003 #include <stdio.h> 00004 #include <string.h> 00005 #include <sys/stat.h> 00006 #include <H5Tpublic.h> 00007 00008 /* Top-level validation functions */ 00009 00010 /* check that group ID ranges are valid and non-overlapping */ 00011 static int check_valid_file_ids( struct mhdf_FileDesc* desc ); 00012 00013 /* check that file doesn't contain holes (unwritten regions) */ 00014 static int check_file_contains_holes( const char* filename ); 00015 00016 /* check IDs are valid for all element connectivity data */ 00017 static int check_valid_connectivity( mhdf_FileHandle file, struct mhdf_FileDesc* desc ); 00018 00019 /* check that any adjacency lists contain valid IDs */ 00020 static int check_valid_adjacencies( mhdf_FileHandle file, struct mhdf_FileDesc* desc ); 00021 00022 /* check that set data is consistent and that sets contain valid ids */ 00023 static int check_valid_sets( mhdf_FileHandle file, struct mhdf_FileDesc* desc ); 00024 00025 /* check tag consistency and for handle tags verify that values are valid ids */ 00026 static int check_valid_tags( mhdf_FileHandle file, struct mhdf_FileDesc* desc ); 00027 00028 /* Low-level helper routines */ 00029 00030 /* Get string name from mhdf_EntDesc pointer */ 00031 static const char* desc_name( struct mhdf_FileDesc* desc, struct mhdf_EntDesc* grp ); 00032 00033 /* Given a list of ID range pairs of [start_id,count] interleaved in 'ranges', 00034 test if the passed file_id is contained in at least one passed range */ 00035 static int id_contained( long file_id, const long* ranges, int num_range ); 00036 00037 /* Like id_contained, only returns logical and for all ids in a passed array */ 00038 static int ids_contained( const long* ids, int num_ids, const long* ranges, int num_ranges ); 00039 00040 /* Like ids_contained, both input lists are in ranged format */ 00041 static int ranges_contained( const long* id_ranges, int num_id_ranges, const long* ranges, int num_ranges ); 00042 00043 /* Search for a string in a null-terminated list of strings */ 00044 static int string_contained( const char* str, const char* const* const list ); 00045 00046 /* Check if an array of longs contains duplicate values. Will sort passed array */ 00047 static int contains_duplicates( long* array, long n ); 00048 00049 /* Check if an array of [start_id,count] range pairs containes duplicate values/overlapping ranges. 00050 Will sort passed array */ 00051 static int ranges_contain_duplicates( long* ranges, long nranges ); 00052 00053 /* Get dynamically allocated array of [start_id,count] range pairs corresponding to all valid 00054 file IDs. If include_null is non-zero, results will also include special ID of zero. */ 00055 static long* all_id_ranges( struct mhdf_FileDesc* desc, int include_null, int* num_ranges_out ); 00056 00057 /* Get dynamically allocated array of [start_id,count] range pairs corresponding to all valid 00058 file IDs for entities with a specific dimension. */ 00059 static long* get_dim_ranges( struct mhdf_FileDesc* desc, int dim, int* num_ranges_out ); 00060 00061 /* Merge adjacent ranges */ 00062 static int merge_ranges( long* ranges, int nranges ); 00063 00064 /* Misc. high-level helper routines */ 00065 00066 /* Check that end-index lists used in various file data for variable-length data 00067 (e.g. set contents, poly connectivity, variable-length tags) is valid. If 00068 min_len is non-zero, it will be considered an error if the data for any entity 00069 contains less than that number of values. It is considered an error if any 00070 index in the list is past the end of a dataset containing max_value entries. */ 00071 static int check_valid_end_indices( const long* indices, 00072 long num_idx, 00073 int min_len, 00074 long start_id, 00075 long max_value, 00076 const char* typestr, 00077 const char* name ); 00078 00079 /* Do check_valid_connectivity for an element group with constant connectivity length */ 00080 static int check_valid_elem_conn( int idx, mhdf_FileHandle file, struct mhdf_FileDesc* desc, int conn_dim ); 00081 00082 /* Do check_valid_connectivity for an element group with old-format variable-length connectivity */ 00083 static int check_valid_poly_conn( int idx, mhdf_FileHandle file, struct mhdf_FileDesc* desc, int conn_dim ); 00084 00085 /* Do check_valid_tags for a fixed-length tag */ 00086 static int check_valid_tag( int tag_idx, mhdf_FileHandle file, struct mhdf_FileDesc* desc ); 00087 00088 /* Do check_valid_tags for a variable-length tag */ 00089 static int check_valid_var_len_tag( int tag_idx, mhdf_FileHandle file, struct mhdf_FileDesc* desc ); 00090 00091 /* Do check_valid_adjacencies for the adjacency list of a single entity group */ 00092 static int check_valid_adj_list( long start_id, 00093 long count, 00094 const long* data, 00095 long data_len, 00096 const long* valid_ranges, 00097 long num_valid_ranges, 00098 const char* name ); 00099 00100 /* Do subset of check_valid_sets for either set parent or set child data */ 00101 static int check_valid_parents_children( long start_id, 00102 long count, 00103 hid_t meta_handle, 00104 hid_t data_handle, 00105 long data_len, 00106 int parents ); 00107 00108 /* Do subset of check_valid_sets for set contents */ 00109 static int check_valid_set_contents( struct mhdf_FileDesc* desc, 00110 long start_id, 00111 long count, 00112 hid_t meta_handle, 00113 hid_t data_handle, 00114 long data_len ); 00115 00116 /* Comparison routines for use with qsort */ 00117 00118 /* Compare two long int values */ 00119 static int lcomp( const void* p1, const void* p2 ) 00120 { 00121 long l1 = *(const long*)p1; 00122 long l2 = *(const long*)p2; 00123 return l1 < l2 ? -1 : l1 > l2 ? 1 : 0; 00124 } 00125 00126 /* Compare start_ids of mhdf_EntDesc pointed to by passed values */ 00127 static int dcomp( const void* p1, const void* p2 ) 00128 { 00129 const struct mhdf_EntDesc* d1 = *(const struct mhdf_EntDesc**)( p1 ); 00130 const struct mhdf_EntDesc* d2 = *(const struct mhdf_EntDesc**)( p2 ); 00131 return lcomp( &d1->start_id, &d2->start_id ); 00132 } 00133 00134 int verbose = 0; 00135 00136 int main( int argc, char* argv[] ) 00137 { 00138 int result = 0; 00139 mhdf_FileHandle file; 00140 mhdf_Status status; 00141 unsigned long max_id; 00142 struct mhdf_FileDesc* desc; 00143 00144 if( argc < 2 || argc > 3 ) 00145 { 00146 fprintf( stderr, "Usage: %s <filename> <verbose_option> \n", argv[0] ); 00147 return 1; 00148 } 00149 00150 file = mhdf_openFile( argv[1], 0, &max_id, -1, &status ); 00151 if( mhdf_isError( &status ) ) 00152 { 00153 fprintf( stderr, "%s: %s\n", argv[1], mhdf_message( &status ) ); 00154 return 1; 00155 } 00156 if( argc == 3 ) 00157 { 00158 verbose = atoi( argv[2] ); 00159 } 00160 desc = mhdf_getFileSummary( file, H5T_NATIVE_LONG, &status, 0 ); /*no extra set info*/ 00161 if( mhdf_isError( &status ) ) 00162 { 00163 fprintf( stderr, "%s: %s\n", argv[1], mhdf_message( &status ) ); 00164 return 1; 00165 } 00166 00167 if( desc->nodes.count < 1 ) puts( "WARNING: file contains no vertices." ); 00168 if( desc->num_elem_desc < 1 ) puts( "WARNING: file contains no elements." ); 00169 00170 result += check_valid_file_ids( desc ); 00171 result += check_file_contains_holes( argv[1] ); 00172 result += check_valid_connectivity( file, desc ); 00173 result += check_valid_adjacencies( file, desc ); 00174 result += check_valid_sets( file, desc ); 00175 result += check_valid_tags( file, desc ); 00176 00177 free( desc ); 00178 mhdf_closeFile( file, &status ); 00179 return result; 00180 } 00181 00182 static const char* desc_name( struct mhdf_FileDesc* desc, struct mhdf_EntDesc* grp ) 00183 { 00184 struct mhdf_ElemDesc junk, *elem; 00185 const size_t diff = (char*)&junk.desc - (char*)&junk; 00186 static const char nodes[] = "Vertices"; 00187 static const char sets[] = "Sets"; 00188 if( grp == &desc->nodes ) return nodes; 00189 if( grp == &desc->sets ) return sets; 00190 00191 elem = (struct mhdf_ElemDesc*)( (char*)grp - diff ); 00192 return elem->handle; 00193 } 00194 00195 int check_valid_file_ids( struct mhdf_FileDesc* desc ) 00196 { 00197 const int ngrp = 2 + desc->num_elem_desc; 00198 int i, err = 0; 00199 struct mhdf_EntDesc** sorted = malloc( ngrp * sizeof( struct mhdf_EntDesc* ) ); 00200 for( i = 0; i < desc->num_elem_desc; ++i ) 00201 sorted[i] = &desc->elems[i].desc; 00202 sorted[i++] = &desc->nodes; 00203 sorted[i] = &desc->sets; 00204 qsort( sorted, ngrp, sizeof( struct mhdf_EntDesc* ), &dcomp ); 00205 for( i = 0; i < ngrp; ++i ) 00206 { 00207 if( sorted[i]->count < 0 ) 00208 { 00209 printf( "Group \"%s\" has negative count!\n", desc_name( desc, sorted[i] ) ); 00210 ++err; 00211 } 00212 if( sorted[i]->count && sorted[i]->start_id == 0 ) 00213 { 00214 printf( "Group \"%s\" contains NULL ID!\n", desc_name( desc, sorted[i] ) ); 00215 ++err; 00216 } 00217 00218 if( i > 0 && sorted[i - 1]->start_id + sorted[i - 1]->count > sorted[i]->start_id ) 00219 { 00220 printf( "Conflicting group IDs for \"%s\" [%ld,%ld] and \"%s\" [%ld,%ld]\n", 00221 desc_name( desc, sorted[i - 1] ), sorted[i - 1]->start_id, 00222 sorted[i - 1]->start_id + sorted[i - 1]->count - 1, desc_name( desc, sorted[i] ), 00223 sorted[i]->start_id, sorted[i]->start_id + sorted[i]->count - 1 ); 00224 ++err; 00225 } 00226 } 00227 free( sorted ); 00228 return err; 00229 } 00230 00231 int check_file_contains_holes( const char* filename ) 00232 { 00233 #ifndef _WIN32 00234 const int blocksize = 512; 00235 #endif 00236 int errorcode; 00237 struct stat buf; 00238 00239 errorcode = stat( filename, &buf ); 00240 if( errorcode ) 00241 { 00242 perror( filename ); 00243 return 1; 00244 } 00245 00246 #ifndef _WIN32 /*Does not have st_blocks*/ 00247 if( buf.st_size / blocksize > buf.st_blocks + 1 ) 00248 { 00249 printf( "File \"%s\" contains holes. This indicates that portions of the file were never " 00250 "written.\n", 00251 filename ); 00252 return 1; 00253 } 00254 #endif 00255 00256 return 0; 00257 } 00258 00259 int check_valid_connectivity( mhdf_FileHandle file, struct mhdf_FileDesc* desc ) 00260 { 00261 int idx, dim, result = 0; 00262 00263 for( idx = 0; idx < desc->num_elem_desc; ++idx ) 00264 { 00265 if( !strcmp( desc->elems[idx].type, mhdf_POLYHEDRON_TYPE_NAME ) ) 00266 dim = 2; 00267 else 00268 dim = 0; 00269 00270 if( desc->elems[idx].desc.vals_per_ent == -1 ) 00271 result += check_valid_poly_conn( idx, file, desc, dim ); 00272 else 00273 result += check_valid_elem_conn( idx, file, desc, dim ); 00274 } 00275 00276 return result; 00277 } 00278 00279 static int id_contained( long file_id, const long* ranges, int num_range ) 00280 { 00281 const long* end = ranges + 2 * num_range; 00282 for( ; ranges != end; ranges += 2 ) 00283 { 00284 if( file_id >= ranges[0] && ( file_id - ranges[0] ) < ranges[1] ) return 1; 00285 } 00286 return 0; 00287 } 00288 00289 static int ids_contained( const long* ids, int num_ids, const long* ranges, int num_ranges ) 00290 { 00291 int i; 00292 for( i = 0; i < num_ids; ++i ) 00293 if( !id_contained( ids[i], ranges, num_ranges ) ) return 0; 00294 return 1; 00295 } 00296 00297 static int ranges_contained( const long* id_ranges, int num_id_ranges, const long* ranges, int num_ranges ) 00298 { 00299 int i; 00300 long start, count, avail; 00301 const long* end = ranges + 2 * num_ranges; 00302 const long* iter; 00303 for( i = 0; i < num_id_ranges; ++i ) 00304 { 00305 start = id_ranges[2 * i]; 00306 count = id_ranges[2 * i + 1]; 00307 while( count > 0 ) 00308 { 00309 for( iter = ranges; iter != end; iter += 2 ) 00310 { 00311 if( start >= iter[0] && ( start - iter[0] ) < iter[1] ) break; 00312 } 00313 if( iter == end ) return 0; 00314 avail = iter[1] - ( start - iter[0] ); 00315 count -= avail; 00316 start += avail; 00317 } 00318 } 00319 return 1; 00320 } 00321 00322 static int string_contained( const char* str, const char* const* list ) 00323 { 00324 for( ; *list; ++list ) 00325 if( !strcmp( str, *list ) ) return 1; 00326 return 0; 00327 } 00328 00329 static long* get_dim_ranges( struct mhdf_FileDesc* desc, int dim, int* num_ranges_out ) 00330 { 00331 long* ranges = 0; 00332 int i, j; 00333 const char* const types1D[] = { mhdf_EDGE_TYPE_NAME, 0 }; 00334 const char* const types2D[] = { mhdf_TRI_TYPE_NAME, mhdf_QUAD_TYPE_NAME, mhdf_POLYGON_TYPE_NAME, 0 }; 00335 const char* const types3D[] = { mhdf_TET_TYPE_NAME, mhdf_PYRAMID_TYPE_NAME, 00336 mhdf_PRISM_TYPE_NAME, mdhf_KNIFE_TYPE_NAME, 00337 mdhf_HEX_TYPE_NAME, mhdf_POLYHEDRON_TYPE_NAME, 00338 mhdf_SEPTAHEDRON_TYPE_NAME, 0 }; 00339 00340 char const* const* typelist; 00341 switch( dim ) 00342 { 00343 case 0: 00344 *num_ranges_out = 1; 00345 ranges = malloc( 2 * sizeof( long ) ); 00346 ranges[0] = desc->nodes.start_id; 00347 ranges[1] = desc->nodes.count; 00348 return ranges; 00349 case 1: 00350 typelist = types1D; 00351 break; 00352 case 2: 00353 typelist = types2D; 00354 break; 00355 case 3: 00356 typelist = types3D; 00357 break; 00358 default: 00359 fprintf( stderr, "Internal error at %s:%d: request for entities of dimesion %d\n", __FILE__, __LINE__, 00360 dim ); 00361 abort(); 00362 } 00363 00364 *num_ranges_out = 0; 00365 for( i = 0; i < desc->num_elem_desc; ++i ) 00366 if( string_contained( desc->elems[i].type, typelist ) ) ++*num_ranges_out; 00367 ranges = malloc( *num_ranges_out * 2 * sizeof( long ) ); 00368 for( i = 0, j = 0; i < desc->num_elem_desc; ++i ) 00369 if( string_contained( desc->elems[i].type, typelist ) ) 00370 { 00371 ranges[j++] = desc->elems[i].desc.start_id; 00372 ranges[j++] = desc->elems[i].desc.count; 00373 } 00374 00375 *num_ranges_out = merge_ranges( ranges, *num_ranges_out ); 00376 return ranges; 00377 } 00378 00379 int check_valid_elem_conn( int idx, mhdf_FileHandle file, struct mhdf_FileDesc* desc, int conn_dim ) 00380 { 00381 long *ranges, *buffer, *iter; 00382 int num_ranges; 00383 long i, invalid = 0; 00384 hid_t handle; 00385 mhdf_Status status; 00386 const long count = desc->elems[idx].desc.count; 00387 const long len = desc->elems[idx].desc.vals_per_ent; 00388 00389 ranges = get_dim_ranges( desc, conn_dim, &num_ranges ); 00390 handle = mhdf_openConnectivitySimple( file, desc->elems[idx].handle, &status ); 00391 if( mhdf_isError( &status ) ) 00392 { 00393 fprintf( stderr, "Internal error opening connectivity for %s: %s\n", desc->elems[idx].handle, 00394 mhdf_message( &status ) ); 00395 free( ranges ); 00396 return 1; 00397 } 00398 00399 buffer = malloc( sizeof( long ) * count * len ); 00400 mhdf_readConnectivity( handle, 0, count, H5T_NATIVE_LONG, buffer, &status ); 00401 if( mhdf_isError( &status ) ) 00402 { 00403 fprintf( stderr, "Internal error reading connectivity for %s: %s\n", desc->elems[idx].handle, 00404 mhdf_message( &status ) ); 00405 free( ranges ); 00406 free( buffer ); 00407 mhdf_closeData( file, handle, &status ); 00408 return 1; 00409 } 00410 mhdf_closeData( file, handle, &status ); 00411 00412 iter = buffer; 00413 for( i = 0; i < count; ++i, iter += len ) 00414 { 00415 if( !ids_contained( iter, len, ranges, num_ranges ) ) 00416 { 00417 if( verbose ) 00418 printf( "Invalid connectivity for element %ld (ID %ld) in %s\n", i, i + desc->elems[idx].desc.start_id, 00419 desc->elems[idx].handle ); 00420 ++invalid; 00421 } 00422 } 00423 free( buffer ); 00424 free( ranges ); 00425 00426 if( invalid ) 00427 { 00428 printf( "%ld elements with invalid connectivity in %s\n", invalid, desc->elems[idx].handle ); 00429 return 1; 00430 } 00431 return 0; 00432 } 00433 00434 static int check_valid_end_indices( const long* indices, 00435 long num_idx, 00436 int min_len, 00437 long start_id, 00438 long max_value, 00439 const char* typestr, 00440 const char* name ) 00441 { 00442 long i, invalid = 0, prev = -1; 00443 00444 if( num_idx == 0 ) 00445 { 00446 printf( "WARNING: Empty index list for %s %s\n", name, typestr ); 00447 return 0; 00448 } 00449 00450 for( i = 0; i < num_idx; ++i ) 00451 { 00452 if( indices[i] < prev ) 00453 { 00454 if( verbose ) 00455 { 00456 if( start_id > 0 ) 00457 printf( "Invalid end index %ld for %s %ld (ID %ld). Prev index is %ld\n", indices[i], name, i, 00458 i + start_id, prev ); 00459 else 00460 printf( "Invalid end index %ld for entry %ld in %s %s. Prev index is %ld\n", indices[i], i, name, 00461 typestr, prev ); 00462 } 00463 ++invalid; 00464 } 00465 else if( indices[i] - prev < min_len ) 00466 { 00467 if( verbose ) 00468 { 00469 if( start_id > 0 ) 00470 printf( "%s %ld (ID %ld) has only %ld values\n", name, i, start_id, indices[i] - prev ); 00471 else 00472 printf( "Entry %ld in %s %s has only %ld values\n", i, name, typestr, indices[i] - prev ); 00473 } 00474 ++invalid; 00475 } 00476 else if( indices[i] >= max_value ) 00477 { 00478 if( verbose ) 00479 { 00480 if( start_id > 0 ) 00481 printf( "%s %ld (ID %ld) end index exceeds upper bound of %ld\n", name, i, start_id, max_value ); 00482 else 00483 printf( "Entry %ld in %s %s end index exceeds uppper bound of %ld\n", i, name, typestr, max_value ); 00484 } 00485 ++invalid; 00486 } 00487 prev = indices[i]; 00488 } 00489 00490 if( invalid ) 00491 { 00492 printf( "%ld invalid end indices for %s %s\n", invalid, typestr, name ); 00493 } 00494 00495 return invalid; 00496 } 00497 00498 int check_valid_poly_conn( int idx, mhdf_FileHandle file, struct mhdf_FileDesc* desc, int conn_dim ) 00499 { 00500 long *ranges, *buffer, *indices, *iter; 00501 int num_ranges; 00502 long i, invalid, num_poly, num_conn, first_id, prev, len; 00503 hid_t handles[2]; 00504 mhdf_Status status; 00505 int min_conn_len; 00506 if( !strcmp( mhdf_POLYHEDRON_TYPE_NAME, desc->elems[idx].type ) ) 00507 min_conn_len = 4; 00508 else 00509 min_conn_len = 3; 00510 00511 mhdf_openPolyConnectivity( file, desc->elems[idx].handle, &num_poly, &num_conn, &first_id, handles, &status ); 00512 if( mhdf_isError( &status ) ) 00513 { 00514 fprintf( stderr, "Internal error opening connectivity for %s: %s\n", desc->elems[idx].handle, 00515 mhdf_message( &status ) ); 00516 return 1; 00517 } 00518 00519 indices = malloc( sizeof( long ) * num_poly ); 00520 mhdf_readPolyConnIndices( handles[0], 0, num_poly, H5T_NATIVE_LONG, indices, &status ); 00521 if( mhdf_isError( &status ) ) 00522 { 00523 fprintf( stderr, "Internal error reading poly indices for %s: %s\n", desc->elems[idx].handle, 00524 mhdf_message( &status ) ); 00525 free( indices ); 00526 mhdf_closeData( file, handles[0], &status ); 00527 mhdf_closeData( file, handles[1], &status ); 00528 return 1; 00529 } 00530 mhdf_closeData( file, handles[0], &status ); 00531 00532 invalid = check_valid_end_indices( indices, num_poly, min_conn_len, first_id, num_conn, "Connectivity", 00533 desc->elems[idx].handle ); 00534 if( invalid ) 00535 { 00536 free( indices ); 00537 mhdf_closeData( file, handles[1], &status ); 00538 return 1; 00539 } 00540 00541 ranges = get_dim_ranges( desc, conn_dim, &num_ranges ); 00542 00543 buffer = malloc( sizeof( long ) * num_conn ); 00544 mhdf_readPolyConnIDs( handles[1], 0, num_conn, H5T_NATIVE_LONG, buffer, &status ); 00545 if( mhdf_isError( &status ) ) 00546 { 00547 fprintf( stderr, "Internal error reading connectivity for %s: %s\n", desc->elems[idx].handle, 00548 mhdf_message( &status ) ); 00549 free( ranges ); 00550 free( indices ); 00551 free( buffer ); 00552 mhdf_closeData( file, handles[1], &status ); 00553 return 1; 00554 } 00555 mhdf_closeData( file, handles[1], &status ); 00556 00557 prev = -1; 00558 iter = buffer; 00559 for( i = 0; i < num_poly; ++i ) 00560 { 00561 len = indices[i] - prev; 00562 prev = indices[i]; 00563 if( !ids_contained( iter, len, ranges, num_ranges ) ) 00564 { 00565 if( verbose ) 00566 printf( "Invalid connectivity for element %ld (ID %ld) in %s\n", i, i + first_id, 00567 desc->elems[idx].handle ); 00568 ++invalid; 00569 } 00570 iter += len; 00571 } 00572 free( indices ); 00573 free( buffer ); 00574 free( ranges ); 00575 00576 if( invalid ) 00577 { 00578 printf( "%ld elements with invalid connectivity in %s\n", invalid, desc->elems[idx].handle ); 00579 return 1; 00580 } 00581 return 0; 00582 } 00583 00584 int check_valid_adjacencies( mhdf_FileHandle file, struct mhdf_FileDesc* desc ) 00585 { 00586 const int num_ranges = desc->num_elem_desc; 00587 long *ranges, *buffer; 00588 int i; 00589 int invalid = 0; 00590 long count; 00591 hid_t handle; 00592 mhdf_Status status; 00593 00594 /* Build list of ID ranges for all elements. Consider any element ID to be a valid 00595 * thing to be adjacent to. So we disallow adjacency to nodes, sets, or undefined IDs */ 00596 ranges = malloc( sizeof( long ) * 2 * num_ranges ); 00597 for( i = 0; i < num_ranges; ++i ) 00598 { 00599 ranges[2 * i] = desc->elems[i].desc.start_id; 00600 ranges[2 * i + 1] = desc->elems[i].desc.count; 00601 } 00602 00603 for( i = 0; i < num_ranges; ++i ) 00604 { 00605 if( !desc->elems[i].have_adj ) continue; 00606 00607 handle = mhdf_openAdjacency( file, desc->elems[i].handle, &count, &status ); 00608 if( mhdf_isError( &status ) ) 00609 { 00610 fprintf( stderr, "Internal error openening adjacency list for %s: %s\n", desc->elems[i].handle, 00611 mhdf_message( &status ) ); 00612 free( ranges ); 00613 return 1; 00614 } 00615 00616 buffer = malloc( sizeof( long ) * count ); 00617 mhdf_readAdjacency( handle, 0, count, H5T_NATIVE_LONG, buffer, &status ); 00618 if( mhdf_isError( &status ) ) 00619 { 00620 fprintf( stderr, "Internal error reading adjacency list for %s: %s\n", desc->elems[i].handle, 00621 mhdf_message( &status ) ); 00622 free( ranges ); 00623 mhdf_closeData( file, handle, &status ); 00624 return 1; 00625 } 00626 mhdf_closeData( file, handle, &status ); 00627 00628 invalid += check_valid_adj_list( desc->elems[i].desc.start_id, desc->elems[i].desc.count, buffer, count, ranges, 00629 num_ranges, desc->elems[i].handle ); 00630 free( buffer ); 00631 } 00632 00633 free( ranges ); 00634 return invalid; 00635 } 00636 00637 static int check_valid_adj_list( long start_id, 00638 long count, 00639 const long* data, 00640 long data_len, 00641 const long* valid_ranges, 00642 long num_valid_ranges, 00643 const char* name ) 00644 { 00645 long i, n, id, invalid_id = 0, invalid_vals = 0; 00646 const long* iter = data; 00647 const long* const end = data + data_len; 00648 int result = 0; 00649 00650 for( i = 0; iter != end; ++i ) 00651 { 00652 id = *iter; 00653 ++iter; 00654 if( iter == end ) 00655 { 00656 printf( "Entry %ld in %s adjacency data (ID %ld) is truncated by the end of the " 00657 "adjacency list.\n", 00658 i, name, id ); 00659 result = 1; 00660 break; 00661 } 00662 00663 if( id < start_id || ( id - start_id ) >= count ) 00664 { 00665 if( verbose ) 00666 printf( "Entry %ld in %s adjacency data has ID %ld outside of group range [%ld,%ld].\n", i, name, id, 00667 start_id, start_id + count - 1 ); 00668 ++invalid_id; 00669 } 00670 00671 n = *iter; 00672 ++iter; 00673 if( n < 1 ) 00674 { 00675 printf( "Entry %ld in %s adjacency data (ID %ld) has %ld adjacency entries.\n", i, name, id, n ); 00676 result = 1; 00677 if( n < 0 ) break; /* data is corrupt. don't proceed further */ 00678 } 00679 00680 if( iter + n > end ) 00681 { 00682 printf( "Entry %ld in %s adjacency data (ID %ld) is truncated by the end of the " 00683 "adjacency list.\n", 00684 i, name, id ); 00685 result = 1; 00686 break; 00687 } 00688 00689 if( !ids_contained( iter, n, valid_ranges, num_valid_ranges ) ) 00690 { 00691 if( verbose ) 00692 printf( "Entry %ld in %s adjacency data (ID %ld) has invalid IDs in its adjacency " 00693 "list.\n", 00694 i, name, id ); 00695 00696 ++invalid_vals; 00697 } 00698 iter += n; 00699 } 00700 00701 if( invalid_id ) 00702 { 00703 printf( "%ld entries in %s adjacency data were for entities not in %s\n", invalid_id, name, name ); 00704 result = 1; 00705 } 00706 if( invalid_vals ) 00707 { 00708 printf( "%ld entries in %s adjacency data contained invalid adjacent entity ids\n", invalid_id, name ); 00709 result = 1; 00710 } 00711 return result; 00712 } 00713 00714 int check_valid_sets( mhdf_FileHandle file, struct mhdf_FileDesc* desc ) 00715 { 00716 long count, start_id, data_len; 00717 mhdf_Status status; 00718 hid_t meta, handle; 00719 int result = 0; 00720 00721 if( desc->sets.count == 0 ) return 0; 00722 00723 meta = mhdf_openSetMeta( file, &count, &start_id, &status ); 00724 if( mhdf_isError( &status ) ) 00725 { 00726 fprintf( stderr, "Internal error opening set description table: %s\n", mhdf_message( &status ) ); 00727 return 1; 00728 } 00729 00730 if( desc->have_set_contents ) 00731 { 00732 handle = mhdf_openSetData( file, &data_len, &status ); 00733 if( mhdf_isError( &status ) ) 00734 { 00735 fprintf( stderr, "Internal error opening set contents table: %s\n", mhdf_message( &status ) ); 00736 } 00737 else 00738 { 00739 result += check_valid_set_contents( desc, start_id, count, meta, handle, data_len ); 00740 mhdf_closeData( file, handle, &status ); 00741 } 00742 } 00743 00744 if( desc->have_set_children ) 00745 { 00746 handle = mhdf_openSetChildren( file, &data_len, &status ); 00747 if( mhdf_isError( &status ) ) 00748 { 00749 fprintf( stderr, "Internal error opening set child table: %s\n", mhdf_message( &status ) ); 00750 mhdf_closeData( file, meta, &status ); 00751 } 00752 else 00753 { 00754 result += check_valid_parents_children( start_id, count, meta, handle, data_len, 0 ); 00755 mhdf_closeData( file, handle, &status ); 00756 } 00757 } 00758 00759 if( desc->have_set_parents ) 00760 { 00761 handle = mhdf_openSetParents( file, &data_len, &status ); 00762 if( mhdf_isError( &status ) ) 00763 { 00764 fprintf( stderr, "Internal error opening set child table: %s\n", mhdf_message( &status ) ); 00765 mhdf_closeData( file, meta, &status ); 00766 } 00767 else 00768 { 00769 result += check_valid_parents_children( start_id, count, meta, handle, data_len, 1 ); 00770 mhdf_closeData( file, handle, &status ); 00771 } 00772 } 00773 00774 mhdf_closeData( file, meta, &status ); 00775 return result; 00776 } 00777 00778 static int contains_duplicates( long* array, long n ) 00779 { 00780 long i; 00781 qsort( array, n, sizeof( long ), &lcomp ); 00782 for( i = 1; i < n; ++i ) 00783 if( array[i - 1] == array[i] ) return 1; 00784 return 0; 00785 } 00786 00787 static int ranges_contain_duplicates( long* ranges, long nranges ) 00788 { 00789 long i; 00790 qsort( ranges, nranges, 2 * sizeof( long ), &lcomp ); /* sort by first value in each pair */ 00791 for( i = 1; i < nranges; ++i ) 00792 if( ranges[2 * i - 2] + ranges[2 * i - 1] > ranges[2 * i] ) return 1; 00793 return 0; 00794 } 00795 00796 static int check_valid_parents_children( long start_id, 00797 long count, 00798 hid_t meta_handle, 00799 hid_t data_handle, 00800 long data_len, 00801 int parents ) 00802 { 00803 mhdf_Status status; 00804 long *indices, *contents; 00805 const char parstr[] = "Parent"; 00806 const char cldstr[] = "Child"; 00807 const char* name = parents ? parstr : cldstr; 00808 long i, prev, start, n; 00809 long invalid = 0, invalid_dup = 0; 00810 long range[2]; 00811 int result = 0; 00812 range[0] = start_id; 00813 range[1] = count; 00814 00815 indices = malloc( sizeof( long ) * count ); 00816 if( parents ) 00817 mhdf_readSetParentEndIndices( meta_handle, 0, count, H5T_NATIVE_LONG, indices, &status ); 00818 else 00819 mhdf_readSetChildEndIndices( meta_handle, 0, count, H5T_NATIVE_LONG, indices, &status ); 00820 if( mhdf_isError( &status ) ) 00821 { 00822 fprintf( stderr, "Internal error reading set %s end indices: %s\n", name, mhdf_message( &status ) ); 00823 free( indices ); 00824 return 1; 00825 } 00826 00827 if( check_valid_end_indices( indices, count, 0, start_id, data_len, "Set", name ) ) 00828 { 00829 free( indices ); 00830 return 1; 00831 } 00832 00833 contents = malloc( sizeof( long ) * data_len ); 00834 mhdf_readSetParentsChildren( data_handle, 0, data_len, H5T_NATIVE_LONG, contents, &status ); 00835 if( mhdf_isError( &status ) ) 00836 { 00837 fprintf( stderr, "Internal error reading set %s IDs: %s\n", name, mhdf_message( &status ) ); 00838 free( indices ); 00839 free( contents ); 00840 return 1; 00841 } 00842 00843 prev = -1; 00844 for( i = 0; i < count; ++i ) 00845 { 00846 start = prev + 1; 00847 n = indices[i] - prev; 00848 prev = indices[i]; 00849 00850 if( !ids_contained( contents + start, n, range, 1 ) ) 00851 { 00852 if( verbose ) printf( "Set %ld (ID %ld) has invalid %s IDs.\n", i, start_id + i, name ); 00853 ++invalid; 00854 } 00855 else if( contains_duplicates( contents + start, n ) ) 00856 { 00857 if( verbose ) printf( "Set %ld (ID %ld) %s list contains duplicate IDs.\n", i, start_id + i, name ); 00858 ++invalid_dup; 00859 } 00860 } 00861 00862 free( indices ); 00863 free( contents ); 00864 00865 if( invalid ) 00866 { 00867 printf( "%ld sets had invalid %s lists.\n", invalid, name ); 00868 result = 1; 00869 } 00870 00871 if( invalid_dup ) 00872 { 00873 printf( "%ld sets had duplicate handles in %s lists.\n", invalid_dup, name ); 00874 result = 1; 00875 } 00876 00877 return result; 00878 } 00879 00880 static int merge_ranges( long* ranges, int nranges ) 00881 { 00882 long i, n; 00883 00884 if( nranges < 1 ) return 0; 00885 00886 /* merge adjacent */ 00887 qsort( ranges, nranges, 2 * sizeof( long ), &lcomp ); 00888 n = 1; 00889 for( i = 1; i < nranges; ++i ) 00890 { 00891 if( ranges[2 * n - 2] + ranges[2 * n - 1] == ranges[2 * i] ) 00892 { 00893 ranges[2 * n - 1] += ranges[2 * i + 1]; /*compact the range*/ 00894 } 00895 else 00896 { 00897 /* do not compact, just copy, and increase number of ranges*/ 00898 ranges[2 * n] = ranges[2 * i]; 00899 ranges[2 * n + 1] = ranges[2 * i + 1]; 00900 ++n; 00901 } 00902 } 00903 00904 return n; 00905 } 00906 00907 static long* all_id_ranges( struct mhdf_FileDesc* desc, int include_null, int* num_ranges_out ) 00908 { 00909 int i, num_ranges = 0; 00910 struct mhdf_EntDesc* group; 00911 long* ranges = malloc( 2 * sizeof( long ) * ( desc->num_elem_desc + 2 + !!include_null ) ); 00912 if( include_null ) 00913 { 00914 num_ranges = 1; 00915 ranges[0] = 0; 00916 ranges[1] = 1; 00917 } 00918 for( i = -1; i <= desc->num_elem_desc; ++i ) 00919 { 00920 if( i == -1 ) 00921 group = &desc->nodes; 00922 else if( i == desc->num_elem_desc ) 00923 group = &desc->sets; 00924 else 00925 group = &desc->elems[i].desc; 00926 00927 if( num_ranges && ranges[2 * num_ranges - 2] + ranges[2 * num_ranges - 1] == group->start_id ) 00928 { 00929 ranges[2 * num_ranges - 1] += group->count; 00930 } 00931 else 00932 { 00933 ranges[2 * num_ranges] = group->start_id; 00934 ranges[2 * num_ranges + 1] = group->count; 00935 ++num_ranges; 00936 } 00937 } 00938 00939 *num_ranges_out = merge_ranges( ranges, num_ranges ); 00940 return ranges; 00941 } 00942 00943 static int check_valid_set_contents( struct mhdf_FileDesc* desc, 00944 long start_id, 00945 long count, 00946 hid_t meta_handle, 00947 hid_t data_handle, 00948 long data_len ) 00949 { 00950 mhdf_Status status; 00951 long *indices, *contents; 00952 short* flags; 00953 long i, prev, start, n; 00954 long invalid_len = 0, invalid_handle = 0, invalid_dup = 0; 00955 long* ranges; 00956 int num_ranges; 00957 int tmpresult; 00958 00959 indices = malloc( sizeof( long ) * count ); 00960 mhdf_readSetContentEndIndices( meta_handle, 0, count, H5T_NATIVE_LONG, indices, &status ); 00961 if( mhdf_isError( &status ) ) 00962 { 00963 fprintf( stderr, "Internal error reading set content end indices: %s\n", mhdf_message( &status ) ); 00964 free( indices ); 00965 return 1; 00966 } 00967 00968 if( check_valid_end_indices( indices, count, 0, start_id, data_len, "Set", "Content" ) ) 00969 { 00970 free( indices ); 00971 return 1; 00972 } 00973 00974 ranges = all_id_ranges( desc, 0, &num_ranges ); 00975 00976 flags = malloc( sizeof( short ) * count ); 00977 mhdf_readSetFlags( meta_handle, 0, count, H5T_NATIVE_SHORT, flags, &status ); 00978 if( mhdf_isError( &status ) ) 00979 { 00980 fprintf( stderr, "Internal error reading set flags: %s\n", mhdf_message( &status ) ); 00981 free( indices ); 00982 free( flags ); 00983 free( ranges ); 00984 return 1; 00985 } 00986 00987 contents = malloc( sizeof( long ) * data_len ); 00988 mhdf_readSetData( data_handle, 0, data_len, H5T_NATIVE_LONG, contents, &status ); 00989 if( mhdf_isError( &status ) ) 00990 { 00991 fprintf( stderr, "Internal error reading set content IDs: %s\n", mhdf_message( &status ) ); 00992 free( indices ); 00993 free( contents ); 00994 free( flags ); 00995 free( ranges ); 00996 return 1; 00997 } 00998 00999 prev = -1; 01000 for( i = 0; i < count; ++i ) 01001 { 01002 start = prev + 1; 01003 n = indices[i] - prev; 01004 prev = indices[i]; 01005 01006 if( flags[i] & mhdf_SET_RANGE_BIT ) 01007 { 01008 if( n % 2 ) 01009 { 01010 if( verbose ) 01011 printf( "Set %ld (ID %ld) is marked as range-compressed but has odd number of " 01012 "content values.\n", 01013 i + 1, start_id + i ); 01014 ++invalid_len; 01015 continue; 01016 } 01017 tmpresult = ranges_contained( contents + start, n / 2, ranges, num_ranges ); 01018 } 01019 else 01020 { 01021 tmpresult = ids_contained( contents + start, n, ranges, num_ranges ); 01022 } 01023 if( !tmpresult ) 01024 { 01025 if( verbose ) printf( "Set %ld (ID %ld) has invalid content IDs.\n", i + 1, start_id + i ); 01026 ++invalid_handle; 01027 continue; 01028 } 01029 01030 if( flags[i] & mhdf_SET_ORDER_BIT ) continue; 01031 01032 if( flags[i] & mhdf_SET_RANGE_BIT ) 01033 tmpresult = ranges_contain_duplicates( contents + start, n / 2 ); 01034 else 01035 tmpresult = contains_duplicates( contents + start, n ); 01036 if( tmpresult ) 01037 { 01038 if( verbose ) 01039 printf( "Set %ld (ID %ld) is not ordered but contains duplicate handles.\n", i + 1, start_id + i ); 01040 ++invalid_dup; 01041 } 01042 } 01043 01044 free( indices ); 01045 free( contents ); 01046 free( flags ); 01047 free( ranges ); 01048 01049 tmpresult = 0; 01050 if( invalid_len ) 01051 { 01052 printf( "%ld ranged sets had invalid (odd) content list lengths.\n", invalid_len ); 01053 tmpresult = 1; 01054 } 01055 if( invalid_handle ) 01056 { 01057 printf( "%ld sets had invalid IDs in their content lists.\n", invalid_handle ); 01058 tmpresult = 1; 01059 } 01060 if( invalid_dup ) 01061 { 01062 printf( "%ld unordered sets had duplicate IDs in their content lists.\n", invalid_dup ); 01063 tmpresult = 1; 01064 } 01065 01066 return tmpresult; 01067 } 01068 01069 int check_valid_tags( mhdf_FileHandle file, struct mhdf_FileDesc* desc ) 01070 { 01071 int i, result = 0; 01072 for( i = 0; i < desc->num_tag_desc; ++i ) 01073 { 01074 if( desc->tags[i].size < 0 ) 01075 result += check_valid_var_len_tag( i, file, desc ); 01076 else 01077 result += check_valid_tag( i, file, desc ); 01078 } 01079 return result; 01080 } 01081 01082 static int check_valid_tag( int tag_idx, mhdf_FileHandle file, struct mhdf_FileDesc* desc ) 01083 { 01084 long *ids = 0, count, junk; 01085 long* ranges; 01086 int nranges; 01087 hid_t handles[3]; 01088 mhdf_Status status; 01089 const struct mhdf_TagDesc* tag = &( desc->tags[tag_idx] ); 01090 int i, result = 0; 01091 long srange[2] = { 0, 0 }; 01092 const char* name; 01093 struct mhdf_EntDesc* group; 01094 hid_t h5type; 01095 hsize_t size; 01096 01097 if( tag->have_sparse ) 01098 { 01099 mhdf_openSparseTagData( file, tag->name, &count, &junk, handles, &status ); 01100 if( mhdf_isError( &status ) ) 01101 { 01102 fprintf( stderr, "Internal error opening sparse data for tag \"%s\": %s\n", tag->name, 01103 mhdf_message( &status ) ); 01104 return 1; 01105 } 01106 01107 ids = malloc( sizeof( long ) * count ); 01108 mhdf_readSparseTagEntities( handles[0], 0, count, H5T_NATIVE_LONG, ids, &status ); 01109 if( mhdf_isError( &status ) ) 01110 { 01111 fprintf( stderr, "Internal error reading sparse entities for tag \"%s\": %s\n", tag->name, 01112 mhdf_message( &status ) ); 01113 mhdf_closeData( file, handles[0], &status ); 01114 mhdf_closeData( file, handles[1], &status ); 01115 free( ids ); 01116 return 1; 01117 } 01118 01119 mhdf_closeData( file, handles[0], &status ); 01120 ranges = all_id_ranges( desc, 0, &nranges ); 01121 if( !ids_contained( ids, count, ranges, nranges ) ) 01122 { 01123 ++result; 01124 printf( "Sparse data for tag \"%s\" has values for invalid IDs\n", tag->name ); 01125 } 01126 else if( contains_duplicates( ids, count ) ) 01127 { 01128 ++result; 01129 printf( "Sparse data for tag \"%s\" has duplicate values for one or more entities\n", tag->name ); 01130 } 01131 free( ranges ); 01132 01133 for( i = 0; i < tag->num_dense_indices; ++i ) 01134 { 01135 if( tag->dense_elem_indices[i] == -2 ) 01136 { 01137 name = mhdf_set_type_handle(); 01138 group = &desc->sets; 01139 } 01140 else if( tag->dense_elem_indices[i] == -1 ) 01141 { 01142 name = mhdf_node_type_handle(); 01143 group = &desc->nodes; 01144 } 01145 else 01146 { 01147 name = desc->elems[tag->dense_elem_indices[i]].handle; 01148 group = &desc->elems[tag->dense_elem_indices[i]].desc; 01149 } 01150 01151 srange[0] = group->start_id; 01152 srange[1] = group->count; 01153 if( ids_contained( ids, count, srange, 2 ) ) 01154 { 01155 ++result; 01156 printf( "Tag \"%s\" has both sparse values and dense values for one or more " 01157 "entities in \"%s\"\n", 01158 tag->name, name ); 01159 } 01160 } 01161 01162 free( ids ); 01163 } 01164 01165 if( tag->type != mhdf_ENTITY_ID ) 01166 { 01167 if( tag->have_sparse ) mhdf_closeData( file, handles[1], &status ); 01168 return result; 01169 } 01170 01171 ranges = all_id_ranges( desc, 1, &nranges ); 01172 if( tag->default_value && !ids_contained( tag->default_value, tag->size, ranges, nranges ) ) 01173 { 01174 ++result; 01175 printf( "Handle tag \"%s\" has invalid ID(s) in its default value.\n", tag->name ); 01176 } 01177 if( tag->global_value && !ids_contained( tag->global_value, tag->size, ranges, nranges ) ) 01178 { 01179 ++result; 01180 printf( "Handle tag \"%s\" has invalid ID(s) in its global/mesh value.\n", tag->name ); 01181 } 01182 01183 h5type = H5T_NATIVE_LONG; 01184 if( tag->size > 1 ) 01185 { 01186 size = tag->size; 01187 #if defined( H5Tarray_create_vers ) && H5Tarray_create_vers > 1 01188 h5type = H5Tarray_create( H5T_NATIVE_LONG, 1, &size ); 01189 #else 01190 h5type = H5Tarray_create( H5T_NATIVE_LONG, 1, &size, NULL ); 01191 #endif 01192 } 01193 01194 if( tag->have_sparse ) 01195 { 01196 ids = malloc( tag->size * count * sizeof( long ) ); 01197 mhdf_readTagValues( handles[1], 0, count, h5type, ids, &status ); 01198 if( mhdf_isError( &status ) ) 01199 { 01200 fprintf( stderr, "Internal error reading sparse values for handle tag \"%s\": %s\n", tag->name, 01201 mhdf_message( &status ) ); 01202 mhdf_closeData( file, handles[1], &status ); 01203 free( ids ); 01204 free( ranges ); 01205 if( tag->size > 1 ) H5Tclose( h5type ); 01206 return 1; 01207 } 01208 mhdf_closeData( file, handles[1], &status ); 01209 01210 if( !ids_contained( ids, tag->size * count, ranges, nranges ) ) 01211 { 01212 ++result; 01213 printf( "Sparse data for one or more entities with handle tag \"%s\" has invalid ID(s).\n", tag->name ); 01214 } 01215 free( ids ); 01216 } 01217 01218 for( i = 0; i < tag->num_dense_indices; ++i ) 01219 { 01220 if( tag->dense_elem_indices[i] == -2 ) 01221 { 01222 name = mhdf_set_type_handle(); 01223 /*group = &desc->sets;*/ 01224 } 01225 else if( tag->dense_elem_indices[i] == -1 ) 01226 { 01227 name = mhdf_node_type_handle(); 01228 /*group = &desc->nodes;*/ 01229 } 01230 else 01231 { 01232 name = desc->elems[tag->dense_elem_indices[i]].handle; 01233 /*group = &desc->elems[ tag->dense_elem_indices[i] ].desc;*/ 01234 } 01235 01236 handles[0] = mhdf_openDenseTagData( file, tag->name, name, &count, &status ); 01237 if( mhdf_isError( &status ) ) 01238 { 01239 fprintf( stderr, "Internal dense values for handle tag \"%s\" on \"%s\": %s\n", tag->name, name, 01240 mhdf_message( &status ) ); 01241 ++result; 01242 continue; 01243 } 01244 01245 ids = malloc( tag->size * count * sizeof( long ) ); 01246 mhdf_readTagValues( handles[0], 0, count, h5type, ids, &status ); 01247 if( mhdf_isError( &status ) ) 01248 { 01249 fprintf( stderr, "Internal error reading dense values for handle tag \"%s\" on \"%s\": %s\n", tag->name, 01250 name, mhdf_message( &status ) ); 01251 mhdf_closeData( file, handles[0], &status ); 01252 free( ids ); 01253 ++result; 01254 continue; 01255 } 01256 mhdf_closeData( file, handles[1], &status ); 01257 01258 if( !ids_contained( ids, count, ranges, nranges ) ) 01259 { 01260 ++result; 01261 printf( "Dense data on \"%s\" for handle tag \"%s\" has invalid ID(s) for one or more " 01262 "entities.\n", 01263 name, tag->name ); 01264 } 01265 free( ids ); 01266 } 01267 01268 if( tag->size > 1 ) H5Tclose( h5type ); 01269 01270 return result; 01271 } 01272 01273 static int check_valid_var_len_tag( int tag_idx, mhdf_FileHandle file, struct mhdf_FileDesc* desc ) 01274 { 01275 long *ids = 0, count, num_val; 01276 long* ranges; 01277 int nranges; 01278 hid_t handles[3]; 01279 mhdf_Status status; 01280 const struct mhdf_TagDesc* tag = &( desc->tags[tag_idx] ); 01281 int result = 0; 01282 01283 if( tag->num_dense_indices != 0 ) 01284 { 01285 printf( "Dense data for tag \"%s\" not allowed for variable-length tags\n", tag->name ); 01286 ++result; 01287 } 01288 01289 if( tag->have_sparse ) 01290 { 01291 mhdf_openSparseTagData( file, tag->name, &count, &num_val, handles, &status ); 01292 if( mhdf_isError( &status ) ) 01293 { 01294 fprintf( stderr, "Internal error opening sparse data for tag \"%s\": %s\n", tag->name, 01295 mhdf_message( &status ) ); 01296 return 1; 01297 } 01298 01299 ids = malloc( sizeof( long ) * count ); 01300 mhdf_readSparseTagEntities( handles[0], 0, count, H5T_NATIVE_LONG, ids, &status ); 01301 if( mhdf_isError( &status ) ) 01302 { 01303 fprintf( stderr, "Internal error reading sparse entities for tag \"%s\": %s\n", tag->name, 01304 mhdf_message( &status ) ); 01305 mhdf_closeData( file, handles[0], &status ); 01306 mhdf_closeData( file, handles[1], &status ); 01307 mhdf_closeData( file, handles[2], &status ); 01308 free( ids ); 01309 return 1; 01310 } 01311 01312 mhdf_closeData( file, handles[0], &status ); 01313 ranges = all_id_ranges( desc, 0, &nranges ); 01314 if( !ids_contained( ids, count, ranges, nranges ) ) 01315 { 01316 ++result; 01317 printf( "Sparse data for tag \"%s\" has values for invalid IDs\n", tag->name ); 01318 } 01319 else if( contains_duplicates( ids, count ) ) 01320 { 01321 ++result; 01322 printf( "Sparse data for tag \"%s\" has duplicate values for one or more entities\n", tag->name ); 01323 } 01324 free( ranges ); 01325 01326 mhdf_readSparseTagIndices( handles[2], 0, count, H5T_NATIVE_LONG, ids, &status ); 01327 if( mhdf_isError( &status ) ) 01328 { 01329 fprintf( stderr, "Internal error reading indices for variable length tag \"%s\": %s\n", tag->name, 01330 mhdf_message( &status ) ); 01331 mhdf_closeData( file, handles[1], &status ); 01332 mhdf_closeData( file, handles[2], &status ); 01333 free( ids ); 01334 return 1; 01335 } 01336 mhdf_closeData( file, handles[2], &status ); 01337 01338 if( check_valid_end_indices( ids, count, 1, 0, num_val, "Variable-length tag", tag->name ) ) ++result; 01339 free( ids ); 01340 } 01341 01342 if( tag->type != mhdf_ENTITY_ID ) 01343 { 01344 if( tag->have_sparse ) mhdf_closeData( file, handles[1], &status ); 01345 return result; 01346 } 01347 01348 ranges = all_id_ranges( desc, 1, &nranges ); 01349 if( tag->default_value && !ids_contained( tag->default_value, tag->default_value_size, ranges, nranges ) ) 01350 { 01351 ++result; 01352 printf( "Handle tag \"%s\" has invalid ID(s) in its default value.\n", tag->name ); 01353 } 01354 if( tag->global_value && !ids_contained( tag->global_value, tag->global_value_size, ranges, nranges ) ) 01355 { 01356 ++result; 01357 printf( "Handle tag \"%s\" has invalid ID(s) in its global/mesh value.\n", tag->name ); 01358 } 01359 01360 if( tag->have_sparse ) 01361 { 01362 ids = malloc( num_val * sizeof( long ) ); 01363 mhdf_readTagValues( handles[1], 0, num_val, H5T_NATIVE_LONG, ids, &status ); 01364 if( mhdf_isError( &status ) ) 01365 { 01366 fprintf( stderr, "Internal error reading values for variable-length handle tag \"%s\": %s\n", tag->name, 01367 mhdf_message( &status ) ); 01368 mhdf_closeData( file, handles[1], &status ); 01369 free( ids ); 01370 free( ranges ); 01371 return 1; 01372 } 01373 mhdf_closeData( file, handles[1], &status ); 01374 01375 if( !ids_contained( ids, tag->size * count, ranges, nranges ) ) 01376 { 01377 ++result; 01378 printf( "Data for one or more entities with variable-length handle tag \"%s\" has " 01379 "invalid ID(s).\n", 01380 tag->name ); 01381 } 01382 free( ids ); 01383 } 01384 01385 return result; 01386 }