/*--------------------------------------------------------------------------- NeXus - Neutron & X-ray Common Data Format Application Program Interface (HDF5) Routines Copyright (C) 1997-2006 Mark Koennecke, Przemek Klosowski This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA For further information, see ----------------------------------------------------------------------------*/ #include #include #include #include #include "napi.h" #include "napi5.h" #define NX_UNKNOWN_GROUP "" /* for when no NX_class attr */ extern void *NXpData; typedef struct __NexusFile5 { struct iStack5 { char irefn[1024]; int iVref; int iCurrentIDX; } iStack5[NXMAXSTACK]; struct iStack5 iAtt5; int iFID; int iCurrentG; int iCurrentD; int iCurrentS; int iCurrentT; int iCurrentA; int iNX; int iNXID; int iStackPtr; char *iCurrentLGG; char *iCurrentLD; char name_ref[1024]; char name_tmp[1024]; char iAccess[2]; } NexusFile5, *pNexusFile5; /* forward declaration of NX5closegroup in order to get rid of a nasty warning */ NXstatus NX5closegroup (NXhandle fid); /*-------------------------------------------------------------------*/ static void ignoreError(void *data, char *text){ } /*--------------------------------------------------------------------*/ static pNexusFile5 NXI5assert(NXhandle fid) { pNexusFile5 pRes; assert(fid != NULL); pRes = (pNexusFile5)fid; assert(pRes->iNXID == NX5SIGNATURE); return pRes; } /*--------------------------------------------------------------------*/ static void NXI5KillDir (pNexusFile5 self) { self->iStack5[self->iStackPtr].iCurrentIDX = 0; } /*--------------------------------------------------------------------*/ static void NXI5KillAttDir (pNexusFile5 self) { self->iAtt5.iCurrentIDX = 0; } /*---------------------------------------------------------------------*/ static void buildCurrentPath(pNexusFile5 self, char *pathBuffer, int pathBufferLen){ int length; memset(pathBuffer,0,pathBufferLen); if(self->iCurrentG != 0) { strcpy(pathBuffer,"/"); if(strlen(self->name_ref) + 1 < pathBufferLen){ strcat(pathBuffer, self->name_ref); } } if(self->iCurrentD != 0){ strcat(pathBuffer,"/"); if(strlen(self->iCurrentLD) + strlen(pathBuffer) < pathBufferLen){ strcat(pathBuffer,self->iCurrentLD); } } } /* ---------------------------------------------------------------------- Definition of NeXus API ---------------------------------------------------------------------*/ NXstatus NX5open(CONSTCHAR *filename, NXaccess am, NXhandle* pHandle) { hid_t attr1,aid1, aid2, iVID; pNexusFile5 pNew = NULL; char pBuffer[512]; char *time_buffer = NULL; char version_nr[10]; int iRet; unsigned int vers_major, vers_minor, vers_release, am1 ; hid_t fapl = -1; int mdc_nelmts; #ifdef H5_WANT_H5_V1_4_COMPAT int rdcc_nelmts; #else size_t rdcc_nelmts; #endif size_t rdcc_nbytes; double rdcc_w0; /* turn off the automatic HDF error handling */ H5Eset_auto(NULL,NULL); #ifdef USE_FTIME struct timeb timeb_struct; #endif *pHandle = NULL; pNew = (pNexusFile5) malloc (sizeof (NexusFile5)); if (!pNew) { NXIReportError (NXpData,"ERROR: no memory to create File datastructure"); return NX_ERROR; } memset (pNew, 0, sizeof (NexusFile5)); /* start HDF5 interface */ if (am == NXACC_CREATE5) { fapl = H5Pcreate(H5P_FILE_ACCESS); iRet=H5Pget_cache(fapl,&mdc_nelmts,&rdcc_nelmts,&rdcc_nbytes,&rdcc_w0); rdcc_nbytes=(size_t)nx_cacheSize; iRet = H5Pset_cache(fapl,mdc_nelmts,rdcc_nelmts,rdcc_nbytes,rdcc_w0); /* setting the close degree is absolutely necessary in HDF5 versions > 1.6. If you use a lessere version and the compiler complains, comment it out but keep this in mind. */ H5Pset_fclose_degree(fapl,H5F_CLOSE_STRONG); am1 = H5F_ACC_TRUNC; pNew->iFID = H5Fcreate (filename, am1, H5P_DEFAULT, fapl); } else { if (am == NXACC_READ) { am1 = H5F_ACC_RDONLY; } else { am1 = H5F_ACC_RDWR; } fapl = H5Pcreate(H5P_FILE_ACCESS); H5Pset_fclose_degree(fapl,H5F_CLOSE_STRONG); pNew->iFID = H5Fopen (filename, am1, fapl); } if (pNew->iFID <= 0) { sprintf (pBuffer, "ERROR: cannot open file: %s", filename); NXIReportError (NXpData, pBuffer); free (pNew); return NX_ERROR; } if(fapl != -1) { H5Pclose(fapl); } /* * need to create global attributes file_name file_time NeXus_version * at some point for new files */ if (am1 != H5F_ACC_RDONLY) { iVID=H5Gopen(pNew->iFID,"/"); aid2 = H5Screate(H5S_SCALAR); aid1 = H5Tcopy(H5T_C_S1); H5Tset_size(aid1, strlen(NEXUS_VERSION)); if (am1 == H5F_ACC_RDWR) { H5Adelete(iVID, "NeXus_version"); } attr1= H5Acreate(iVID, "NeXus_version", aid1, aid2, H5P_DEFAULT); if (attr1<0) { NXIReportError (NXpData, "ERROR: HDF failed to store NeXus_version attribute "); return NX_ERROR; } if (H5Awrite(attr1, aid1,NEXUS_VERSION)<0) { NXIReportError (NXpData, "ERROR: HDF failed to store NeXus_version attribute "); return NX_ERROR; } /* Close attribute dataspace */ iRet = H5Tclose(aid1); iRet = H5Sclose(aid2); /* Close attribute */ iRet = H5Aclose(attr1); H5Gclose(iVID); } if (am1 == H5F_ACC_TRUNC) { iVID=H5Gopen(pNew->iFID,"/"); aid2=H5Screate(H5S_SCALAR); aid1 = H5Tcopy(H5T_C_S1); H5Tset_size(aid1, strlen(filename)); attr1= H5Acreate(iVID, "file_name", aid1, aid2, H5P_DEFAULT); if (attr1 < 0) { NXIReportError (NXpData, "ERROR: HDF failed to store file_name attribute "); return NX_ERROR; } if (H5Awrite(attr1, aid1, (char*)filename) < 0) { NXIReportError (NXpData, "ERROR: HDF failed to store file_name attribute "); return NX_ERROR; } iRet = H5Tclose(aid1); iRet = H5Sclose(aid2); iRet = H5Aclose(attr1); /* ------- library version ------*/ H5get_libversion(&vers_major, &vers_minor, &vers_release); sprintf (version_nr, "%d.%d.%d", vers_major,vers_minor,vers_release); aid2=H5Screate(H5S_SCALAR); aid1 = H5Tcopy(H5T_C_S1); H5Tset_size(aid1, strlen(version_nr)); attr1= H5Acreate(iVID, "HDF5_Version", aid1, aid2, H5P_DEFAULT); if (attr1 < 0) { NXIReportError (NXpData, "ERROR: HDF failed to store file_name attribute "); return NX_ERROR; } if (H5Awrite(attr1, aid1, (char*)version_nr) < 0) { NXIReportError (NXpData, "ERROR: HDF failed to store file_name attribute "); return NX_ERROR; } iRet = H5Tclose(aid1); iRet = H5Sclose(aid2); iRet = H5Aclose(attr1); /*----------- file time */ time_buffer = NXIformatNeXusTime(); if(time_buffer != NULL){ aid2=H5Screate(H5S_SCALAR); aid1 = H5Tcopy(H5T_C_S1); H5Tset_size(aid1, strlen(time_buffer)); attr1=H5Acreate(iVID, "file_time", aid1, aid2, H5P_DEFAULT); if (attr1 < 0) { NXIReportError (NXpData, "ERROR: HDF failed to store file_time attribute "); free(time_buffer); return NX_ERROR; } if (H5Awrite(attr1, aid1, time_buffer) < 0) { NXIReportError (NXpData, "ERROR: HDF failed to store file_time attribute "); free(time_buffer); return NX_ERROR; } /* Close attribute dataspace */ iRet = H5Tclose(aid1); iRet = H5Sclose(aid2); /* Close attribute */ iRet = H5Aclose(attr1); free(time_buffer); } H5Gclose(iVID); } /* Set HDFgroup access mode */ if (am1 == H5F_ACC_RDONLY) { strcpy(pNew->iAccess,"r"); } else { strcpy(pNew->iAccess,"w"); } pNew->iNXID = NX5SIGNATURE; pNew->iStack5[0].iVref = 0; /* root! */ *pHandle = (NXhandle)pNew; return NX_OK; } /* ------------------------------------------------------------------------- */ NXstatus NX5close (NXhandle* fid) { pNexusFile5 pFile = NULL; int iRet; pFile=NXI5assert(*fid); iRet=0; /* printf("HDF5 object count before close: %d\n", H5Fget_obj_count(pFile->iFID,H5F_OBJ_ALL)); */ iRet = H5Fclose(pFile->iFID); /* leave this here: it helps in debugging leakage problems printf("HDF5 object count after close: %d\n", H5Fget_obj_count(H5F_OBJ_ALL,H5F_OBJ_ALL)); printf("HDF5 dataset count after close: %d\n", H5Fget_obj_count(H5F_OBJ_ALL,H5F_OBJ_DATASET)); printf("HDF5 group count after close: %d\n", H5Fget_obj_count(H5F_OBJ_ALL,H5F_OBJ_GROUP)); printf("HDF5 datatype count after close: %d\n", H5Fget_obj_count(H5F_OBJ_ALL,H5F_OBJ_DATATYPE)); printf("HDF5 attribute count after close: %d\n", H5Fget_obj_count(H5F_OBJ_ALL,H5F_OBJ_ATTR)); */ if (iRet < 0) { NXIReportError (NXpData, "ERROR: HDF cannot close HDF file"); } /* release memory */ NXI5KillDir (pFile); if(pFile->iCurrentLGG != NULL){ free(pFile->iCurrentLGG); } if(pFile->iCurrentLD != NULL){ free(pFile->iCurrentLD); } free (pFile); *fid = NULL; H5garbage_collect(); return NX_OK; } /*-----------------------------------------------------------------------*/ NXstatus NX5makegroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) { pNexusFile5 pFile; hid_t iRet, iVID; hid_t attr1,aid1, aid2; char pBuffer[1024] = ""; pFile = NXI5assert (fid); /* create and configure the group */ if (pFile->iCurrentG==0) { iRet = H5Gcreate(pFile->iFID,(const char*)name, 0); snprintf(pBuffer,1023,"/%s",name); } else { snprintf(pBuffer,1023,"/%s/%s",pFile->name_ref,name); iRet = H5Gcreate(pFile->iFID,(const char*)pBuffer, 0); } if (iRet < 0) { NXIReportError (NXpData, "ERROR: HDF could not create Group"); return NX_ERROR; } iVID = iRet; strncpy(pFile->name_ref,pBuffer,1023); aid2 = H5Screate(H5S_SCALAR); aid1 = H5Tcopy(H5T_C_S1); H5Tset_size(aid1, strlen(nxclass)); attr1= H5Acreate(iVID, "NX_class", aid1, aid2, H5P_DEFAULT); if (attr1 < 0) { NXIReportError (NXpData, "ERROR: HDF failed to store class name!"); return NX_ERROR; } if (H5Awrite(attr1, aid1, (char*)nxclass) < 0) { NXIReportError (NXpData, "ERROR: HDF failed to store class name!"); return NX_ERROR; } /* close group */ iRet=H5Sclose(aid2); iRet=H5Tclose(aid1); iRet=H5Aclose(attr1); iRet=H5Gclose(iVID); return NX_OK; } /*------------------------------------------------------------------------*/ herr_t attr_check (hid_t loc_id, const char *member_name, void *opdata) { char attr_name[8+1]; /* need to leave space for \0 as well */ strcpy(attr_name,"NX_class"); return strstr(member_name, attr_name) ? 1 : 0; } /*------------------------------------------------------------------------*/ NXstatus NX5opengroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) { pNexusFile5 pFile; hid_t iRet, attr1, atype; char pBuffer[1024]; char data[128]; pFile = NXI5assert (fid); if (pFile->iCurrentG == 0) { strcpy(pBuffer,name); } else { sprintf(pBuffer,"%s/%s",pFile->name_tmp,name); } iRet = H5Gopen (pFile->iFID,(const char *)pBuffer); if (iRet < 0) { sprintf (pBuffer, "ERROR: Group %s does not exist!", pFile->name_tmp); NXIReportError (NXpData, pBuffer); return NX_ERROR; } pFile->iCurrentG = iRet; strcpy(pFile->name_tmp,pBuffer); strcpy(pFile->name_ref,pBuffer); if ((nxclass != NULL) && (strcmp(nxclass, NX_UNKNOWN_GROUP) != 0)) { /* check group attribute */ iRet=H5Aiterate(pFile->iCurrentG,NULL,attr_check,NULL); if (iRet < 0) { NXIReportError (NXpData, "ERROR iterating through group!"); return NX_ERROR; } else if (iRet == 1) { /* group attribute was found */ } else { /* no group attribute available */ NXIReportError (NXpData, "No group attribute available"); return NX_ERROR; } /* check contents of group attribute */ attr1 = H5Aopen_name(pFile->iCurrentG, "NX_class"); if (attr1 < 0) { NXIReportError (NXpData, "Error opening NX_class group attribute!"); return NX_ERROR; } atype=H5Tcopy(H5T_C_S1); H5Tset_size(atype,128); iRet = H5Aread(attr1, atype, data); if (strcmp(data, nxclass) == 0) { /* test OK */ } else { NXIReportError (NXpData, "Group class is not identical!"); iRet = H5Tclose(atype); iRet = H5Aclose(attr1); return NX_ERROR; } iRet = H5Tclose(atype); iRet = H5Aclose(attr1); } /* maintain stack */ pFile->iStackPtr++; pFile->iStack5[pFile->iStackPtr].iVref=pFile->iCurrentG; strcpy(pFile->iStack5[pFile->iStackPtr].irefn,name); pFile->iAtt5.iCurrentIDX=0; pFile->iCurrentD = 0; if(pFile->iCurrentLGG != NULL){ free(pFile->iCurrentLGG); } pFile->iCurrentLGG = strdup(name); NXI5KillDir (pFile); return NX_OK; } /* ------------------------------------------------------------------- */ NXstatus NX5closegroup (NXhandle fid) { pNexusFile5 pFile; int i,ii; char *uname = NULL; char *u1name = NULL; pFile = NXI5assert (fid); /* first catch the trivial case: we are at root and cannot get deeper into a negative directory hierarchy (anti-directory) */ if (pFile->iCurrentG == 0) { NXI5KillDir (pFile); return NX_OK; } else { /* close the current group and decrement name_ref */ H5Gclose (pFile->iCurrentG); i = 0; i = strlen(pFile->iStack5[pFile->iStackPtr].irefn); ii = strlen(pFile->name_ref); if (pFile->iStackPtr>1) { ii=ii-i-1; } else { ii=ii-i; } if (ii>0) { uname = strdup(pFile->name_ref); u1name = (char*) malloc((ii+1)*sizeof(char)); memset(u1name,0,ii); for (i=0; iname_ref,u1name); strcpy(pFile->name_tmp,u1name); free(uname); free(u1name); } else { strcpy(pFile->name_ref,""); strcpy(pFile->name_tmp,""); } NXI5KillDir (pFile); pFile->iStackPtr--; if (pFile->iStackPtr>0) { pFile->iCurrentG=pFile->iStack5[pFile->iStackPtr].iVref; } else { pFile->iCurrentG=0; } } return NX_OK; } /*-----------------------------------------------------------------------*/ static int nxToHDF5Type(int datatype) { int type; if (datatype == NX_CHAR) { type=H5T_C_S1; } else if (datatype == NX_INT8) { type=H5T_NATIVE_CHAR; } else if (datatype == NX_UINT8) { type=H5T_NATIVE_UCHAR; } else if (datatype == NX_INT16) { type=H5T_NATIVE_SHORT; } else if (datatype == NX_UINT16) { type=H5T_NATIVE_USHORT; } else if (datatype == NX_INT32) { type=H5T_NATIVE_INT; } else if (datatype == NX_UINT32) { type=H5T_NATIVE_UINT; } else if (datatype == NX_INT64) { type = H5T_NATIVE_INT64; } else if (datatype == NX_UINT64) { type = H5T_NATIVE_UINT64; } else if (datatype == NX_FLOAT32) { type=H5T_NATIVE_FLOAT; } else if (datatype == NX_FLOAT64) { type=H5T_NATIVE_DOUBLE; } else { NXIReportError (NXpData, "ERROR: nxToHDF5Type: unknown type"); type = -1; } return type; } /* --------------------------------------------------------------------- */ NXstatus NX5compmakedata (NXhandle fid, CONSTCHAR *name, int datatype, int rank, int dimensions[], int compress_type, int chunk_size[]) { hid_t datatype1, dataspace, iNew, iRet; hid_t type, cparms = -1; pNexusFile5 pFile; char pBuffer[256]; int i, byte_zahl = 0; hsize_t chunkdims[H5S_MAX_RANK]; hsize_t mydim[H5S_MAX_RANK], mydim1[H5S_MAX_RANK]; hsize_t size[H5S_MAX_RANK]; hsize_t maxdims[H5S_MAX_RANK]; pFile = NXI5assert (fid); for (i = 0; i < rank; i++) { chunkdims[i]=chunk_size[i]; mydim[i] = dimensions[i]; maxdims[i] = dimensions[i]; size[i] = dimensions[i]; } type = nxToHDF5Type(datatype); if (rank <= 0) { sprintf (pBuffer, "ERROR: invalid rank specified %s", name); NXIReportError (NXpData, pBuffer); return NX_ERROR; } /* Check dimensions for consistency. The first dimension may be -1 thus denoting an unlimited dimension. */ for (i = 1; i < rank; i++) { if (dimensions[i] <= 0) { sprintf (pBuffer, "ERROR: invalid dimension %d, value %d given for Dataset %s", i, dimensions[i], name); NXIReportError (NXpData, pBuffer); return NX_ERROR; } } if (datatype == NX_CHAR) { /* * This assumes string lenght is in the last dimensions and * the logic must be the same as used in NX5getslab and NX5getinfo * * search for tests on H5T_STRING */ byte_zahl=dimensions[rank-1]; for(i = 0; i < rank; i++) { mydim1[i] = dimensions[i]; } mydim1[rank-1] = 1; if (dimensions[rank-1] > 1) { mydim[rank-1] = maxdims[rank-1] = size[rank-1] = 1; } if (chunkdims[rank-1] > 1) { chunkdims[rank-1] = 1; } if (dimensions[0] == NX_UNLIMITED) { mydim1[0] = 1; maxdims[0] = H5S_UNLIMITED; } dataspace=H5Screate_simple(rank,mydim1,maxdims); } else { if (dimensions[0] == NX_UNLIMITED) { mydim[0] = 1; maxdims[0] = H5S_UNLIMITED; dataspace=H5Screate_simple(rank, mydim, maxdims); } else { /* dataset creation */ dataspace=H5Screate_simple(rank, mydim, NULL); } } datatype1=H5Tcopy(type); if (datatype == NX_CHAR) { H5Tset_size(datatype1, byte_zahl); /* H5Tset_strpad(H5T_STR_SPACEPAD); */ } if(compress_type == NX_COMP_LZW) { cparms = H5Pcreate(H5P_DATASET_CREATE); iNew = H5Pset_chunk(cparms,rank,chunkdims); if (iNew < 0) { NXIReportError (NXpData, "ERROR: Size of chunks could not be set!"); return NX_ERROR; } H5Pset_deflate(cparms,6); iRet = H5Dcreate (pFile->iCurrentG, (char*)name, datatype1, dataspace, cparms); } else if (compress_type == NX_COMP_NONE) { if (dimensions[0] == NX_UNLIMITED) { cparms = H5Pcreate(H5P_DATASET_CREATE); iNew = H5Pset_chunk(cparms,rank,chunkdims); if (iNew < 0) { NXIReportError (NXpData, "ERROR: Size of chunks could not be set!"); return NX_ERROR; } iRet = H5Dcreate (pFile->iCurrentG, (char*)name, datatype1, dataspace, cparms); } else { iRet = H5Dcreate (pFile->iCurrentG, (char*)name, datatype1, dataspace, H5P_DEFAULT); } } else { NXIReportError (NXpData, "HDF5 doesn't support selected compression method! Dataset was saved without compression"); iRet = H5Dcreate (pFile->iCurrentG, (char*)name, datatype1, dataspace, H5P_DEFAULT); } if (iRet < 0) { NXIReportError (NXpData, "ERROR: Creating chunked dataset failed!"); return NX_ERROR; } else { pFile->iCurrentD = iRet; } if (dimensions[0] == NX_UNLIMITED) { size[0] = 1; iNew = H5Dextend (pFile->iCurrentD, size); if (iNew < 0) { sprintf (pBuffer, "ERROR: cannot create Dataset %s, check arguments", name); NXIReportError (NXpData, pBuffer); return NX_ERROR; } } if (cparms != -1) { iRet = H5Pclose(cparms); } iRet = H5Sclose(dataspace); iRet = H5Tclose(datatype1); iRet = H5Dclose(pFile->iCurrentD); pFile->iCurrentD = 0; if (iRet < 0) { NXIReportError (NXpData, "ERROR: HDF cannot close Dataset"); return NX_ERROR; } return NX_OK; } /* --------------------------------------------------------------------- */ NXstatus NX5makedata (NXhandle fid, CONSTCHAR *name, int datatype, int rank, int dimensions[]) { pNexusFile5 pFile; int chunk_size[H5S_MAX_RANK]; int i; pFile = NXI5assert (fid); memset(chunk_size,0,H5S_MAX_RANK*sizeof(int)); if (dimensions[0] == NX_UNLIMITED) { for (i = 0; i < H5S_MAX_RANK; i++) { chunk_size[i]= 1; } } return NX5compmakedata (fid, name, datatype, rank, dimensions, NX_COMP_NONE, chunk_size); return NX_OK; } /* --------------------------------------------------------------------- */ NXstatus NX5compress (NXhandle fid, int compress_type) { printf(" NXcompress ERROR: NeXus API based on HDF5 doesn't support\n"); printf(" NXcompress function! Using HDF5 library,\n"); printf(" the NXcompmakedata function can be applied\n"); printf(" for compression of data!\n"); return NX_ERROR; } /* --------------------------------------------------------------------- */ NXstatus NX5opendata (NXhandle fid, CONSTCHAR *name) { pNexusFile5 pFile; char pBuffer[256]; pFile = NXI5assert (fid); /* clear pending attribute directories first */ NXI5KillAttDir (pFile); /* find the ID number and open the dataset */ pFile->iCurrentD = H5Dopen(pFile->iCurrentG, name); if (pFile->iCurrentD < 0) { sprintf (pBuffer, "ERROR: Dataset %s not found at this level", name); NXIReportError (NXpData, pBuffer); return NX_ERROR; } /* find the ID number of datatype */ pFile->iCurrentT = H5Dget_type(pFile->iCurrentD); if (pFile->iCurrentT < 0) { NXIReportError (NXpData, "ERROR:HDF error opening Dataset"); pFile->iCurrentT=0; return NX_ERROR; } /* find the ID number of dataspace */ pFile->iCurrentS = H5Dget_space(pFile->iCurrentD); if (pFile->iCurrentS < 0) { NXIReportError (NXpData, "ERROR:HDF error opening Dataset"); pFile->iCurrentS=0; return NX_ERROR; } if(pFile->iCurrentLD != NULL){ free(pFile->iCurrentLD); } pFile->iCurrentLD = strdup(name); return NX_OK; } /* ----------------------------------------------------------------- */ NXstatus NX5closedata (NXhandle fid) { pNexusFile5 pFile; int iRet; pFile = NXI5assert (fid); iRet = H5Sclose(pFile->iCurrentS); iRet = H5Tclose(pFile->iCurrentT); iRet = H5Dclose(pFile->iCurrentD); if (iRet < 0) { NXIReportError (NXpData, "ERROR: HDF cannot end access to Dataset"); return NX_ERROR; } pFile->iCurrentD=0; return NX_OK; } /* ------------------------------------------------------------------- */ NXstatus NX5putdata (NXhandle fid, void *data) { pNexusFile5 pFile; hid_t iRet; char pError[512] = ""; pFile = NXI5assert (fid); /* actually write */ iRet = H5Dwrite (pFile->iCurrentD, pFile->iCurrentT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); if (iRet < 0) { snprintf (pError,511, "ERROR: failure to write data"); NXIReportError (NXpData, pError); return NX_ERROR; } return NX_OK; } /*------------------------------------------------------------------*/ static int getAttVID(pNexusFile5 pFile){ int vid; if(pFile->iCurrentG == 0 && pFile->iCurrentD == 0){ /* global attribute */ vid = H5Gopen(pFile->iFID,"/"); } else if(pFile->iCurrentD != 0) { /* dataset attribute */ vid = pFile->iCurrentD; } else { /* group attribute */; vid = pFile->iCurrentG; } return vid; } /*---------------------------------------------------------------*/ static void killAttVID(pNexusFile5 pFile, int vid){ if(pFile->iCurrentG == 0 && pFile->iCurrentD == 0){ H5Gclose(vid); } } /* ------------------------------------------------------------------- */ NXstatus NX5putattr (NXhandle fid, CONSTCHAR *name, void *data, int datalen, int iType) { pNexusFile5 pFile; hid_t attr1, aid1, aid2; hid_t type; int iRet; int vid; pFile = NXI5assert (fid); type = nxToHDF5Type(iType); /* determine vid */ vid = getAttVID(pFile); aid2=H5Screate(H5S_SCALAR); aid1=H5Tcopy(type); if (iType == NX_CHAR){ H5Tset_size(aid1,datalen); } iRet = H5Aopen_name(vid, name); if (iRet>0) { H5Aclose(iRet); iRet=H5Adelete(vid,name); if (iRet<0) { NXIReportError (NXpData, "ERROR: Old attribute cannot removed! "); killAttVID(pFile,vid); return NX_ERROR; } } attr1 = H5Acreate(vid, name, aid1, aid2, H5P_DEFAULT); if (attr1 < 0) { NXIReportError (NXpData, "ERROR: Attribute cannot created! "); killAttVID(pFile,vid); return NX_ERROR; } if (H5Awrite(attr1,aid1,data) < 0) { NXIReportError (NXpData, "ERROR: HDF failed to store attribute "); killAttVID(pFile,vid); return NX_ERROR; } /* Close attribute dataspace */ iRet=H5Tclose(aid1); iRet=H5Sclose(aid2); /* Close attribute */ iRet=H5Aclose(attr1); killAttVID(pFile,vid); return NX_OK; } /* ------------------------------------------------------------------- */ NXstatus NX5putslab (NXhandle fid, void *data, int iStart[], int iSize[]) { pNexusFile5 pFile; int iRet, i; int rank; hsize_t myStart[H5S_MAX_RANK]; hsize_t mySize[H5S_MAX_RANK]; hsize_t size[H5S_MAX_RANK],maxdims[H5S_MAX_RANK]; hid_t filespace,dataspace; pFile = NXI5assert (fid); /* check if there is an Dataset open */ if (pFile->iCurrentD == 0) { NXIReportError (NXpData, "ERROR: no dataset open"); return NX_ERROR; } rank = H5Sget_simple_extent_ndims(pFile->iCurrentS); iRet = H5Sget_simple_extent_dims(pFile->iCurrentS, NULL, maxdims); for(i = 0; i < rank; i++) { myStart[i] = iStart[i]; mySize[i] = iSize[i]; size[i] = iSize[i]; } if (H5Tget_class(pFile->iCurrentT) == H5T_STRING) { mySize[rank - 1] = 1; myStart[rank - 1] = 0; } dataspace = H5Screate_simple (rank, mySize, NULL); if (maxdims[0] == NX_UNLIMITED) { size[0]=iStart[0] + iSize[0]; iRet = H5Dextend(pFile->iCurrentD, size); if (iRet < 0) { NXIReportError (NXpData, "ERROR: extend slab failed"); return NX_ERROR; } filespace = H5Dget_space(pFile->iCurrentD); /* define slab */ iRet = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, myStart, NULL, mySize, NULL); /* deal with HDF errors */ if (iRet < 0) { NXIReportError (NXpData, "ERROR: selecting slab failed"); return NX_ERROR; } /* write slab */ iRet = H5Dwrite(pFile->iCurrentD, pFile->iCurrentT, dataspace, filespace, H5P_DEFAULT,data); if (iRet < 0) { NXIReportError (NXpData, "ERROR: writing slab failed"); } iRet = H5Sclose(filespace); } else { /* define slab */ iRet = H5Sselect_hyperslab(pFile->iCurrentS, H5S_SELECT_SET, myStart, NULL, mySize, NULL); /* deal with HDF errors */ if (iRet < 0) { NXIReportError (NXpData, "ERROR: selecting slab failed"); return NX_ERROR; } /* write slab */ iRet = H5Dwrite(pFile->iCurrentD, pFile->iCurrentT, dataspace, pFile->iCurrentS, H5P_DEFAULT,data); if (iRet < 0) { NXIReportError (NXpData, "ERROR: writing slab failed"); } } /* deal with HDF errors */ iRet = H5Sclose(dataspace); if (iRet < 0) { NXIReportError (NXpData, "ERROR: closing slab failed"); return NX_ERROR; } return NX_OK; } /* ------------------------------------------------------------------- */ NXstatus NX5getdataID (NXhandle fid, NXlink* sRes) { pNexusFile5 pFile; ErrFunc oldErr; int datalen, type = NX_CHAR; pFile = NXI5assert (fid); /* we cannot return ID's when no datset is open */ if(pFile->iCurrentD <= 0){ return NX_ERROR; } /* this means: if the item is already linked: use the target attribute else, the path to the current node */ oldErr = NXMGetError(); NXMSetError(NXpData, ignoreError); datalen = 1024; memset(&sRes->targetPath,0,datalen*sizeof(char)); if(NX5getattr(fid,"target",&sRes->targetPath,&datalen,&type) != NX_OK) { buildCurrentPath(pFile, sRes->targetPath, 1024); } NXMSetError(NXpData,oldErr); sRes->linkType = 1; return NX_OK; } /* ------------------------------------------------------------------- */ NXstatus NX5printlink (NXhandle fid, NXlink* sLink) { pNexusFile5 pFile; pFile = NXI5assert (fid); printf("HDF5 link: targetPath = \"%s\", linkType = \"%d\"\n", sLink->targetPath, sLink->linkType); return NX_OK; } /*--------------------------------------------------------------------*/ static NXstatus NX5settargetattribute(pNexusFile5 pFile, NXlink *sLink) { herr_t length, dataID, status, aid2, aid1, attID; int type = NX_CHAR; char name[] = "target"; length = strlen(sLink->targetPath); /* set the target attribute */ if(sLink->linkType > 0) { dataID = H5Dopen(pFile->iFID,sLink->targetPath); } else { dataID = H5Gopen(pFile->iFID,sLink->targetPath); } if(dataID < 0) { NXIReportError(NXpData,"Internal error, path to link does not exist"); return NX_ERROR; } status = H5Aopen_name(dataID,name); if(status > 0) { H5Aclose(status); status = H5Adelete(dataID,name); if(status < 0) { return NX_OK; } } aid2 = H5Screate(H5S_SCALAR); aid1 = H5Tcopy(H5T_C_S1); H5Tset_size(aid1,strlen(sLink->targetPath)); attID = H5Acreate(dataID,name,aid1,aid2,H5P_DEFAULT); if(attID < 0) { return NX_OK; } status = H5Awrite(attID,aid1,sLink->targetPath); H5Tclose(aid1); H5Sclose(aid2); H5Aclose(attID); if(sLink->linkType > 0){ H5Dclose(dataID); } else { H5Gclose(dataID); } return NX_OK; } /*---------------------------------------------------------------------*/ NXstatus NX5makenamedlink(NXhandle fid, CONSTCHAR *name, NXlink *sLink) { pNexusFile5 pFile; char linkTarget[1024]; int type = NX_CHAR, length; int status; pFile = NXI5assert (fid); if (pFile->iCurrentG == 0) { /* root level, can not link here */ return NX_ERROR; } /* build pathname to link from our current group and the name of the thing to link */ if(strlen(pFile->name_ref) + strlen(name) + 2 < 1024) { strcpy(linkTarget,"/"); strcat(linkTarget,pFile->name_ref); strcat(linkTarget,"/"); strcat(linkTarget,name); } else { NXIReportError(NXpData,"Path string to long"); return NX_ERROR; } status = H5Glink(pFile->iFID, H5G_LINK_HARD, sLink->targetPath, linkTarget); return NX5settargetattribute(pFile,sLink); } /* ------------------------------------------------------------------- */ NXstatus NX5makelink (NXhandle fid, NXlink* sLink) { pNexusFile5 pFile; char linkTarget[1024]; int type = NX_CHAR, length; char *itemName = NULL; int status; pFile = NXI5assert (fid); if (pFile->iCurrentG == 0) { /* root level, can not link here */ return NX_ERROR; } /* locate name of the element to link */ itemName = strrchr(sLink->targetPath,'/'); if(itemName == NULL){ NXIReportError(NXpData,"Bad link structure"); return NX_ERROR; } itemName++; /* build pathname to link from our current group and the name of the thing to link */ if(strlen(pFile->name_ref) + strlen(itemName) + 2 < 1024) { strcpy(linkTarget,"/"); strcat(linkTarget,pFile->name_ref); strcat(linkTarget,"/"); strcat(linkTarget,itemName); } else { NXIReportError(NXpData,"Path string to long"); return NX_ERROR; } status = H5Glink(pFile->iFID, H5G_LINK_HARD, sLink->targetPath, linkTarget); return NX5settargetattribute(pFile,sLink); } /*----------------------------------------------------------------------*/ NXstatus NX5flush(NXhandle *pHandle) { pNexusFile5 pFile = NULL; int iRet; pFile = NXI5assert (*pHandle); if (pFile->iCurrentD != 0) { iRet=H5Fflush(pFile->iCurrentD,H5F_SCOPE_LOCAL); } else if (pFile->iCurrentG != 0) { iRet=H5Fflush(pFile->iCurrentG,H5F_SCOPE_LOCAL); } else { iRet=H5Fflush(pFile->iFID,H5F_SCOPE_LOCAL); } if (iRet < 0){ NXIReportError (NXpData, "ERROR: The object cannot be flushed"); return NX_ERROR; } return NX_OK; } /*-------------------------------------------------------------------------*/ /* Operator function. */ herr_t nxgroup_info(hid_t loc_id, const char *name, void *op_data) { H5G_stat_t statbuf; pinfo self; self = (pinfo)op_data; H5Gget_objinfo(loc_id, name, 0, &statbuf); switch (statbuf.type) { case H5G_GROUP: self->iname = strdup(name); self->type = H5G_GROUP; break; case H5G_DATASET: self->iname = strdup(name); self->type = H5G_DATASET; break; default: self->type=0; break; } return 1; } /* --------------------------------------------------------------------- */ /* Operator function. */ herr_t group_info1(hid_t loc_id, const char *name, void *opdata) { NexusFile5 self; H5G_stat_t statbuf; self.iNX = *((int*)opdata); H5Gget_objinfo(loc_id, name, 0, &statbuf); switch (statbuf.type) { case H5G_GROUP: self.iNX++; *((int*)opdata)=self.iNX; break; case H5G_DATASET: self.iNX++; *((int*)opdata)=self.iNX; break; default: break; } return 0; } /*-------------------------------------------------------------------------*/ NXstatus NX5getgroupinfo (NXhandle fid, int *iN, NXname pName, NXname pClass) { pNexusFile5 pFile; hid_t atype,attr_id; char data[64]; int iRet; pFile = NXI5assert (fid); /* check if there is a group open */ if (pFile->iCurrentG == 0) { strcpy (pName, "root"); strcpy (pClass, "NXroot"); pFile->iNX=0; iRet=H5Giterate(pFile->iFID,"/",0,group_info1,&pFile->iNX); *iN=pFile->iNX; } else { strcpy (pName,pFile->name_ref); attr_id = H5Aopen_name(pFile->iCurrentG,"NX_class"); if (attr_id<0) { strcpy(pClass, NX_UNKNOWN_GROUP); } else { atype=H5Tcopy(H5T_C_S1); H5Tset_size(atype,64); H5Aread(attr_id, atype, data); strcpy(pClass,data); pFile->iNX=0; iRet=H5Giterate(pFile->iFID,pFile->name_ref,0,group_info1, &pFile->iNX); *iN=pFile->iNX; H5Aclose(attr_id); } } return NX_OK; } /*------------------------------------------------------------------------*/ static int hdf5ToNXType(int data_id, hid_t atype) { int iPtype = -1; hid_t sign_id, size_id; if (data_id==H5T_STRING) { iPtype=NX_CHAR; } if (data_id==H5T_INTEGER) { size_id=H5Tget_size(atype); sign_id=H5Tget_sign(atype); if (size_id==1) { if (sign_id==H5T_SGN_2) { iPtype=NX_INT8; } else { iPtype=NX_UINT8; } } else if (size_id==2) { if (sign_id==H5T_SGN_2) { iPtype=NX_INT16; } else { iPtype=NX_UINT16; } } else if (size_id==4) { if (sign_id==H5T_SGN_2) { iPtype=NX_INT32; } else { iPtype=NX_UINT32; } } else if(size_id == 8) { if (sign_id==H5T_SGN_2) { iPtype=NX_INT64; } else { iPtype=NX_UINT64; } } } else if (data_id==H5T_FLOAT) { size_id=H5Tget_size(atype); if (size_id==4) { iPtype=NX_FLOAT32; } else if (size_id==8) { iPtype=NX_FLOAT64; } } if (iPtype == -1) { NXIReportError (NXpData, "ERROR: hdf5ToNXtype: invalid type"); } return iPtype; } /*--------------------------------------------------------------------------*/ static int h5MemType(hid_t atype) { hid_t data_id, size_id, sign_id, memtype_id = -1; data_id = H5Tget_class(atype); if (data_id==H5T_INTEGER) { size_id=H5Tget_size(atype); sign_id=H5Tget_sign(atype); if (size_id==1) { if (sign_id==H5T_SGN_2) { memtype_id = H5T_NATIVE_INT8; } else { memtype_id = H5T_NATIVE_UINT8; } } else if (size_id==2) { if (sign_id==H5T_SGN_2) { memtype_id = H5T_NATIVE_INT16; } else { memtype_id = H5T_NATIVE_UINT16; } } else if (size_id==4) { if (sign_id==H5T_SGN_2) { memtype_id = H5T_NATIVE_INT32; } else { memtype_id = H5T_NATIVE_UINT32; } } else if (size_id==8) { if (sign_id==H5T_SGN_2) { memtype_id = H5T_NATIVE_INT64; } else { memtype_id = H5T_NATIVE_UINT64; } } } else if (data_id==H5T_FLOAT) { size_id=H5Tget_size(atype); if (size_id==4) { memtype_id = H5T_NATIVE_FLOAT; } else if (size_id==8) { memtype_id = H5T_NATIVE_DOUBLE; } } if (memtype_id == -1) { NXIReportError (NXpData, "ERROR: h5MemType: invalid type"); } return memtype_id; } /*-------------------------------------------------------------------------*/ NXstatus NX5getnextentry (NXhandle fid,NXname name, NXname nxclass, int *datatype) { pNexusFile5 pFile; hid_t grp, attr1,type,atype; int iRet,iPtype, i; int idx,data_id,size_id, sign_id; char data[128]; char ph_name[1024]; info_type op_data; int iRet_iNX=-1; char pBuffer[256]; pFile = NXI5assert (fid); op_data.iname = NULL; /* iterate to next entry in group list */ idx=pFile->iStack5[pFile->iStackPtr].iCurrentIDX; if (strlen(pFile->name_ref) == 0) { /* root group */ strcpy(pFile->name_ref,"/"); } iRet=H5Giterate(pFile->iFID,pFile->name_ref,&idx,nxgroup_info,&op_data); strcpy(nxclass, NX_UNKNOWN_GROUP); /* figure out the number of items in the current group. We need this in order to find out if we are at the end of the search. */ if (pFile->iCurrentG == 0) { pFile->iNX=0; iRet_iNX = H5Giterate(pFile->iFID,"/",0,group_info1,&pFile->iNX); } else { pFile->iNX=0; iRet_iNX = H5Giterate(pFile->iFID,pFile->name_ref,0,group_info1, &pFile->iNX); } if (idx == pFile->iNX) { iRet_iNX = 2; } if (iRet > 0) { pFile->iStack5[pFile->iStackPtr].iCurrentIDX++; if (op_data.iname != NULL) { strcpy(name,op_data.iname); free(op_data.iname); } else { pFile->iStack5[pFile->iStackPtr].iCurrentIDX = 0; return NX_EOD; } if (op_data.type == H5G_GROUP) { /* open group and find class name attribute */ strcpy(ph_name,""); for(i = 1; i < (pFile->iStackPtr + 1); i++) { strcat(ph_name,pFile->iStack5[i].irefn); strcat(ph_name,"/"); } strcat(ph_name,name); grp=H5Gopen(pFile->iFID,ph_name); if (grp < 0) { sprintf (pBuffer, "ERROR: Group %s does not exist!", ph_name); NXIReportError (NXpData, pBuffer); return NX_ERROR; } attr1 = H5Aopen_name(grp, "NX_class"); if (attr1 < 0) { strcpy(nxclass, NX_UNKNOWN_GROUP); } else { type=H5T_C_S1; atype=H5Tcopy(type); H5Tset_size(atype,128); iRet = H5Aread(attr1, atype, data); strcpy(nxclass,data); H5Tclose(atype); H5Aclose(attr1); } H5Gclose(grp); } else if (op_data.type==H5G_DATASET) { /* open dataset and find type */ grp=H5Dopen(pFile->iCurrentG,name); type=H5Dget_type(grp); atype=H5Tcopy(type); data_id = H5Tget_class(atype); iPtype = hdf5ToNXType(data_id, atype); *datatype=iPtype; strcpy(nxclass, "SDS"); H5Tclose(atype); H5Tclose(type); H5Dclose(grp); } return NX_OK; } else { /* we are at the end of the search: clear the data structure and reset iCurrentIDX to 0 */ if (iRet_iNX == 2) { if (op_data.iname != NULL) { free(op_data.iname); } pFile->iStack5[pFile->iStackPtr].iCurrentIDX = 0; return NX_EOD; } if (op_data.iname != NULL) { free(op_data.iname); } NXIReportError (NXpData, "ERROR: Iteration (directory) was not successful"); return NX_ERROR; } } /*-------------------------------------------------------------------------*/ NXstatus NX5getdata (NXhandle fid, void *data) { pNexusFile5 pFile; int iStart[H5S_MAX_RANK], status; hid_t data_id, memtype_id, size_id, sign_id; int dims; pFile = NXI5assert (fid); /* check if there is an Dataset open */ if (pFile->iCurrentD == 0) { NXIReportError (NXpData, "ERROR: no Dataset open"); return NX_ERROR; } memset (iStart, 0, H5S_MAX_RANK * sizeof(int)); /* map datatypes of other plateforms */ data_id = H5Tget_class(pFile->iCurrentT); if (data_id==H5T_STRING) { dims = H5Tget_size(pFile->iCurrentT); memtype_id = H5Tcopy(H5T_C_S1); H5Tset_size(memtype_id, dims); } else { memtype_id = h5MemType(pFile->iCurrentT); } /* actually read */ status = H5Dread (pFile->iCurrentD, memtype_id, H5S_ALL, H5S_ALL,H5P_DEFAULT, data); if(data_id == H5T_STRING) { H5Tclose(memtype_id); } if(status < 0) { NXIReportError (NXpData, "ERROR: failed to transfer dataset"); return NX_ERROR; } return NX_OK; } /*-------------------------------------------------------------------------*/ NXstatus NX5getinfo (NXhandle fid, int *rank, int dimension[], int *iType) { pNexusFile5 pFile; int i, iRank, mType, iRet; hsize_t myDim[H5S_MAX_RANK]; hid_t data_id,size_id,sign_id; pFile = NXI5assert (fid); /* check if there is an Dataset open */ if (pFile->iCurrentD == 0) { NXIReportError (NXpData, "ERROR: no Dataset open"); return NX_ERROR; } /* read information */ data_id = H5Tget_class(pFile->iCurrentT); mType = hdf5ToNXType(data_id,pFile->iCurrentT); iRank = H5Sget_simple_extent_ndims(pFile->iCurrentS); iRet = H5Sget_simple_extent_dims(pFile->iCurrentS, myDim, NULL); /* conversion to proper ints for the platform */ *iType = (int)mType; if (data_id==H5T_STRING && myDim[iRank-1] == 1) { myDim[iRank-1] = H5Tget_size(pFile->iCurrentT); } *rank = (int)iRank; for (i = 0; i < iRank; i++) { dimension[i] = (int)myDim[i]; } return NX_OK; } /*-------------------------------------------------------------------------*/ NXstatus NX5getslab (NXhandle fid, void *data, int iStart[], int iSize[]) { pNexusFile5 pFile; hsize_t myStart[H5S_MAX_RANK]; hsize_t mySize[H5S_MAX_RANK]; hsize_t mStart[H5S_MAX_RANK]; hid_t memspace, iRet, data_id; hid_t memtype_id, size_id, sign_id; char *tmp_data = NULL; char *data1; int i, dims, iRank, mtype = 0; pFile = NXI5assert (fid); /* check if there is an Dataset open */ if (pFile->iCurrentD == 0) { NXIReportError (NXpData, "ERROR: no Dataset open"); return NX_ERROR; } iRank = H5Sget_simple_extent_ndims(pFile->iCurrentS); for (i = 0; i < iRank; i++) { myStart[i] = (hssize_t)iStart[i]; mySize[i] = (hsize_t)iSize[i]; mStart[i] = (hsize_t)0; } data_id = H5Tget_class(pFile->iCurrentT); if (data_id == H5T_STRING) { /* * FAA 24/1/2007: I don't think this will work for multidimensional * string arrays. * MK 23/7/2007: You are right Freddie. */ mtype = NX_CHAR; if (mySize[0] == 1) { mySize[0] = H5Tget_size(pFile->iCurrentT); } tmp_data = (char*) malloc(mySize[0]); memset(tmp_data,0,sizeof(mySize[0])); iRet = H5Sselect_hyperslab(pFile->iCurrentS, H5S_SELECT_SET, mStart, NULL, mySize, NULL); } else { iRet = H5Sselect_hyperslab(pFile->iCurrentS, H5S_SELECT_SET, myStart, NULL, mySize, NULL); } /* define slab */ /* deal with HDF errors */ if (iRet < 0) { NXIReportError (NXpData, "ERROR: selecting slab failed"); return NX_ERROR; } memspace=H5Screate_simple(iRank, mySize, NULL); iRet = H5Sselect_hyperslab(memspace, H5S_SELECT_SET, mStart, NULL, mySize, NULL); if (iRet < 0) { NXIReportError (NXpData, "ERROR: Select memspace failed"); return NX_ERROR; } /* map datatypes of other plateforms */ if (data_id==H5T_STRING) { dims = H5Tget_size(pFile->iCurrentT); memtype_id = H5Tcopy(H5T_C_S1); H5Tset_size(memtype_id, dims); } else { memtype_id = h5MemType(pFile->iCurrentT); } /* read slab */ if (mtype == NX_CHAR) { iRet = H5Dread(pFile->iCurrentD, memtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT,tmp_data); data1 = tmp_data + myStart[0]; strncpy(data,data1,(hsize_t)iSize[0]); free(tmp_data); } else { iRet = H5Dread(pFile->iCurrentD, memtype_id, memspace, pFile->iCurrentS, H5P_DEFAULT,data); } if (iRet < 0) { NXIReportError (NXpData, "ERROR: Reading slab failed"); return NX_ERROR; } return NX_OK; } /*-------------------------------------------------------------------------*/ /* Operator function. */ herr_t attr_info(hid_t loc_id, const char *name, void *opdata) { *((char**)opdata)=strdup(name); return 1; } NXstatus NX5getnextattr (NXhandle fileid, NXname pName, int *iLength, int *iType) { pNexusFile5 pFile; hid_t attr_id,size_id,sign_id; hid_t iRet, atype, aspace; int iPType,rank; char *iname = NULL; unsigned int idx; int intern_idx=-1; int vid; pFile = NXI5assert (fileid); vid = getAttVID(pFile); idx=pFile->iAtt5.iCurrentIDX; iRet=0; intern_idx=H5Aget_num_attrs(vid); if(intern_idx == idx) { killAttVID(pFile,vid); return NX_EOD; } if (intern_idx > idx) { iRet=H5Aiterate(vid,&idx,attr_info,&iname); } else { iRet=0; } intern_idx=-1; if (iRet < 0) { NXIReportError (NXpData, "ERROR iterating through attribute list!"); killAttVID(pFile,vid); return NX_ERROR; } pFile->iAtt5.iCurrentIDX++; if (iname != NULL) { if(strcmp(iname, "NX_class") == 0 && pFile->iCurrentG != 0) { /* skip NXclass attribute which is internal */ killAttVID(pFile, vid); return NX5getnextattr(fileid, pName, iLength, iType); } strcpy(pName, iname); free(iname); iname = NULL; } else { strcpy(pName,"What is this?"); } pFile->iCurrentA = H5Aopen_name(vid, pName); atype = H5Aget_type(pFile->iCurrentA); aspace = H5Aget_space(pFile->iCurrentA); rank = H5Sget_simple_extent_ndims(aspace); attr_id = H5Tget_class(atype); if (attr_id==H5T_STRING) { iPType=NX_CHAR; rank = H5Tget_size(atype); } if (rank == 0) { rank++; } iPType = hdf5ToNXType(attr_id,atype); *iType=iPType; *iLength=rank; H5Tclose(atype); H5Sclose(aspace); H5Aclose(pFile->iCurrentA); intern_idx=H5Aget_num_attrs(vid); killAttVID(pFile,vid); return NX_OK; } /*-------------------------------------------------------------------------*/ NXstatus NX5getattr (NXhandle fid, char *name, void *data, int* datalen, int* iType) { pNexusFile5 pFile; int iNew, iRet, vid; hid_t type, atype = -1, glob; char pBuffer[256]; pFile = NXI5assert (fid); type = *iType; glob = 0; type = nxToHDF5Type(type); vid = getAttVID(pFile); iNew = H5Aopen_name(vid, name); if (iNew < 0) { sprintf (pBuffer, "ERROR: attribute %s not found", name); killAttVID(pFile,vid); NXIReportError (NXpData, pBuffer); return NX_ERROR; } pFile->iCurrentA = iNew; /* finally read the data */ if (type==H5T_C_S1) { atype=H5Tcopy(type); H5Tset_size(atype,*datalen); iRet = H5Aread(pFile->iCurrentA, atype, data); *datalen=strlen(data); } else { iRet = H5Aread(pFile->iCurrentA, type, data); *datalen=1; } if (iRet < 0) { sprintf (pBuffer, "ERROR: HDF could not read attribute data"); NXIReportError (NXpData, pBuffer); killAttVID(pFile,vid); return NX_ERROR; } iRet = H5Aclose(pFile->iCurrentA); killAttVID(pFile,vid); if (type==H5T_C_S1) { H5Tclose(atype); } return NX_OK; } /*-------------------------------------------------------------------------*/ NXstatus NX5getattrinfo (NXhandle fid, int *iN) { pNexusFile5 pFile; char *iname = NULL; unsigned int idx; int vid; herr_t iRet; pFile = NXI5assert (fid); idx=0; *iN = idx; vid = getAttVID(pFile); idx=H5Aget_num_attrs(vid); if (idx > 0) { if(pFile->iCurrentG > 0 && pFile->iCurrentD == 0){ *iN = idx -1; } else { *iN = idx; } } else { *iN = 0; } killAttVID(pFile,vid); return NX_OK; } /*-------------------------------------------------------------------------*/ NXstatus NX5getgroupID (NXhandle fileid, NXlink* sRes) { pNexusFile5 pFile; int u, datalen, type = NX_CHAR; char group_name[64], class_name[64]; ErrFunc oldErr; pFile = NXI5assert (fileid); if (pFile->iCurrentG == 0) { return NX_ERROR; } else { /* this means: if the item is already linked: use the target attribute, else the path to the current node */ oldErr = NXMGetError(); NXMSetError(NXpData, ignoreError); datalen = 1024; memset(sRes->targetPath,0,datalen*sizeof(char)); if(NX5getattr(fileid,"target",sRes->targetPath,&datalen,&type) != NX_OK){ buildCurrentPath(pFile,sRes->targetPath,1024); } NXMSetError(NXpData,oldErr); sRes->linkType = 0; return NX_OK; } /* not reached */ return NX_ERROR; } /* ------------------------------------------------------------------- */ NXstatus NX5sameID (NXhandle fileid, NXlink* pFirstID, NXlink* pSecondID) { pNexusFile5 pFile; pFile = NXI5assert (fileid); if ((strcmp(pFirstID->targetPath,pSecondID->targetPath) == 0)){ return NX_OK; } else { return NX_ERROR; } } /*-------------------------------------------------------------------------*/ NXstatus NX5initattrdir (NXhandle fid) { pNexusFile5 pFile; pFile = NXI5assert (fid); NXI5KillAttDir (fid); return NX_OK; } /*-------------------------------------------------------------------------*/ NXstatus NX5initgroupdir (NXhandle fid) { pNexusFile5 pFile; pFile = NXI5assert (fid); NXI5KillDir (fid); return NX_OK; } /*------------------------------------------------------------------------*/ void NX5assignFunctions(pNexusFunction fHandle) { fHandle->nxclose=NX5close; fHandle->nxflush=NX5flush; fHandle->nxmakegroup=NX5makegroup; fHandle->nxopengroup=NX5opengroup; fHandle->nxclosegroup=NX5closegroup; fHandle->nxmakedata=NX5makedata; fHandle->nxcompmakedata=NX5compmakedata; fHandle->nxcompress=NX5compress; fHandle->nxopendata=NX5opendata; fHandle->nxclosedata=NX5closedata; fHandle->nxputdata=NX5putdata; fHandle->nxputattr=NX5putattr; fHandle->nxputslab=NX5putslab; fHandle->nxgetdataID=NX5getdataID; fHandle->nxmakelink=NX5makelink; fHandle->nxmakenamedlink=NX5makenamedlink; fHandle->nxgetdata=NX5getdata; fHandle->nxgetinfo=NX5getinfo; fHandle->nxgetnextentry=NX5getnextentry; fHandle->nxgetslab=NX5getslab; fHandle->nxgetnextattr=NX5getnextattr; fHandle->nxgetattr=NX5getattr; fHandle->nxgetattrinfo=NX5getattrinfo; fHandle->nxgetgroupID=NX5getgroupID; fHandle->nxgetgroupinfo=NX5getgroupinfo; fHandle->nxsameID=NX5sameID; fHandle->nxinitgroupdir=NX5initgroupdir; fHandle->nxinitattrdir=NX5initattrdir; fHandle->nxprintlink=NX5printlink; }