Files
sics/napi4.c
2012-11-26 11:33:14 +11:00

1984 lines
54 KiB
C

/*---------------------------------------------------------------------------
NeXus - Neutron & X-ray Common Data Format
Application Program Interface (HDF4) 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 <http://www.nexusformat.org>
$Id$
----------------------------------------------------------------------------*/
#ifdef HDF4
#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 int findNapiClass(pNexusFile pFile, int groupRef, NXname nxclass)
{
NXname classText, linkClass;
int32 tags[2], attID, linkID, groupID;
groupID = Vattach(pFile->iVID,groupRef,"r");
Vgetclass(groupID, classText);
if(strcmp(classText,"NAPIlink") != 0)
{
/* normal group */
strcpy(nxclass,classText);
Vdetach(groupID);
return groupRef;
}
else
{
/* code for linked renamed groups */
attID = Vfindattr(groupID,"NAPIlink");
if(attID >= 0)
{
Vgetattr(groupID,attID, tags);
linkID = Vattach(pFile->iVID,tags[1],"r");
Vgetclass(linkID, linkClass);
Vdetach(groupID);
Vdetach(linkID);
strcpy(nxclass,linkClass);
return tags[1];
}
else
{
/* this allows for finding the NAPIlink group in NXmakenamedlink */
strcpy(nxclass,classText);
Vdetach(groupID);
return groupRef;
}
}
}
/* --------------------------------------------------------------------- */
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) {
NXReportError( "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);
Vdetach(iNew);
if (strcmp (pText, name) == 0) {
pArray[i] = findNapiClass(pFile,pArray[i],pText);
if (strcmp (pText, nxclass) == 0) {
/* found ! */
iNew = pArray[i];
free (pArray);
return 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);
Vdetach(iNew);
if (strcmp (pText, name) == 0) {
iRef = findNapiClass(pFile,iRef, pText);
if (strcmp (pText, nxclass) == 0) {
return iRef;
}
}
}
} /* 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[H4_MAX_VAR_DIMS];
self = NXIassert (fid);
/* root level search */
if (self->iCurrentVG == 0) {
i = SDfileinfo (self->iSID, &iN, &iA);
if (i < 0) {
NXReportError( "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) {
NXReportError( "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)) {
NXReportError( "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[H4_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 {
if(pFile->iCurrentVG == 0){
/* global level */
iRet = SDfileinfo (pFile->iSID, &iData, &iAtt);
} else {
/* group attribute */
iRet = Vnattrs(pFile->iCurrentVG);
iAtt = iRet;
}
}
if (iRet < 0) {
NXReportError( "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[H4_MAX_VAR_DIMS];
NXname pText;
buffer[0] = '\0';
for(i = 1; i <= pFile->iStackPtr; i++){
strncat(buffer,"/",bufLen-strlen(buffer));
groupID = Vattach(pFile->iVID,pFile->iStack[i].iVref, "r");
if (groupID != -1)
{
if (Vgetname(groupID, pText) != -1) {
strncat(buffer,pText,bufLen-strlen(buffer));
} else {
NXReportError( "ERROR: NXIbuildPath cannot get vgroup name");
}
Vdetach(groupID);
}
else
{
NXReportError( "ERROR: NXIbuildPath cannot attach to vgroup");
}
}
if(pFile->iCurrentSDS != 0){
if (SDgetinfo(pFile->iCurrentSDS,pText,&iA,iDim,&iD1,&iD2) != -1) {
strncat(buffer,"/",bufLen-strlen(buffer));
strncat(buffer,pText,bufLen-strlen(buffer));
}
else
{
NXReportError( "ERROR: NXIbuildPath cannot read SDS");
}
}
}
/* ----------------------------------------------------------------------
Definition of NeXus API
---------------------------------------------------------------------*/
NXstatus NX4open(CONSTCHAR *filename, NXaccess am,
NXhandle* pHandle)
{
pNexusFile pNew = NULL;
char pBuffer[512];
char *time_puffer = NULL;
char HDF_VERSION[64];
uint32 lmajor, lminor, lrelease;
int32 am1=0;
*pHandle = NULL;
/* mask off any options for now */
am = (NXaccess)(am & NXACCMASK_REMOVEFLAGS);
/* 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) {
NXReportError( "ERROR: no memory to create File datastructure");
return NX_ERROR;
}
memset (pNew, 0, sizeof (NexusFile));
#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);
NXReportError( 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);
NXReportError( 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);
NXReportError( 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) {
NXReportError( "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) {
NXReportError( "ERROR: HDF failed to store HDF_version attribute ");
return NX_ERROR;
}
}
time_puffer = NXIformatNeXusTime();
if (am == NXACC_CREATE || am == NXACC_CREATE4) {
if (SDsetattr(pNew->iSID, "file_name", DFNT_CHAR8, strlen(filename), (char*)filename) < 0) {
NXReportError( "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) {
NXReportError(
"ERROR: HDF failed to store file_time attribute ");
free(time_puffer);
return NX_ERROR;
}
}
}
if (time_puffer != NULL) {
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);
NXReportError( 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) {
NXReportError( "ERROR: ending access to SDS");
}
/* close the SDS and Vgroup API's */
Vend (pFile->iVID);
iRet = SDend (pFile->iSID);
if (iRet < 0) {
NXReportError( "ERROR: HDF cannot close SDS interface");
}
iRet = Hclose (pFile->iVID);
if (iRet < 0) {
NXReportError( "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);
NXReportError( pBuffer);
return NX_ERROR;
}
/* create and configure the group */
iNew = Vattach (pFile->iVID, -1, "w");
if (iNew < 0) {
NXReportError( "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) {
NXReportError( "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);
NXReportError( 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 NX4makedata64 (NXhandle fid, CONSTCHAR *name, int datatype, int rank,
int64_t dimensions[])
{
pNexusFile pFile;
int32 iNew;
char pBuffer[256];
int i, iRet, type;
int32 myDim[H4_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);
NXReportError( 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;
}
else
{
NXReportError( "ERROR: invalid type in NX4makedata");
return NX_ERROR;
}
if (rank <= 0) {
sprintf (pBuffer, "ERROR: invalid rank specified for SDS %s",
name);
NXReportError( 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 %lld given for SDS %s",
i, (long long)dimensions[i], name);
NXReportError( 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");
NXReportError( 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);
NXReportError( 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) {
NXReportError( "ERROR: HDF cannot end access to SDS");
return NX_ERROR;
}
return NX_OK;
}
/* --------------------------------------------------------------------- */
NXstatus NX4compmakedata64 (NXhandle fid, CONSTCHAR *name, int datatype, int rank,
int64_t dimensions[],int compress_type, int64_t chunk_size[])
{
pNexusFile pFile;
int32 iNew, iRet, type;
char pBuffer[256];
int i, compress_level;
int32 myDim[H4_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);
NXReportError( 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;
}
else
{
NXReportError( "ERROR: invalid datatype in NX4compmakedata");
return NX_ERROR;
}
if (rank <= 0) {
sprintf (pBuffer, "ERROR: invalid rank specified for SDS %s",
name);
NXReportError( 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 %lld given for SDS %s",
i, (long long)dimensions[i], name);
NXReportError( 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");
NXReportError( 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);
NXReportError( pBuffer);
return NX_ERROR;
}
/* compress SD data set */
compress_level = 6;
if( (compress_type / 100) == NX_COMP_LZW )
{
compress_level = compress_type % 100;
compress_type = NX_COMP_LZW;
}
if(compress_type == NX_COMP_LZW)
{
compstruct.deflate.level = compress_level;
iRet = SDsetcompress(iNew, COMP_CODE_DEFLATE, &compstruct);
if (iRet < 0)
{
NXReportError( "LZW-Compression failure!");
return NX_ERROR;
}
}
else if (compress_type == NX_COMP_RLE)
{
iRet = SDsetcompress(iNew, COMP_CODE_RLE, &compstruct);
if (iRet < 0)
{
NXReportError( "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)
{
NXReportError( "HUF-Compression failure!");
return NX_ERROR;
}
}
else if (compress_type == NX_COMP_NONE)
{
/* */
}
else
{
NXReportError( "Unknown compression method!");
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) {
NXReportError( "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[H4_MAX_VAR_DIMS];
comp_coder_t compress_typei = COMP_CODE_NONE;
NXname pBuffer;
char pError[512];
comp_info compstruct;
int compress_level = 6;
pFile = NXIassert (fid);
/* check if there is an SDS open */
if (pFile->iCurrentSDS == 0) {
NXReportError( "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 / 100) == NX_COMP_LZW )
{
compress_typei = COMP_CODE_DEFLATE;
compress_level = compress_type % 100;
compress_type = NX_COMP_LZW;
}
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 = compress_level;
}
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);
NXReportError( pError);
return NX_ERROR;
}
return NX_OK;
}
/* --------------------------------------------------------------------- */
NXstatus NX4opendata (NXhandle fid, CONSTCHAR *name)
{
pNexusFile pFile;
int32 iNew, attID, tags[2];
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);
NXReportError( 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) {
NXReportError( "ERROR: HDF cannot end access to SDS");
}
}
/* clear pending attribute directories first */
NXIKillAttDir (pFile);
/* open the SDS, thereby watching for linked SDS under a different name */
iNew = SDreftoindex (pFile->iSID, iNew);
pFile->iCurrentSDS = SDselect (pFile->iSID, iNew);
attID = SDfindattr(pFile->iCurrentSDS,"NAPIlink");
if(attID >= 0)
{
SDreadattr(pFile->iCurrentSDS,attID, tags);
SDendaccess(pFile->iCurrentSDS);
iNew = SDreftoindex (pFile->iSID, tags[1]);
pFile->iCurrentSDS = SDselect (pFile->iSID, iNew);
}
if (pFile->iCurrentSDS < 0) {
NXReportError( "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) {
NXReportError( "ERROR: HDF cannot end access to SDS");
return NX_ERROR;
}
} else {
NXReportError( "ERROR: no SDS open --> nothing to do");
return NX_ERROR;
}
NXIKillAttDir (pFile); /* for attribute data */
return NX_OK;
}
/* ------------------------------------------------------------------- */
NXstatus NX4putdata (NXhandle fid, const void *data)
{
pNexusFile pFile;
int32 iStart[H4_MAX_VAR_DIMS], iSize[H4_MAX_VAR_DIMS], iStride[H4_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) {
NXReportError( "ERROR: no SDS open");
return NX_ERROR;
}
/* first read dimension information */
memset (iStart, 0, H4_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, (void*)data);
if (iRet < 0) {
/* HEprint(stdout,0); */
sprintf (pError, "ERROR: failure to write data to %s", pBuffer);
NXReportError( pError);
return NX_ERROR;
}
return NX_OK;
}
/* ------------------------------------------------------------------- */
NXstatus
NX4putattr (NXhandle fid, CONSTCHAR *name, const 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;
}
else
{
NXReportError( "ERROR: Invalid data type for HDF attribute");
return NX_ERROR;
}
if (pFile->iCurrentSDS != 0) {
/* SDS attribute */
iRet = SDsetattr (pFile->iCurrentSDS, (char*)name, (int32)type,
(int32)datalen, data);
} else {
if(pFile->iCurrentVG == 0){
/* global attribute */
iRet = SDsetattr (pFile->iSID, (char*)name, (int32)type,
(int32)datalen, data);
} else {
/* group attribute */
iRet = Vsetattr(pFile->iCurrentVG, (char *)name, (int32) type,
(int32)datalen,data);
}
}
iType = type;
if (iRet < 0) {
NXReportError( "ERROR: HDF failed to store attribute ");
return NX_ERROR;
}
return NX_OK;
}
/* ------------------------------------------------------------------- */
NXstatus NX4putslab64 (NXhandle fid, const void *data, const int64_t iStart[], const int64_t iSize[])
{
pNexusFile pFile;
int iRet;
int32 iStride[H4_MAX_VAR_DIMS];
int32 myStart[H4_MAX_VAR_DIMS], mySize[H4_MAX_VAR_DIMS];
int32 i, iRank, iType, iAtt;
NXname pBuffer;
pFile = NXIassert (fid);
/* check if there is an SDS open */
if (pFile->iCurrentSDS == 0) {
NXReportError( "ERROR: no SDS open");
return NX_ERROR;
}
/* initialise stride to 1 */
for (i = 0; i < H4_MAX_VAR_DIMS; i++) {
iStride[i] = 1;
}
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, (void*)data);
/* deal with HDF errors */
if (iRet < 0) {
NXReportError( "ERROR: writing slab failed");
return NX_ERROR;
}
return NX_OK;
}
/* ------------------------------------------------------------------- */
NXstatus NX4getdataID (NXhandle fid, NXlink* sRes)
{
pNexusFile pFile;
int datalen, type = NX_CHAR;
pFile = NXIassert (fid);
if (pFile->iCurrentSDS == 0) {
sRes->iTag = NX_ERROR;
return NX_ERROR;
} else {
sRes->iTag = DFTAG_NDG;
sRes->iRef = SDidtoref (pFile->iCurrentSDS);
NXMDisableErrorReporting();
datalen = 1024;
memset(&sRes->targetPath,0,1024);
if(NX4getattr(fid,"target",&sRes->targetPath,&datalen,&type) != NX_OK)
{
NXIbuildPath(pFile,sRes->targetPath,1024);
}
NXMEnableErrorReporting();
return NX_OK;
}
sRes->iTag = NX_ERROR;
return NX_ERROR; /* not reached */
}
/* ------------------------------------------------------------------- */
NXstatus NX4makelink (NXhandle fid, NXlink* sLink)
{
pNexusFile pFile;
int32 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);
length = strlen(sLink->targetPath);
if(sLink->iTag == DFTAG_SDG || sLink->iTag == DFTAG_NDG ||
sLink->iTag == DFTAG_SDS)
{
dataID = SDreftoindex(pFile->iSID,sLink->iRef);
dataID = SDselect(pFile->iSID,dataID);
SDsetattr(dataID,name,type,length,sLink->targetPath);
SDendaccess(dataID);
}
else
{
dataID = Vattach(pFile->iVID,sLink->iRef,"w");
Vsetattr(dataID, (char *)name, type, (int32) length, sLink->targetPath);
Vdetach(dataID);
}
return NX_OK;
}
/* ------------------------------------------------------------------- */
NXstatus NX4makenamedlink (NXhandle fid, CONSTCHAR* newname, NXlink* sLink)
{
pNexusFile pFile;
int32 dataID, type = DFNT_CHAR8, length, dataType = NX_CHAR,
rank = 1, attType = NX_INT32;
int64_t iDim[1];
char name[] = "target";
int tags[2];
pFile = NXIassert (fid);
if (pFile->iCurrentVG == 0) { /* root level, can not link here */
return NX_ERROR;
}
tags[0] = sLink->iTag;
tags[1] = sLink->iRef;
length = strlen(sLink->targetPath);
if(sLink->iTag == DFTAG_SDG || sLink->iTag == DFTAG_NDG ||
sLink->iTag == DFTAG_SDS)
{
iDim[0] = 1;
NX4makedata64(fid,newname, dataType,rank,iDim);
NX4opendata(fid,newname);
NX4putattr(fid,"NAPIlink",tags, 2, attType);
NX4closedata(fid);
dataID = SDreftoindex(pFile->iSID,sLink->iRef);
dataID = SDselect(pFile->iSID,dataID);
SDsetattr(dataID,name,type,length,sLink->targetPath);
SDendaccess(dataID);
} else {
NX4makegroup(fid,newname,"NAPIlink");
NX4opengroup(fid,newname,"NAPIlink");
NX4putattr(fid,"NAPIlink",tags, 2, attType);
NX4closegroup(fid);
dataID = Vattach(pFile->iVID,sLink->iRef,"w");
Vsetattr(dataID, (char *)name, type, (int32) length, sLink->targetPath);
Vdetach(dataID);
}
return NX_OK;
}
/*----------------------------------------------------------------------*/
NXstatus NX4printlink (NXhandle fid, NXlink* sLink)
{
NXIassert (fid);
printf("HDF4 link: iTag = %ld, iRef = %ld, 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) {
NXReportError(
"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;
} else {
NXReportError(
"ERROR: NX4flush failed to determine file access mode");
return NX_ERROR;
}
pCopy = (char *)malloc((strlen(pFileName)+10)*sizeof(char));
if(!pCopy) {
NXReportError(
"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){
NXReportError(
"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[H4_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) {
NXReportError(
"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) {
NXReportError( "ERROR: HDF cannot attach to Vgroup");
return NX_ERROR;
}
Vgetname (iTemp, name);
Vdetach (iTemp);
findNapiClass(pFile, pFile->iStack[pFile->iStackPtr].iRefDir[iCurDir], nxclass);
*datatype = DFTAG_VG;
pFile->iStack[pFile->iStackPtr].iCurDir++;
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) {
NXReportError( "ERROR: HDF cannot attach to Vgroup");
return NX_ERROR;
}
Vgetname (iTemp, name);
Vdetach(iTemp);
findNapiClass(pFile, pFile->iStack[pFile->iStackPtr].iRefDir[iCurDir], 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[H4_MAX_VAR_DIMS], iSize[H4_MAX_VAR_DIMS];
NXname pBuffer;
int32 iRank, iAtt, iType;
pFile = NXIassert (fid);
/* check if there is an SDS open */
if (pFile->iCurrentSDS == 0) {
NXReportError( "ERROR: no SDS open");
return NX_ERROR;
}
/* first read dimension information */
memset (iStart, 0, H4_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
NX4getinfo64 (NXhandle fid, int *rank, int64_t dimension[],
int *iType)
{
pNexusFile pFile;
NXname pBuffer;
int32 iAtt, myDim[H4_MAX_VAR_DIMS], i, iRank, mType;
pFile = NXIassert (fid);
/* check if there is an SDS open */
if (pFile->iCurrentSDS == 0) {
NXReportError( "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 NX4getslab64 (NXhandle fid, void *data, const int64_t iStart[], const int64_t iSize[])
{
pNexusFile pFile;
int32 myStart[H4_MAX_VAR_DIMS], mySize[H4_MAX_VAR_DIMS];
int32 i, iRank, iType, iAtt;
NXname pBuffer;
pFile = NXIassert (fid);
/* check if there is an SDS open */
if (pFile->iCurrentSDS == 0) {
NXReportError( "ERROR: no SDS open");
return NX_ERROR;
}
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;
}
/*-------------------------------------------------------------------------*/
NXstatus NX4getnextattr (NXhandle fileid, NXname pName,
int *iLength, int *iType)
{
pNexusFile pFile;
int iRet;
int32 iPType, iCount, count;
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) {
if(pFile->iCurrentVG == 0) {
/* global attribute */
iRet = SDattrinfo (pFile->iSID, pFile->iAtt.iCurDir,
pName, &iPType, &iCount);
}else {
/* group attribute */
iRet = Vattrinfo(pFile->iCurrentVG, pFile->iAtt.iCurDir,
pName, &iPType, &iCount, &count);
}
} else {
iRet = SDattrinfo (pFile->iCurrentSDS, pFile->iAtt.iCurDir,
pName, &iPType, &iCount);
}
if (iRet < 0) {
NXReportError( "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, count;
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 {
if(pFile->iCurrentVG == 0){
/* global attribute */
iNew = SDfindattr (pFile->iSID, name);
} else {
/* group attribute */
iNew = Vfindattr(pFile->iCurrentVG, name);
}
}
if (iNew < 0) {
sprintf (pBuffer, "ERROR: attribute \"%s\" not found", name);
NXReportError( 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 {
if(pFile->iCurrentVG == 0){
iRet = SDattrinfo (pFile->iSID, iNew, pNam, &iType32, &iLen);
} else {
iRet = Vattrinfo(pFile->iCurrentVG,iNew,pNam,&iType32,&count,
&iLen);
}
}
if (iRet < 0) {
sprintf (pBuffer, "ERROR: HDF could not read attribute info");
NXReportError( pBuffer);
return NX_ERROR;
}
*iType = (int)iType32;
iLen = iLen * DFKNTsize (*iType);
if(*iType == NX_CHAR){
iLen += 1;
}
pData = (void *) malloc (iLen);
if (!pData) {
NXReportError( "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 {
if(pFile->iCurrentVG == 0){
iRet = SDreadattr (pFile->iSID, iNew, pData);
} else {
iRet = Vgetattr(pFile->iCurrentVG, iNew, pData);
}
}
if (iRet < 0) {
sprintf (pBuffer, "ERROR: HDF could not read attribute data");
NXReportError( 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; /* this enforces NULL termination regardless of size of datalen */
}
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[H4_MAX_VAR_DIMS];
NXname pNam;
pFile = NXIassert (fid);
if (pFile->iCurrentSDS != 0) { /* SDS level */
iRet = SDgetinfo (pFile->iCurrentSDS, pNam, &iRank, iDim, &iType,
&iAtt);
} else {
if(pFile->iCurrentVG == 0){
/* global level */
iRet = SDfileinfo (pFile->iSID, &iData, &iAtt);
} else {
iRet = Vnattrs(pFile->iCurrentVG);
iAtt = iRet;
}
}
if (iRet < 0) {
NXReportError( "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)
{
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 (pFile);
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 (pFile);
iRet = NXIInitDir (pFile);
if (iRet < 0) {
NXReportError("NX_ERROR: no memory to store directory info");
return NX_EOD;
}
return NX_OK;
}
/*--------------------------------------------------------------------*/
void NX4assignFunctions(pNexusFunction fHandle)
{
fHandle->nxclose=NX4close;
fHandle->nxreopen=NULL;
fHandle->nxflush=NX4flush;
fHandle->nxmakegroup=NX4makegroup;
fHandle->nxopengroup=NX4opengroup;
fHandle->nxclosegroup=NX4closegroup;
fHandle->nxmakedata64=NX4makedata64;
fHandle->nxcompmakedata64=NX4compmakedata64;
fHandle->nxcompress=NX4compress;
fHandle->nxopendata=NX4opendata;
fHandle->nxclosedata=NX4closedata;
fHandle->nxputdata=NX4putdata;
fHandle->nxputattr=NX4putattr;
fHandle->nxputslab64=NX4putslab64;
fHandle->nxgetdataID=NX4getdataID;
fHandle->nxmakelink=NX4makelink;
fHandle->nxmakenamedlink=NX4makenamedlink;
fHandle->nxgetdata=NX4getdata;
fHandle->nxgetinfo64=NX4getinfo64;
fHandle->nxgetnextentry=NX4getnextentry;
fHandle->nxgetslab64=NX4getslab64;
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;
fHandle->nxnativeexternallink=NULL;
}
#endif /*HDF4*/