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