MOAB: Mesh Oriented datABase  (version 5.2.1)
validate.c
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines