Files
sics/nxxml.c
koennecke 91d4af0541 - Adapted indenation to new agreed upon system
- Added support for second generation scriptcontext based counter
2009-02-13 09:00:03 +00:00

1631 lines
46 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>
*/
#include <stdio.h>
#include <napi.h>
#include <assert.h>
#include <mxml.h>
#include <nxxml.h>
#include "nxio.h"
#include "nxdataset.h"
extern void *NXpData;
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;
} xmlStack;
/*---------------------------------------------------------------------*/
typedef struct {
mxml_node_t *root; /* root node */
int readOnly; /* read only flag */
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) {
NXIReportError(NXpData, "Cannot follow broken link");
return NULL;
} else {
node = testNode;
}
}
return node;
}
/*==================== file functions ===================================*/
static void errorCallbackForMxml(const char *txt)
{
NXIReportError(NXpData, (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) {
NXIReportError(NXpData, "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);
/*
open file
*/
strncpy(xmlHandle->filename, filename, 1023);
switch (am) {
case NXACC_READ:
xmlHandle->readOnly = 1;
case NXACC_RDWR:
fp = fopen(filename, "r");
if (fp == NULL) {
NXIReportError(NXpData, "Failed to open file:");
NXIReportError(NXpData, (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;
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);
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;
break;
default:
NXIReportError(NXpData, "Bad access parameter specified in NXXopen");
return NX_ERROR;
}
if (xmlHandle->stack[0].current == NULL) {
NXIReportError(NXpData,
"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) {
NXIReportError(NXpData, "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) {
NXIReportError(NXpData, "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)
{
pXMLNexus xmlHandle = NULL;
mxml_node_t *newGroup = NULL;
xmlHandle = (pXMLNexus) fid;
assert(xmlHandle);
if (isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)) {
NXIReportError(NXpData,
"Close dataset before trying to create a group");
return NX_ERROR;
}
newGroup =
mxmlNewElement(xmlHandle->stack[xmlHandle->stackPointer].current,
nxclass);
if (!newGroup) {
NXIReportError(NXpData, "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)) {
NXIReportError(NXpData, "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);
NXIReportError(NXpData, error);
return NX_ERROR;
}
xmlHandle->stackPointer++;
xmlHandle->stack[xmlHandle->stackPointer].current = newGroup;
xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL;
xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0;
return NX_OK;
}
/*----------------------------------------------------------------------*/
NXstatus NXXclosegroup(NXhandle fid)
{
pXMLNexus xmlHandle = NULL;
mxml_node_t *newGroup = NULL;
char error[1024];
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 NXXcompmakedata(NXhandle fid, CONSTCHAR * name,
int datatype,
int rank,
int dimensions[],
int compress_type, int chunk_size[])
{
/*
compression does not relly make sense with XML
*/
return NXXmakedata(fid, name, datatype, rank, dimensions);
}
/*-----------------------------------------------------------------------*/
static char *buildTypeString(int datatype, int rank, int dimensions[])
{
char *typestring = NULL;
char pNumber[20];
int i;
/*
allocate data
*/
typestring = (char *) malloc(132 * sizeof(char));
if (!typestring) {
NXIReportError(NXpData, "Failed to allocate typestring");
return NULL;
}
memset(typestring, 0, 132 * sizeof(char));
getNumberText(datatype, typestring, 130);
if (rank > 1 || dimensions[0] > 1) {
strcat(typestring, "[");
snprintf(pNumber, 19, "%d", dimensions[0]);
strncat(typestring, pNumber, 130 - strlen(typestring));
for (i = 1; i < rank; i++) {
snprintf(pNumber, 19, ",%d", dimensions[i]);
strncat(typestring, pNumber, 130 - strlen(typestring));
}
strcat(typestring, "]");
}
return typestring;
}
/*------------------------------------------------------------------------*/
NXstatus NXXmakedata(NXhandle fid,
CONSTCHAR * name, int datatype,
int rank, int dimensions[])
{
pXMLNexus xmlHandle = NULL;
mxml_node_t *dataNode = NULL;
mxml_node_t *newData = NULL;
mxml_node_t *current;
char *typestring;
xmlHandle = (pXMLNexus) fid;
assert(xmlHandle);
if (isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)) {
NXIReportError(NXpData,
"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 {
NXIReportError(NXpData, "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) {
NXIReportError(NXpData, "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) {
NXIReportError(NXpData, "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 NXXopendata(NXhandle fid, CONSTCHAR * name)
{
pXMLNexus xmlHandle = NULL;
mxml_node_t *dataNode = 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;
}
}
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);
NXIReportError(NXpData, error);
return NX_ERROR;
}
xmlHandle->stackPointer++;
xmlHandle->stack[xmlHandle->stackPointer].current = dataNode;
xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL;
xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 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;
}
/*------------------------------------------------------------------------*/
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, dim[NX_MAXRANK];
char *pPtr = NULL;
xmlHandle = (pXMLNexus) fid;
assert(xmlHandle);
if (!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)) {
NXIReportError(NXpData, "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 (NXXgetinfo(fid, &rank, dim, &type) == NX_OK) {
length = 1;
for (i = 0; i < rank; i++) {
length *= dim[i];
}
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 {
NXIReportError(NXpData,
"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 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, dim[NX_MAXRANK];
xmlHandle = (pXMLNexus) fid;
assert(xmlHandle);
if (!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)) {
NXIReportError(NXpData, "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 (NXXgetinfo(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 NXXgetinfo(NXhandle fid, int *rank, int 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)) {
NXIReportError(NXpData, "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 {
analyzeDim(attr, rank, dimension, iType);
*iType = NX_CHAR;
}
} 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, void *data, int 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 = (int *) malloc(rank * sizeof(int));
for (i = 0; i < rank; i++) {
slabData->dim[i] = size[i];
}
slabData->type = getNXDatasetType(dataset);
slabData->u.ptr = data;
slabData->magic = dataset->magic;
return slabData;
}
/*--------------------------------------------------------------------
This goes by recursion
----------------------------------------------------------------------*/
static void putSlabData(pNXDS dataset, pNXDS slabData, int dim,
int start[], int sourcePos[], int targetPos[])
{
int 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,
int start[], int size[])
{
int 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 {
NXIReportError(NXpData, "Failed to allocate typestring");
return 0;
}
}
return 1;
}
/*----------------------------------------------------------------------*/
NXstatus NXXputslab(NXhandle fid, void *data, int iStart[], int iSize[])
{
pXMLNexus xmlHandle = NULL;
mxml_node_t *userData = NULL;
mxml_node_t *current = NULL;
pNXDS dataset, slabData;
int sourcePos[NX_MAXRANK], targetPos[NX_MAXRANK], status;
xmlHandle = (pXMLNexus) fid;
assert(xmlHandle);
if (!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)) {
NXIReportError(NXpData, "No dataset open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
userData = findData(current);
assert(userData != NULL);
if (userData->type == MXML_OPAQUE) {
NXIReportError(NXpData,
"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) {
NXIReportError(NXpData, "Out of memory extending dataset");
return NX_ERROR;
}
slabData = makeSlabData(dataset, data, iSize);
if (slabData == NULL) {
NXIReportError(NXpData, "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,
int start[], int sourcePos[], int targetPos[])
{
int 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 NXXgetslab(NXhandle fid, void *data, int iStart[], int iSize[])
{
pXMLNexus xmlHandle = NULL;
mxml_node_t *userData = NULL;
mxml_node_t *current = NULL;
pNXDS dataset, slabData;
int sourcePos[NX_MAXRANK], targetPos[NX_MAXRANK];
xmlHandle = (pXMLNexus) fid;
assert(xmlHandle);
if (!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)) {
NXIReportError(NXpData, "No dataset open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
userData = findData(current);
assert(userData != NULL);
if (userData->type == MXML_OPAQUE) {
NXIReportError(NXpData,
"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) {
NXIReportError(NXpData, "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(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) {
NXIReportError(NXpData, "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)
{
pXMLNexus xmlHandle = NULL;
mxml_node_t *current = NULL;
char *numberData = NULL;
xmlHandle = (pXMLNexus) fid;
assert(xmlHandle);
current = xmlHandle->stack[xmlHandle->stackPointer].current;
if (isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)) {
if (strcmp(name, TYPENAME) == 0) {
NXIReportError(NXpData,
"type is a reserved attribute name, rejected");
return NX_ERROR;
}
}
numberData = formatAttributeData(data, datalen, iType);
if (numberData == NULL) {
NXIReportError(NXpData, "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];
char *attData = NULL;
int iValue, nx_type;
float fValue;
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);
NXIReportError(NXpData, 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) {
NXIReportError(NXpData, "ERROR: bad attribute string, : missing");
return NX_ERROR;
}
attData++;
}
}
*iType = nx_type;
switch (nx_type) {
case NX_CHAR:
strncpy((char *) data, attribute, *datalen);
*datalen = strlen(attribute);
*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;
}
/*====================== search functions =================================*/
NXstatus NXXgetnextentry(NXhandle fid, NXname name,
NXname nxclass, int *datatype)
{
pXMLNexus xmlHandle = NULL;
mxml_node_t *next = NULL, *userData;
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
*/
xmlHandle->stack[stackPtr].currentChild =
xmlHandle->stack[stackPtr].current->child;
} else {
/*
proceed
*/
xmlHandle->stack[stackPtr].currentChild =
xmlHandle->stack[stackPtr].currentChild->next;
}
next = xmlHandle->stack[stackPtr].currentChild;
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) {
NXIReportError(NXpData, "Corrupted file, NAPIlink without target");
return NX_ERROR;
}
next = getLinkTarget(xmlHandle, target);
if (next == NULL) {
NXIReportError(NXpData, "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);
NXIReportError(NXpData, 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)) {
NXIReportError(NXpData, "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 *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)) {
NXIReportError(NXpData, "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);
childCount = 0;
child = current->child;
while (child != NULL) {
childCount++;
child = child->next;
}
*iN = childCount;
return NX_OK;
}
/*----------------------------------------------------------------------*/
NXstatus NXXgetattrinfo(NXhandle fid, int *iN)
{
pXMLNexus xmlHandle = NULL;
mxml_node_t *current = NULL;
int stackPtr, currentAtt;
xmlHandle = (pXMLNexus) fid;
assert(xmlHandle);
stackPtr = xmlHandle->stackPointer;
current = xmlHandle->stack[stackPtr].current;
/*
hide type and group name attributes
*/
if (!isDataNode(current)) {
*iN = current->value.element.num_attrs - 1;
return NX_OK;
}
if (mxmlElementGetAttr(current, TYPENAME) != NULL) {
*iN = current->value.element.num_attrs - 1;
} else {
*iN = current->value.element.num_attrs;
}
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 *pathString = NULL, *result = NULL;
int count;
path = (mxml_node_t **) malloc(NXMAXSTACK * sizeof(mxml_node_t *));
if (path == NULL) {
NXIReportError(NXpData, "ERROR: out of memory follwoing 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) {
NXIReportError(NXpData, "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)) {
NXIReportError(NXpData, "No group open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
if (xmlHandle->stackPointer == 0) {
return NX_ERROR;
}
linkPath = findLinkPath(current);
if (!linkPath) {
NXIReportError(NXpData, "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)) {
NXIReportError(NXpData, "No group to link to open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
linkNode = mxmlNewElement(current, "NAPIlink");
if (!linkNode) {
NXIReportError(NXpData, "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;
xmlHandle = (pXMLNexus) fid;
assert(xmlHandle);
if (isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)) {
NXIReportError(NXpData, "No group to link to open");
return NX_ERROR;
}
current = xmlHandle->stack[xmlHandle->stackPointer].current;
linkNode = mxmlNewElement(current, "NAPIlink");
if (!linkNode) {
NXIReportError(NXpData, "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)
{
NXIReportError(NXpData, "NXcompress is deprecated, IGNORED");
return NX_OK;
}
/*----------------------------------------------------------------------*/
void NXXassignFunctions(pNexusFunction fHandle)
{
fHandle->nxclose = NXXclose;
fHandle->nxflush = NXXflush;
fHandle->nxmakegroup = NXXmakegroup;
fHandle->nxopengroup = NXXopengroup;
fHandle->nxclosegroup = NXXclosegroup;
fHandle->nxmakedata = NXXmakedata;
fHandle->nxcompmakedata = NXXcompmakedata;
fHandle->nxcompress = NXXcompress;
fHandle->nxopendata = NXXopendata;
fHandle->nxclosedata = NXXclosedata;
fHandle->nxputdata = NXXputdata;
fHandle->nxputattr = NXXputattr;
fHandle->nxputslab = NXXputslab;
fHandle->nxgetdataID = NXXgetdataID;
fHandle->nxmakelink = NXXmakelink;
fHandle->nxmakenamedlink = NXXmakenamedlink;
fHandle->nxgetdata = NXXgetdata;
fHandle->nxgetinfo = NXXgetinfo;
fHandle->nxgetnextentry = NXXgetnextentry;
fHandle->nxgetslab = NXXgetslab;
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;
}