Files
sics/nxxml.c
Ferdi Franceschini 6921d0426c PSI UPDATE
r1724 | ffr | 2007-03-27 07:56:13 +1000 (Tue, 27 Mar 2007) | 2 lines
2012-11-15 13:10:21 +11:00

1993 lines
56 KiB
C

/*
* This is the implementation file for the XML file driver
* for NeXus
*
* Copyright (C) 2006 Mark Koennecke
*
* 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>
*/
#ifdef NXXML
#include <stdio.h>
#include <assert.h>
#include <stdint.h>
#include <mxml.h>
#include <napi.h>
#include <nxxml.h>
#include "nxio.h"
#include "nxdataset.h"
#ifdef _MSC_VER
#define snprintf _snprintf
#endif /* _MSC_VER */
extern void *NXpData;
extern int validNXName(const char* name, int allow_colon); /* from napi.c */
char *nxitrim(char *str); /* from napi.c */
/*----------------------- our data structures --------------------------
One might wonder why a node stack is still needed even if this API
operates on top of a tree API. The reason for this are the links.
Following a link on any NXopenpath, data means a jump through the
whole tree. In order to correctly return from such adventures,
a stack is needed. Moreover we need it in order to keep track of the
state of search operations.
The true NXroot node is always at stack[0]. The root in the data
structure is the ?xml element. The latter one is needed to store
the tree.
-----------------------------------------------------------------------*/
typedef struct {
mxml_node_t *current;
mxml_node_t *currentChild;
int currentAttribute;
int options; /**< additional information about the node */
}xmlStack;
/*
* Freddie Akeroyd, 19/03/2008
*
* Add in support for table style data writing - this is
* indicated internally via the XMLSTACK_OPTION_TABLE flag
* and separates the dimensions and data into separate nodes contained
* in DIMS_NODE_NAME and DATA_NODE_NAME. This is a first commit and
* involves some code duplication that will need to be cleaned up later.
* Also writing in table style is only enabled for 1D arrays as
* I haven't done slab writing yet which the nexus test program uses
* for writing 2D arrays.
*
* Table output is enabled by opening a file with (NXACC_CREATEXML | NXACC_TABLE)
*
* See http://trac.nexusformat.org/code/ticket/111 for further details
*/
#define XMLSTACK_OPTION_TABLE 0x1 /**< indicates table option in xmlStack */
/*---------------------------------------------------------------------*/
typedef struct {
mxml_node_t *root; /* root node */
int readOnly; /* read only flag */
int tableStyle; /**< whether to output data in XML table style */
int stackPointer; /* stack pointer */
char filename[1024]; /* file name, for NXflush, NXclose */
xmlStack stack[NXMAXSTACK]; /* stack */
}XMLNexus, *pXMLNexus;
/*===================== support functions ===============================*/
extern char *stptok(char *s, char *tok, size_t toklen, char *brk);
/*----------------------------------------------------------------------*/
static mxml_node_t *getLinkTarget(pXMLNexus xmlHandle, const char *target){
mxml_node_t *node = NULL;
mxml_node_t *testNode = NULL;
char path[132], *pPtr;
pPtr = (char *)target + 1;
node = xmlHandle->stack[0].current;
while((pPtr = stptok(pPtr,path,131,"/")) != NULL){
/*
search for group node
*/
testNode = mxmlFindElement(node,node,NULL,"name",path,MXML_DESCEND_FIRST);
if(testNode == NULL){
/*
it can still be a data node
*/
testNode = mxmlFindElement(node,node,path,NULL,NULL,MXML_DESCEND_FIRST);
}
if(testNode == NULL){
NXReportError("Cannot follow broken link");
return NULL;
} else {
node = testNode;
}
}
return node;
}
/*==================== file functions ===================================*/
static void errorCallbackForMxml(const char *txt){
NXReportError((char *)txt);
}
/*-----------------------------------------------------------------------*/
NXstatus NXXopen(CONSTCHAR *filename, NXaccess am,
NXhandle* pHandle) {
pXMLNexus xmlHandle = NULL;
FILE *fp = NULL;
char *time_buffer = NULL;
mxml_node_t *current;
/*
allocate data
*/
xmlHandle = (pXMLNexus)malloc(sizeof(XMLNexus));
if(!xmlHandle){
NXReportError( "Out of memory allocating XML file handle");
return NX_ERROR;
}
memset(xmlHandle,0,sizeof(XMLNexus));
/*
initialize mxml XML parser
*/
mxmlSetCustomHandlers(nexusLoadCallback, nexusWriteCallback);
initializeNumberFormats();
mxmlSetErrorCallback(errorCallbackForMxml);
xmlHandle->tableStyle = ((am & NXACC_TABLE) ? 1 : 0);
/*
open file
*/
strncpy(xmlHandle->filename,filename,1023);
switch(am & NXACCMASK_REMOVEFLAGS){
case NXACC_READ:
xmlHandle->readOnly = 1;
case NXACC_RDWR:
fp = fopen(filename,"r");
if(fp == NULL){
NXReportError("Failed to open file:");
NXReportError((char *)filename);
free(xmlHandle);
return NX_ERROR;
}
xmlHandle->root = mxmlLoadFile(NULL,fp,nexusTypeCallback);
xmlHandle->stack[0].current = mxmlFindElement(xmlHandle->root,
xmlHandle->root,
"NXroot",
NULL,NULL,
MXML_DESCEND);
xmlHandle->stack[0].currentChild = NULL;
xmlHandle->stack[0].currentAttribute = 0;
xmlHandle->stack[0].options = 0;
fclose(fp);
break;
case NXACC_CREATEXML:
xmlHandle->root = mxmlNewElement(NULL,
"?xml version=\"1.0\" encoding=\"UTF-8\"?");
current = mxmlNewElement(xmlHandle->root,"NXroot");
mxmlElementSetAttr(current,"NeXus_version",NEXUS_VERSION);
mxmlElementSetAttr(current,"XML_version","mxml");
mxmlElementSetAttr(current,"file_name",filename);
mxmlElementSetAttr(current,"xmlns", NEXUS_SCHEMA_NAMESPACE);
mxmlElementSetAttr(current,"xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
mxmlElementSetAttr(current,"xsi:schemaLocation",
NEXUS_SCHEMA_NAMESPACE " " NEXUS_SCHEMA_URL);
time_buffer = NXIformatNeXusTime();
if(time_buffer != NULL){
mxmlElementSetAttr(current,"file_time",time_buffer);
free(time_buffer);
}
xmlHandle->stack[0].current = current;
xmlHandle->stack[0].currentChild = NULL;
xmlHandle->stack[0].currentAttribute = 0;
xmlHandle->stack[0].options = 0;
break;
default:
NXReportError("Bad access parameter specified in NXXopen");
return NX_ERROR;
}
if(xmlHandle->stack[0].current == NULL){
NXReportError(
"No NXroot element in XML-file, no NeXus-XML file");
return NX_ERROR;
}
*pHandle = xmlHandle;
return NX_OK;
}
/*----------------------------------------------------------------------*/
NXstatus NXXclose (NXhandle* fid){
pXMLNexus xmlHandle = NULL;
FILE *fp = NULL;
xmlHandle = (pXMLNexus)*fid;
assert(xmlHandle);
if(xmlHandle->readOnly == 0) {
fp = fopen(xmlHandle->filename,"w");
if(fp == NULL){
NXReportError("Failed to open NeXus XML file for writing");
return NX_ERROR;
}
mxmlSaveFile(xmlHandle->root,fp,NXwhitespaceCallback);
fclose(fp);
}
mxmlDelete(xmlHandle->root);
free(xmlHandle);
*fid = NULL;
return NX_OK;
}
/*----------------------------------------------------------------------*/
NXstatus NXXflush(NXhandle *fid){
pXMLNexus xmlHandle = NULL;
FILE *fp = NULL;
xmlHandle = (pXMLNexus)*fid;
assert(xmlHandle);
if(xmlHandle->readOnly == 0) {
fp = fopen(xmlHandle->filename,"w");
if(fp == NULL){
NXReportError("Failed to open NeXus XML file for writing");
return NX_ERROR;
}
mxmlSaveFile(xmlHandle->root,fp,NXwhitespaceCallback);
fclose(fp);
}
return NX_OK;
}
/*=======================================================================
Group functions
=========================================================================*/
NXstatus NXXmakegroup (NXhandle fid, CONSTCHAR *name,
CONSTCHAR *nxclass){
char buffer[256];
pXMLNexus xmlHandle = NULL;
mxml_node_t *newGroup = NULL;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if (!validNXName(name, 0))
{
sprintf(buffer, "ERROR: invalid characters in group name \"%s\"", name);
NXReportError(buffer);
return NX_ERROR;
}
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("Close dataset before trying to create a group");
return NX_ERROR;
}
newGroup = mxmlNewElement(xmlHandle->stack[xmlHandle->stackPointer].current,
nxclass);
if(!newGroup){
NXReportError("failed to allocate new group");
return NX_ERROR;
}
mxmlElementSetAttr(newGroup,"name",name);
return NX_OK;
}
/*----------------------------------------------------------------------*/
static mxml_node_t *searchGroupLinks(pXMLNexus xmlHandle, CONSTCHAR *name,
CONSTCHAR *nxclass){
mxml_node_t *linkNode = NULL;
mxml_node_t *current;
mxml_node_t *test = NULL;
const char *linkTarget;
const char *linkName = NULL;
current = xmlHandle->stack[xmlHandle->stackPointer].current;
linkNode = current;
while((linkNode = mxmlFindElement(linkNode,current,"NAPIlink",NULL,NULL,
MXML_DESCEND_FIRST)) != NULL){
linkTarget = mxmlElementGetAttr(linkNode,"target");
test = getLinkTarget(xmlHandle,linkTarget);
if(test != NULL){
if(strcmp(test->value.element.name,nxclass) == 0){
if(strcmp(mxmlElementGetAttr(test,"name"),name) == 0){
return test;
}
}
}
/*
test for named links
*/
linkName = mxmlElementGetAttr(linkNode,"name");
if(test != NULL && linkName != NULL){
if(strcmp(test->value.element.name,nxclass) == 0){
if(strcmp(linkName, name) == 0){
return test;
}
}
}
}
return NULL;
}
/*------------------------------------------------------------------------*/
NXstatus NXXopengroup (NXhandle fid, CONSTCHAR *name,
CONSTCHAR *nxclass){
pXMLNexus xmlHandle = NULL;
mxml_node_t *newGroup = NULL;
char error[1024];
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("Close dataset before trying to open a group");
return NX_ERROR;
}
newGroup = mxmlFindElement(xmlHandle->stack[xmlHandle->stackPointer].current,
xmlHandle->stack[xmlHandle->stackPointer].current,
nxclass,
"name",
name,
MXML_DESCEND_FIRST);
if(newGroup == NULL){
newGroup = searchGroupLinks(xmlHandle,name,nxclass);
}
if(!newGroup){
snprintf(error,1023,"Failed to open %s, %s",name,nxclass);
NXReportError(error);
return NX_ERROR;
}
xmlHandle->stackPointer++;
xmlHandle->stack[xmlHandle->stackPointer].current = newGroup;
xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL;
xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0;
xmlHandle->stack[xmlHandle->stackPointer].options = 0;
return NX_OK;
}
/*----------------------------------------------------------------------*/
NXstatus NXXclosegroup (NXhandle fid){
pXMLNexus xmlHandle = NULL;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
/*
silently fix this
*/
NXXclosedata(fid);
}
if(xmlHandle->stackPointer > 0){
xmlHandle->stackPointer--;
}
return NX_OK;
}
/*=========================================================================
dataset functions
=========================================================================*/
NXstatus NXXcompmakedata64 (NXhandle fid, CONSTCHAR *name,
int datatype,
int rank,
int64_t dimensions[],
int compress_type, int64_t chunk_size[]){
/*
compression does not relly make sense with XML
*/
return NXXmakedata64(fid,name,datatype,rank,dimensions);
}
/*-----------------------------------------------------------------------*/
static char *buildTypeString(int datatype, int rank, int64_t dimensions[]){
char *typestring = NULL;
char pNumber[20];
int i;
/*
allocate data
*/
typestring = (char *)malloc(132*sizeof(char));
if(!typestring){
NXReportError("Failed to allocate typestring");
return NULL;
}
memset(typestring,0,132*sizeof(char));
getNumberText(datatype,typestring,130);
if(rank > 1 || datatype == NX_CHAR || dimensions[0] > 1) {
strcat(typestring,"[");
snprintf(pNumber,19,"%lld", (long long)dimensions[0]);
strncat(typestring,pNumber,130-strlen(typestring));
for(i = 1; i < rank; i++){
snprintf(pNumber,19,",%lld", (long long)dimensions[i]);
strncat(typestring,pNumber,130-strlen(typestring));
}
strcat(typestring,"]");
}
return typestring;
}
/*------------------------------------------------------------------------*/
NXstatus NXXmakedatatable64 (NXhandle fid,
CONSTCHAR *name, int datatype,
int rank, int64_t dimensions[]){
pXMLNexus xmlHandle = NULL;
mxml_node_t *dataNode = NULL, *dataNodeRoot = NULL, *dimsNode = NULL, *dimsNodeRoot = NULL;
mxml_node_t *newData = NULL;
mxml_node_t *current;
char *typestring;
int i, ndata;
char buffer[256];
static int64_t one = 1;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if (!validNXName(name, 0))
{
sprintf(buffer, "ERROR: invalid characters in dataset name \"%s\"", name);
NXReportError(buffer);
return NX_ERROR;
}
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("Close dataset before trying to create a dataset");
return NX_ERROR;
}
if(dimensions[0] < 0){
dimensions[0] = 1;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
dimsNodeRoot = mxmlFindElement(current, current, DIMS_NODE_NAME, NULL, NULL, MXML_DESCEND_FIRST);
if (dimsNodeRoot == NULL)
{
dimsNodeRoot = mxmlNewElement(current, DIMS_NODE_NAME);
}
dimsNode = mxmlNewElement(dimsNodeRoot, name);
mxmlNewOpaque(dimsNode, "");
typestring = buildTypeString(datatype,rank,dimensions);
if(typestring != NULL){
mxmlElementSetAttr(dimsNode,TYPENAME,typestring);
free(typestring);
} else {
NXReportError("Failed to allocate typestring");
return NX_ERROR;
}
ndata = 1;
for(i=0; i<rank; i++)
{
ndata *= dimensions[i];
}
dataNodeRoot = current;
for(i=0; i<ndata; i++)
{
dataNodeRoot = mxmlFindElement(dataNodeRoot, current, DATA_NODE_NAME, NULL, NULL, (i == 0 ? MXML_DESCEND_FIRST : MXML_NO_DESCEND) );
if (dataNodeRoot == NULL)
{
dataNodeRoot = mxmlNewElement(current, DATA_NODE_NAME);
}
dataNode = mxmlNewElement(dataNodeRoot,name);
newData = (mxml_node_t *)malloc(sizeof(mxml_node_t));
if(!newData){
NXReportError("Failed to allocate space for dataset");
return NX_ERROR;
}
memset(newData,0,sizeof(mxml_node_t));
mxmlAdd(dataNode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, newData);
newData->type = MXML_CUSTOM;
/* newData->value.custom.data = createNXDataset(rank,datatype,dimensions); */
newData->value.custom.data = createNXDataset(1,datatype,&one);
if(!newData->value.custom.data){
NXReportError("Failed to allocate space for dataset");
return NX_ERROR;
}
newData->value.custom.destroy = destroyDataset;
}
return NX_OK;
}
NXstatus NXXmakedata64 (NXhandle fid,
CONSTCHAR *name, int datatype,
int rank, int64_t dimensions[]){
pXMLNexus xmlHandle = NULL;
mxml_node_t *dataNode = NULL;
mxml_node_t *newData = NULL;
mxml_node_t *current;
char *typestring;
char buffer[256];
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if (!validNXName(name, 0))
{
sprintf(buffer, "ERROR: invalid characters in dataset name \"%s\"", name);
NXReportError(buffer);
return NX_ERROR;
}
if (xmlHandle->tableStyle && datatype != NX_CHAR && dimensions[0] != NX_UNLIMITED && rank == 1)
{
return NXXmakedatatable64(fid,name,datatype,rank,dimensions);
}
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("Close dataset before trying to create a dataset");
return NX_ERROR;
}
if(dimensions[0] < 0){
dimensions[0] = 1;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
dataNode = mxmlNewElement(current,name);
typestring = buildTypeString(datatype,rank,dimensions);
if(typestring != NULL){
mxmlElementSetAttr(dataNode,TYPENAME,typestring);
free(typestring);
} else {
NXReportError("Failed to allocate typestring");
return NX_ERROR;
}
/*
NX_CHAR maps to MXML_OPAQUE datasets
*/
if(datatype == NX_CHAR){
newData = mxmlNewOpaque(dataNode,"");
return NX_OK;
} else {
newData = (mxml_node_t *)malloc(sizeof(mxml_node_t));
if(!newData){
NXReportError("Failed to allocate space for dataset");
return NX_ERROR;
}
memset(newData,0,sizeof(mxml_node_t));
mxmlAdd(dataNode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, newData);
newData->type = MXML_CUSTOM;
newData->value.custom.data = createNXDataset(rank,datatype,dimensions);
if(!newData->value.custom.data){
NXReportError("Failed to allocate space for dataset");
return NX_ERROR;
}
newData->value.custom.destroy = destroyDataset;
}
return NX_OK;
}
/*----------------------------------------------------------------------*/
static mxml_node_t *searchSDSLinks(pXMLNexus xmlHandle, CONSTCHAR *name){
mxml_node_t *linkNode = NULL;
mxml_node_t *current;
mxml_node_t *test = NULL;
const char *linkTarget;
const char *linkName = NULL;
current = xmlHandle->stack[xmlHandle->stackPointer].current;
linkNode = current;
while((linkNode = mxmlFindElement(linkNode,current,"NAPIlink",NULL,NULL,
MXML_DESCEND_FIRST)) != NULL){
linkTarget = mxmlElementGetAttr(linkNode,"target");
test = getLinkTarget(xmlHandle,linkTarget);
if(test != NULL){
if(strcmp(test->value.element.name,name) == 0){
return test;
}
}
/*
test for named links
*/
linkName = mxmlElementGetAttr(linkNode,"name");
if(test != NULL && linkName != NULL){
if(strcmp(linkName,name) == 0){
return test;
}
}
}
return NULL;
}
/*-----------------------------------------------------------------------*/
NXstatus NXXopendatatable (NXhandle fid, CONSTCHAR *name){
pXMLNexus xmlHandle = NULL;
mxml_node_t *dataNode = NULL, *dimsNode = NULL;
char error[1024];
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
/*
silently fix this
*/
xmlHandle->stackPointer--;
if(xmlHandle->stackPointer < 0){
xmlHandle->stackPointer = 0;
}
}
dimsNode = mxmlFindElement(xmlHandle->stack[xmlHandle->stackPointer].current,
xmlHandle->stack[xmlHandle->stackPointer].current,
DIMS_NODE_NAME,
NULL,
NULL,
MXML_DESCEND_FIRST);
if(!dimsNode){
snprintf(error,1023,"Failed to open dataset %s",name);
NXReportError(error);
return NX_ERROR;
}
dataNode = mxmlFindElement(dimsNode,
dimsNode,
name,
NULL,
NULL,
MXML_DESCEND_FIRST);
if(dataNode == NULL){
dataNode = searchSDSLinks(xmlHandle,name);
}
if(!dataNode){
snprintf(error,1023,"Failed to open dataset %s",name);
NXReportError(error);
return NX_ERROR;
}
xmlHandle->stackPointer++;
xmlHandle->stack[xmlHandle->stackPointer].current = dataNode;
xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL;
xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0;
xmlHandle->stack[xmlHandle->stackPointer].options = XMLSTACK_OPTION_TABLE;
return NX_OK;
}
NXstatus NXXopendata (NXhandle fid, CONSTCHAR *name){
pXMLNexus xmlHandle = NULL;
mxml_node_t *dataNode = NULL, *current = NULL;
char error[1024];
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
/* is this a table style node ? */
current = xmlHandle->stack[xmlHandle->stackPointer].current;
dataNode = mxmlFindElement(current,
current,
DATA_NODE_NAME,
NULL,
NULL,
MXML_DESCEND_FIRST);
if (dataNode != NULL)
{
dataNode = mxmlFindElement(dataNode,
dataNode,
name,
NULL,
NULL,
MXML_DESCEND_FIRST);
}
if (dataNode != NULL)
{
return NXXopendatatable(fid, name);
}
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
/*
silently fix this
*/
xmlHandle->stackPointer--;
if(xmlHandle->stackPointer < 0){
xmlHandle->stackPointer = 0;
}
}
dataNode = mxmlFindElement(xmlHandle->stack[xmlHandle->stackPointer].current,
xmlHandle->stack[xmlHandle->stackPointer].current,
name,
NULL,
NULL,
MXML_DESCEND_FIRST);
if(dataNode == NULL){
dataNode = searchSDSLinks(xmlHandle,name);
}
if(!dataNode){
snprintf(error,1023,"Failed to open dataset %s",name);
NXReportError(error);
return NX_ERROR;
}
xmlHandle->stackPointer++;
xmlHandle->stack[xmlHandle->stackPointer].current = dataNode;
xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL;
xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0;
xmlHandle->stack[xmlHandle->stackPointer].options = 0;
return NX_OK;
}
/*----------------------------------------------------------------------*/
NXstatus NXXclosedata (NXhandle fid){
pXMLNexus xmlHandle = NULL;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
if(xmlHandle->stackPointer > 0){
xmlHandle->stackPointer--;
}
return NX_OK;
}
return NX_OK;
}
/*----------------------------------------------------------------------*/
static mxml_node_t *findData(mxml_node_t *node){
mxml_node_t *baby = node;
while( (baby = mxmlWalkNext(baby,node,MXML_DESCEND_FIRST)) != NULL){
if(baby->type == MXML_OPAQUE || baby->type == MXML_CUSTOM){
return baby;
}
}
return NULL;
}
/* we only havv to deal with non-character data here */
NXstatus NXXputdatatable (NXhandle fid, const void *data){
pXMLNexus xmlHandle = NULL;
mxml_node_t *userData = NULL;
mxml_node_t *current = NULL;
mxml_node_t *nodeRoot = NULL;
mxml_node_t *dataNodeRoot = NULL;
mxml_node_t *dataNode = NULL;
const char* name;
pNXDS dataset;
int i, offset, length;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
/* current points at the Idims node as done in NXXopendatatable */
current = xmlHandle->stack[xmlHandle->stackPointer].current;
name = current->value.element.name;
/* we want to walk all Idata nodes and set name */
nodeRoot = current->parent->parent;
dataNodeRoot = nodeRoot;
offset = 0;
for(i=0; dataNodeRoot != NULL; i++)
{
dataNodeRoot = mxmlFindElement(dataNodeRoot, nodeRoot, DATA_NODE_NAME, NULL, NULL, (i == 0 ? MXML_DESCEND_FIRST : MXML_NO_DESCEND) );
if (dataNodeRoot != NULL)
{
dataNode = mxmlFindElement(dataNodeRoot,dataNodeRoot,name,NULL,NULL,MXML_DESCEND_FIRST);
if (dataNode != NULL)
{
userData = findData(dataNode);
assert(userData != NULL);
dataset = (pNXDS)userData->value.custom.data;
assert(dataset);
length = getNXDatasetByteLength(dataset);
memcpy(dataset->u.ptr,(char*)data + offset,length);
offset += length;
}
}
}
return NX_OK;
}
/*------------------------------------------------------------------------*/
NXstatus NXXputdata (NXhandle fid, void *data){
pXMLNexus xmlHandle = NULL;
mxml_node_t *userData = NULL;
mxml_node_t *current = NULL;
pNXDS dataset;
int i, length, type, rank;
int64_t dim[NX_MAXRANK];
char *pPtr = NULL;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if (xmlHandle->stack[xmlHandle->stackPointer].options & XMLSTACK_OPTION_TABLE)
{
return NXXputdatatable(fid,data);
}
if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("No dataset open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
userData = findData(current);
assert(userData != NULL);
if(userData->type == MXML_OPAQUE){
/*
Text data. We have to make sure that the text is \0 terminated.
Some language bindings do not ensure that this is the case.
*/
if(NXXgetinfo64(fid,&rank, dim, &type) == NX_OK){
length = 1;
for(i=0; i<rank; i++)
{
length *= dim[i];
}
/* we seem to have trouble reading an empty node back (no userData), so make sure we have at least a single space present even for empty strings */
if (length == 0)
{
mxmlSetOpaque(userData," ");
}
else
{
pPtr = (char *)malloc((length+1)*sizeof(char));
if(pPtr != NULL){
memcpy(pPtr,data,length);
pPtr[length] = '\0';
mxmlSetOpaque(userData,(const char *)pPtr);
free(pPtr);
}
}
}
else
{
NXReportError("Unable to determine size of character dataset");
return NX_ERROR;
}
} else {
dataset = (pNXDS)userData->value.custom.data;
assert(dataset);
length = getNXDatasetByteLength(dataset);
memcpy(dataset->u.ptr,data,length);
}
return NX_OK;
}
NXstatus NXXgetdatatable (NXhandle fid, void *data){
pXMLNexus xmlHandle = NULL;
mxml_node_t *userData = NULL;
mxml_node_t *current = NULL;
mxml_node_t *nodeRoot = NULL;
mxml_node_t *dataNodeRoot = NULL;
mxml_node_t *dataNode = NULL;
const char* name;
pNXDS dataset;
int i, offset, length;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
/* current points at the Idims node as done in NXXopendatatable */
current = xmlHandle->stack[xmlHandle->stackPointer].current;
name = current->value.element.name;
/* we want to walk all Idata nodes and set name */
nodeRoot = current->parent->parent;
dataNodeRoot = nodeRoot;
offset = 0;
for(i=0; dataNodeRoot != NULL; i++)
{
dataNodeRoot = mxmlFindElement(dataNodeRoot, nodeRoot, DATA_NODE_NAME, NULL, NULL, (i == 0 ? MXML_DESCEND_FIRST : MXML_NO_DESCEND) );
if (dataNodeRoot != NULL)
{
dataNode = mxmlFindElement(dataNodeRoot,dataNodeRoot,name,NULL,NULL,MXML_DESCEND_FIRST);
if (dataNode != NULL)
{
userData = findData(dataNode);
assert(userData != NULL);
dataset = (pNXDS)userData->value.custom.data;
assert(dataset);
length = getNXDatasetByteLength(dataset);
memcpy((char*)data + offset, dataset->u.ptr, length);
offset += length;
}
}
}
return NX_OK;
}
/*------------------------------------------------------------------------*/
NXstatus NXXgetdata (NXhandle fid, void *data){
pXMLNexus xmlHandle = NULL;
mxml_node_t *userData = NULL;
mxml_node_t *current = NULL;
pNXDS dataset;
int i, length, type, rank;
int64_t dim[NX_MAXRANK];
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if (xmlHandle->stack[xmlHandle->stackPointer].options & XMLSTACK_OPTION_TABLE)
{
return NXXgetdatatable(fid,data);
}
if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("No dataset open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
userData = findData(current);
assert(userData != NULL);
if(userData->type == MXML_OPAQUE){
/*
text data
*/
if(NXXgetinfo64(fid,&rank, dim, &type) == NX_OK){
length = 1;
for(i=0; i<rank; i++)
{
length *= dim[i];
}
strncpy((char *)data,userData->value.opaque,length);
} else {
strcpy((char *)data,nxitrim(userData->value.opaque));
}
} else {
dataset = (pNXDS)userData->value.custom.data;
assert(dataset);
length = getNXDatasetByteLength(dataset);
memcpy(data,dataset->u.ptr,length);
}
return NX_OK;
}
/*------------------------------------------------------------------------*/
NXstatus NXXgetinfo64 (NXhandle fid, int *rank,
int64_t dimension[], int *iType){
pXMLNexus xmlHandle = NULL;
mxml_node_t *userData = NULL;
mxml_node_t *current = NULL;
pNXDS dataset;
int myRank, i;
const char *attr = NULL;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("No dataset open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
userData = findData(current);
assert(userData != NULL);
if(userData->type == MXML_OPAQUE){
/*
text data
*/
attr = mxmlElementGetAttr(current, TYPENAME);
if(attr == NULL){
*rank = 1;
*iType = NX_CHAR;
dimension[0]= strlen(userData->value.opaque);
} else {
*iType = translateTypeCode(attr);
analyzeDim(attr,rank,dimension,iType);
if (dimension[0] == -1) /* 1D strings are NX_CHAR not NX_CHAR[] so length will not be correct */
{
dimension[0] = strlen(userData->value.opaque);
}
}
} else {
dataset = (pNXDS)userData->value.custom.data;
assert(dataset);
myRank = getNXDatasetRank(dataset);
*rank = myRank;
*iType = getNXDatasetType(dataset);
for(i = 0; i < myRank; i++){
dimension[i] = getNXDatasetDim(dataset,i);
}
}
return NX_OK;
}
/*---------------------------------------------------------------------
clone the dataset and set the data pointer. This in order to use
the addressing and type conversion implemented in nxdataset
---------------------------------------------------------------------*/
static pNXDS makeSlabData(pNXDS dataset, const void *data, const int64_t size[]){
pNXDS slabData = NULL;
int rank, i;
slabData = (pNXDS)malloc(sizeof(NXDS));
if(slabData == NULL){
return NULL;
}
rank = getNXDatasetRank(dataset);
slabData->rank = rank;
slabData->dim = (int64_t *)malloc(rank*sizeof(int64_t));
for(i = 0; i < rank; i++){
slabData->dim[i] = size[i];
}
slabData->type = getNXDatasetType(dataset);
slabData->u.ptr = (void*)data;
slabData->magic = dataset->magic;
return slabData;
}
/*--------------------------------------------------------------------
This goes by recursion
----------------------------------------------------------------------*/
static void putSlabData(pNXDS dataset, pNXDS slabData, int dim,
const int64_t start[],
int64_t sourcePos[], int64_t targetPos[]){
int64_t i, rank, length;
rank = getNXDatasetRank(slabData);
length = getNXDatasetDim(slabData,dim);
if(dim != rank-1){
for(i = 0; i < length; i++){
targetPos[dim] = start[dim] +i;
sourcePos[dim] = i;
putSlabData(dataset,slabData, dim+1,start,
sourcePos,targetPos);
}
} else {
for(i = 0; i < length; i++){
targetPos[dim] = start[dim] +i;
sourcePos[dim] = i;
putNXDatasetValue(dataset,targetPos,
getNXDatasetValue(slabData,sourcePos));
}
}
}
/*----------------------------------------------------------------------
This is in order to support unlimited dimensions along the first axis
-----------------------------------------------------------------------*/
static int checkAndExtendDataset(mxml_node_t *node, pNXDS dataset,
const int64_t start[], const int64_t size[]){
int64_t dim0, byteLength;
void *oldData = NULL;
char *typestring = NULL;
dim0 = start[0] + size[0];
if(dim0 > dataset->dim[0]){
byteLength = getNXDatasetByteLength(dataset);
oldData = dataset->u.ptr;
dataset->dim[0] = dim0;
dataset->u.ptr = malloc(getNXDatasetByteLength(dataset));
if(dataset->u.ptr == NULL){
return 0;
}
memset(dataset->u.ptr,0,getNXDatasetByteLength(dataset));
memcpy(dataset->u.ptr,oldData,byteLength);
free(oldData);
typestring = buildTypeString(dataset->type,dataset->rank,dataset->dim);
if(typestring != NULL){
mxmlElementSetAttr(node,TYPENAME,typestring);
free(typestring);
} else {
NXReportError("Failed to allocate typestring");
return 0;
}
}
return 1;
}
NXstatus NXXputslabtable (NXhandle fid, const void *data,
const int64_t iStart[], const int64_t iSize[]){
return NX_OK;
}
/*----------------------------------------------------------------------*/
NXstatus NXXputslab64 (NXhandle fid, void *data,
int64_t iStart[], int64_t iSize[]){
pXMLNexus xmlHandle = NULL;
mxml_node_t *userData = NULL;
mxml_node_t *current = NULL;
pNXDS dataset, slabData;
int64_t sourcePos[NX_MAXRANK], targetPos[NX_MAXRANK];
int status;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if (xmlHandle->stack[xmlHandle->stackPointer].options & XMLSTACK_OPTION_TABLE)
{
return NXXputslabtable(fid,data,iStart,iSize);
}
if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("No dataset open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
userData = findData(current);
assert(userData != NULL);
if(userData->type == MXML_OPAQUE){
NXReportError("This API does not support slabs on text data");
return NX_ERROR;
}
dataset = (pNXDS)userData->value.custom.data;
assert(dataset);
status = checkAndExtendDataset(current,dataset,iStart,iSize);
if(status == 0){
NXReportError("Out of memory extending dataset");
return NX_ERROR;
}
slabData = makeSlabData(dataset, data, iSize);
if(slabData == NULL){
NXReportError("Failed to allocate slab data");
return NX_ERROR;
}
putSlabData(dataset,slabData,0,iStart,sourcePos,targetPos);
free(slabData->dim);
free(slabData);
return NX_OK;
}
/*--------------------------------------------------------------------
This goes by recursion
----------------------------------------------------------------------*/
static void getSlabData(pNXDS dataset, pNXDS slabData, int dim,
const int64_t start[],
int64_t sourcePos[],int64_t targetPos[]){
int64_t i, rank, length;
rank = getNXDatasetRank(slabData);
length = getNXDatasetDim(slabData,dim);
if(dim != rank-1){
for(i = 0; i < length; i++){
sourcePos[dim] = start[dim] +i;
targetPos[dim] = i;
getSlabData(dataset,slabData, dim+1,start,
sourcePos,targetPos);
}
} else {
for(i = 0; i < length; i++){
sourcePos[dim] = start[dim] +i;
targetPos[dim] = i;
putNXDatasetValue(slabData,targetPos,
getNXDatasetValue(dataset,sourcePos));
}
}
}
/*----------------------------------------------------------------------*/
NXstatus NXXgetslab64 (NXhandle fid, void *data,
const int64_t iStart[], const int64_t iSize[]){
pXMLNexus xmlHandle = NULL;
mxml_node_t *userData = NULL;
mxml_node_t *current = NULL;
pNXDS dataset, slabData;
int64_t sourcePos[NX_MAXRANK], targetPos[NX_MAXRANK];
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("No dataset open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
userData = findData(current);
assert(userData != NULL);
if(userData->type == MXML_OPAQUE){
NXReportError("This API does not support slabs on text data");
return NX_ERROR;
}
dataset = (pNXDS)userData->value.custom.data;
assert(dataset);
slabData = makeSlabData(dataset, data, iSize);
if(slabData == NULL){
NXReportError("Failed to allocate slab data");
return NX_ERROR;
}
getSlabData(dataset,slabData,0,iStart,sourcePos,targetPos);
free(slabData->dim);
free(slabData);
return NX_OK;
}
/*----------------------------------------------------------------------*/
static NXstatus NXXsetnumberformat(NXhandle fid,
int type, char *format){
pXMLNexus xmlHandle = NULL;
mxml_node_t *current = NULL;
mxml_node_t *userData = NULL;
pNXDS dataset;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
current = xmlHandle->stack[xmlHandle->stackPointer].current;
userData = findData(current);
assert(userData != NULL);
if(userData->type == MXML_OPAQUE){
return NX_OK;
}
dataset = (pNXDS)userData->value.custom.data;
assert(dataset);
if(dataset->format != NULL){
free(dataset->format);
}
dataset->format = strdup(format);
} else {
setNumberFormat(type, format);
}
return NX_OK;
}
/*============================ Attributes ============================*/
static char *formatAttributeData(const void *data, int datalen, int iType){
int intData = 0;
long iValue = -99999;
double dValue = -1e38;
char type[20];
char *number;
if(iType == NX_CHAR){
/* data may not be NULL terminated */
number = (char*)malloc((datalen+1) * sizeof(char));
memcpy(number, data, datalen * sizeof(char));
number[datalen] = '\0';
return number;
}
number = (char *)malloc(132*sizeof(char));
if(!number){
NXReportError("Failed to allocate attribute number buffer");
return NULL;
}
if(datalen > 1){
return NULL;
}
type[0] = '\0';
switch(iType){
case NX_INT32:
iValue = ((int *)data)[0];
intData = 1;
strcpy(type,"NX_INT32:");
break;
case NX_UINT32:
iValue = ((unsigned int *)data)[0];
intData = 1;
strcpy(type,"NX_UINT32:");
break;
case NX_INT16:
iValue = ((short *)data)[0];
intData = 1;
strcpy(type,"NX_INT16:");
break;
case NX_UINT16:
iValue = ((unsigned short *)data)[0];
intData = 1;
strcpy(type,"NX_UINT16:");
break;
case NX_INT8:
iValue = (int)((char *)data)[0];
intData = 1;
strcpy(type,"NX_INT8:");
break;
case NX_UINT8:
intData = 1;
iValue = (int)((unsigned char *)data)[0];
strcpy(type,"NX_UINT8:");
break;
case NX_FLOAT32:
dValue = ((float *)data)[0];
strcpy(type,"NX_FLOAT32:");
intData = 0;
break;
case NX_FLOAT64:
dValue = ((double *)data)[0];
strcpy(type,"NX_FLOAT64:");
intData = 0;
break;
}
if(intData){
snprintf(number,79,"%s%ld",type,iValue);
} else {
snprintf(number,79,"%s%f",type,dValue);
}
return number;
}
/*---------------------------------------------------------------------*/
NXstatus NXXputattr (NXhandle fid, CONSTCHAR *name, void *data,
int datalen, int iType){
char buffer[256];
pXMLNexus xmlHandle = NULL;
mxml_node_t *current = NULL;
char *numberData = NULL;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if (!validNXName(name, 1))
{
sprintf(buffer, "ERROR: invalid characters in attribute name \"%s\"", name);
NXReportError(buffer);
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
if(strcmp(name,TYPENAME) == 0){
NXReportError("type is a reserved attribute name, rejected");
return NX_ERROR;
}
}
numberData = formatAttributeData(data,datalen,iType);
if(numberData == NULL){
NXReportError("This API does not support non number arrays");
return NX_ERROR;
} else {
mxmlElementSetAttr(current,name,numberData);
free(numberData);
}
return NX_OK;
}
/*--------------------------------------------------------------------------*/
NXstatus NXXgetattr (NXhandle fid, char *name,
void *data, int* datalen, int* iType){
pXMLNexus xmlHandle = NULL;
mxml_node_t *current = NULL;
const char *attribute = NULL;
char error[1024];
const char *attData = NULL;
int nx_type;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
current = xmlHandle->stack[xmlHandle->stackPointer].current;
attribute = mxmlElementGetAttr(current,name);
if(!attribute){
snprintf(error,1023,"Attribute %s not found", name);
NXReportError(error);
return NX_ERROR;
}
nx_type = translateTypeCode((char *)attribute);
if(nx_type < 0) {
/*
no type code == text attribute
*/
nx_type = NX_CHAR;
} else {
/*
We need to find the number after the type code. However, there is
the complication of the datatype type attribute ...
*/
if(strcmp(name,TYPENAME) == 0){
nx_type = NX_CHAR;
} else {
attData = strchr(attribute,(int)':');
if(attData == NULL){
NXReportError("ERROR: bad attribute string, : missing");
return NX_ERROR;
}
attData++;
}
}
*iType = nx_type;
switch(nx_type){
case NX_CHAR:
/* enforce NULL termination regardless of length of datalen */
strncpy((char *)data, attribute, *datalen-1);
((char*)data)[*datalen-1] = '\0';
/* *datalen = strlen(attribute); */
*datalen = strlen((char*)data);
*iType = NX_CHAR;
break;
case NX_INT32:
((int *)data)[0] = atoi(attData);
*datalen = 1;
break;
case NX_UINT32:
((unsigned int *)data)[0] = atoi(attData);
*datalen = 1;
break;
case NX_INT16:
((short *)data)[0] = atoi(attData);
*datalen = 1;
break;
case NX_UINT16:
((unsigned short *)data)[0] = atoi(attData);
*datalen = 1;
break;
case NX_INT8:
((char *)data)[0] = atoi(attData);
*datalen = 1;
break;
case NX_UINT8:
((unsigned char *)data)[0] = atoi(attData);
*datalen = 1;
break;
case NX_FLOAT32:
((float *)data)[0] = atof(attData);
*datalen = 1;
break;
case NX_FLOAT64:
((double *)data)[0] = atof(attData);
*datalen = 1;
break;
}
return NX_OK;
}
/* find the next node, ignoring Idata */
static mxml_node_t* find_node(mxml_node_t* node, int next)
{
int done = 0;
mxml_node_t* parent_next = NULL; /* parent to use if we are in an Idims search */
if (node == NULL)
{
return NULL;
}
if ( (node->parent != NULL) && !strcmp(node->parent->value.element.name, DIMS_NODE_NAME) )
{
parent_next = node->parent->next;
}
else
{
parent_next = NULL;
}
if (next)
{
if (node->next != NULL)
{
node = node->next;
}
else
{
node = parent_next;
}
}
while(node != NULL && !done)
{
if ( (node->parent != NULL) && !strcmp(node->parent->value.element.name, DIMS_NODE_NAME) )
{
parent_next = node->parent->next;
}
else
{
parent_next = NULL;
}
if ( (node->type != MXML_ELEMENT) || !strcmp(node->value.element.name, DATA_NODE_NAME) )
{
if (node->next != NULL)
{
node = node->next;
}
else
{
node = parent_next;
}
continue;
}
if (!strcmp(node->value.element.name, DIMS_NODE_NAME))
{
node = node->child;
continue;
}
done = 1;
}
return node;
}
/*====================== search functions =================================*/
NXstatus NXXgetnextentry (NXhandle fid,NXname name,
NXname nxclass, int *datatype){
pXMLNexus xmlHandle = NULL;
mxml_node_t *next = NULL, *userData, *node = NULL;
int stackPtr;
const char *target = NULL, *attname = NULL;
pNXDS dataset;
char pBueffel[256];
const char *linkName = NULL;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
/*
be nice to user: silently fix this problem
*/
NXXclosedata(fid);
}
stackPtr = xmlHandle->stackPointer;
if(xmlHandle->stack[stackPtr].currentChild == NULL){
/*
initialization of search
*/
node = find_node(xmlHandle->stack[stackPtr].current->child, 0);
} else {
/*
proceed
*/
node = find_node(xmlHandle->stack[stackPtr].currentChild, 1);
}
xmlHandle->stack[stackPtr].currentChild = node;
next = node;
if(next == NULL){
return NX_EOD;
}
if(strcmp(next->value.element.name,"NAPIlink") == 0){
target = mxmlElementGetAttr(next,"target");
linkName = mxmlElementGetAttr(next,"name");
if(target == NULL){
NXReportError("Corrupted file, NAPIlink without target");
return NX_ERROR;
}
next = getLinkTarget(xmlHandle,target);
if(next == NULL){
NXReportError("Corrupted file, broken link");
return NX_ERROR;
}
}
if(isDataNode(next)){
strcpy(name,next->value.element.name);
strcpy(nxclass,"SDS");
userData = findData(next);
if(userData == NULL){
snprintf(pBueffel,255,"Corrupted file, userData for %s not found",
name);
NXReportError(pBueffel);
return NX_ERROR;
}
if(userData->type == MXML_OPAQUE){
*datatype = NX_CHAR;
} else {
dataset = (pNXDS)userData->value.custom.data;
assert(dataset);
*datatype = getNXDatasetType(dataset);
}
} else {
strcpy(nxclass,next->value.element.name);
attname = mxmlElementGetAttr(next,"name");
strcpy(name,attname);
}
/*
this is for named links
*/
if(linkName != NULL){
strcpy(name,linkName);
}
return NX_OK;
}
/*----------------------------------------------------------------------*/
extern NXstatus NXXinitgroupdir(NXhandle fid){
pXMLNexus xmlHandle = NULL;
int stackPtr;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("Cannot search datasets");
return NX_ERROR;
}
stackPtr = xmlHandle->stackPointer;
xmlHandle->stack[stackPtr].currentChild = NULL;
return NX_OK;
}
/*-------------------------------------------------------------------------*/
NXstatus NXXgetnextattr (NXhandle fid, NXname pName,
int *iLength, int *iType){
pXMLNexus xmlHandle = NULL;
mxml_node_t *current = NULL;
int stackPtr, currentAtt, nx_type;
char *attVal;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
stackPtr = xmlHandle->stackPointer;
current = xmlHandle->stack[stackPtr].current;
currentAtt = xmlHandle->stack[stackPtr].currentAttribute;
if(currentAtt >=
current->value.element.num_attrs ){
xmlHandle->stack[stackPtr].currentAttribute = 0;
return NX_EOD;
}
/*
hide group name attribute
*/
if(strcmp(current->value.element.attrs[currentAtt].name,"name") == 0
&& !isDataNode(current) ){
xmlHandle->stack[stackPtr].currentAttribute++;
return NXXgetnextattr(fid,pName,iLength,iType);
}
/*
hide type attribute
*/
if(strcmp(current->value.element.attrs[currentAtt].name,TYPENAME) == 0
&& isDataNode(current)){
xmlHandle->stack[stackPtr].currentAttribute++;
return NXXgetnextattr(fid,pName,iLength,iType);
}
strcpy(pName,current->value.element.attrs[currentAtt].name);
attVal = current->value.element.attrs[currentAtt].value;
nx_type = translateTypeCode((char *)attVal);
if(nx_type < 0 || strcmp(pName,TYPENAME) == 0){
/*
no type == NX_CHAR
*/
*iLength = strlen(attVal);
*iType = NX_CHAR;
} else {
*iLength = 1;
*iType = nx_type;
}
xmlHandle->stack[stackPtr].currentAttribute++;
return NX_OK;
}
/*-------------------------------------------------------------------------*/
extern NXstatus NXXinitattrdir(NXhandle fid){
pXMLNexus xmlHandle = NULL;
int stackPtr;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
stackPtr = xmlHandle->stackPointer;
xmlHandle->stack[stackPtr].currentAttribute = 0;
return NX_OK;
}
/*-------------------------------------------------------------------------*/
NXstatus NXXgetgroupinfo (NXhandle fid, int *iN,
NXname pName, NXname pClass){
pXMLNexus xmlHandle = NULL;
mxml_node_t *node = NULL, *child = NULL;
mxml_node_t *current = NULL;
const char *nameAtt = NULL;
int childCount;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("No group open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
nameAtt = mxmlElementGetAttr(current,"name");
if(nameAtt != NULL){
strcpy(pName,nameAtt);
}
strcpy(pClass,current->value.element.name);
/* count all child nodes, but need to ignore DATA_NODE_NAME and
* descend into DIMS_NODE_NAME
*/
childCount = 0;
node = current->child;
while(node != NULL)
{
if (!strcmp(node->value.element.name, DATA_NODE_NAME))
{
; /* names also exist in DIMS_NODE_NAME so do nothing here */
}
else if (!strcmp(node->value.element.name, DIMS_NODE_NAME))
{
child = node->child;
while(child != NULL)
{
/* not sure why this check is needed, but you double count otherwise */
if (child->type == MXML_ELEMENT)
{
childCount++;
}
child = child->next;
}
}
else
{
childCount++;
}
node = node->next;
}
*iN = childCount;
return NX_OK;
}
/*----------------------------------------------------------------------*/
NXstatus NXXgetattrinfo (NXhandle fid, int *iN){
pXMLNexus xmlHandle = NULL;
mxml_node_t *current = NULL;
int stackPtr, skip;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
stackPtr = xmlHandle->stackPointer;
current = xmlHandle->stack[stackPtr].current;
/*
hide type and group name attributes
*/
skip=0;
if(isDataNode(current)) {
/* data nodes may have type */
if(mxmlElementGetAttr(current,TYPENAME) != NULL) skip=1;
} else {
/* group nodes (except root) have name */
if(mxmlElementGetAttr(current,"name") != NULL) skip=1;
}
*iN = current->value.element.num_attrs - skip;
return NX_OK;
}
/*================= Linking functions =================================*/
static int countPathChars(mxml_node_t *path[], int stackPtr){
int count = 1;
const char *name = NULL;
while(stackPtr >= 0) {
if(isDataNode(path[stackPtr])){
count += strlen(path[stackPtr]->value.element.name);
} else {
name = mxmlElementGetAttr(path[stackPtr],"name");
if(name != NULL){
count += strlen(name);
}
}
stackPtr--;
count += 1;
}
return count;
}
/*-------------------------------------------------------------------*/
static char *buildPathString(mxml_node_t *path[], int stackPtr){
int count = 0;
const char *name = NULL;
char *pathString = NULL;
count = countPathChars(path,stackPtr);
pathString = (char *)malloc((count+10)*sizeof(char));
if(pathString == NULL){
return NULL;
}
memset(pathString,0,(count+10)*sizeof(char));
while(stackPtr >= 0) {
if(isDataNode(path[stackPtr])){
strcat(pathString,"/");
strcat(pathString,path[stackPtr]->value.element.name);
} else {
name = mxmlElementGetAttr(path[stackPtr],"name");
if(name != NULL){
strcat(pathString,"/");
strcat(pathString,name);
}
}
stackPtr--;
}
return pathString;
}
/*--------------------------------------------------------------------*/
static char *findLinkPath(mxml_node_t *node){
mxml_node_t **path = NULL;
int stackPtr;
mxml_node_t *current = NULL;
char *result = NULL;
path = (mxml_node_t **)malloc(NXMAXSTACK*sizeof(mxml_node_t *));
if(path == NULL){
NXReportError("ERROR: out of memory following link path");
return NULL;
}
memset(path,0,NXMAXSTACK*sizeof(mxml_node_t *));
/*
first path: walk up the tree untill NXroot is found
*/
current = node;
stackPtr = 0;
while(current != NULL &&
strcmp(current->value.element.name,"NXroot") != 0){
path[stackPtr] = current;
stackPtr++;
current = current->parent;
}
stackPtr--;
/*
path now contains the nodes to the root node in reverse order.
From this build the path string
*/
result = buildPathString(path,stackPtr);
free(path);
return result;
}
/*--------------------------------------------------------------------*/
NXstatus NXXgetdataID (NXhandle fid, NXlink* sRes){
pXMLNexus xmlHandle = NULL;
mxml_node_t *current = NULL;
char *linkPath = NULL;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
linkPath = findLinkPath(current);
if(!linkPath){
NXReportError("Failed to allocate link path string");
return NX_ERROR;
}
strncpy(sRes->targetPath,linkPath,1023);
free(linkPath);
return NX_OK;
}
/*--------------------------------------------------------------------*/
NXstatus NXXgetgroupID (NXhandle fid, NXlink* sRes){
pXMLNexus xmlHandle = NULL;
mxml_node_t *current = NULL;
char *linkPath = NULL;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("No group open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
if(xmlHandle->stackPointer == 0){
return NX_ERROR;
}
linkPath = findLinkPath(current);
if(!linkPath){
NXReportError("Failed to allocate link path string");
return NX_ERROR;
}
strncpy(sRes->targetPath,linkPath,1023);
free(linkPath);
return NX_OK;
}
/*-----------------------------------------------------------------------*/
NXstatus NXXprintlink (NXhandle fid, NXlink* sLink)
{
pXMLNexus xmlHandle = NULL;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
printf("XML link: target=\"%s\"\n", sLink->targetPath);
return NX_OK;
}
/*-----------------------------------------------------------------------*/
NXstatus NXXmakelink (NXhandle fid, NXlink* sLink){
pXMLNexus xmlHandle = NULL;
mxml_node_t *current = NULL, *linkNode = NULL;
mxml_node_t *linkedNode = NULL;
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("No group to link to open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
linkNode = mxmlNewElement(current,"NAPIlink");
if(!linkNode){
NXReportError("Failed to allocate new link element");
return NX_ERROR;
}
mxmlElementSetAttr(linkNode,"target",sLink->targetPath);
linkedNode = getLinkTarget(xmlHandle,sLink->targetPath);
if(linkedNode != NULL){
mxmlElementSetAttr(linkedNode,"target",sLink->targetPath);
}
return NX_OK;
}
/*-----------------------------------------------------------------------*/
NXstatus NXXmakenamedlink (NXhandle fid, CONSTCHAR *name, NXlink* sLink){
pXMLNexus xmlHandle = NULL;
mxml_node_t *current = NULL, *linkNode = NULL;
mxml_node_t *linkedNode = NULL;
char buffer[256];
xmlHandle = (pXMLNexus)fid;
assert(xmlHandle);
if (!validNXName(name, 0))
{
sprintf(buffer, "ERROR: invalid characters in link name \"%s\"", name);
NXReportError(buffer);
return NX_ERROR;
}
if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
NXReportError("No group to link to open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
linkNode = mxmlNewElement(current,"NAPIlink");
if(!linkNode){
NXReportError("Failed to allocate new link element");
return NX_ERROR;
}
mxmlElementSetAttr(linkNode,"target",sLink->targetPath);
mxmlElementSetAttr(linkNode,"name",name);
linkedNode = getLinkTarget(xmlHandle,sLink->targetPath);
if(linkedNode != NULL){
mxmlElementSetAttr(linkedNode,"target",sLink->targetPath);
}
return NX_OK;
}
/*----------------------------------------------------------------------*/
NXstatus NXXsameID (NXhandle fileid, NXlink* pFirstID,
NXlink* pSecondID){
if(strcmp(pFirstID->targetPath,pSecondID->targetPath) == 0) {
return NX_OK;
} else {
return NX_ERROR;
}
}
/*--------------------------------------------------------------------*/
int NXXcompress(NXhandle fid, int comp){
/* that will throw an exception in the Java API, errors have to be fatal */
/* NXReportError("NXcompress is deprecated, IGNORED"); */
return NX_OK;
}
/*----------------------------------------------------------------------*/
void NXXassignFunctions(pNexusFunction fHandle){
fHandle->nxclose=NXXclose;
fHandle->nxreopen=NULL;
fHandle->nxflush=NXXflush;
fHandle->nxmakegroup=NXXmakegroup;
fHandle->nxopengroup=NXXopengroup;
fHandle->nxclosegroup=NXXclosegroup;
fHandle->nxmakedata64=NXXmakedata64;
fHandle->nxcompmakedata64=NXXcompmakedata64;
fHandle->nxcompress=NXXcompress;
fHandle->nxopendata=NXXopendata;
fHandle->nxclosedata=NXXclosedata;
fHandle->nxputdata=NXXputdata;
fHandle->nxputattr=NXXputattr;
fHandle->nxputslab64=NXXputslab64;
fHandle->nxgetdataID=NXXgetdataID;
fHandle->nxmakelink=NXXmakelink;
fHandle->nxmakenamedlink=NXXmakenamedlink;
fHandle->nxgetdata=NXXgetdata;
fHandle->nxgetinfo64=NXXgetinfo64;
fHandle->nxgetnextentry=NXXgetnextentry;
fHandle->nxgetslab64=NXXgetslab64;
fHandle->nxgetnextattr=NXXgetnextattr;
fHandle->nxgetattr=NXXgetattr;
fHandle->nxgetattrinfo=NXXgetattrinfo;
fHandle->nxgetgroupID=NXXgetgroupID;
fHandle->nxgetgroupinfo=NXXgetgroupinfo;
fHandle->nxsameID=NXXsameID;
fHandle->nxinitgroupdir=NXXinitgroupdir;
fHandle->nxinitattrdir=NXXinitattrdir;
fHandle->nxsetnumberformat=NXXsetnumberformat;
fHandle->nxprintlink=NXXprintlink;
fHandle->nxnativeexternallink=NULL;
}
#endif /*NXXML*/