/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by the Board of Trustees of the University of Illinois. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the files COPYING and Copyright.html. COPYING can be found at the root * * of the source code distribution tree; Copyright.html can be found at the * * root level of an installed copy of the electronic HDF5 document set and * * is linked from the top-level documents page. It can also be found at * * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "h5diff.h" #include "H5private.h" #include #include /*------------------------------------------------------------------------- * Function: h5diff * * Purpose: public function, can be called in an applicattion program. * return differences between 2 HDF5 files * * Return: Number of differences found; -1 for error. * * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu * * Date: October 22, 2003 * *------------------------------------------------------------------------- */ int h5diff(const char *fname1, const char *fname2, const char *objname1, const char *objname2, diff_opt_t *options) { int nobjects1, nobjects2; trav_info_t *info1=NULL; trav_info_t *info2=NULL; hid_t file1_id, file2_id; int nfound=0; /*------------------------------------------------------------------------- * open the files first; if they are not valid, no point in continuing *------------------------------------------------------------------------- */ /* disable error reporting */ H5E_BEGIN_TRY { /* Open the files */ if ((file1_id=H5Fopen(fname1,H5F_ACC_RDONLY,H5P_DEFAULT))<0 ) { printf("h5diff: %s: No such file or directory\n", fname1 ); nfound = -1; } if ((file2_id=H5Fopen(fname2,H5F_ACC_RDONLY,H5P_DEFAULT))<0 ) { printf("h5diff: %s: No such file or directory\n", fname2 ); nfound = -1; } /* enable error reporting */ } H5E_END_TRY; if (nfound<0) return -1; /*------------------------------------------------------------------------- * get the number of objects in the files *------------------------------------------------------------------------- */ nobjects1 = h5trav_getinfo( file1_id, NULL ); nobjects2 = h5trav_getinfo( file2_id, NULL ); /*------------------------------------------------------------------------- * get the list of objects in the files *------------------------------------------------------------------------- */ info1 = (trav_info_t*) malloc( nobjects1 * sizeof(trav_info_t)); info2 = (trav_info_t*) malloc( nobjects2 * sizeof(trav_info_t)); if (info1==NULL || info2==NULL) { nfound=-1; goto out; } h5trav_getinfo( file1_id, info1 ); h5trav_getinfo( file2_id, info2 ); /*------------------------------------------------------------------------- * object name was supplied *------------------------------------------------------------------------- */ if ( objname1 ) { assert(objname2); nfound=diff_compare(file1_id,fname1,objname1,nobjects1,info1, file2_id,fname2,objname2,nobjects2,info2,options); } /*------------------------------------------------------------------------- * compare all *------------------------------------------------------------------------- */ else { nfound=diff_match(file1_id,nobjects1,info1, file2_id,nobjects2,info2,options); } h5trav_freeinfo(info1,nobjects1); h5trav_freeinfo(info2,nobjects2); out: /* close */ H5Fclose(file1_id); H5Fclose(file2_id); return nfound; } /*------------------------------------------------------------------------- * Function: diff_match * * Purpose: Find common objects; the algorithm used for this search is the * cosequential match algorithm and is described in * Folk, Michael; Zoellick, Bill. (1992). File Structures. Addison-Wesley. * * Return: Number of differences found * * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu * * Date: May 9, 2003 * *------------------------------------------------------------------------- */ int diff_match( hid_t file1_id, int nobjects1, trav_info_t *info1, hid_t file2_id, int nobjects2, trav_info_t *info2, diff_opt_t *options ) { int more_names_exist = (nobjects1>0 && nobjects2>0) ? 1 : 0; trav_table_t *table=NULL; int cmp; int curr1=0; int curr2=0; unsigned infile[2]; char c1, c2; int nfound=0, i; /*------------------------------------------------------------------------- * build the list *------------------------------------------------------------------------- */ trav_table_init( &table ); while ( more_names_exist ) { /* criteria is string compare */ cmp = strcmp( info1[curr1].name, info2[curr2].name ); if ( cmp == 0 ) { infile[0]=1; infile[1]=1; trav_table_addflags(infile, info1[curr1].name, info1[curr1].type, table ); curr1++; curr2++; } else if ( cmp < 0 ) { infile[0]=1; infile[1]=0; trav_table_addflags(infile, info1[curr1].name, info1[curr1].type, table ); curr1++; } else { infile[0]=0; infile[1]=1; trav_table_addflags(infile, info2[curr2].name, info2[curr2].type, table ); curr2++; } more_names_exist = (curr1verbose) { printf("\n"); printf("file1 file2\n"); printf("---------------------------------------\n"); for (i = 0; i < table->nobjs; i++) { c1 = (table->objs[i].flags[0]) ? 'x' : ' '; c2 = (table->objs[i].flags[1]) ? 'x' : ' '; printf("%5c %6c %-15s\n", c1, c2, table->objs[i].objname); } printf("\n"); } /*------------------------------------------------------------------------- * do the diff for common objects *------------------------------------------------------------------------- */ for (i = 0; i < table->nobjs; i++) { if ( table->objs[i].flags[0] && table->objs[i].flags[1] ) nfound+=diff( file1_id, table->objs[i].objname, file2_id, table->objs[i].objname, options, table->objs[i].type ); } /* free table */ trav_table_free(table); /*------------------------------------------------------------------------- * do the diff for the root. * this is a special case, we get an ID for the root group and call diff() * with this ID; it compares only the root group attributes *------------------------------------------------------------------------- */ nfound+=diff( file1_id, "/", file2_id, "/", options, H5G_GROUP ); return nfound; } /*------------------------------------------------------------------------- * Function: diff_compare * * Purpose: get objects from list, and check for the same type * * Return: Number of differences found * * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu * * Date: May 9, 2003 * *------------------------------------------------------------------------- */ int diff_compare( hid_t file1_id, const char *file1_name, const char *obj1_name, int nobjects1, trav_info_t *info1, hid_t file2_id, const char *file2_name, const char *obj2_name, int nobjects2, trav_info_t *info2, diff_opt_t *options ) { int f1=0, f2=0; int nfound=0; int i = h5trav_getindex( obj1_name, nobjects1, info1 ); int j = h5trav_getindex( obj2_name, nobjects2, info2 ); if ( i == -1 ) { printf( "Object <%s> could not be found in <%s>\n", obj1_name, file1_name ); f1=1; } if ( j == -1 ) { printf( "Object <%s> could not be found in <%s>\n", obj2_name, file2_name ); f2=1; } if ( f1 || f2 ) return -1; /* use the name with "/" first, as obtained by iterator function */ obj1_name=info1[i].name; obj2_name=info2[j].name; /* objects are not the same type */ if ( info1[i].type != info2[j].type && options->verbose) { printf("Comparison not possible: <%s> is of type %s and <%s> is of type %s\n", obj1_name, get_type(info1[i].type), obj2_name, get_type(info2[j].type) ); return 1; } nfound=diff( file1_id, obj1_name, file2_id, obj2_name, options, info1[i].type ); return nfound; } /*------------------------------------------------------------------------- * Function: diff * * Purpose: switch between types and choose the diff function * TYPE is either * H5G_LINK Object is a symbolic link * H5G_GROUP Object is a group * H5G_DATASET Object is a dataset * H5G_TYPE Object is a named data type * * Return: Number of differences found * * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu * * Date: May 9, 2003 * *------------------------------------------------------------------------- */ int diff( hid_t file1_id, const char *path1, hid_t file2_id, const char *path2, diff_opt_t *options, H5G_obj_t type ) { hid_t type1_id; hid_t type2_id; hid_t grp1_id; hid_t grp2_id; int ret; H5G_stat_t sb1; H5G_stat_t sb2; char *buf1=NULL; char *buf2=NULL; int nfound=-1; switch ( type ) { /*------------------------------------------------------------------------- * H5G_DATASET *------------------------------------------------------------------------- */ case H5G_DATASET: if (options->verbose) printf( "Dataset: <%s> and <%s>\n",path1,path2); nfound=diff_dataset(file1_id,file2_id,path1,path2,options); break; /*------------------------------------------------------------------------- * H5G_TYPE *------------------------------------------------------------------------- */ case H5G_TYPE: if (options->verbose) printf( "Datatype: <%s> and <%s>\n",path1,path2); if ((type1_id = H5Topen(file1_id, path1))<0) goto out; if ((type2_id = H5Topen(file2_id, path2))<0) goto out; if ((ret = H5Tequal(type1_id,type2_id))<0) goto out; /* if H5Tequal is > 0 then the datatypes refer to the same datatype */ nfound = (ret>0) ? 0 : 1; /*------------------------------------------------------------------------- * compare attributes * the if condition refers to cases when the dataset is a referenced object *------------------------------------------------------------------------- */ if (path1) nfound=diff_attr(type1_id,type2_id,path1,path2,options); if ( H5Tclose(type1_id)<0) goto out; if ( H5Tclose(type2_id)<0) goto out; break; /*------------------------------------------------------------------------- * H5G_GROUP *------------------------------------------------------------------------- */ case H5G_GROUP: if (options->verbose) printf( "Group: <%s> and <%s>\n",path1,path2); if ((grp1_id = H5Gopen(file1_id, path1))<0) goto out; if ((grp2_id = H5Gopen(file2_id, path2))<0) goto out; ret = HDstrcmp(path1,path2); /* if "path1" != "path2" then the groups are "different" */ nfound = (ret!=0) ? 1 : 0; /*------------------------------------------------------------------------- * compare attributes * the if condition refers to cases when the dataset is a referenced object *------------------------------------------------------------------------- */ if (path1) nfound=diff_attr(grp1_id,grp2_id,path1,path2,options); if ( H5Gclose(grp1_id)<0) goto out; if ( H5Gclose(grp2_id)<0) goto out; break; /*------------------------------------------------------------------------- * H5G_LINK *------------------------------------------------------------------------- */ case H5G_LINK: if (options->verbose) printf( "Link: <%s> and <%s>\n",path1,path2); if (H5Gget_objinfo(file1_id,path1,FALSE,&sb1)<0) goto out; if (H5Gget_objinfo(file1_id,path1,FALSE,&sb2)<0) goto out; buf1 = malloc(sb1.linklen); buf2 = malloc(sb2.linklen); if (H5Gget_linkval(file1_id,path1,sb1.linklen,buf1)<0) goto out; if (H5Gget_linkval(file2_id,path2,sb1.linklen,buf2)<0) goto out; ret = HDstrcmp(buf1,buf2); /* if "buf1" != "buf2" then the links are "different" */ nfound = (ret!=0) ? 1 : 0; if (buf1) { free(buf1); buf1=NULL; } if (buf2) { free(buf2); buf2=NULL; } break; default: nfound=0; if (options->verbose) { printf("Comparison not supported: <%s> and <%s> are of type %s\n", path1, path2, get_type(type) ); } break; } out: /* close */ /* disable error reporting */ H5E_BEGIN_TRY { H5Tclose(type1_id); H5Tclose(type2_id); H5Gclose(grp1_id); H5Tclose(grp2_id); /* enable error reporting */ } H5E_END_TRY; if (buf1) free(buf1); if (buf2) free(buf2); return nfound; } /*------------------------------------------------------------------------- * Function: diff_list * * Purpose: print list of objects in file * * Return: void * * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu * * Date: May 9, 2003 * * Comments: * * Modifications: * *------------------------------------------------------------------------- */ #ifdef NOT_YET void diff_list( const char *filename, int nobjects, trav_info_t *info ) { int i; printf("File <%s>: # of entries = %d\n", filename, nobjects ); for ( i = 0; i < nobjects; i++) { switch ( info[i].type ) { case H5G_GROUP: printf(" %-10s %s\n", "group", info[i].name ); break; case H5G_DATASET: printf(" %-10s %s\n", "dataset", info[i].name ); break; case H5G_TYPE: printf(" %-10s %s\n", "datatype", info[i].name ); break; case H5G_LINK: printf(" %-10s %s\n", "link", info[i].name ); break; default: printf(" %-10s %s\n", "User defined object", info[i].name ); break; } } } #endif