Files
sics/napi.c
cvs 8f84d45dd6 - Added a multiple histogram memory control module. This required a
tiny change in the countable interface which in turn required updating
  of header file includes in a lot of files.
- Some small fixes to TRICS writing as well.
2001-06-08 15:18:35 +00:00

1557 lines
42 KiB
C

/*---------------------------------------------------------------------------
NeXus - Neutron & X-ray Common Data Format
Application Program Interface Routines
Copyright (C) 1997-2000 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
Contact : Mark Koennecke <Mark.Koennecke@psi.ch>
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5232 Villigen-PSI
Switzerland
Przemek Klosowski <Przemek.Klosowski@nist.gov>
NIST Center for Neutron Research
100 Bureau Drive, Stop 8562
Gaithersburg, MD 20899-8562
USA
For further information, see <http://www.neutron.anl.gov/NeXus/>
----------------------------------------------------------------------------*/
static const char* rscid = "$Id: napi.c,v 1.4 2001/06/08 15:18:37 cvs Exp $"; /* Revision interted by CVS */
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <mfhdf.h>
#include "napi.h"
#define NXMAXSTACK 50
#define NXSIGNATURE 959697
typedef struct __NexusFile {
struct iStack {
int32 *iRefDir;
int32 *iTagDir;
int32 iVref;
int32 __iStack_pad; /* for 64 bit alignment */
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 void NXNXNXReportError(void *pData, char *string)
{
printf("%s \n",string);
}
/*---------------------------------------------------------------------*/
void *NXpData = NULL;
void (*NXIReportError)(void *pData, char *string) = NXNXNXReportError;
/*---------------------------------------------------------------------*/
void NXMSetError(void *pData, void (*NewError)(void *pD, char *text))
{
NXpData = pData;
NXIReportError = NewError;
}
/*--------------------------------------------------------------------*/
static pNexusFile NXIassert(NXhandle fid)
{
pNexusFile pRes;
assert(fid != NULL);
pRes = (pNexusFile)fid;
assert(pRes->iNXID == NXSIGNATURE);
return pRes;
}
/*----------------------------------------------------------------------*/
static int32
NXIFindVgroup (pNexusFile pFile, char *name, char *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, &iD2, &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, &iD2, &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, iCurDir;
/*
* 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;
}
/*
* We store the whole of the NeXus file in the array - that way
* we can just pass the array name to C as it will be a valid
* NXhandle. We could store the NXhandle value in the FORTRAN array
* instead, but that would mean writing far more wrappers
*/
NXstatus NXfopen(char * filename, NXaccess* am, NexusFile* pHandle)
{
NXstatus ret;
NXhandle fileid = NULL;
ret = NXopen(filename, *am, &fileid);
if (ret == NX_OK)
{
memcpy(pHandle, fileid, sizeof(NexusFile));
}
else
{
memset(pHandle, 0, sizeof(NexusFile));
}
if (fileid != NULL)
{
free(fileid);
}
return ret;
}
/*
* the following deals with how we do our timezone calculation.
* Not all systems have a timezone field as part of "struct tm"
* that is passed to localtime(), so we need to look elsewhere
*
* If you encounter problems, try defining USE_FTIME first, with
* NEED_TZSET is your system provides the tzset() function
*/
#if defined(_WIN32)
# define NEED_TZSET /* call tzset() to initialise time variables */
# define USE_TIMEZONE /* use timezone and daylight variables */
#elif (defined(__VMS) && (__VMS_VER < 70000000))
# define USE_FTIME /* use ftime() function */
# include <sys/timeb.h>
#endif /* __VMS && __VMS_VER < 70000000 */
NXstatus NXopen(CONSTCHAR * filename, NXaccess am, NXhandle* pHandle)
{
pNexusFile pNew = NULL;
char pBuffer[512], time_buffer[64];
int iRet;
int32 file_id, an_id, ann_id;
time_t timer;
struct tm *time_info;
const char* time_format;
long gmt_offset;
#ifdef USE_FTIME
struct timeb timeb_struct;
#endif /* USE_FTIME */
*pHandle = NULL;
/* 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));
/*
* get time in ISO 8601 format
*/
#ifdef NEED_TZSET
tzset();
#endif /* NEED_TZSET */
time(&timer);
time_info = localtime(&timer);
#if defined(USE_TIMEZONE)
gmt_offset = -timezone + ( (daylight != 0) ? 3600 : 0 );
#elif defined(USE_FTIME)
ftime(&timeb_struct);
gmt_offset = -timeb_struct.timezone * 60;
if (timeb_struct.dstflag != 0)
{
gmt_offset += 3600;
}
#elif defined(__MWERKS__)
gmt_offset = difftime (timer, mktime(gmtime(&timer)));
#else
gmt_offset = time_info->tm_gmtoff;
#endif
if (time_info != NULL)
{
if (gmt_offset < 0)
{
time_format = "%04d-%02d-%02d %02d:%02d:%02d-%02d%02d";
}
else
{
time_format = "%04d-%02d-%02d %02d:%02d:%02d+%02d%02d";
}
sprintf(time_buffer, time_format,
1900 + time_info->tm_year,
1 + time_info->tm_mon,
time_info->tm_mday,
time_info->tm_hour,
time_info->tm_min,
time_info->tm_sec,
abs(gmt_offset / 3600),
abs((gmt_offset % 3600) / 60)
);
}
else
{
strcpy(time_buffer, "1970-01-01 00:00:00+0000");
}
#if WRITE_OLD_IDENT /* not used at moment */
/*
* write something that can be used by OLE
*/
if (am == NXACC_CREATE)
{
if ( (file_id = Hopen(filename, am, 0)) == -1 )
{
sprintf (pBuffer, "ERROR: cannot open file: %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, am);
if (pNew->iSID <= 0) {
sprintf (pBuffer, "ERROR: cannot open file: %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;
}
}
if (am == NXACC_CREATE)
{
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 (SDsetattr(pNew->iSID, "file_time", DFNT_CHAR8, strlen(time_buffer), time_buffer) < 0)
{
NXIReportError (NXpData, "ERROR: HDF failed to store file_time attribute ");
return NX_ERROR;
}
}
/*
* Otherwise we try to create the file two times which makes HDF
* Throw up on us.
*/
if (am == NXACC_CREATE) {
am = NXACC_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, am, 5000);
if (pNew->iVID <= 0) {
sprintf (pBuffer, "ERROR: cannot open file: %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;
}
/*
* The pHandle from FORTRAN is a pointer to a static FORTRAN
* array holding the NexusFile structure. We need to malloc()
* a temporary copy as NXclose will try to free() this
*/
NXstatus
NXfclose (NexusFile* pHandle)
{
NXhandle h;
NXstatus ret;
h = (NXhandle)malloc(sizeof(NexusFile));
memcpy(h, pHandle, sizeof(NexusFile));
ret = NXclose(&h); /* does free(h) */
memset(pHandle, 0, sizeof(NexusFile));
return ret;
}
NXstatus
NXclose (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 NXmakegroup (NXhandle fid, CONSTCHAR *name, char *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
NXopengroup (NXhandle fid, CONSTCHAR *name, char *nxclass)
{
pNexusFile pFile;
int32 iNew, 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
NXclosegroup (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 NXfmakedata(NXhandle fid, char *name, int *pDatatype,
int *pRank, int dimensions[])
{
NXstatus ret;
static char buffer[256];
int i, *reversed_dimensions;
reversed_dimensions = (int*)malloc(*pRank * sizeof(int));
if (reversed_dimensions == NULL)
{
sprintf (buffer, "ERROR: Cannot allocate space for array rank of %d in NXfmakedata", *pRank);
NXIReportError (NXpData, buffer);
return NX_ERROR;
}
/*
* Reverse dimensions array as FORTRAN is column major, C row major
*/
for(i=0; i < *pRank; i++)
{
reversed_dimensions[i] = dimensions[*pRank - i - 1];
}
ret = NXmakedata(fid, name, *pDatatype, *pRank, reversed_dimensions);
free(reversed_dimensions);
return ret;
}
NXstatus NXmakedata (NXhandle fid, CONSTCHAR *name, int datatype, int rank,
int dimensions[])
{
pNexusFile pFile;
int32 iNew;
char pBuffer[256];
int i, iRet;
int32 myDim[MAX_VAR_DIMS];
pFile = NXIassert (fid);
if ((iNew = NXIFindSDS (fid, name))>=0) {
sprintf (pBuffer, "ERROR: SDS %s already exists at this level", name);
NXIReportError (NXpData, pBuffer);
return NX_ERROR;
}
/* Do some argument checking */
switch (datatype) {
case DFNT_FLOAT32: break;
case DFNT_FLOAT64: break;
case DFNT_INT8: break;
case DFNT_UINT8: break;
case DFNT_CHAR8: break;
case DFNT_UCHAR8: break;
case DFNT_INT16: break;
case DFNT_UINT16: break;
case DFNT_INT32: break;
case DFNT_UINT32: break;
default:
sprintf (pBuffer, "ERROR: unknown datatype specified for SDS %s",
name);
NXIReportError (NXpData, pBuffer);
return NX_ERROR;
}
if (rank <= 0) {
sprintf (pBuffer, "ERROR: invalid rank specified for SDS %s",
name);
NXIReportError (NXpData, pBuffer);
return NX_ERROR;
}
for (i = 0; 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)datatype,
(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
NXopendata (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 NXfcompress(NXhandle fid, int *compr_type)
{
return NXcompress(fid,*compr_type);
}
NXstatus
NXcompress (NXhandle fid, int compress_type)
{
pNexusFile pFile;
int32 iRank, iAtt, iType, iRet, i, e;
int32 iSize[MAX_VAR_DIMS];
NXname pBuffer;
char pError[512];
comp_info compstruct;
char *str;
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 */
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_type, &compstruct);
if (iRet < 0) {
sprintf (pError, "ERROR: failure to compress data to %s", pBuffer);
NXIReportError (NXpData, pError);
return NX_ERROR;
}
return NX_OK;
}
NXstatus
NXclosedata (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
NXgetdata (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
NXgetslab (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
NXgetattr (NXhandle fid, char *name, void *data, int* datalen, int* iType)
{
pNexusFile pFile;
int32 iNew;
void *pData = NULL;
int32 iLen, iRet;
char pBuffer[256];
NXname pNam;
*datalen = (*datalen) * DFKNTsize(*iType);
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 */
if (pFile->iCurrentSDS != 0) {
iRet = SDattrinfo (pFile->iCurrentSDS, iNew, pNam, (int32*)iType, &iLen);
} else {
iRet = SDattrinfo (pFile->iSID, iNew, pNam, (int32*)iType, &iLen);
}
if (iRet < 0) {
sprintf (pBuffer, "ERROR: HDF could not read attribute info");
NXIReportError (NXpData, pBuffer);
return NX_ERROR;
}
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
NXsetdimname(NXhandle fid, int iDim, CONSTCHAR *name)
{
pNexusFile pFile;
int32 dim_id, iRet;
pFile = NXIassert (fid);
/* check if there is an SDS open */
if (pFile->iCurrentSDS == 0) {
NXIReportError (NXpData, "ERROR: no SDS open");
return NX_ERROR;
}
/*
get dimension ID
*/
dim_id = SDgetdimid(pFile->iCurrentSDS,iDim);
if(dim_id < 0){
NXIReportError(NXpData,
"ERROR: trying to set dimension name for non existent dimension");
return NX_ERROR;
}
/*
set name
*/
iRet = SDsetdimname(dim_id,name);
if(iRet < 0){
NXIReportError(NXpData,
"ERROR: failed to set dimension name");
return NX_ERROR;
}
return NX_OK;
}
NXstatus
NXputdata (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, e;
char pError[512];
char *str;
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
NXputslab (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
NXfputattr(NXhandle fid, char *name, void *data, int *pDatalen, int *pIType)
{
return NXputattr(fid, name, data, *pDatalen, *pIType);
}
NXstatus
NXputattr (NXhandle fid, CONSTCHAR *name, void *data, int datalen, int iType)
{
pNexusFile pFile;
int iRet;
pFile = NXIassert (fid);
if (pFile->iCurrentSDS != 0) {
/* SDS attribute */
iRet = SDsetattr (pFile->iCurrentSDS, (char*)name, (int32)iType,
(int32)datalen, data);
} else {
/* global attribute */
iRet = SDsetattr (pFile->iSID, (char*)name, (int32)iType,
(int32)datalen, data);
}
if (iRet < 0) {
NXIReportError (NXpData, "ERROR: HDf failed to store attribute ");
return NX_ERROR;
}
return NX_OK;
}
NXstatus
NXgetinfo (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
NXgetgroupinfo (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
NXgetattrinfo (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 iRet;
}
NXstatus
NXinitgroupdir (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;
}
/*-------------------------------------------------------------------------*/
NXstatus
NXgetnextentry (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
NXinitattrdir (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
NXgetnextattr (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
NXgetgroupID (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);
return NX_OK;
}
/* not reached */
sRes->iTag = NX_ERROR;
return NX_ERROR;
}
NXstatus
NXgetdataID (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);
return NX_OK;
}
sRes->iTag = NX_ERROR;
return NX_ERROR; /* not reached */
}
NXstatus
NXmakelink (NXhandle fid, NXlink* sLink)
{
pNexusFile pFile;
pFile = NXIassert (fid);
if (pFile->iCurrentVG == 0) { /* root level, can not link here */
return NX_ERROR;
}
Vaddtagref (pFile->iCurrentVG, sLink->iTag, sLink->iRef);
return NX_OK;
}
/* allocate space for an array of given dimensions and type */
NXstatus
NXmalloc (void** data, int rank, int dimensions[], int datatype)
{
int i;
size_t size = 1;
*data = NULL;
for(i=0; i<rank; i++)
size *= dimensions[i];
switch(datatype)
{
case DFNT_INT8:
case DFNT_UINT8:
case DFNT_CHAR8:
case DFNT_UCHAR8:
break; /* size is correct already */
case DFNT_INT16:
case DFNT_UINT16:
size *= 2;
break;
case DFNT_INT32:
case DFNT_UINT32:
case DFNT_FLOAT32:
size *= 4;
break;
case DFNT_FLOAT64:
size *= 8;
break;
default:
NXIReportError (NXpData, "ERROR: NXmalloc - unknown data type in array");
return NX_ERROR;
break;
}
*data = (void*)malloc(size);
return NX_OK;
}
/* free space allocated by NXmalloc */
NXstatus
NXfree (void** data)
{
if (data == NULL)
{
NXIReportError (NXpData, "ERROR: passing NULL to NXfree");
return NX_ERROR;
}
if (*data == NULL)
{
NXIReportError (NXpData, "ERROR: passing already freed pointer to NXfree");
return NX_ERROR;
}
free(*data);
*data = NULL;
return NX_OK;
}