From cb4334cbf1dccc40613d6c95ad1ca9b718f87268 Mon Sep 17 00:00:00 2001 From: Mark Koennecke Date: Fri, 15 Jul 2016 13:39:20 +0200 Subject: [PATCH] Added support for validating NeXus files without an application definition. As implemented now, validation happens against a minimal application definition containing just an NXentry. Refs #13 --- nxvmain.c | 6 +++--- src/minimal.c | 17 ++++++++++++++++ src/nxdlutil.c | 7 ++++++- src/nxvcontext.h | 12 ++++++++++++ src/nxvfield.c | 46 +++++++++++++++++++++++++++++++++++++++++++ src/nxvgroup.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-- src/nxvmainloop.c | 9 +++++---- src/nxvutil.c | 4 +--- 8 files changed, 138 insertions(+), 13 deletions(-) create mode 100644 src/minimal.c diff --git a/nxvmain.c b/nxvmain.c index 088dd9a..d6259c0 100644 --- a/nxvmain.c +++ b/nxvmain.c @@ -68,9 +68,9 @@ int main(int argc, char *argv[]) /* should all be 0 in production */ - filt.warnOpt = 1; - filt.warnBase = 1; - filt.warnUndefined = 1; + filt.warnOpt = 0; + filt.warnBase = 0; + filt.warnUndefined = 0; filt.debug = 0; diff --git a/src/minimal.c b/src/minimal.c new file mode 100644 index 0000000..0eccff8 --- /dev/null +++ b/src/minimal.c @@ -0,0 +1,17 @@ +/* + Just a morsel of code to define the minimal application definition. For + checking NeXus files without an application definition +*/ + +static const char xmlMinimal[] = "\ +\ +\ + \ + \ +"; diff --git a/src/nxdlutil.c b/src/nxdlutil.c index 0e6dc6f..c4b4fac 100644 --- a/src/nxdlutil.c +++ b/src/nxdlutil.c @@ -242,6 +242,7 @@ static void mergeInheritance(pNXVcontext self) mergeInheritance(self); } +#include "minimal.c" /*--------------------------------------------------------------*/ int NXVloadAppDef(pNXVcontext self, char *nxdlFile) { @@ -257,7 +258,11 @@ int NXVloadAppDef(pNXVcontext self, char *nxdlFile) pPtr = nxdlFile; } - xmlData = self->nxdlRetriever(pPtr,self->retrieverUserData); + if(strstr(pPtr,"NXminimal") == NULL){ + xmlData = self->nxdlRetriever(pPtr,self->retrieverUserData); + } else { + xmlData = strdup(xmlMinimal); + } if(xmlData == NULL){ NXVsetLog(self,"sev","fatal"); NXVsetLog(self,"message","Failed to load application definition"); diff --git a/src/nxvcontext.h b/src/nxvcontext.h index e6a9c3f..59f28c3 100644 --- a/src/nxvcontext.h +++ b/src/nxvcontext.h @@ -78,3 +78,15 @@ int testISO8601(char *date); * strings are not properly read by this HDF5 function. Implemented in nxvutil.c */ herr_t H5NXget_attribute_string( hid_t loc_id, const char *obj_name, const char *attr_name, char *data ); + +/* + * validate a base class filed as fas as this is possible. Implemented in nxvfield.c + */ +void validateBaseClassField(pNXVcontext self, hid_t groupID, hid_t dataID); + +/* + validation of the depends_on chain. In nxvgroup.c +*/ +void validateDependsOn(pNXVcontext self, hid_t groupID, + hid_t fieldID); + diff --git a/src/nxvfield.c b/src/nxvfield.c index 73808ff..fbe9353 100644 --- a/src/nxvfield.c +++ b/src/nxvfield.c @@ -1060,3 +1060,49 @@ int NXVvalidateField(pNXVcontext self, hid_t fieldID, self->nxdlPath = myPath; return 0; } +/*-----------------------------------------------------------------------*/ +void validateBaseClassField(pNXVcontext self, hid_t groupID, hid_t dataID) +{ + char fName[512]; + + H5Iget_name(dataID,fName,sizeof(fName)); + NXVsetLog(self,"sev","debug"); + NXVsetLog(self,"message","Validating field"); + NXVsetLog(self,"dataPath",fName); + NXVlog(self); + + validateDataOffsetStride(self, dataID); + validateAxes(self, dataID); + validateInterpretation(self,dataID); + validateCalibration(self,dataID); + + if(H5LTfind_attribute(dataID,"depends_on") == 1){ + validateDependsOn(self,groupID,dataID); + } + + if(H5LTfind_attribute(dataID,"axis") == 1 && + testAttType(dataID,"axis",H5T_INTEGER) == 0 && + testAttType(dataID,"axis",H5T_STRING) == 0){ + NXVsetLog(self,"sev","error"); + NXVprintLog(self,"message","Attribute %s to %s has wrong type", "axis",fName); + NXVlog(self); + } + + if(H5LTfind_attribute(dataID,"signal") == 1 && + testAttType(dataID,"signal",H5T_INTEGER) == 0 && + testAttType(dataID,"signal",H5T_STRING) == 0){ + NXVsetLog(self,"sev","error"); + NXVprintLog(self,"message","Attribute %s to %s has wrong type", "signal",fName); + NXVlog(self); + } + + if(H5LTfind_attribute(dataID,"primary") == 1 && + testAttType(dataID,"primary",H5T_INTEGER) == 0 && + testAttType(dataID,"primary",H5T_STRING) == 0){ + NXVsetLog(self,"sev","error"); + NXVprintLog(self,"message","Attribute %s to %s has wrong type", "primary",fName); + NXVlog(self); + } + +} + diff --git a/src/nxvgroup.c b/src/nxvgroup.c index 998ef63..84ef353 100644 --- a/src/nxvgroup.c +++ b/src/nxvgroup.c @@ -560,7 +560,7 @@ static void validateDependsOnField(pNXVcontext self, } } /*--------------------------------------------------------------*/ -static void validateDependsOn(pNXVcontext self, hid_t groupID, +void validateDependsOn(pNXVcontext self, hid_t groupID, hid_t fieldID) { char fname[512], dpData[1024]; @@ -632,6 +632,48 @@ typedef struct { hash_table *baseNames; pNXVcontext self; } SecondPassData; +/*------------------ forward declaration ----------------------------*/ +static herr_t SecondPassIterator(hid_t g_id, + const char *name, + const H5L_info_t *info, void *op_data); + +/*--------------------------------------------------------------*/ +static void validateBaseClassGroup(pNXVcontext self, hid_t group_id, char *baseClass) +{ + SecondPassData spd; + char *oldNXDLPath; + char myNXDLPath[512], fName[1024]; + hash_table namesSeen, baseNames; + hsize_t idx = 0; + + oldNXDLPath = self->nxdlPath; + snprintf(myNXDLPath,sizeof(myNXDLPath),"/BASE/%s", baseClass); + self->nxdlPath = myNXDLPath; + NXVsetLog(self,"nxdlPath", myNXDLPath); + + H5Iget_name(group_id,fName,sizeof(fName)); + NXVsetLog(self,"sev","debug"); + NXVsetLog(self,"dataPath",fName); + NXVsetLog(self,"message","Validating group against base class"); + NXVlog(self); + + hash_construct_table(&baseNames,100); + hash_construct_table(&namesSeen,2); + NXVloadBaseClass(self,&baseNames,baseClass); + spd.baseNames = &baseNames; + spd.namesSeen = &namesSeen; + spd.self = self; + H5Literate(group_id, H5_INDEX_NAME, H5_ITER_INC, &idx, + SecondPassIterator, &spd); + + /* + clean up + */ + hash_free_table(&namesSeen,free); + hash_free_table(&baseNames,free); + self->nxdlPath = oldNXDLPath; + NXVsetLog(self,"nxdlPath", oldNXDLPath); +} /*--------------------------------------------------------------*/ static herr_t SecondPassIterator(hid_t g_id, const char *name, @@ -667,6 +709,7 @@ static herr_t SecondPassIterator(hid_t g_id, name, nxClass); NXVlog(spd->self); spd->self->warnCount++; + validateBaseClassGroup(spd->self, groupID, nxClass); } else { NXVsetLog(spd->self,"sev","warnbase"); NXVprintLog(spd->self,"message", @@ -674,6 +717,7 @@ static herr_t SecondPassIterator(hid_t g_id, name, nxClass); NXVlog(spd->self); spd->self->warnCount++; + validateBaseClassGroup(spd->self, groupID, nxClass); } } else { NXVsetLog(spd->self,"sev","warnundef"); @@ -687,7 +731,6 @@ static herr_t SecondPassIterator(hid_t g_id, } else if (obj_info.type == H5O_TYPE_DATASET) { dataID = H5Dopen(g_id,name,H5P_DEFAULT); H5Iget_name(dataID, fname,sizeof(fname)); - H5Dclose(dataID); NXVsetLog(spd->self,"dataPath",fname); if(hash_lookup((char *)name,spd->baseNames) == NULL){ NXVsetLog(spd->self,"sev","warnundef"); @@ -701,7 +744,10 @@ static herr_t SecondPassIterator(hid_t g_id, name); NXVlog(spd->self); spd->self->warnCount++; + validateBaseClassField(spd->self, g_id, dataID); + } + H5Dclose(dataID); } return 0; diff --git a/src/nxvmainloop.c b/src/nxvmainloop.c index 79248fa..7ff9f41 100644 --- a/src/nxvmainloop.c +++ b/src/nxvmainloop.c @@ -82,7 +82,7 @@ static int validatePath(pNXVcontext self, char *path, char *rawNxdlFile) hid_t groupID; xmlNodePtr groupNode = NULL; char nxdlFile[512]; - + /* first fix the appDef: the nxdl.xml postfix may be missing */ @@ -195,7 +195,7 @@ static herr_t NXVrootIterator(hid_t g_id, if(strcmp(nxClass,"NXentry") != 0){ NXVsetLog(self,"sev","error"); NXVprintLog(self,"dataPath","/%s",name); - NXVprintLog(self,"message", + NXVprintLog(self,"message", "Wrong root group class %s, expected NXentry",nxClass); NXVlog(self); } @@ -241,10 +241,11 @@ static herr_t NXVrootIterator(hid_t g_id, NXVsetLog(self,"sev","error"); NXVprintLog(self,"dataPath","/%s",name); NXVprintLog(self,"message", - "Cannot validate %s, failed to find application definition", + "No application definition found for %s, continuing with NXminimal", name); self->errCount++; - NXVlog(self); + NXVlog(self); + validatePath(self,nxPath,"NXminimal"); } } diff --git a/src/nxvutil.c b/src/nxvutil.c index ef7be08..f069cba 100644 --- a/src/nxvutil.c +++ b/src/nxvutil.c @@ -44,11 +44,9 @@ herr_t H5NXget_attribute_string( hid_t loc_id, const char *obj_name, const char This is a memory issue waiting to happen. IMHO, there is a design issue with H5LTget_attribute_string in itself that it does not pass in the length of the string. Thus no check can be performed. - - There is also a mmeory leak with varData. However, if I call the reclaim function - from the HDF5 API on it, I get a core dump..... */ strcpy(data,varData); + H5Dvlen_reclaim(attr_type, space, H5P_DEFAULT, &varData); } else { result = H5Aread(attr_id,attr_type,data); }