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