1809 lines
50 KiB
C
1809 lines
50 KiB
C
/*---------------------------------------------------------------------------
|
|
NeXus - Neutron & X-ray Common Data Format
|
|
|
|
Application Program Interface (HDF4) Routines
|
|
|
|
Copyright (C) 1997-2002 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 <http://www.neutron.anl.gov/NeXus/>
|
|
|
|
$Id: napi4.c,v 1.6 2006/03/03 15:30:55 koennecke Exp $
|
|
|
|
----------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include "napi.h"
|
|
#include "napi4.h"
|
|
|
|
extern void *NXpData;
|
|
|
|
typedef struct __NexusFile {
|
|
struct iStack {
|
|
int32 *iRefDir;
|
|
int32 *iTagDir;
|
|
int32 iVref;
|
|
int32 __iStack_pad;
|
|
int iNDir;
|
|
int iCurDir;
|
|
} iStack[NXMAXSTACK];
|
|
struct iStack iAtt;
|
|
int32 iVID;
|
|
int32 iSID;
|
|
int32 iCurrentVG;
|
|
int32 iCurrentSDS;
|
|
int iNXID;
|
|
int iStackPtr;
|
|
char iAccess[2];
|
|
} NexusFile, *pNexusFile;
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
static pNexusFile NXIassert(NXhandle fid)
|
|
{
|
|
pNexusFile pRes;
|
|
|
|
assert(fid != NULL);
|
|
pRes = (pNexusFile)fid;
|
|
assert(pRes->iNXID == NXSIGNATURE);
|
|
return pRes;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
static int32 NXIFindVgroup (pNexusFile pFile, CONSTCHAR *name, CONSTCHAR *nxclass)
|
|
{
|
|
int32 iNew, iRef, iTag;
|
|
int iN, i;
|
|
int32 *pArray = NULL;
|
|
NXname pText;
|
|
|
|
assert (pFile != NULL);
|
|
|
|
if (pFile->iCurrentVG == 0) { /* root level */
|
|
/* get the number and ID's of all lone Vgroups in the file */
|
|
iN = Vlone (pFile->iVID, NULL, 0);
|
|
if(iN == 0) {
|
|
return NX_EOD;
|
|
}
|
|
pArray = (int32 *) malloc (iN * sizeof (int32));
|
|
if (!pArray) {
|
|
NXIReportError (NXpData, "ERROR: out of memory in NXIFindVgroup");
|
|
return NX_EOD;
|
|
}
|
|
Vlone (pFile->iVID, pArray, iN);
|
|
|
|
/* loop and check */
|
|
for (i = 0; i < iN; i++) {
|
|
iNew = Vattach (pFile->iVID, pArray[i], "r");
|
|
Vgetname (iNew, pText);
|
|
if (strcmp (pText, name) == 0) {
|
|
Vgetclass (iNew, pText);
|
|
if (strcmp (pText, nxclass) == 0) {
|
|
/* found ! */
|
|
Vdetach (iNew);
|
|
iNew = pArray[i];
|
|
free (pArray);
|
|
return iNew;
|
|
}
|
|
}
|
|
Vdetach (iNew);
|
|
}
|
|
/* nothing found */
|
|
free (pArray);
|
|
return NX_EOD;
|
|
} else { /* case in Vgroup */
|
|
iN = Vntagrefs (pFile->iCurrentVG);
|
|
for (i = 0; i < iN; i++) {
|
|
Vgettagref (pFile->iCurrentVG, i, &iTag, &iRef);
|
|
if (iTag == DFTAG_VG) {
|
|
iNew = Vattach (pFile->iVID, iRef, "r");
|
|
Vgetname (iNew, pText);
|
|
if (strcmp (pText, name) == 0) {
|
|
Vgetclass (iNew, pText);
|
|
if (strcmp (pText, nxclass) == 0) {
|
|
/* found ! */
|
|
Vdetach (iNew);
|
|
return iRef;
|
|
}
|
|
}
|
|
Vdetach (iNew);
|
|
}
|
|
} /* end for */
|
|
} /* end else */
|
|
/* not found */
|
|
return NX_EOD;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
static int32 NXIFindSDS (NXhandle fid, CONSTCHAR *name)
|
|
{
|
|
pNexusFile self;
|
|
int32 iNew, iRet, iTag, iRef;
|
|
int32 i, iN, iA, iD1, iD2;
|
|
NXname pNam;
|
|
int32 iDim[MAX_VAR_DIMS];
|
|
|
|
self = NXIassert (fid);
|
|
|
|
/* root level search */
|
|
if (self->iCurrentVG == 0) {
|
|
i = SDfileinfo (self->iSID, &iN, &iA);
|
|
if (i < 0) {
|
|
NXIReportError (NXpData, "ERROR: failure to read file information");
|
|
return NX_EOD;
|
|
}
|
|
for (i = 0; i < iN; i++) {
|
|
iNew = SDselect (self->iSID, i);
|
|
SDgetinfo (iNew, pNam, &iA, iDim, &iD1, &iD2);
|
|
if (strcmp (pNam, name) == 0) {
|
|
iRet = SDidtoref (iNew);
|
|
SDendaccess (iNew);
|
|
return iRet;
|
|
} else {
|
|
SDendaccess (iNew);
|
|
}
|
|
}
|
|
/* not found */
|
|
return NX_EOD;
|
|
}
|
|
/* end root level */
|
|
else { /* search in a Vgroup */
|
|
iN = Vntagrefs (self->iCurrentVG);
|
|
for (i = 0; i < iN; i++) {
|
|
Vgettagref (self->iCurrentVG, i, &iTag, &iRef);
|
|
/* we are now writing using DFTAG_NDG, but need others for backward compatability */
|
|
if ((iTag == DFTAG_SDG) || (iTag == DFTAG_NDG) || (iTag == DFTAG_SDS)) {
|
|
iNew = SDreftoindex (self->iSID, iRef);
|
|
iNew = SDselect (self->iSID, iNew);
|
|
SDgetinfo (iNew, pNam, &iA, iDim, &iD1, &iD2);
|
|
if (strcmp (pNam, name) == 0) {
|
|
SDendaccess (iNew);
|
|
return iRef;
|
|
}
|
|
SDendaccess (iNew);
|
|
}
|
|
} /* end for */
|
|
} /* end Vgroup */
|
|
/* we get here, only if nothing found */
|
|
return NX_EOD;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
static int NXIInitDir (pNexusFile self)
|
|
{
|
|
int i;
|
|
int32 iTag, iRef;
|
|
int iStackPtr;
|
|
|
|
/*
|
|
* Note: the +1 to various malloc() operations is to avoid a
|
|
* malloc(0), which is an error on some operating systems
|
|
*/
|
|
iStackPtr = self->iStackPtr;
|
|
if (self->iCurrentVG == 0 &&
|
|
self->iStack[iStackPtr].iRefDir == NULL) { /* root level */
|
|
/* get the number and ID's of all lone Vgroups in the file */
|
|
self->iStack[iStackPtr].iNDir = Vlone (self->iVID, NULL, 0);
|
|
self->iStack[iStackPtr].iRefDir =
|
|
(int32 *) malloc (self->iStack[iStackPtr].iNDir * sizeof (int32) + 1);
|
|
if (!self->iStack[iStackPtr].iRefDir) {
|
|
NXIReportError (NXpData, "ERROR: out of memory in NXIInitDir");
|
|
return NX_EOD;
|
|
}
|
|
Vlone (self->iVID,
|
|
self->iStack[self->iStackPtr].iRefDir,
|
|
self->iStack[self->iStackPtr].iNDir);
|
|
} else {
|
|
/* Vgroup level */
|
|
self->iStack[iStackPtr].iNDir = Vntagrefs (self->iCurrentVG);
|
|
self->iStack[iStackPtr].iRefDir =
|
|
(int32 *) malloc (self->iStack[iStackPtr].iNDir * sizeof (int32) + 1);
|
|
self->iStack[iStackPtr].iTagDir =
|
|
(int32 *) malloc (self->iStack[iStackPtr].iNDir * sizeof (int32) + 1);
|
|
if ((!self->iStack[iStackPtr].iRefDir) ||
|
|
(!self->iStack[iStackPtr].iTagDir)) {
|
|
NXIReportError (NXpData, "ERROR: out of memory in NXIInitDir");
|
|
return NX_EOD;
|
|
}
|
|
for (i = 0; i < self->iStack[self->iStackPtr].iNDir; i++) {
|
|
Vgettagref (self->iCurrentVG, i, &iTag, &iRef);
|
|
self->iStack[iStackPtr].iRefDir[i] = iRef;
|
|
self->iStack[iStackPtr].iTagDir[i] = iTag;
|
|
}
|
|
}
|
|
self->iStack[iStackPtr].iCurDir = 0;
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
static void NXIKillDir (pNexusFile self)
|
|
{
|
|
if (self->iStack[self->iStackPtr].iRefDir) {
|
|
free (self->iStack[self->iStackPtr].iRefDir);
|
|
self->iStack[self->iStackPtr].iRefDir = NULL;
|
|
}
|
|
if (self->iStack[self->iStackPtr].iTagDir) {
|
|
free (self->iStack[self->iStackPtr].iTagDir);
|
|
self->iStack[self->iStackPtr].iTagDir = NULL;
|
|
}
|
|
self->iStack[self->iStackPtr].iCurDir = 0;
|
|
self->iStack[self->iStackPtr].iNDir = 0;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
static int NXIInitAttDir (pNexusFile pFile)
|
|
{
|
|
int iRet;
|
|
int32 iData, iAtt, iRank, iType;
|
|
int32 iDim[MAX_VAR_DIMS];
|
|
NXname pNam;
|
|
|
|
pFile->iAtt.iCurDir = 0;
|
|
if (pFile->iCurrentSDS != 0) { /* SDS level */
|
|
iRet = SDgetinfo (pFile->iCurrentSDS, pNam, &iRank, iDim, &iType,
|
|
&iAtt);
|
|
} else { /* global level */
|
|
iRet = SDfileinfo (pFile->iSID, &iData, &iAtt);
|
|
}
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF cannot read attribute numbers");
|
|
pFile->iAtt.iNDir = 0;
|
|
return NX_ERROR;
|
|
}
|
|
pFile->iAtt.iNDir = iAtt;
|
|
return NX_OK;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
static void NXIKillAttDir (pNexusFile self)
|
|
{
|
|
if (self->iAtt.iRefDir) {
|
|
free (self->iAtt.iRefDir);
|
|
self->iAtt.iRefDir = NULL;
|
|
}
|
|
if (self->iAtt.iTagDir) {
|
|
free (self->iAtt.iTagDir);
|
|
self->iAtt.iTagDir = NULL;
|
|
}
|
|
self->iAtt.iCurDir = 0;
|
|
self->iAtt.iNDir = 0;
|
|
}
|
|
/*------------------------------------------------------------------*/
|
|
static void NXIbuildPath(pNexusFile pFile, char *buffer, int bufLen)
|
|
{
|
|
int i;
|
|
int32 groupID, iA, iD1, iD2, iDim[MAX_VAR_DIMS];
|
|
NXname pText;
|
|
|
|
buffer[0] = '\0';
|
|
for(i = 0; i < pFile->iStackPtr; i++){
|
|
strncat(buffer,"/",bufLen-strlen(buffer));
|
|
groupID = Vattach(pFile->iVID,pFile->iStack[pFile->iStackPtr].iVref,
|
|
"r");
|
|
Vgetname(groupID, pText);
|
|
strncat(buffer,pText,bufLen-strlen(buffer));
|
|
Vdetach(groupID);
|
|
}
|
|
if(pFile->iCurrentSDS != 0){
|
|
strncat(buffer,"/",bufLen-strlen(buffer));
|
|
SDgetinfo(pFile->iCurrentSDS,pText,&iA,iDim,&iD1,&iD2);
|
|
strncat(buffer,pText,bufLen-strlen(buffer));
|
|
}
|
|
}
|
|
/* ----------------------------------------------------------------------
|
|
|
|
Definition of NeXus API
|
|
|
|
---------------------------------------------------------------------*/
|
|
|
|
|
|
NXstatus NX4open(CONSTCHAR *filename, NXaccess am,
|
|
NXhandle* pHandle)
|
|
{
|
|
pNexusFile pNew = NULL;
|
|
char pBuffer[512];
|
|
char *time_puffer;
|
|
char HDF_VERSION[64];
|
|
uint32 lmajor, lminor, lrelease;
|
|
int32 am1=0;
|
|
int32 file_id=0, an_id=0, ann_id=0;
|
|
|
|
*pHandle = NULL;
|
|
/* map Nexus NXaccess types to HDF4 types */
|
|
if (am == NXACC_CREATE) {
|
|
am1 = DFACC_CREATE;
|
|
} else if (am == NXACC_CREATE4) {
|
|
am1 = DFACC_CREATE;
|
|
} else if (am == NXACC_READ) {
|
|
am1 = DFACC_READ;
|
|
} else if (am == NXACC_RDWR) {
|
|
am1 = DFACC_RDWR;
|
|
}
|
|
/* get memory */
|
|
pNew = (pNexusFile) malloc (sizeof (NexusFile));
|
|
if (!pNew) {
|
|
NXIReportError (NXpData, "ERROR: no memory to create File datastructure");
|
|
return NX_ERROR;
|
|
}
|
|
memset (pNew, 0, sizeof (NexusFile));
|
|
|
|
time_puffer = NXIformatNeXusTime();
|
|
|
|
#if WRITE_OLD_IDENT /* not used at moment */
|
|
/*
|
|
* write something that can be used by OLE
|
|
*/
|
|
|
|
if (am == NXACC_CREATE || am == NXACC_CREATE4) {
|
|
if ( (file_id = Hopen(filename, am1, 0)) == -1 ) {
|
|
sprintf (pBuffer, "ERROR: cannot open file_a: %s", filename);
|
|
NXIReportError (NXpData, pBuffer);
|
|
free (pNew);
|
|
return NX_ERROR;
|
|
}
|
|
an_id = ANstart(file_id);
|
|
ann_id = ANcreatef(an_id, AN_FILE_LABEL); /* AN_FILE_DESC */
|
|
ANwriteann(ann_id, "NeXus", 5);
|
|
ANendaccess(ann_id);
|
|
ANend(an_id);
|
|
if (Hclose(file_id) == -1) {
|
|
sprintf (pBuffer, "ERROR: cannot close file: %s", filename);
|
|
NXIReportError (NXpData, pBuffer);
|
|
free (pNew);
|
|
return NX_ERROR;
|
|
}
|
|
am = NXACC_RDWR;
|
|
}
|
|
#endif /* WRITE_OLD_IDENT */
|
|
|
|
/* start SDS interface */
|
|
pNew->iSID = SDstart (filename, am1);
|
|
if (pNew->iSID <= 0) {
|
|
sprintf (pBuffer, "ERROR: cannot open file_b: %s", filename);
|
|
NXIReportError (NXpData, pBuffer);
|
|
free (pNew);
|
|
return NX_ERROR;
|
|
}
|
|
/*
|
|
* need to create global attributes file_name file_time NeXus_version
|
|
* at some point for new files
|
|
*/
|
|
if (am != NXACC_READ) {
|
|
if (SDsetattr(pNew->iSID, "NeXus_version", DFNT_CHAR8, strlen(NEXUS_VERSION), NEXUS_VERSION) < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF failed to store NeXus_version attribute ");
|
|
return NX_ERROR;
|
|
}
|
|
Hgetlibversion(&lmajor, &lminor, &lrelease, HDF_VERSION);
|
|
if (SDsetattr(pNew->iSID, "HDF_version", DFNT_CHAR8, strlen(HDF_VERSION), HDF_VERSION) < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF failed to store HDF_version attribute ");
|
|
return NX_ERROR;
|
|
}
|
|
}
|
|
if (am == NXACC_CREATE || am == NXACC_CREATE4) {
|
|
if (SDsetattr(pNew->iSID, "file_name", DFNT_CHAR8, strlen(filename), (char*)filename) < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF failed to store file_name attribute ");
|
|
return NX_ERROR;
|
|
}
|
|
if(time_puffer != NULL){
|
|
if (SDsetattr(pNew->iSID, "file_time", DFNT_CHAR8,
|
|
strlen(time_puffer), time_puffer) < 0) {
|
|
NXIReportError (NXpData,
|
|
"ERROR: HDF failed to store file_time attribute ");
|
|
free(time_puffer);
|
|
return NX_ERROR;
|
|
}
|
|
free(time_puffer);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Otherwise we try to create the file two times which makes HDF
|
|
* Throw up on us.
|
|
*/
|
|
if (am == NXACC_CREATE || am == NXACC_CREATE4) {
|
|
am = NXACC_RDWR;
|
|
am1 = DFACC_RDWR;
|
|
}
|
|
|
|
/* Set Vgroup access mode */
|
|
if (am == NXACC_READ) {
|
|
strcpy(pNew->iAccess,"r");
|
|
} else {
|
|
strcpy(pNew->iAccess,"w");
|
|
}
|
|
|
|
/* start Vgroup API */
|
|
|
|
pNew->iVID = Hopen(filename, am1, 100);
|
|
if (pNew->iVID <= 0) {
|
|
sprintf (pBuffer, "ERROR: cannot open file_c: %s", filename);
|
|
NXIReportError (NXpData, pBuffer);
|
|
free (pNew);
|
|
return NX_ERROR;
|
|
}
|
|
Vstart (pNew->iVID);
|
|
pNew->iNXID = NXSIGNATURE;
|
|
pNew->iStack[0].iVref = 0; /* root! */
|
|
|
|
*pHandle = (NXhandle)pNew;
|
|
return NX_OK;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
NXstatus NX4close (NXhandle* fid)
|
|
{
|
|
pNexusFile pFile = NULL;
|
|
int iRet;
|
|
|
|
pFile = NXIassert(*fid);
|
|
iRet = 0;
|
|
/* close links into vGroups or SDS */
|
|
if (pFile->iCurrentVG != 0) {
|
|
Vdetach (pFile->iCurrentVG);
|
|
}
|
|
if (pFile->iCurrentSDS != 0) {
|
|
iRet = SDendaccess (pFile->iCurrentSDS);
|
|
}
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData, "ERROR: ending access to SDS");
|
|
}
|
|
/* close the SDS and Vgroup API's */
|
|
Vend (pFile->iVID);
|
|
iRet = SDend (pFile->iSID);
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF cannot close SDS interface");
|
|
}
|
|
iRet = Hclose (pFile->iVID);
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF cannot close HDF file");
|
|
}
|
|
/* release memory */
|
|
NXIKillDir (pFile);
|
|
free (pFile);
|
|
*fid = NULL;
|
|
return NX_OK;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
|
|
NXstatus NX4makegroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass)
|
|
{
|
|
pNexusFile pFile;
|
|
int32 iNew, iRet;
|
|
char pBuffer[256];
|
|
|
|
pFile = NXIassert (fid);
|
|
/*
|
|
* Make sure that a group with the same name and nxclass does not
|
|
* already exist.
|
|
*/
|
|
if ((iRet = NXIFindVgroup (pFile, (char*)name, nxclass)) >= 0) {
|
|
sprintf (pBuffer, "ERROR: Vgroup %s, class %s already exists",
|
|
name, nxclass);
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
|
|
/* create and configure the group */
|
|
iNew = Vattach (pFile->iVID, -1, "w");
|
|
if (iNew < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF could not create Vgroup");
|
|
return NX_ERROR;
|
|
}
|
|
Vsetname (iNew, name);
|
|
Vsetclass (iNew, nxclass);
|
|
|
|
/* Insert it into the hierarchy, when appropriate */
|
|
iRet = 0;
|
|
if (pFile->iCurrentVG != 0) {
|
|
iRet = Vinsert (pFile->iCurrentVG, iNew);
|
|
}
|
|
Vdetach (iNew);
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF failed to insert Vgroup");
|
|
return NX_ERROR;
|
|
}
|
|
return NX_OK;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
|
|
NXstatus NX4opengroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass)
|
|
{
|
|
pNexusFile pFile;
|
|
int32 iRef;
|
|
char pBuffer[256];
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
iRef = NXIFindVgroup (pFile, (char*)name, nxclass);
|
|
if (iRef < 0) {
|
|
sprintf (pBuffer, "ERROR: Vgroup %s, class %s NOT found", name, nxclass);
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
/* are we at root level ? */
|
|
if (pFile->iCurrentVG == 0) {
|
|
pFile->iCurrentVG = Vattach (pFile->iVID, iRef,pFile->iAccess);
|
|
pFile->iStackPtr++;
|
|
pFile->iStack[pFile->iStackPtr].iVref = iRef;
|
|
} else {
|
|
Vdetach (pFile->iCurrentVG);
|
|
pFile->iStackPtr++;
|
|
pFile->iStack[pFile->iStackPtr].iVref = iRef;
|
|
pFile->iCurrentVG = Vattach (pFile->iVID,
|
|
pFile->iStack[pFile->iStackPtr].iVref,
|
|
pFile->iAccess);
|
|
}
|
|
NXIKillDir (pFile);
|
|
return NX_OK;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
|
|
NXstatus NX4closegroup (NXhandle fid)
|
|
{
|
|
pNexusFile pFile;
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
/* first catch the trivial case: we are at root and cannot get
|
|
deeper into a negative directory hierarchy (anti-directory)
|
|
*/
|
|
if (pFile->iCurrentVG == 0) {
|
|
NXIKillDir (pFile);
|
|
return NX_OK;
|
|
} else { /* Sighhh. Some work to do */
|
|
/* close the current VG and decrement stack */
|
|
Vdetach (pFile->iCurrentVG);
|
|
NXIKillDir (pFile);
|
|
pFile->iStackPtr--;
|
|
if (pFile->iStackPtr <= 0) { /* we hit root */
|
|
pFile->iStackPtr = 0;
|
|
pFile->iCurrentVG = 0;
|
|
} else {
|
|
/* attach to the lower Vgroup */
|
|
pFile->iCurrentVG = Vattach (pFile->iVID,
|
|
pFile->iStack[pFile->iStackPtr].iVref,
|
|
pFile->iAccess);
|
|
}
|
|
}
|
|
return NX_OK;
|
|
}
|
|
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
NXstatus NX4makedata (NXhandle fid, CONSTCHAR *name, int datatype, int rank,
|
|
int dimensions[])
|
|
{
|
|
pNexusFile pFile;
|
|
int32 iNew;
|
|
char pBuffer[256];
|
|
int i, iRet, type;
|
|
int32 myDim[MAX_VAR_DIMS];
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
if (dimensions[0] == NX_UNLIMITED)
|
|
{
|
|
dimensions[0] = SD_UNLIMITED;
|
|
}
|
|
|
|
if ((iNew = NXIFindSDS (fid, name))>=0) {
|
|
sprintf (pBuffer, "ERROR: SDS %s already exists at this level", name);
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
|
|
if (datatype == NX_CHAR)
|
|
{
|
|
type=DFNT_CHAR8;
|
|
}
|
|
else if (datatype == NX_INT8)
|
|
{
|
|
type=DFNT_INT8;
|
|
}
|
|
else if (datatype == NX_UINT8)
|
|
{
|
|
type=DFNT_UINT8;
|
|
}
|
|
else if (datatype == NX_INT16)
|
|
{
|
|
type=DFNT_INT16;
|
|
}
|
|
else if (datatype == NX_UINT16)
|
|
{
|
|
type=DFNT_UINT16;
|
|
}
|
|
else if (datatype == NX_INT32)
|
|
{
|
|
type=DFNT_INT32;
|
|
}
|
|
else if (datatype == NX_UINT32)
|
|
{
|
|
type=DFNT_UINT32;
|
|
}
|
|
else if (datatype == NX_FLOAT32)
|
|
{
|
|
type=DFNT_FLOAT32;
|
|
}
|
|
else if (datatype == NX_FLOAT64)
|
|
{
|
|
type=DFNT_FLOAT64;
|
|
}
|
|
|
|
if (rank <= 0) {
|
|
sprintf (pBuffer, "ERROR: invalid rank specified for SDS %s",
|
|
name);
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
|
|
/*
|
|
Check dimensions for consistency. The first dimension may be 0
|
|
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 SDS %s",
|
|
i, dimensions[i], name);
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
}
|
|
|
|
/* cast the dimensions array properly for non 32-bit ints */
|
|
for(i = 0; i < rank; i++)
|
|
{
|
|
myDim[i] = (int32)dimensions[i];
|
|
}
|
|
|
|
|
|
/* behave nicely, if there is still an SDS open */
|
|
if (pFile->iCurrentSDS != 0) {
|
|
SDendaccess (pFile->iCurrentSDS);
|
|
pFile->iCurrentSDS = 0;
|
|
}
|
|
|
|
/* Do not allow creation of SDS's at the root level */
|
|
if (pFile->iCurrentVG == 0) {
|
|
sprintf(pBuffer, "ERROR: SDS creation at root level is not permitted");
|
|
NXIReportError(NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
|
|
/* dataset creation */
|
|
iNew = SDcreate (pFile->iSID, (char*)name, (int32)type,
|
|
(int32)rank, myDim);
|
|
if (iNew < 0) {
|
|
sprintf (pBuffer, "ERROR: cannot create SDS %s, check arguments",
|
|
name);
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
/* link into Vgroup, if in one */
|
|
if (pFile->iCurrentVG != 0) {
|
|
iRet = Vaddtagref (pFile->iCurrentVG, DFTAG_NDG, SDidtoref (iNew));
|
|
}
|
|
iRet = SDendaccess (iNew);
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF cannot end access to SDS");
|
|
return NX_ERROR;
|
|
}
|
|
return NX_OK;
|
|
}
|
|
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
|
|
NXstatus NX4compmakedata (NXhandle fid, CONSTCHAR *name, int datatype, int rank,
|
|
int dimensions[],int compress_type, int chunk_size[])
|
|
{
|
|
pNexusFile pFile;
|
|
int32 iNew, iRet, type;
|
|
char pBuffer[256];
|
|
int i;
|
|
int32 myDim[MAX_VAR_DIMS];
|
|
comp_info compstruct;
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
if (dimensions[0] == NX_UNLIMITED)
|
|
{
|
|
dimensions[0] = SD_UNLIMITED;
|
|
}
|
|
|
|
if ((iNew = NXIFindSDS (fid, name))>=0) {
|
|
sprintf (pBuffer, "ERROR: SDS %s already exists at this level", name);
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
|
|
if (datatype == NX_CHAR)
|
|
{
|
|
type=DFNT_CHAR8;
|
|
}
|
|
else if (datatype == NX_INT8)
|
|
{
|
|
type=DFNT_INT8;
|
|
}
|
|
else if (datatype == NX_UINT8)
|
|
{
|
|
type=DFNT_UINT8;
|
|
}
|
|
else if (datatype == NX_INT16)
|
|
{
|
|
type=DFNT_INT16;
|
|
}
|
|
else if (datatype == NX_UINT16)
|
|
{
|
|
type=DFNT_UINT16;
|
|
}
|
|
else if (datatype == NX_INT32)
|
|
{
|
|
type=DFNT_INT32;
|
|
}
|
|
else if (datatype == NX_UINT32)
|
|
{
|
|
type=DFNT_UINT32;
|
|
}
|
|
else if (datatype == NX_FLOAT32)
|
|
{
|
|
type=DFNT_FLOAT32;
|
|
}
|
|
else if (datatype == NX_FLOAT64)
|
|
{
|
|
type=DFNT_FLOAT64;
|
|
}
|
|
|
|
if (rank <= 0) {
|
|
sprintf (pBuffer, "ERROR: invalid rank specified for SDS %s",
|
|
name);
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
|
|
/*
|
|
Check dimensions for consistency. The first dimension may be 0
|
|
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 SDS %s",
|
|
i, dimensions[i], name);
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
}
|
|
|
|
/* cast the dimensions array properly for non 32-bit ints */
|
|
for(i = 0; i < rank; i++)
|
|
{
|
|
myDim[i] = (int32)dimensions[i];
|
|
}
|
|
|
|
|
|
/* behave nicely, if there is still an SDS open */
|
|
if (pFile->iCurrentSDS != 0) {
|
|
SDendaccess (pFile->iCurrentSDS);
|
|
pFile->iCurrentSDS = 0;
|
|
}
|
|
|
|
/* Do not allow creation of SDS's at the root level */
|
|
if (pFile->iCurrentVG == 0) {
|
|
sprintf(pBuffer, "ERROR: SDS creation at root level is not permitted");
|
|
NXIReportError(NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
|
|
/* dataset creation */
|
|
iNew = SDcreate (pFile->iSID, (char*)name, (int32)type,
|
|
(int32)rank, myDim);
|
|
if (iNew < 0) {
|
|
sprintf (pBuffer, "ERROR: cannot create SDS %s, check arguments",
|
|
name);
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
|
|
/* compress SD data set */
|
|
|
|
if(compress_type == NX_COMP_LZW)
|
|
{
|
|
compstruct.deflate.level = 6;
|
|
iRet = SDsetcompress(iNew, COMP_CODE_DEFLATE, &compstruct);
|
|
if (iRet < 0)
|
|
{
|
|
NXIReportError (NXpData, "LZW-Compression failure!");
|
|
return NX_ERROR;
|
|
}
|
|
}
|
|
else if (compress_type == NX_COMP_RLE)
|
|
{
|
|
iRet = SDsetcompress(iNew, COMP_CODE_RLE, &compstruct);
|
|
if (iRet < 0)
|
|
{
|
|
NXIReportError (NXpData, "RLE-Compression failure!");
|
|
return NX_ERROR;
|
|
}
|
|
}
|
|
else if (compress_type == NX_COMP_HUF)
|
|
{
|
|
compstruct.skphuff.skp_size = DFKNTsize(type);
|
|
iRet = SDsetcompress(iNew, COMP_CODE_SKPHUFF, &compstruct);
|
|
if (iRet < 0)
|
|
{
|
|
NXIReportError (NXpData, "HUF-Compression failure!");
|
|
return NX_ERROR;
|
|
}
|
|
}
|
|
else if (compress_type == NX_COMP_NONE)
|
|
{
|
|
/* */
|
|
}
|
|
else
|
|
{
|
|
NXIReportError (NXpData, "Unknown compression method!");
|
|
NX_ERROR;
|
|
}
|
|
/* link into Vgroup, if in one */
|
|
if (pFile->iCurrentVG != 0) {
|
|
iRet = Vaddtagref (pFile->iCurrentVG, DFTAG_NDG, SDidtoref (iNew));
|
|
}
|
|
iRet = SDendaccess (iNew);
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF cannot end access to SDS");
|
|
return NX_ERROR;
|
|
}
|
|
|
|
return NX_OK;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
|
|
NXstatus NX4compress (NXhandle fid, int compress_type)
|
|
{
|
|
pNexusFile pFile;
|
|
int32 iRank, iAtt, iType, iRet;
|
|
int32 iSize[MAX_VAR_DIMS];
|
|
int compress_typei;
|
|
NXname pBuffer;
|
|
char pError[512];
|
|
comp_info compstruct;
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
/* check if there is an SDS open */
|
|
if (pFile->iCurrentSDS == 0) {
|
|
NXIReportError (NXpData, "ERROR: no SDS open");
|
|
return NX_ERROR;
|
|
}
|
|
|
|
if (compress_type == NX_COMP_NONE)
|
|
{
|
|
compress_typei = COMP_CODE_NONE;
|
|
}
|
|
else if (compress_type == NX_COMP_LZW)
|
|
{
|
|
compress_typei = COMP_CODE_DEFLATE;
|
|
}
|
|
else if (compress_type == NX_COMP_RLE)
|
|
{
|
|
compress_typei = COMP_CODE_RLE;
|
|
}
|
|
else if
|
|
(compress_type == NX_COMP_HUF)
|
|
{
|
|
compress_typei = COMP_CODE_SKPHUFF;
|
|
}
|
|
|
|
/* first read dimension information */
|
|
SDgetinfo (pFile->iCurrentSDS, pBuffer, &iRank, iSize, &iType, &iAtt);
|
|
|
|
/*
|
|
according to compression type initialize compression
|
|
information
|
|
*/
|
|
if(compress_type == NX_COMP_LZW)
|
|
{
|
|
compstruct.deflate.level = 6;
|
|
}
|
|
else if(compress_type == NX_COMP_HUF)
|
|
{
|
|
compstruct.skphuff.skp_size = DFKNTsize(iType);
|
|
}
|
|
|
|
iRet = SDsetcompress(pFile->iCurrentSDS, compress_typei, &compstruct);
|
|
if (iRet < 0) {
|
|
sprintf (pError, "ERROR: failure to compress data to %s", pBuffer);
|
|
NXIReportError (NXpData, pError);
|
|
return NX_ERROR;
|
|
}
|
|
return NX_OK;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------- */
|
|
|
|
|
|
NXstatus NX4opendata (NXhandle fid, CONSTCHAR *name)
|
|
{
|
|
pNexusFile pFile;
|
|
int32 iNew;
|
|
char pBuffer[256];
|
|
int iRet;
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
/* First find the reference number of the SDS */
|
|
iNew = NXIFindSDS (fid, name);
|
|
if (iNew < 0) {
|
|
sprintf (pBuffer, "ERROR: SDS %s not found at this level", name);
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
/* Be nice: properly close the old open SDS silently if there is
|
|
* still an SDS open.
|
|
*/
|
|
if (pFile->iCurrentSDS) {
|
|
iRet = SDendaccess (pFile->iCurrentSDS);
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF cannot end access to SDS");
|
|
}
|
|
}
|
|
/* clear pending attribute directories first */
|
|
NXIKillAttDir (pFile);
|
|
|
|
/* open the SDS */
|
|
iNew = SDreftoindex (pFile->iSID, iNew);
|
|
pFile->iCurrentSDS = SDselect (pFile->iSID, iNew);
|
|
if (pFile->iCurrentSDS < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF error opening SDS");
|
|
pFile->iCurrentSDS = 0;
|
|
return NX_ERROR;
|
|
}
|
|
return NX_OK;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
|
|
|
|
NXstatus NX4closedata (NXhandle fid)
|
|
{
|
|
pNexusFile pFile;
|
|
int iRet;
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
if (pFile->iCurrentSDS != 0) {
|
|
iRet = SDendaccess (pFile->iCurrentSDS);
|
|
pFile->iCurrentSDS = 0;
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF cannot end access to SDS");
|
|
return NX_ERROR;
|
|
}
|
|
} else {
|
|
NXIReportError (NXpData, "ERROR: no SDS open --> nothing to do");
|
|
return NX_ERROR;
|
|
}
|
|
NXIKillAttDir (pFile); /* for attribute data */
|
|
return NX_OK;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
NXstatus NX4putdata (NXhandle fid, void *data)
|
|
{
|
|
pNexusFile pFile;
|
|
int32 iStart[MAX_VAR_DIMS], iSize[MAX_VAR_DIMS], iStride[MAX_VAR_DIMS];
|
|
NXname pBuffer;
|
|
int32 iRank, iAtt, iType, iRet, i;
|
|
char pError[512];
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
/* check if there is an SDS open */
|
|
if (pFile->iCurrentSDS == 0) {
|
|
NXIReportError (NXpData, "ERROR: no SDS open");
|
|
return NX_ERROR;
|
|
}
|
|
/* first read dimension information */
|
|
memset (iStart, 0, MAX_VAR_DIMS * sizeof (int32));
|
|
SDgetinfo (pFile->iCurrentSDS, pBuffer, &iRank, iSize, &iType, &iAtt);
|
|
|
|
/* initialise stride to 1 */
|
|
for (i = 0; i < iRank; i++) {
|
|
iStride[i] = 1;
|
|
}
|
|
|
|
/* actually write */
|
|
iRet = SDwritedata (pFile->iCurrentSDS, iStart, iStride, iSize, data);
|
|
if (iRet < 0) {
|
|
sprintf (pError, "ERROR: failure to write data to %s", pBuffer);
|
|
NXIReportError (NXpData, pError);
|
|
return NX_ERROR;
|
|
}
|
|
return NX_OK;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
NXstatus
|
|
NX4putattr (NXhandle fid, CONSTCHAR *name, void *data, int datalen, int iType)
|
|
{
|
|
pNexusFile pFile;
|
|
int iRet, type;
|
|
|
|
pFile = NXIassert (fid);
|
|
if (iType == NX_CHAR)
|
|
{
|
|
type=DFNT_CHAR8;
|
|
}
|
|
else if (iType == NX_INT8)
|
|
{
|
|
type=DFNT_INT8;
|
|
}
|
|
else if (iType == NX_UINT8)
|
|
{
|
|
type=DFNT_UINT8;
|
|
}
|
|
else if (iType == NX_INT16)
|
|
{
|
|
type=DFNT_INT16;
|
|
}
|
|
else if (iType == NX_UINT16)
|
|
{
|
|
type=DFNT_UINT16;
|
|
}
|
|
else if (iType == NX_INT32)
|
|
{
|
|
type=DFNT_INT32;
|
|
}
|
|
else if (iType == NX_UINT32)
|
|
{
|
|
type=DFNT_UINT32;
|
|
}
|
|
else if (iType == NX_FLOAT32)
|
|
{
|
|
type=DFNT_FLOAT32;
|
|
}
|
|
else if (iType == NX_FLOAT64)
|
|
{
|
|
type=DFNT_FLOAT64;
|
|
}
|
|
if (pFile->iCurrentSDS != 0) {
|
|
/* SDS attribute */
|
|
iRet = SDsetattr (pFile->iCurrentSDS, (char*)name, (int32)type,
|
|
(int32)datalen, data);
|
|
} else {
|
|
/* global attribute */
|
|
iRet = SDsetattr (pFile->iSID, (char*)name, (int32)type,
|
|
(int32)datalen, data);
|
|
|
|
}
|
|
iType = type;
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF failed to store attribute ");
|
|
return NX_ERROR;
|
|
}
|
|
return NX_OK;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
|
|
NXstatus NX4putslab (NXhandle fid, void *data, int iStart[], int iSize[])
|
|
{
|
|
pNexusFile pFile;
|
|
int iRet;
|
|
int32 iStride[MAX_VAR_DIMS];
|
|
int32 myStart[MAX_VAR_DIMS], mySize[MAX_VAR_DIMS];
|
|
int32 i, iRank, iType, iAtt;
|
|
NXname pBuffer;
|
|
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
/* check if there is an SDS open */
|
|
if (pFile->iCurrentSDS == 0) {
|
|
NXIReportError (NXpData, "ERROR: no SDS open");
|
|
return NX_ERROR;
|
|
}
|
|
/* initialise stride to 1 */
|
|
for (i = 0; i < MAX_VAR_DIMS; i++) {
|
|
iStride[i] = 1;
|
|
}
|
|
|
|
/* if an int is not 32-bit we have to cast them properly in order
|
|
to kill a bug.
|
|
*/
|
|
if(sizeof(int) != 4)
|
|
{
|
|
SDgetinfo (pFile->iCurrentSDS, pBuffer,
|
|
&iRank, myStart, &iType, &iAtt);
|
|
for(i = 0; i < iRank; i++)
|
|
{
|
|
myStart[i] = (int32)iStart[i];
|
|
mySize[i] = (int32)iSize[i];
|
|
}
|
|
/* finally write */
|
|
iRet = SDwritedata (pFile->iCurrentSDS, myStart,
|
|
iStride, mySize, data);
|
|
|
|
}
|
|
else
|
|
{
|
|
/* write directly */
|
|
|
|
iRet = SDwritedata (pFile->iCurrentSDS,(int32*)iStart, iStride, (int32*)iSize, data);
|
|
}
|
|
|
|
/* deal with HDF errors */
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData, "ERROR: writing slab failed");
|
|
return NX_ERROR;
|
|
}
|
|
return NX_OK;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
NXstatus NX4getdataID (NXhandle fid, NXlink* sRes)
|
|
{
|
|
pNexusFile pFile;
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
if (pFile->iCurrentSDS == 0) {
|
|
sRes->iTag = NX_ERROR;
|
|
return NX_ERROR;
|
|
} else {
|
|
sRes->iTag = DFTAG_NDG;
|
|
sRes->iRef = SDidtoref (pFile->iCurrentSDS);
|
|
NXIbuildPath(pFile,sRes->targetPath,1024);
|
|
return NX_OK;
|
|
}
|
|
sRes->iTag = NX_ERROR;
|
|
return NX_ERROR; /* not reached */
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
|
|
NXstatus NX4makelink (NXhandle fid, NXlink* sLink)
|
|
{
|
|
pNexusFile pFile;
|
|
int32 iVG, iRet, dataID, type = DFNT_CHAR8, length;
|
|
char name[] = "target";
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
if (pFile->iCurrentVG == 0) { /* root level, can not link here */
|
|
return NX_ERROR;
|
|
}
|
|
Vaddtagref(pFile->iCurrentVG, sLink->iTag, sLink->iRef);
|
|
if(sLink->iTag == DFTAG_SDG || sLink->iTag == DFTAG_NDG ||
|
|
sLink->iTag == DFTAG_SDS)
|
|
{
|
|
dataID = SDreftoindex(pFile->iSID,sLink->iRef);
|
|
dataID = SDselect(pFile->iSID,dataID);
|
|
length = strlen(sLink->targetPath);
|
|
SDsetattr(dataID,name,type,length,sLink->targetPath);
|
|
SDendaccess(dataID);
|
|
}
|
|
return NX_OK;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
NXstatus NX4printlink (NXhandle fid, NXlink* sLink)
|
|
{
|
|
pNexusFile pFile;
|
|
pFile = NXIassert (fid);
|
|
printf("HDF4 link: iTag = %d, iRef = %d, target=\"%s\"\n", sLink->iTag, sLink->iRef, sLink->targetPath);
|
|
return NX_OK;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
NXstatus NX4flush(NXhandle *pHandle)
|
|
{
|
|
char *pFileName, *pCopy = NULL;
|
|
int access, dummy, iRet, i, iStack;
|
|
pNexusFile pFile = NULL;
|
|
NXaccess ac;
|
|
int *iRefs = NULL;
|
|
|
|
pFile = NXIassert(*pHandle);
|
|
|
|
/*
|
|
The HDF4-API does not support a flush. We help ourselves with
|
|
inquiring the name and access type of the file, closing it and
|
|
opening it again. This is also the reason why this needs a pointer
|
|
to the handle structure as the handle changes. The other thing we
|
|
do is to store the refs of all open vGroups in a temporary array
|
|
in order to recover the position in the vGroup hierarchy before the
|
|
flush.
|
|
*/
|
|
iRet = Hfidinquire(pFile->iVID,&pFileName,&access,&dummy);
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData,
|
|
"ERROR: Failed to inquire file name for HDF file");
|
|
return NX_ERROR;
|
|
}
|
|
if(pFile->iAccess[0] == 'r') {
|
|
ac = NXACC_READ;
|
|
}else if(pFile->iAccess[0] == 'w') {
|
|
ac = NXACC_RDWR;
|
|
}
|
|
pCopy = (char *)malloc((strlen(pFileName)+10)*sizeof(char));
|
|
if(!pCopy) {
|
|
NXIReportError (NXpData,
|
|
"ERROR: Failed to allocate data for filename copy");
|
|
return NX_ERROR;
|
|
}
|
|
memset(pCopy,0,strlen(pFileName)+10);
|
|
strcpy(pCopy,pFileName);
|
|
|
|
/* get refs for recovering vGroup position */
|
|
iStack = 0;
|
|
if(pFile->iStackPtr > 0) {
|
|
iStack = pFile->iStackPtr + 1;
|
|
iRefs = (int *)malloc(iStack*sizeof(int));
|
|
if(!iRefs){
|
|
NXIReportError (NXpData,
|
|
"ERROR: Failed to allocate data for hierarchy copy");
|
|
return NX_ERROR;
|
|
}
|
|
for(i = 0; i < iStack; i++){
|
|
iRefs[i] = pFile->iStack[i].iVref;
|
|
}
|
|
}
|
|
|
|
iRet = NX4close(pHandle);
|
|
if(iRet != NX_OK) {
|
|
return iRet;
|
|
}
|
|
|
|
iRet = NX4open(pCopy, ac, pHandle);
|
|
free(pCopy);
|
|
|
|
/* return to position in vGroup hierarchy */
|
|
pFile = NXIassert(*pHandle);
|
|
if(iStack > 0){
|
|
pFile->iStackPtr = iStack - 1;
|
|
for(i = 0; i < iStack; i++){
|
|
pFile->iStack[i].iVref = iRefs[i];
|
|
}
|
|
free(iRefs);
|
|
pFile->iCurrentVG = Vattach(pFile->iVID,
|
|
pFile->iStack[pFile->iStackPtr].iVref,
|
|
pFile->iAccess);
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
NXstatus NX4getnextentry (NXhandle fid, NXname name, NXname nxclass, int *datatype)
|
|
{
|
|
pNexusFile pFile;
|
|
int iRet, iStackPtr, iCurDir;
|
|
int32 iTemp, iD1, iD2, iA;
|
|
int32 iDim[MAX_VAR_DIMS];
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
iStackPtr = pFile->iStackPtr;
|
|
iCurDir = pFile->iStack[pFile->iStackPtr].iCurDir;
|
|
|
|
/* first case to check for: no directory entry */
|
|
if (pFile->iStack[pFile->iStackPtr].iRefDir == NULL) {
|
|
iRet = NXIInitDir (pFile);
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData,
|
|
"ERROR: no memory to store directory info");
|
|
return NX_EOD;
|
|
}
|
|
}
|
|
/* Next case: end of directory */
|
|
if (iCurDir >= pFile->iStack[pFile->iStackPtr].iNDir) {
|
|
NXIKillDir (pFile);
|
|
return NX_EOD;
|
|
}
|
|
/* Next case: we have data! supply it and increment counter */
|
|
if (pFile->iCurrentVG == 0) { /* root level */
|
|
iTemp = Vattach (pFile->iVID,
|
|
pFile->iStack[iStackPtr].iRefDir[iCurDir], "r");
|
|
if (iTemp < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF cannot attach to Vgroup");
|
|
return NX_ERROR;
|
|
}
|
|
Vgetname (iTemp, name);
|
|
Vgetclass (iTemp, nxclass);
|
|
*datatype = DFTAG_VG;
|
|
pFile->iStack[pFile->iStackPtr].iCurDir++;
|
|
Vdetach (iTemp);
|
|
return NX_OK;
|
|
} else { /* in Vgroup */
|
|
if (pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_VG) {/* Vgroup */
|
|
iTemp = Vattach (pFile->iVID,
|
|
pFile->iStack[iStackPtr].iRefDir[iCurDir], "r");
|
|
if (iTemp < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF cannot attach to Vgroup");
|
|
return NX_ERROR;
|
|
}
|
|
Vgetname (iTemp, name);
|
|
Vgetclass (iTemp, nxclass);
|
|
*datatype = DFTAG_VG;
|
|
pFile->iStack[pFile->iStackPtr].iCurDir++;
|
|
Vdetach (iTemp);
|
|
return NX_OK;
|
|
/* we are now writing using DFTAG_NDG, but need others for backward compatability */
|
|
} else if ((pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_SDG) ||
|
|
(pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_NDG) ||
|
|
(pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_SDS)) {
|
|
iTemp = SDreftoindex (pFile->iSID,
|
|
pFile->iStack[iStackPtr].iRefDir[iCurDir]);
|
|
iTemp = SDselect (pFile->iSID, iTemp);
|
|
SDgetinfo (iTemp, name, &iA, iDim, &iD1, &iD2);
|
|
strcpy (nxclass, "SDS");
|
|
*datatype = iD1;
|
|
SDendaccess (iTemp);
|
|
pFile->iStack[pFile->iStackPtr].iCurDir++;
|
|
return NX_OK;
|
|
} else { /* unidentified */
|
|
strcpy (name, "UNKNOWN");
|
|
strcpy (nxclass, "UNKNOWN");
|
|
*datatype = pFile->iStack[iStackPtr].iTagDir[iCurDir];
|
|
pFile->iStack[pFile->iStackPtr].iCurDir++;
|
|
return NX_OK;
|
|
}
|
|
}
|
|
return NX_ERROR; /* not reached */
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
NXstatus NX4getdata (NXhandle fid, void *data)
|
|
{
|
|
pNexusFile pFile;
|
|
int32 iStart[MAX_VAR_DIMS], iSize[MAX_VAR_DIMS];
|
|
NXname pBuffer;
|
|
int32 iRank, iAtt, iType;
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
/* check if there is an SDS open */
|
|
if (pFile->iCurrentSDS == 0) {
|
|
NXIReportError (NXpData, "ERROR: no SDS open");
|
|
return NX_ERROR;
|
|
}
|
|
/* first read dimension information */
|
|
memset (iStart, 0, MAX_VAR_DIMS * sizeof (int32));
|
|
SDgetinfo (pFile->iCurrentSDS, pBuffer, &iRank, iSize, &iType, &iAtt);
|
|
/* actually read */
|
|
SDreaddata (pFile->iCurrentSDS, iStart, NULL, iSize, data);
|
|
return NX_OK;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
NXstatus
|
|
NX4getinfo (NXhandle fid, int *rank, int dimension[],
|
|
int *iType)
|
|
{
|
|
pNexusFile pFile;
|
|
NXname pBuffer;
|
|
int32 iAtt, myDim[MAX_VAR_DIMS], i, iRank, mType;
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
/* check if there is an SDS open */
|
|
if (pFile->iCurrentSDS == 0) {
|
|
NXIReportError (NXpData, "ERROR: no SDS open");
|
|
return NX_ERROR;
|
|
}
|
|
/* read information */
|
|
SDgetinfo (pFile->iCurrentSDS, pBuffer, &iRank, myDim,
|
|
&mType, &iAtt);
|
|
|
|
/* conversion to proper ints for the platform */
|
|
*iType = (int)mType;
|
|
*rank = (int)iRank;
|
|
for(i = 0; i < iRank; i++)
|
|
{
|
|
dimension[i] = (int)myDim[i];
|
|
}
|
|
return NX_OK;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
NXstatus NX4getslab (NXhandle fid, void *data, int iStart[], int iSize[])
|
|
{
|
|
pNexusFile pFile;
|
|
int32 myStart[MAX_VAR_DIMS], mySize[MAX_VAR_DIMS];
|
|
int32 i, iRank, iType, iAtt;
|
|
NXname pBuffer;
|
|
|
|
pFile = NXIassert (fid);
|
|
|
|
/* check if there is an SDS open */
|
|
if (pFile->iCurrentSDS == 0) {
|
|
NXIReportError (NXpData, "ERROR: no SDS open");
|
|
return NX_ERROR;
|
|
}
|
|
|
|
/* if an int is not 32-bit we have to cast them properly in order
|
|
to kill a bug.
|
|
*/
|
|
if(sizeof(int) != 4)
|
|
{
|
|
SDgetinfo (pFile->iCurrentSDS, pBuffer,
|
|
&iRank, myStart, &iType, &iAtt);
|
|
for(i = 0; i < iRank; i++)
|
|
{
|
|
myStart[i] = (int32)iStart[i];
|
|
mySize[i] = (int32)iSize[i];
|
|
}
|
|
/* finally read */
|
|
SDreaddata (pFile->iCurrentSDS, myStart, NULL,
|
|
mySize, data);
|
|
return NX_OK;
|
|
}
|
|
else
|
|
{
|
|
/* read directly */
|
|
SDreaddata (pFile->iCurrentSDS, (int32*)iStart, NULL,
|
|
(int32*)iSize, data);
|
|
return NX_OK;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
NXstatus NX4getnextattr (NXhandle fileid, NXname pName,
|
|
int *iLength, int *iType)
|
|
{
|
|
pNexusFile pFile;
|
|
int iRet;
|
|
int32 iPType, iCount;
|
|
|
|
pFile = NXIassert (fileid);
|
|
|
|
/* first check if we have to start a new attribute search */
|
|
if (pFile->iAtt.iNDir == 0) {
|
|
iRet = NXIInitAttDir (pFile);
|
|
if (iRet == NX_ERROR) {
|
|
return NX_ERROR;
|
|
}
|
|
}
|
|
/* are we done ? */
|
|
if (pFile->iAtt.iCurDir >= pFile->iAtt.iNDir) {
|
|
NXIKillAttDir (pFile);
|
|
return NX_EOD;
|
|
}
|
|
/* well, there must be data to copy */
|
|
if (pFile->iCurrentSDS == 0) { /* global attribute */
|
|
iRet = SDattrinfo (pFile->iSID, pFile->iAtt.iCurDir,
|
|
pName, &iPType, &iCount);
|
|
} else {
|
|
iRet = SDattrinfo (pFile->iCurrentSDS, pFile->iAtt.iCurDir,
|
|
pName, &iPType, &iCount);
|
|
}
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData, "ERROR: HDF cannot read attribute info");
|
|
return NX_ERROR;
|
|
}
|
|
*iLength = iCount;
|
|
*iType = iPType;
|
|
pFile->iAtt.iCurDir++;
|
|
return NX_OK;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
NXstatus NX4getattr (NXhandle fid, char *name, void *data, int* datalen, int* iType)
|
|
{
|
|
pNexusFile pFile;
|
|
int32 iNew, iType32;
|
|
void *pData = NULL;
|
|
int32 iLen, iRet;
|
|
int type;
|
|
char pBuffer[256];
|
|
NXname pNam;
|
|
|
|
type = *iType;
|
|
if (type == NX_CHAR)
|
|
{
|
|
type=DFNT_CHAR8;
|
|
}
|
|
else if (type == NX_INT8)
|
|
{
|
|
type=DFNT_INT8;
|
|
}
|
|
else if (type == NX_UINT8)
|
|
{
|
|
type=DFNT_UINT8;
|
|
}
|
|
else if (type == NX_INT16)
|
|
{
|
|
type=DFNT_INT16;
|
|
}
|
|
else if (type == NX_UINT16)
|
|
{
|
|
type=DFNT_UINT16;
|
|
}
|
|
else if (type == NX_INT32)
|
|
{
|
|
type=DFNT_INT32;
|
|
}
|
|
else if (type == NX_UINT32)
|
|
{
|
|
type=DFNT_UINT32;
|
|
}
|
|
else if (type == NX_FLOAT32)
|
|
{
|
|
type=DFNT_FLOAT32;
|
|
}
|
|
else if (type == NX_FLOAT64)
|
|
{
|
|
type=DFNT_FLOAT64;
|
|
}
|
|
*datalen = (*datalen) * DFKNTsize(type);
|
|
pFile = NXIassert (fid);
|
|
|
|
/* find attribute */
|
|
if (pFile->iCurrentSDS != 0) {
|
|
/* SDS attribute */
|
|
iNew = SDfindattr (pFile->iCurrentSDS, name);
|
|
} else {
|
|
/* global attribute */
|
|
iNew = SDfindattr (pFile->iSID, name);
|
|
}
|
|
if (iNew < 0) {
|
|
sprintf (pBuffer, "ERROR: attribute %s not found", name);
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
/* get more info, allocate temporary data space */
|
|
iType32 = (int32)type;
|
|
if (pFile->iCurrentSDS != 0) {
|
|
iRet = SDattrinfo (pFile->iCurrentSDS, iNew, pNam, &iType32, &iLen);
|
|
} else {
|
|
iRet = SDattrinfo (pFile->iSID, iNew, pNam, &iType32, &iLen);
|
|
}
|
|
if (iRet < 0) {
|
|
sprintf (pBuffer, "ERROR: HDF could not read attribute info");
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
*iType = (int)iType32;
|
|
iLen = iLen * DFKNTsize (*iType);
|
|
pData = (void *) malloc (iLen);
|
|
if (!pData) {
|
|
NXIReportError (NXpData, "ERROR: allocating memory in NXgetattr");
|
|
return NX_ERROR;
|
|
}
|
|
memset (pData, 0, iLen);
|
|
|
|
/* finally read the data */
|
|
if (pFile->iCurrentSDS != 0) {
|
|
iRet = SDreadattr (pFile->iCurrentSDS, iNew, pData);
|
|
} else {
|
|
iRet = SDreadattr (pFile->iSID, iNew, pData);
|
|
}
|
|
if (iRet < 0) {
|
|
sprintf (pBuffer, "ERROR: HDF could not read attribute data");
|
|
NXIReportError (NXpData, pBuffer);
|
|
return NX_ERROR;
|
|
}
|
|
/* copy data to caller */
|
|
memset (data, 0, *datalen);
|
|
if ((*datalen <= iLen) && (*iType == DFNT_UINT8 || *iType == DFNT_CHAR8 || *iType == DFNT_UCHAR8)) {
|
|
iLen = *datalen - 1;
|
|
}
|
|
memcpy (data, pData, iLen);
|
|
*datalen = iLen / DFKNTsize(*iType);
|
|
free (pData);
|
|
return NX_OK;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
NXstatus NX4getattrinfo (NXhandle fid, int *iN)
|
|
{
|
|
pNexusFile pFile;
|
|
int iRet;
|
|
int32 iData, iAtt, iRank, iType;
|
|
int32 iDim[MAX_VAR_DIMS];
|
|
NXname pNam;
|
|
|
|
pFile = NXIassert (fid);
|
|
if (pFile->iCurrentSDS != 0) { /* SDS level */
|
|
iRet = SDgetinfo (pFile->iCurrentSDS, pNam, &iRank, iDim, &iType,
|
|
&iAtt);
|
|
} else { /* global level */
|
|
iRet = SDfileinfo (pFile->iSID, &iData, &iAtt);
|
|
}
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData, "NX_ERROR: HDF cannot read attribute numbers");
|
|
*iN = 0;
|
|
return NX_ERROR;
|
|
}
|
|
*iN = iAtt;
|
|
return NX_OK;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
NXstatus NX4getgroupID (NXhandle fileid, NXlink* sRes)
|
|
{
|
|
pNexusFile pFile;
|
|
|
|
pFile = NXIassert (fileid);
|
|
|
|
if (pFile->iCurrentVG == 0) {
|
|
sRes->iTag = NX_ERROR;
|
|
return NX_ERROR;
|
|
} else {
|
|
sRes->iTag = DFTAG_VG;
|
|
sRes->iRef = VQueryref(pFile->iCurrentVG);
|
|
NXIbuildPath(pFile,sRes->targetPath,1024);
|
|
return NX_OK;
|
|
}
|
|
/* not reached */
|
|
sRes->iTag = NX_ERROR;
|
|
return NX_ERROR;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
NXstatus
|
|
NX4getgroupinfo (NXhandle fid, int *iN, NXname pName, NXname pClass)
|
|
{
|
|
pNexusFile pFile;
|
|
|
|
pFile = NXIassert (fid);
|
|
/* check if there is a group open */
|
|
if (pFile->iCurrentVG == 0) {
|
|
*iN = Vlone (pFile->iVID, NULL, 0);
|
|
strcpy (pName, "root");
|
|
strcpy (pClass, "NXroot");
|
|
}
|
|
else {
|
|
*iN = Vntagrefs (pFile->iCurrentVG);
|
|
Vgetname (pFile->iCurrentVG, pName);
|
|
Vgetclass (pFile->iCurrentVG, pClass);
|
|
}
|
|
return NX_OK;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
NXstatus NX4sameID (NXhandle fileid, NXlink* pFirstID, NXlink* pSecondID)
|
|
{
|
|
pNexusFile pFile;
|
|
|
|
pFile = NXIassert (fileid);
|
|
if ((pFirstID->iTag == pSecondID->iTag) & (pFirstID->iRef == pSecondID->iRef)) {
|
|
return NX_OK;
|
|
} else {
|
|
return NX_ERROR;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
NXstatus NX4initattrdir (NXhandle fid)
|
|
{
|
|
pNexusFile pFile;
|
|
int iRet;
|
|
|
|
pFile = NXIassert (fid);
|
|
NXIKillAttDir (fid);
|
|
iRet = NXIInitAttDir (pFile);
|
|
if (iRet == NX_ERROR)
|
|
return NX_ERROR;
|
|
return NX_OK;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
NXstatus NX4initgroupdir (NXhandle fid)
|
|
{
|
|
pNexusFile pFile;
|
|
int iRet;
|
|
|
|
pFile = NXIassert (fid);
|
|
NXIKillDir (fid);
|
|
iRet = NXIInitDir (pFile);
|
|
if (iRet < 0) {
|
|
NXIReportError (NXpData,"NX_ERROR: no memory to store directory info");
|
|
return NX_EOD;
|
|
}
|
|
return NX_OK;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
void NX4assignFunctions(pNexusFunction fHandle)
|
|
{
|
|
fHandle->nxclose=NX4close;
|
|
fHandle->nxflush=NX4flush;
|
|
fHandle->nxmakegroup=NX4makegroup;
|
|
fHandle->nxopengroup=NX4opengroup;
|
|
fHandle->nxclosegroup=NX4closegroup;
|
|
fHandle->nxmakedata=NX4makedata;
|
|
fHandle->nxcompmakedata=NX4compmakedata;
|
|
fHandle->nxcompress=NX4compress;
|
|
fHandle->nxopendata=NX4opendata;
|
|
fHandle->nxclosedata=NX4closedata;
|
|
fHandle->nxputdata=NX4putdata;
|
|
fHandle->nxputattr=NX4putattr;
|
|
fHandle->nxputslab=NX4putslab;
|
|
fHandle->nxgetdataID=NX4getdataID;
|
|
fHandle->nxmakelink=NX4makelink;
|
|
fHandle->nxgetdata=NX4getdata;
|
|
fHandle->nxgetinfo=NX4getinfo;
|
|
fHandle->nxgetnextentry=NX4getnextentry;
|
|
fHandle->nxgetslab=NX4getslab;
|
|
fHandle->nxgetnextattr=NX4getnextattr;
|
|
fHandle->nxgetattr=NX4getattr;
|
|
fHandle->nxgetattrinfo=NX4getattrinfo;
|
|
fHandle->nxgetgroupID=NX4getgroupID;
|
|
fHandle->nxgetgroupinfo=NX4getgroupinfo;
|
|
fHandle->nxsameID=NX4sameID;
|
|
fHandle->nxinitgroupdir=NX4initgroupdir;
|
|
fHandle->nxinitattrdir=NX4initattrdir;
|
|
fHandle->nxprintlink=NX4printlink;
|
|
}
|