source: trunk/src/nxxml.c @ 1822

Revision 1792, 56.4 KB checked in by Freddie Akeroyd, 6 months ago (diff)

Fix constness of various functions. Refs #286

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * This is the implementation file for the XML file driver
3 * for NeXus
4 *
5 *   Copyright (C) 2006 Mark Koennecke
6 *
7 *  This library is free software; you can redistribute it and/or
8 *  modify it under the terms of the GNU Lesser General Public
9 *  License as published by the Free Software Foundation; either
10 *  version 2 of the License, or (at your option) any later version.
11 *
12 *  This library is distributed in the hope that it will be useful,
13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 *  Lesser General Public License for more details.
16 *
17 *  You should have received a copy of the GNU Lesser General Public
18 *  License along with this library; if not, write to the Free Software
19 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 *
21 *  For further information, see <http://www.nexusformat.org>
22 */
23
24
25#ifdef NXXML
26
27#include <stdio.h>
28#include <assert.h>
29#include <stdint.h>
30#include <mxml.h>
31#include <napi.h>
32#include <nxxml.h>
33#include "nxio.h"
34#include "nxdataset.h"
35
36#ifdef _MSC_VER
37#define snprintf _snprintf
38#endif /* _MSC_VER */
39
40extern  void *NXpData;
41extern int validNXName(const char* name, int allow_colon); /* from napi.c */
42char *nxitrim(char *str); /* from napi.c */
43
44/*----------------------- our data structures --------------------------
45  One might wonder why a node stack is still needed even if this API
46  operates on top of a tree API. The reason for this are the links.
47  Following a link on any NXopenpath, data means a jump through the
48  whole tree. In order to correctly return from such adventures,
49  a stack is needed. Moreover we need it in order to keep track of the
50  state of search operations.
51
52  The true NXroot node is always at stack[0]. The root in the data
53  structure is the ?xml element. The latter one is needed to store
54  the tree.
55-----------------------------------------------------------------------*/
56typedef struct {
57    mxml_node_t *current;
58    mxml_node_t *currentChild;
59    int currentAttribute;
60    int options; /**< additional information about the node */
61}xmlStack;
62
63/*
64 * Freddie Akeroyd, 19/03/2008
65 *
66 * Add in support for table style data writing - this is
67 * indicated internally via the XMLSTACK_OPTION_TABLE flag
68 * and separates the dimensions and data into separate nodes contained
69 * in DIMS_NODE_NAME and DATA_NODE_NAME. This is a first commit and
70 * involves some code duplication that will need to be cleaned up later.
71 * Also writing in table style is only enabled for 1D arrays as
72 * I haven't done slab writing yet which the nexus test program uses
73 * for writing 2D arrays.
74 *
75 * Table output is enabled by opening a file with (NXACC_CREATEXML | NXACC_TABLE)
76 *
77 * See http://trac.nexusformat.org/code/ticket/111 for further details
78 */
79#define XMLSTACK_OPTION_TABLE           0x1 /**< indicates table option in xmlStack */
80
81
82/*---------------------------------------------------------------------*/
83typedef struct {
84  mxml_node_t *root;           /* root node */
85  int readOnly;                /* read only flag */
86  int tableStyle;              /**< whether to output data in XML table style */
87  int stackPointer;            /* stack pointer */
88  char filename[1024];         /* file name, for NXflush, NXclose */
89  xmlStack stack[NXMAXSTACK];  /* stack */
90}XMLNexus, *pXMLNexus;
91/*===================== support functions ===============================*/
92extern char *stptok(char *s, char *tok, size_t toklen, char *brk);
93/*----------------------------------------------------------------------*/
94static mxml_node_t *getLinkTarget(pXMLNexus xmlHandle, const char *target){
95  mxml_node_t *node = NULL;
96  mxml_node_t *testNode = NULL;
97  char path[132], *pPtr;
98
99  pPtr = (char *)target + 1;
100  node = xmlHandle->stack[0].current;
101  while((pPtr = stptok(pPtr,path,131,"/")) != NULL){
102    /*
103      search for group node
104    */
105    testNode = mxmlFindElement(node,node,NULL,"name",path,MXML_DESCEND_FIRST);
106    if(testNode == NULL){
107      /*
108        it can still be a data node
109      */
110      testNode = mxmlFindElement(node,node,path,NULL,NULL,MXML_DESCEND_FIRST);
111    }
112    if(testNode == NULL){
113      NXReportError("Cannot follow broken link");
114      return NULL;
115    } else {
116      node = testNode;
117    }
118  }
119  return node;
120}
121/*==================== file functions ===================================*/
122static void errorCallbackForMxml(const char *txt){
123  NXReportError((char *)txt);
124}
125/*-----------------------------------------------------------------------*/
126NXstatus  NXXopen(CONSTCHAR *filename, NXaccess am, 
127                               NXhandle* pHandle) {
128  pXMLNexus xmlHandle = NULL;
129  FILE *fp = NULL;
130  char *time_buffer = NULL;
131  mxml_node_t *current;
132
133  /*
134    allocate data
135  */
136  xmlHandle = (pXMLNexus)malloc(sizeof(XMLNexus));
137  if(!xmlHandle){
138    NXReportError( "Out of memory allocating XML file handle");
139    return NX_ERROR;
140  }
141  memset(xmlHandle,0,sizeof(XMLNexus));
142
143  /*
144    initialize mxml XML parser
145  */
146  mxmlSetCustomHandlers(nexusLoadCallback, nexusWriteCallback);
147  initializeNumberFormats();
148  mxmlSetErrorCallback(errorCallbackForMxml);
149
150  xmlHandle->tableStyle = ((am & NXACC_TABLE) ? 1 : 0);
151  /*
152    open file
153  */
154  strncpy(xmlHandle->filename,filename,1023);
155  switch(am & NXACCMASK_REMOVEFLAGS){
156  case NXACC_READ:
157    xmlHandle->readOnly = 1;
158  case NXACC_RDWR:
159    fp = fopen(filename,"r");
160    if(fp == NULL){
161      NXReportError("Failed to open file:");
162      NXReportError((char *)filename);
163      free(xmlHandle);
164      return NX_ERROR;
165    }
166    xmlHandle->root = mxmlLoadFile(NULL,fp,nexusTypeCallback);
167    xmlHandle->stack[0].current = mxmlFindElement(xmlHandle->root,
168                                                  xmlHandle->root,
169                                                  "NXroot",
170                                                  NULL,NULL,
171                                                  MXML_DESCEND);
172    xmlHandle->stack[0].currentChild = NULL;
173    xmlHandle->stack[0].currentAttribute = 0;
174    xmlHandle->stack[0].options = 0;
175    fclose(fp);
176    break;
177  case NXACC_CREATEXML:
178    xmlHandle->root = mxmlNewElement(NULL,
179                   "?xml version=\"1.0\" encoding=\"UTF-8\"?");
180    current = mxmlNewElement(xmlHandle->root,"NXroot");
181    mxmlElementSetAttr(current,"NeXus_version",NEXUS_VERSION);
182    mxmlElementSetAttr(current,"XML_version","mxml");
183    mxmlElementSetAttr(current,"file_name",filename);
184    mxmlElementSetAttr(current,"xmlns", NEXUS_SCHEMA_NAMESPACE);
185    mxmlElementSetAttr(current,"xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
186    mxmlElementSetAttr(current,"xsi:schemaLocation",
187        NEXUS_SCHEMA_NAMESPACE " " NEXUS_SCHEMA_URL);
188    time_buffer = NXIformatNeXusTime();
189    if(time_buffer != NULL){
190      mxmlElementSetAttr(current,"file_time",time_buffer);
191      free(time_buffer);
192    } 
193    xmlHandle->stack[0].current = current;
194    xmlHandle->stack[0].currentChild = NULL;
195    xmlHandle->stack[0].currentAttribute = 0;
196    xmlHandle->stack[0].options = 0;
197    break;
198  default:
199    NXReportError("Bad access parameter specified in NXXopen");
200    return NX_ERROR;
201  }
202  if(xmlHandle->stack[0].current == NULL){
203      NXReportError(
204                     "No NXroot element in XML-file, no NeXus-XML file");
205      return NX_ERROR;
206  }
207
208  *pHandle = xmlHandle;
209  return NX_OK;
210}
211/*----------------------------------------------------------------------*/
212NXstatus  NXXclose (NXhandle* fid){
213  pXMLNexus xmlHandle = NULL;
214  FILE *fp = NULL;
215
216  xmlHandle = (pXMLNexus)*fid;
217  assert(xmlHandle);
218 
219  if(xmlHandle->readOnly == 0) {
220    fp = fopen(xmlHandle->filename,"w");
221    if(fp == NULL){
222      NXReportError("Failed to open NeXus XML file for writing");
223      return NX_ERROR;
224    }
225    mxmlSaveFile(xmlHandle->root,fp,NXwhitespaceCallback);
226    fclose(fp);
227  }
228  mxmlDelete(xmlHandle->root);
229  free(xmlHandle);
230  *fid = NULL;
231  return NX_OK;
232}
233/*----------------------------------------------------------------------*/
234NXstatus  NXXflush(NXhandle *fid){
235  pXMLNexus xmlHandle = NULL;
236  FILE *fp = NULL;
237
238  xmlHandle = (pXMLNexus)*fid;
239  assert(xmlHandle);
240 
241  if(xmlHandle->readOnly == 0) {
242    fp = fopen(xmlHandle->filename,"w");
243    if(fp == NULL){
244      NXReportError("Failed to open NeXus XML file for writing");
245      return NX_ERROR;
246    }
247    mxmlSaveFile(xmlHandle->root,fp,NXwhitespaceCallback);
248    fclose(fp);
249  }
250  return NX_OK;
251}
252/*=======================================================================
253                   Group functions
254=========================================================================*/
255NXstatus  NXXmakegroup (NXhandle fid, CONSTCHAR *name, 
256                                     CONSTCHAR *nxclass){
257  char buffer[256];
258  pXMLNexus xmlHandle = NULL;
259  mxml_node_t *newGroup = NULL;
260
261  xmlHandle = (pXMLNexus)fid;
262  assert(xmlHandle);
263
264  if (!validNXName(name, 0))
265  {
266    sprintf(buffer, "ERROR: invalid characters in group name \"%s\"", name);
267    NXReportError(buffer);
268    return NX_ERROR;
269  }
270
271  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
272    NXReportError("Close dataset before trying to create a group");
273    return NX_ERROR;
274  }
275
276  newGroup = mxmlNewElement(xmlHandle->stack[xmlHandle->stackPointer].current,
277                            nxclass);
278  if(!newGroup){
279    NXReportError("failed to allocate new group");
280    return NX_ERROR;
281  }
282  mxmlElementSetAttr(newGroup,"name",name);
283  return NX_OK;
284} 
285/*----------------------------------------------------------------------*/
286static mxml_node_t *searchGroupLinks(pXMLNexus xmlHandle, CONSTCHAR *name, 
287                                CONSTCHAR *nxclass){
288  mxml_node_t *linkNode = NULL;
289  mxml_node_t *current;
290  mxml_node_t *test = NULL;
291  const char *linkTarget;
292  const char *linkName = NULL;
293
294  current = xmlHandle->stack[xmlHandle->stackPointer].current;
295  linkNode = current;
296  while((linkNode = mxmlFindElement(linkNode,current,"NAPIlink",NULL,NULL,
297                                    MXML_DESCEND_FIRST)) != NULL){
298    linkTarget = mxmlElementGetAttr(linkNode,"target");
299    test = getLinkTarget(xmlHandle,linkTarget);
300    if(test != NULL){
301      if(strcmp(test->value.element.name,nxclass) == 0){
302        if(strcmp(mxmlElementGetAttr(test,"name"),name) == 0){
303          return test;
304        }
305      }
306    }
307    /*
308      test for named links
309    */
310    linkName = mxmlElementGetAttr(linkNode,"name");
311    if(test != NULL && linkName != NULL){
312      if(strcmp(test->value.element.name,nxclass) == 0){
313        if(strcmp(linkName, name) == 0){
314          return test;
315        }
316      }
317    }
318  }
319  return NULL;
320}
321/*------------------------------------------------------------------------*/
322NXstatus  NXXopengroup (NXhandle fid, CONSTCHAR *name, 
323                                     CONSTCHAR *nxclass){
324  pXMLNexus xmlHandle = NULL;
325  mxml_node_t *newGroup = NULL;
326  char error[1024];
327
328  xmlHandle = (pXMLNexus)fid;
329  assert(xmlHandle);
330
331  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
332    NXReportError("Close dataset before trying to open a group");
333    return NX_ERROR;
334  }
335  newGroup = mxmlFindElement(xmlHandle->stack[xmlHandle->stackPointer].current,
336                             xmlHandle->stack[xmlHandle->stackPointer].current,
337                             nxclass,
338                             "name",
339                             name,
340                             MXML_DESCEND_FIRST);
341  if(newGroup == NULL){
342    newGroup = searchGroupLinks(xmlHandle,name,nxclass);
343  }
344  if(!newGroup){
345    snprintf(error,1023,"Failed to open %s, %s",name,nxclass);
346    NXReportError(error);
347    return NX_ERROR;
348  }
349  xmlHandle->stackPointer++;
350  xmlHandle->stack[xmlHandle->stackPointer].current = newGroup;
351  xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL;
352  xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0;
353  xmlHandle->stack[xmlHandle->stackPointer].options = 0;
354  return NX_OK;
355}
356/*----------------------------------------------------------------------*/
357NXstatus  NXXclosegroup (NXhandle fid){
358  pXMLNexus xmlHandle = NULL;
359
360  xmlHandle = (pXMLNexus)fid;
361  assert(xmlHandle);
362
363  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
364    /*
365      silently fix this
366    */
367    NXXclosedata(fid);
368  }
369  if(xmlHandle->stackPointer > 0){
370    xmlHandle->stackPointer--;
371  }
372  return NX_OK;
373}
374/*=========================================================================
375         dataset functions
376=========================================================================*/
377NXstatus  NXXcompmakedata64 (NXhandle fid, CONSTCHAR *name, 
378                                        int datatype, 
379                                        int rank, 
380                                        int64_t dimensions[],
381                                        int compress_type, int64_t chunk_size[]){
382  /*
383    compression does not relly make sense with XML
384  */
385  return NXXmakedata64(fid,name,datatype,rank,dimensions);
386}
387/*-----------------------------------------------------------------------*/
388static char *buildTypeString(int datatype, int rank, int64_t dimensions[]){
389  char *typestring = NULL;
390  char pNumber[20];
391  int i;
392
393  /*
394    allocate data
395  */
396  typestring = (char *)malloc(132*sizeof(char));
397  if(!typestring){
398    NXReportError("Failed to allocate typestring");
399    return NULL;
400  }
401  memset(typestring,0,132*sizeof(char));
402
403  getNumberText(datatype,typestring,130);
404  if(rank > 1 || datatype == NX_CHAR || dimensions[0] > 1) {
405    strcat(typestring,"[");
406    snprintf(pNumber,19,"%lld", (long long)dimensions[0]);
407    strncat(typestring,pNumber,130-strlen(typestring));
408    for(i = 1; i < rank; i++){
409      snprintf(pNumber,19,",%lld", (long long)dimensions[i]);
410      strncat(typestring,pNumber,130-strlen(typestring));
411    }
412    strcat(typestring,"]");
413  }
414  return typestring;
415}
416
417/*------------------------------------------------------------------------*/
418NXstatus  NXXmakedatatable64 (NXhandle fid, 
419                                    CONSTCHAR *name, int datatype, 
420                                    int rank, int64_t dimensions[]){
421  pXMLNexus xmlHandle = NULL;
422  mxml_node_t *dataNode = NULL, *dataNodeRoot = NULL, *dimsNode = NULL, *dimsNodeRoot = NULL;
423  mxml_node_t *newData = NULL;
424  mxml_node_t *current;
425  char *typestring;
426  int i, ndata; 
427  char buffer[256];
428  static int64_t one = 1;
429
430  xmlHandle = (pXMLNexus)fid;
431  assert(xmlHandle);
432  if (!validNXName(name, 0))
433  {
434    sprintf(buffer, "ERROR: invalid characters in dataset name \"%s\"", name);
435    NXReportError(buffer);
436    return NX_ERROR;
437  }
438
439  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
440    NXReportError("Close dataset before trying to create a dataset");
441    return NX_ERROR;
442  }
443  if(dimensions[0] < 0){
444    dimensions[0] = 1;
445  }
446
447  current = xmlHandle->stack[xmlHandle->stackPointer].current;
448
449  dimsNodeRoot = mxmlFindElement(current, current, DIMS_NODE_NAME, NULL, NULL, MXML_DESCEND_FIRST);
450  if (dimsNodeRoot == NULL)
451  {
452      dimsNodeRoot = mxmlNewElement(current, DIMS_NODE_NAME);
453  }
454  dimsNode = mxmlNewElement(dimsNodeRoot, name);
455  mxmlNewOpaque(dimsNode, "");
456  typestring = buildTypeString(datatype,rank,dimensions);
457  if(typestring != NULL){
458    mxmlElementSetAttr(dimsNode,TYPENAME,typestring);
459    free(typestring);
460  } else {
461    NXReportError("Failed to allocate typestring");
462    return NX_ERROR;
463  }
464  ndata = 1;
465  for(i=0; i<rank; i++)
466  {
467     ndata *= dimensions[i];
468  }
469  dataNodeRoot = current;
470  for(i=0; i<ndata; i++)
471  {
472      dataNodeRoot = mxmlFindElement(dataNodeRoot, current, DATA_NODE_NAME, NULL, NULL, (i == 0 ? MXML_DESCEND_FIRST : MXML_NO_DESCEND) );
473      if (dataNodeRoot == NULL)
474      {
475          dataNodeRoot = mxmlNewElement(current, DATA_NODE_NAME);
476      }
477      dataNode = mxmlNewElement(dataNodeRoot,name);
478      newData = (mxml_node_t *)malloc(sizeof(mxml_node_t));
479      if(!newData){
480        NXReportError("Failed to allocate space for dataset");
481        return NX_ERROR;
482      }
483      memset(newData,0,sizeof(mxml_node_t));
484      mxmlAdd(dataNode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, newData);
485      newData->type = MXML_CUSTOM;
486/*        newData->value.custom.data = createNXDataset(rank,datatype,dimensions); */
487      newData->value.custom.data = createNXDataset(1,datatype,&one);
488      if(!newData->value.custom.data){
489        NXReportError("Failed to allocate space for dataset");
490        return NX_ERROR;
491      }
492      newData->value.custom.destroy = destroyDataset;
493  }
494  return NX_OK;
495}
496
497NXstatus  NXXmakedata64 (NXhandle fid, 
498                                    CONSTCHAR *name, int datatype, 
499                                    int rank, int64_t dimensions[]){
500  pXMLNexus xmlHandle = NULL;
501  mxml_node_t *dataNode = NULL;
502  mxml_node_t *newData = NULL;
503  mxml_node_t *current;
504  char *typestring;
505  char buffer[256];
506
507
508  xmlHandle = (pXMLNexus)fid;
509  assert(xmlHandle);
510  if (!validNXName(name, 0))
511  {
512    sprintf(buffer, "ERROR: invalid characters in dataset name \"%s\"", name);
513    NXReportError(buffer);
514    return NX_ERROR;
515  }
516
517  if (xmlHandle->tableStyle && datatype != NX_CHAR && dimensions[0] != NX_UNLIMITED && rank == 1)
518  {
519      return NXXmakedatatable64(fid,name,datatype,rank,dimensions);
520  }
521
522  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
523    NXReportError("Close dataset before trying to create a dataset");
524    return NX_ERROR;
525  }
526  if(dimensions[0] < 0){
527    dimensions[0] = 1;
528  }
529
530  current = xmlHandle->stack[xmlHandle->stackPointer].current;
531  dataNode = mxmlNewElement(current,name);
532  typestring = buildTypeString(datatype,rank,dimensions);
533  if(typestring != NULL){
534    mxmlElementSetAttr(dataNode,TYPENAME,typestring);
535    free(typestring);
536  } else {
537    NXReportError("Failed to allocate typestring");
538    return NX_ERROR;
539  }
540  /*
541    NX_CHAR maps to MXML_OPAQUE datasets
542  */
543  if(datatype == NX_CHAR){
544    newData = mxmlNewOpaque(dataNode,"");
545    return NX_OK;
546  } else {
547    newData = (mxml_node_t *)malloc(sizeof(mxml_node_t));
548    if(!newData){
549      NXReportError("Failed to allocate space for dataset");
550      return NX_ERROR;
551    }
552    memset(newData,0,sizeof(mxml_node_t));
553    mxmlAdd(dataNode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, newData);
554    newData->type = MXML_CUSTOM;
555    newData->value.custom.data = createNXDataset(rank,datatype,dimensions);
556    if(!newData->value.custom.data){
557      NXReportError("Failed to allocate space for dataset");
558      return NX_ERROR;
559    }
560    newData->value.custom.destroy = destroyDataset;
561  }
562  return NX_OK;
563}
564/*----------------------------------------------------------------------*/
565static mxml_node_t *searchSDSLinks(pXMLNexus xmlHandle, CONSTCHAR *name){
566  mxml_node_t *linkNode = NULL;
567  mxml_node_t *current;
568  mxml_node_t *test = NULL;
569  const char *linkTarget;
570  const char *linkName = NULL;
571
572  current = xmlHandle->stack[xmlHandle->stackPointer].current;
573  linkNode = current;
574  while((linkNode = mxmlFindElement(linkNode,current,"NAPIlink",NULL,NULL,
575                                    MXML_DESCEND_FIRST)) != NULL){
576    linkTarget = mxmlElementGetAttr(linkNode,"target");
577    test = getLinkTarget(xmlHandle,linkTarget);
578    if(test != NULL){
579      if(strcmp(test->value.element.name,name) == 0){
580        return test;
581      }
582    }
583    /*
584      test for named links
585    */
586    linkName = mxmlElementGetAttr(linkNode,"name");
587    if(test != NULL && linkName != NULL){
588      if(strcmp(linkName,name) == 0){
589        return test;
590      }
591    }
592  }
593  return NULL;
594}
595/*-----------------------------------------------------------------------*/
596NXstatus  NXXopendatatable (NXhandle fid, CONSTCHAR *name){
597  pXMLNexus xmlHandle = NULL;
598  mxml_node_t *dataNode = NULL, *dimsNode = NULL;
599  char error[1024];
600
601  xmlHandle = (pXMLNexus)fid;
602  assert(xmlHandle);
603
604
605  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
606    /*
607      silently fix this
608    */
609    xmlHandle->stackPointer--;
610    if(xmlHandle->stackPointer < 0){
611      xmlHandle->stackPointer = 0;
612    }
613  }
614 
615  dimsNode = mxmlFindElement(xmlHandle->stack[xmlHandle->stackPointer].current,
616                             xmlHandle->stack[xmlHandle->stackPointer].current,
617                             DIMS_NODE_NAME,
618                             NULL,
619                             NULL,
620                             MXML_DESCEND_FIRST);
621
622  if(!dimsNode){
623    snprintf(error,1023,"Failed to open dataset %s",name);
624    NXReportError(error);
625    return NX_ERROR;
626  }
627
628  dataNode = mxmlFindElement(dimsNode,
629                             dimsNode,
630                             name,
631                             NULL,
632                             NULL,
633                             MXML_DESCEND_FIRST);
634  if(dataNode == NULL){
635    dataNode = searchSDSLinks(xmlHandle,name);
636  }
637  if(!dataNode){
638    snprintf(error,1023,"Failed to open dataset %s",name);
639    NXReportError(error);
640    return NX_ERROR;
641  }
642  xmlHandle->stackPointer++;
643  xmlHandle->stack[xmlHandle->stackPointer].current = dataNode;
644  xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL;
645  xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0;
646  xmlHandle->stack[xmlHandle->stackPointer].options = XMLSTACK_OPTION_TABLE;
647  return NX_OK;
648}
649
650
651NXstatus  NXXopendata (NXhandle fid, CONSTCHAR *name){
652  pXMLNexus xmlHandle = NULL;
653  mxml_node_t *dataNode = NULL, *current = NULL;
654  char error[1024];
655
656  xmlHandle = (pXMLNexus)fid;
657  assert(xmlHandle);
658
659  /* is this a table style node ? */
660  current = xmlHandle->stack[xmlHandle->stackPointer].current;
661  dataNode = mxmlFindElement(current,
662                             current,
663                             DATA_NODE_NAME,
664                             NULL,
665                             NULL,
666                             MXML_DESCEND_FIRST);
667  if (dataNode != NULL)
668  {
669      dataNode = mxmlFindElement(dataNode,
670                             dataNode,
671                             name,
672                             NULL,
673                             NULL,
674                             MXML_DESCEND_FIRST);
675  }
676  if (dataNode != NULL)
677  {
678        return NXXopendatatable(fid, name);
679  }
680
681  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
682    /*
683      silently fix this
684    */
685    xmlHandle->stackPointer--;
686    if(xmlHandle->stackPointer < 0){
687      xmlHandle->stackPointer = 0;
688    }
689  }
690 
691  dataNode = mxmlFindElement(xmlHandle->stack[xmlHandle->stackPointer].current,
692                             xmlHandle->stack[xmlHandle->stackPointer].current,
693                             name,
694                             NULL,
695                             NULL,
696                             MXML_DESCEND_FIRST);
697  if(dataNode == NULL){
698    dataNode = searchSDSLinks(xmlHandle,name);
699  }
700  if(!dataNode){
701    snprintf(error,1023,"Failed to open dataset %s",name);
702    NXReportError(error);
703    return NX_ERROR;
704  }
705  xmlHandle->stackPointer++;
706  xmlHandle->stack[xmlHandle->stackPointer].current = dataNode;
707  xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL;
708  xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0;
709  xmlHandle->stack[xmlHandle->stackPointer].options = 0;
710  return NX_OK;
711}
712/*----------------------------------------------------------------------*/
713
714NXstatus  NXXclosedata (NXhandle fid){
715  pXMLNexus xmlHandle = NULL;
716
717  xmlHandle = (pXMLNexus)fid;
718  assert(xmlHandle);
719
720  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
721    if(xmlHandle->stackPointer > 0){
722      xmlHandle->stackPointer--;
723    }
724    return NX_OK;
725  }
726  return NX_OK;
727}
728/*----------------------------------------------------------------------*/
729static mxml_node_t *findData(mxml_node_t *node){
730  mxml_node_t *baby = node;
731 
732  while( (baby = mxmlWalkNext(baby,node,MXML_DESCEND_FIRST)) != NULL){
733    if(baby->type == MXML_OPAQUE || baby->type == MXML_CUSTOM){
734      return baby;
735    }
736  }
737  return NULL;
738}
739
740/* we only havv to deal with non-character data here */
741NXstatus  NXXputdatatable (NXhandle fid, const void *data){
742  pXMLNexus xmlHandle = NULL;
743  mxml_node_t *userData = NULL;
744  mxml_node_t *current = NULL;
745  mxml_node_t *nodeRoot = NULL;
746  mxml_node_t *dataNodeRoot = NULL;
747  mxml_node_t *dataNode = NULL;
748  const char* name;
749  pNXDS dataset;
750  int i, offset, length;
751  xmlHandle = (pXMLNexus)fid;
752  assert(xmlHandle);
753  /* current points at the Idims node as done in NXXopendatatable */
754  current = xmlHandle->stack[xmlHandle->stackPointer].current;
755  name = current->value.element.name;
756  /* we want to walk all Idata nodes and set name */
757  nodeRoot =  current->parent->parent;
758  dataNodeRoot = nodeRoot;
759  offset = 0;
760  for(i=0; dataNodeRoot != NULL; i++)
761  {
762      dataNodeRoot = mxmlFindElement(dataNodeRoot, nodeRoot, DATA_NODE_NAME, NULL, NULL, (i == 0 ? MXML_DESCEND_FIRST : MXML_NO_DESCEND) );
763      if (dataNodeRoot != NULL)
764      {
765        dataNode = mxmlFindElement(dataNodeRoot,dataNodeRoot,name,NULL,NULL,MXML_DESCEND_FIRST);
766        if (dataNode != NULL)
767        {
768            userData = findData(dataNode);
769            assert(userData != NULL);
770            dataset = (pNXDS)userData->value.custom.data;
771            assert(dataset);
772            length = getNXDatasetByteLength(dataset);
773            memcpy(dataset->u.ptr,(char*)data + offset,length);
774            offset += length;
775        }
776      }
777    } 
778    return NX_OK;
779}
780
781/*------------------------------------------------------------------------*/
782NXstatus  NXXputdata (NXhandle fid, const void *data){
783  pXMLNexus xmlHandle = NULL;
784  mxml_node_t *userData = NULL;
785  mxml_node_t *current = NULL;
786  pNXDS dataset;
787  int i, length, type, rank; 
788  int64_t dim[NX_MAXRANK];
789  char *pPtr = NULL;
790
791  xmlHandle = (pXMLNexus)fid;
792  assert(xmlHandle);
793
794  if (xmlHandle->stack[xmlHandle->stackPointer].options & XMLSTACK_OPTION_TABLE)
795  {
796      return NXXputdatatable(fid,data);
797  }
798
799  if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
800    NXReportError("No dataset open");
801    return NX_ERROR;
802  }
803 
804  current = xmlHandle->stack[xmlHandle->stackPointer].current;
805  userData = findData(current);
806  assert(userData != NULL);
807  if(userData->type == MXML_OPAQUE){
808    /*
809      Text data. We have to make sure that the text is \0 terminated.
810      Some language bindings do not ensure that this is the case.
811    */
812    if(NXXgetinfo64(fid,&rank, dim, &type) == NX_OK){
813      length = 1;
814      for(i=0; i<rank; i++)
815      {
816        length *= dim[i];
817      }
818      /* 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 */
819      if (length == 0)
820      {
821        mxmlSetOpaque(userData," ");
822      }
823      else
824      {
825        pPtr = (char *)malloc((length+1)*sizeof(char));
826        if(pPtr != NULL){
827          memcpy(pPtr,data,length);
828          pPtr[length] = '\0';
829          mxmlSetOpaque(userData,(const char *)pPtr);
830          free(pPtr);
831        }
832      }
833    }
834    else
835    {
836        NXReportError("Unable to determine size of character dataset");
837        return NX_ERROR;
838    }
839  } else {
840    dataset = (pNXDS)userData->value.custom.data;
841    assert(dataset);
842    length = getNXDatasetByteLength(dataset);
843    memcpy(dataset->u.ptr,data,length);
844  }
845  return NX_OK;
846}
847
848NXstatus  NXXgetdatatable (NXhandle fid, void *data){
849  pXMLNexus xmlHandle = NULL;
850  mxml_node_t *userData = NULL;
851  mxml_node_t *current = NULL;
852  mxml_node_t *nodeRoot = NULL;
853  mxml_node_t *dataNodeRoot = NULL;
854  mxml_node_t *dataNode = NULL;
855  const char* name;
856  pNXDS dataset;
857  int i, offset, length;
858  xmlHandle = (pXMLNexus)fid;
859  assert(xmlHandle);
860
861  /* current points at the Idims node as done in NXXopendatatable */
862  current = xmlHandle->stack[xmlHandle->stackPointer].current;
863  name = current->value.element.name;
864  /* we want to walk all Idata nodes and set name */
865  nodeRoot =  current->parent->parent;
866  dataNodeRoot = nodeRoot;
867  offset = 0;
868  for(i=0; dataNodeRoot != NULL; i++)
869  {
870      dataNodeRoot = mxmlFindElement(dataNodeRoot, nodeRoot, DATA_NODE_NAME, NULL, NULL, (i == 0 ? MXML_DESCEND_FIRST : MXML_NO_DESCEND) );
871      if (dataNodeRoot != NULL)
872      {
873        dataNode = mxmlFindElement(dataNodeRoot,dataNodeRoot,name,NULL,NULL,MXML_DESCEND_FIRST);
874        if (dataNode != NULL)
875        {
876            userData = findData(dataNode);
877            assert(userData != NULL);
878            dataset = (pNXDS)userData->value.custom.data;
879            assert(dataset);
880            length = getNXDatasetByteLength(dataset);
881            memcpy((char*)data + offset, dataset->u.ptr, length);
882            offset += length;
883        }
884      }
885    } 
886    return NX_OK;
887}
888
889
890/*------------------------------------------------------------------------*/
891NXstatus  NXXgetdata (NXhandle fid, void *data){
892  pXMLNexus xmlHandle = NULL;
893  mxml_node_t *userData = NULL;
894  mxml_node_t *current = NULL;
895  pNXDS dataset;
896  int i, length, type, rank; 
897  int64_t dim[NX_MAXRANK];
898
899  xmlHandle = (pXMLNexus)fid;
900  assert(xmlHandle);
901
902  if (xmlHandle->stack[xmlHandle->stackPointer].options & XMLSTACK_OPTION_TABLE)
903  {
904      return NXXgetdatatable(fid,data);
905  }
906
907  if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
908    NXReportError("No dataset open");
909    return NX_ERROR;
910  }
911 
912  current = xmlHandle->stack[xmlHandle->stackPointer].current;
913  userData = findData(current);
914  assert(userData != NULL);
915  if(userData->type == MXML_OPAQUE){
916    /*
917      text data
918    */
919    if(NXXgetinfo64(fid,&rank, dim, &type) == NX_OK){
920      length = 1;
921      for(i=0; i<rank; i++)
922      {
923          length *= dim[i];
924      }
925      strncpy((char *)data,userData->value.opaque,length);
926    } else {
927      strcpy((char *)data,nxitrim(userData->value.opaque));
928    }
929
930  } else {
931    dataset = (pNXDS)userData->value.custom.data;
932    assert(dataset);
933    length = getNXDatasetByteLength(dataset);
934    memcpy(data,dataset->u.ptr,length);
935  }
936  return NX_OK;
937}
938/*------------------------------------------------------------------------*/
939NXstatus  NXXgetinfo64 (NXhandle fid, int *rank, 
940                                   int64_t dimension[], int *iType){
941  pXMLNexus xmlHandle = NULL;
942  mxml_node_t *userData = NULL;
943  mxml_node_t *current = NULL;
944  pNXDS dataset;
945  int myRank, i;
946  const char *attr = NULL;
947
948  xmlHandle = (pXMLNexus)fid;
949  assert(xmlHandle);
950
951  if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
952    NXReportError("No dataset open");
953    return NX_ERROR;
954  }
955 
956  current = xmlHandle->stack[xmlHandle->stackPointer].current;
957  userData = findData(current);
958  assert(userData != NULL);
959  if(userData->type == MXML_OPAQUE){
960    /*
961      text data
962    */
963    attr = mxmlElementGetAttr(current, TYPENAME);
964    if(attr == NULL){
965      *rank = 1;
966      *iType = NX_CHAR;
967      dimension[0]= strlen(userData->value.opaque);
968    } else {
969      *iType = translateTypeCode(attr);
970      analyzeDim(attr,rank,dimension,iType);
971      if (dimension[0] == -1) /* 1D strings are NX_CHAR not NX_CHAR[] so length will not be correct */
972      {
973        dimension[0] = strlen(userData->value.opaque);
974      }
975     
976    }
977  } else { 
978    dataset = (pNXDS)userData->value.custom.data;
979    assert(dataset);
980    myRank = getNXDatasetRank(dataset);
981    *rank = myRank;
982    *iType = getNXDatasetType(dataset);
983    for(i = 0; i < myRank; i++){
984      dimension[i] = getNXDatasetDim(dataset,i);
985    }
986  }
987  return NX_OK;
988}
989/*---------------------------------------------------------------------
990  clone the dataset and set the data pointer. This in order to use
991  the addressing and type conversion implemented in nxdataset
992---------------------------------------------------------------------*/ 
993static pNXDS makeSlabData(pNXDS dataset, const void *data, const int64_t size[]){
994  pNXDS slabData = NULL;
995  int rank, i;
996 
997  slabData = (pNXDS)malloc(sizeof(NXDS));
998  if(slabData == NULL){
999    return NULL;
1000  }
1001
1002  rank = getNXDatasetRank(dataset);
1003  slabData->rank = rank;
1004  slabData->dim = (int64_t *)malloc(rank*sizeof(int64_t));
1005  for(i = 0; i < rank; i++){
1006    slabData->dim[i] = size[i];
1007  }
1008  slabData->type = getNXDatasetType(dataset);
1009  slabData->u.ptr = (void*)data;
1010  slabData->magic = dataset->magic;
1011  return slabData;
1012} 
1013/*--------------------------------------------------------------------
1014  This goes by recursion
1015----------------------------------------------------------------------*/
1016static void putSlabData(pNXDS dataset, pNXDS slabData, int dim,
1017                        const int64_t start[], 
1018                        int64_t sourcePos[], int64_t targetPos[]){
1019  int64_t i, rank, length;
1020
1021  rank = getNXDatasetRank(slabData);
1022  length = getNXDatasetDim(slabData,dim);
1023  if(dim != rank-1){
1024    for(i = 0; i < length; i++){
1025      targetPos[dim] = start[dim] +i;
1026      sourcePos[dim] = i;
1027      putSlabData(dataset,slabData, dim+1,start,
1028                  sourcePos,targetPos);
1029    }
1030  } else {
1031    for(i = 0; i < length; i++){
1032      targetPos[dim] = start[dim] +i;
1033      sourcePos[dim] = i;
1034      putNXDatasetValue(dataset,targetPos,
1035                        getNXDatasetValue(slabData,sourcePos));
1036    }
1037  }
1038}
1039/*----------------------------------------------------------------------
1040 This is in order to support unlimited dimensions along the first axis
1041 -----------------------------------------------------------------------*/
1042static int checkAndExtendDataset(mxml_node_t *node, pNXDS dataset, 
1043                                 const int64_t start[], const int64_t size[]){
1044  int64_t dim0, byteLength;
1045  void *oldData = NULL;
1046  char *typestring = NULL;
1047
1048  dim0 = start[0] + size[0];
1049  if(dim0 > dataset->dim[0]){
1050    byteLength = getNXDatasetByteLength(dataset);
1051    oldData = dataset->u.ptr;
1052    dataset->dim[0] = dim0;
1053    dataset->u.ptr = malloc(getNXDatasetByteLength(dataset));
1054    if(dataset->u.ptr == NULL){
1055      return 0;
1056    }
1057    memset(dataset->u.ptr,0,getNXDatasetByteLength(dataset));
1058    memcpy(dataset->u.ptr,oldData,byteLength);
1059    free(oldData);
1060    typestring = buildTypeString(dataset->type,dataset->rank,dataset->dim);
1061    if(typestring != NULL){
1062      mxmlElementSetAttr(node,TYPENAME,typestring);
1063      free(typestring);
1064    } else {
1065      NXReportError("Failed to allocate typestring");
1066      return 0;
1067    }
1068  }
1069  return 1;
1070}
1071
1072NXstatus  NXXputslabtable (NXhandle fid, const void *data, 
1073                                   const int64_t iStart[], const int64_t iSize[]){
1074    return NX_OK;
1075}
1076/*----------------------------------------------------------------------*/
1077NXstatus  NXXputslab64 (NXhandle fid, const void *data, 
1078                                   const int64_t iStart[], const int64_t iSize[]){
1079 
1080  pXMLNexus xmlHandle = NULL;
1081  mxml_node_t *userData = NULL;
1082  mxml_node_t *current = NULL;
1083  pNXDS dataset, slabData;
1084  int64_t sourcePos[NX_MAXRANK], targetPos[NX_MAXRANK];
1085  int status;
1086
1087  xmlHandle = (pXMLNexus)fid;
1088  assert(xmlHandle);
1089
1090  if (xmlHandle->stack[xmlHandle->stackPointer].options & XMLSTACK_OPTION_TABLE)
1091  {
1092      return NXXputslabtable(fid,data,iStart,iSize);
1093  }
1094
1095  if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
1096    NXReportError("No dataset open");
1097    return NX_ERROR;
1098  }
1099 
1100  current = xmlHandle->stack[xmlHandle->stackPointer].current;
1101  userData = findData(current);
1102  assert(userData != NULL);
1103  if(userData->type == MXML_OPAQUE){
1104    NXReportError("This API does not support slabs on text data");
1105    return NX_ERROR;
1106  }
1107  dataset = (pNXDS)userData->value.custom.data;
1108  assert(dataset);
1109
1110  status = checkAndExtendDataset(current,dataset,iStart,iSize);
1111  if(status == 0){
1112    NXReportError("Out of memory extending dataset");
1113    return NX_ERROR;
1114  }
1115
1116  slabData = makeSlabData(dataset, data, iSize);
1117  if(slabData == NULL){
1118    NXReportError("Failed to allocate slab data");
1119    return NX_ERROR;
1120  }
1121 
1122
1123  putSlabData(dataset,slabData,0,iStart,sourcePos,targetPos);
1124  free(slabData->dim);
1125  free(slabData);
1126 
1127  return NX_OK;
1128}
1129/*--------------------------------------------------------------------
1130  This goes by recursion
1131----------------------------------------------------------------------*/
1132static void getSlabData(pNXDS dataset, pNXDS slabData, int dim,
1133                        const int64_t start[], 
1134                        int64_t sourcePos[],int64_t targetPos[]){
1135  int64_t i, rank, length;
1136
1137  rank = getNXDatasetRank(slabData);
1138  length = getNXDatasetDim(slabData,dim);
1139  if(dim != rank-1){
1140    for(i = 0; i < length; i++){
1141      sourcePos[dim] = start[dim] +i;
1142      targetPos[dim] = i;
1143      getSlabData(dataset,slabData, dim+1,start,
1144                  sourcePos,targetPos);
1145    }
1146  } else {
1147    for(i = 0; i < length; i++){
1148      sourcePos[dim] = start[dim] +i;
1149      targetPos[dim] = i;
1150      putNXDatasetValue(slabData,targetPos,
1151                        getNXDatasetValue(dataset,sourcePos));
1152    }
1153  }
1154}
1155/*----------------------------------------------------------------------*/
1156NXstatus  NXXgetslab64 (NXhandle fid, void *data, 
1157                                   const int64_t iStart[], const int64_t iSize[]){
1158  pXMLNexus xmlHandle = NULL;
1159  mxml_node_t *userData = NULL;
1160  mxml_node_t *current = NULL;
1161  pNXDS dataset, slabData;
1162  int64_t sourcePos[NX_MAXRANK], targetPos[NX_MAXRANK];
1163
1164  xmlHandle = (pXMLNexus)fid;
1165  assert(xmlHandle);
1166
1167  if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
1168    NXReportError("No dataset open");
1169    return NX_ERROR;
1170  }
1171 
1172  current = xmlHandle->stack[xmlHandle->stackPointer].current;
1173  userData = findData(current);
1174  assert(userData != NULL);
1175  if(userData->type == MXML_OPAQUE){
1176    NXReportError("This API does not support slabs on text data");
1177    return NX_ERROR;
1178  }
1179  dataset = (pNXDS)userData->value.custom.data;
1180  assert(dataset);
1181  slabData = makeSlabData(dataset, data, iSize);
1182  if(slabData == NULL){
1183    NXReportError("Failed to allocate slab data");
1184    return NX_ERROR;
1185  }
1186  getSlabData(dataset,slabData,0,iStart,sourcePos,targetPos);
1187  free(slabData->dim);
1188  free(slabData);
1189 
1190  return NX_OK;
1191}
1192/*----------------------------------------------------------------------*/
1193static NXstatus  NXXsetnumberformat(NXhandle fid,
1194                                                 int type, char *format){
1195  pXMLNexus xmlHandle = NULL;
1196  mxml_node_t *current = NULL;
1197  mxml_node_t *userData = NULL;
1198  pNXDS dataset;
1199 
1200  xmlHandle = (pXMLNexus)fid;
1201  assert(xmlHandle);
1202
1203  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
1204    current = xmlHandle->stack[xmlHandle->stackPointer].current;
1205    userData = findData(current);
1206    assert(userData != NULL);
1207    if(userData->type == MXML_OPAQUE){
1208      return NX_OK;
1209    }
1210    dataset = (pNXDS)userData->value.custom.data;
1211    assert(dataset);
1212    if(dataset->format != NULL){
1213      free(dataset->format);
1214    }
1215    dataset->format = strdup(format);
1216  } else {
1217    setNumberFormat(type, format);
1218  }
1219  return NX_OK;
1220}
1221/*============================ Attributes ============================*/
1222static char *formatAttributeData(const void *data, int datalen, int iType){
1223  int intData = 0;
1224  long iValue = -99999;
1225  double dValue = -1e38;
1226  char type[20];
1227  char *number;
1228
1229
1230  if(iType == NX_CHAR){
1231/* data may not be NULL terminated */
1232    number = (char*)malloc((datalen+1) * sizeof(char));
1233    memcpy(number, data, datalen * sizeof(char));
1234    number[datalen] = '\0';
1235    return number;
1236  }
1237
1238  number = (char *)malloc(132*sizeof(char));
1239  if(!number){
1240    NXReportError("Failed to allocate attribute number buffer");
1241    return NULL;
1242  }
1243 
1244  if(datalen > 1){
1245    return NULL;
1246  }
1247  type[0] = '\0';
1248  switch(iType){
1249  case NX_INT32:
1250    iValue = ((int *)data)[0];
1251    intData = 1;
1252    strcpy(type,"NX_INT32:");
1253    break;
1254  case NX_UINT32:
1255    iValue = ((unsigned int *)data)[0];
1256    intData = 1;
1257    strcpy(type,"NX_UINT32:");
1258    break;
1259  case NX_INT16:
1260    iValue = ((short *)data)[0];
1261    intData = 1;
1262    strcpy(type,"NX_INT16:");
1263    break;
1264  case NX_UINT16:
1265    iValue = ((unsigned short *)data)[0];
1266    intData = 1;
1267    strcpy(type,"NX_UINT16:");
1268    break;
1269  case NX_INT8:
1270    iValue = (int)((char *)data)[0];
1271    intData = 1;
1272    strcpy(type,"NX_INT8:");
1273    break;
1274  case NX_UINT8:
1275    intData = 1;
1276    iValue = (int)((unsigned char *)data)[0];
1277    strcpy(type,"NX_UINT8:");
1278    break;
1279  case NX_FLOAT32:
1280    dValue = ((float *)data)[0];
1281    strcpy(type,"NX_FLOAT32:");
1282    intData = 0;
1283    break;
1284  case NX_FLOAT64:
1285    dValue = ((double *)data)[0];
1286    strcpy(type,"NX_FLOAT64:");
1287    intData = 0;
1288    break;
1289  }
1290  if(intData){
1291    snprintf(number,79,"%s%ld",type,iValue);
1292  } else {
1293    snprintf(number,79,"%s%f",type,dValue);
1294  }
1295  return number;
1296}
1297/*---------------------------------------------------------------------*/
1298NXstatus  NXXputattr (NXhandle fid, CONSTCHAR *name, const void *data, 
1299                                   int datalen, int iType){
1300  char buffer[256];
1301  pXMLNexus xmlHandle = NULL;
1302  mxml_node_t *current = NULL;
1303  char *numberData = NULL;
1304
1305  xmlHandle = (pXMLNexus)fid;
1306  assert(xmlHandle);
1307  if (!validNXName(name, 1))
1308  {
1309    sprintf(buffer, "ERROR: invalid characters in attribute name \"%s\"", name);
1310    NXReportError(buffer);
1311    return NX_ERROR;
1312  }
1313
1314  current = xmlHandle->stack[xmlHandle->stackPointer].current;
1315  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
1316    if(strcmp(name,TYPENAME) == 0){
1317      NXReportError("type is a reserved attribute name, rejected");
1318      return  NX_ERROR;
1319    }
1320  }
1321
1322  numberData = formatAttributeData(data,datalen,iType);
1323  if(numberData == NULL){
1324    NXReportError("This API does not support non number arrays");
1325    return NX_ERROR;
1326  } else {
1327    mxmlElementSetAttr(current,name,numberData);
1328    free(numberData);
1329  }
1330  return NX_OK;
1331}
1332/*--------------------------------------------------------------------------*/
1333NXstatus  NXXgetattr (NXhandle fid, char *name, 
1334                                   void *data, int* datalen, int* iType){
1335  pXMLNexus xmlHandle = NULL;
1336  mxml_node_t *current = NULL;
1337  const char *attribute = NULL;
1338  char error[1024];
1339  const char *attData = NULL;
1340  int nx_type;
1341
1342  xmlHandle = (pXMLNexus)fid;
1343  assert(xmlHandle);
1344
1345  current = xmlHandle->stack[xmlHandle->stackPointer].current;
1346
1347  attribute = mxmlElementGetAttr(current,name);
1348  if(!attribute){
1349    snprintf(error,1023,"Attribute %s not found", name);
1350    NXReportError(error);
1351    return NX_ERROR;
1352  }
1353  nx_type = translateTypeCode((char *)attribute);
1354  if(nx_type < 0) {
1355    /*
1356      no type code == text attribute
1357    */
1358    nx_type = NX_CHAR;
1359  } else {
1360    /*
1361      We need to find the number after the type code. However, there is
1362      the complication of the datatype type attribute ...
1363    */
1364    if(strcmp(name,TYPENAME) == 0){
1365      nx_type = NX_CHAR;
1366    } else {
1367      attData = strchr(attribute,(int)':');
1368      if(attData == NULL){
1369        NXReportError("ERROR: bad attribute string, : missing");
1370        return NX_ERROR;
1371      }
1372      attData++;
1373    }
1374  }
1375  *iType = nx_type;
1376  switch(nx_type){
1377  case NX_CHAR:
1378    /* enforce NULL termination regardless of length of datalen */
1379    strncpy((char *)data, attribute, *datalen-1);
1380    ((char*)data)[*datalen-1] = '\0';
1381    /* *datalen = strlen(attribute); */
1382    *datalen = strlen((char*)data);
1383    *iType = NX_CHAR;
1384    break;
1385  case NX_INT32:
1386    ((int *)data)[0] = atoi(attData);
1387    *datalen = 1;
1388    break;
1389  case NX_UINT32:
1390    ((unsigned int *)data)[0] = atoi(attData);
1391    *datalen = 1;
1392    break;
1393  case NX_INT16:
1394    ((short *)data)[0] = atoi(attData);
1395    *datalen = 1;
1396    break;
1397  case NX_UINT16:
1398    ((unsigned short *)data)[0] = atoi(attData);
1399    *datalen = 1;
1400    break;
1401  case NX_INT8:
1402    ((char *)data)[0] = atoi(attData);
1403    *datalen = 1;
1404    break;
1405  case NX_UINT8:
1406    ((unsigned char *)data)[0] = atoi(attData);
1407    *datalen = 1;
1408    break;
1409  case NX_FLOAT32:
1410    ((float *)data)[0] = atof(attData);
1411    *datalen = 1;
1412    break;
1413  case NX_FLOAT64:
1414    ((double *)data)[0] = atof(attData);
1415    *datalen = 1;
1416    break;
1417  }
1418
1419  return NX_OK;
1420}
1421
1422/* find the next node, ignoring Idata */
1423static mxml_node_t* find_node(mxml_node_t* node, int next)
1424{
1425  int done = 0;
1426  mxml_node_t* parent_next = NULL; /* parent to use if we are in an Idims  search */
1427   if (node == NULL)
1428   {
1429        return NULL;
1430   }
1431   if ( (node->parent != NULL)  && !strcmp(node->parent->value.element.name, DIMS_NODE_NAME) )
1432   {
1433        parent_next = node->parent->next;
1434   }
1435   else
1436   {
1437        parent_next = NULL;
1438   }
1439   if (next)
1440   {
1441       if (node->next != NULL)
1442       {
1443            node = node->next;
1444       }
1445       else
1446       {
1447            node = parent_next;
1448       }
1449   }
1450   while(node != NULL && !done)
1451   {
1452     if ( (node->parent != NULL)  && !strcmp(node->parent->value.element.name, DIMS_NODE_NAME) )
1453     {
1454        parent_next = node->parent->next;
1455     }
1456     else
1457     {
1458        parent_next = NULL;
1459     }
1460     if ( (node->type != MXML_ELEMENT) || !strcmp(node->value.element.name, DATA_NODE_NAME) )
1461     {
1462        if (node->next != NULL)
1463        {
1464            node = node->next;
1465        }
1466        else
1467        {
1468            node = parent_next;
1469        }
1470        continue;
1471     }
1472     if (!strcmp(node->value.element.name, DIMS_NODE_NAME))
1473     {
1474        node = node->child;
1475        continue;
1476     }
1477     done = 1;
1478  }
1479  return node;
1480}
1481
1482/*====================== search functions =================================*/
1483NXstatus  NXXgetnextentry (NXhandle fid,NXname name, 
1484                                        NXname nxclass, int *datatype){
1485  pXMLNexus xmlHandle = NULL;
1486  mxml_node_t *next = NULL, *userData, *node = NULL;
1487  int stackPtr;
1488  const char *target = NULL, *attname = NULL;
1489  pNXDS dataset;
1490  char pBueffel[256];
1491  const char *linkName = NULL;
1492
1493  xmlHandle = (pXMLNexus)fid;
1494  assert(xmlHandle);
1495
1496  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
1497    /*
1498      be nice to user: silently fix this problem
1499    */
1500    NXXclosedata(fid);
1501  }
1502
1503  stackPtr = xmlHandle->stackPointer;
1504  if(xmlHandle->stack[stackPtr].currentChild == NULL){
1505    /*
1506      initialization of search
1507    */
1508      node = find_node(xmlHandle->stack[stackPtr].current->child, 0);
1509  } else {
1510    /*
1511      proceed
1512    */
1513    node = find_node(xmlHandle->stack[stackPtr].currentChild, 1);
1514  }
1515  xmlHandle->stack[stackPtr].currentChild = node;
1516  next = node;
1517  if(next == NULL){
1518    return NX_EOD;
1519  }
1520  if(strcmp(next->value.element.name,"NAPIlink") == 0){
1521    target = mxmlElementGetAttr(next,"target");
1522    linkName = mxmlElementGetAttr(next,"name");
1523    if(target == NULL){
1524      NXReportError("Corrupted file, NAPIlink without target");
1525      return NX_ERROR;
1526    }
1527    next = getLinkTarget(xmlHandle,target);
1528    if(next == NULL){
1529      NXReportError("Corrupted file, broken link");
1530      return NX_ERROR;
1531    }
1532  }
1533
1534  if(isDataNode(next)){
1535    strcpy(name,next->value.element.name);
1536    strcpy(nxclass,"SDS");
1537    userData = findData(next);
1538    if(userData == NULL){
1539        snprintf(pBueffel,255,"Corrupted file, userData for %s not found",
1540                 name);
1541      NXReportError(pBueffel);
1542      return NX_ERROR;
1543    }
1544    if(userData->type == MXML_OPAQUE){
1545      *datatype = NX_CHAR;
1546    } else {
1547      dataset = (pNXDS)userData->value.custom.data;
1548      assert(dataset);
1549      *datatype = getNXDatasetType(dataset);
1550    }
1551  } else {
1552    strcpy(nxclass,next->value.element.name);
1553    attname = mxmlElementGetAttr(next,"name");
1554    strcpy(name,attname);
1555  }
1556  /*
1557    this is for named links
1558  */
1559  if(linkName != NULL){
1560    strcpy(name,linkName);
1561  }
1562  return NX_OK;
1563}
1564/*----------------------------------------------------------------------*/
1565extern  NXstatus NXXinitgroupdir(NXhandle fid){
1566  pXMLNexus xmlHandle = NULL;
1567  int stackPtr;
1568
1569  xmlHandle = (pXMLNexus)fid;
1570  assert(xmlHandle);
1571
1572  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
1573    NXReportError("Cannot search datasets");
1574    return NX_ERROR;
1575  }
1576
1577  stackPtr = xmlHandle->stackPointer;
1578  xmlHandle->stack[stackPtr].currentChild = NULL;
1579  return NX_OK;
1580}
1581/*-------------------------------------------------------------------------*/
1582NXstatus  NXXgetnextattr (NXhandle fid, NXname pName,
1583                                          int *iLength, int *iType){
1584  pXMLNexus xmlHandle = NULL;
1585  mxml_node_t *current = NULL;
1586  int stackPtr, currentAtt, nx_type;
1587  char *attVal; 
1588
1589  xmlHandle = (pXMLNexus)fid;
1590  assert(xmlHandle);
1591
1592  stackPtr = xmlHandle->stackPointer;
1593
1594  current = xmlHandle->stack[stackPtr].current;
1595  currentAtt = xmlHandle->stack[stackPtr].currentAttribute;
1596  if(currentAtt >= 
1597     current->value.element.num_attrs ){
1598    xmlHandle->stack[stackPtr].currentAttribute = 0;
1599    return NX_EOD;
1600  }
1601
1602  /*
1603    hide group name attribute
1604  */
1605  if(strcmp(current->value.element.attrs[currentAtt].name,"name") == 0
1606     && !isDataNode(current) ){
1607    xmlHandle->stack[stackPtr].currentAttribute++;
1608    return NXXgetnextattr(fid,pName,iLength,iType);
1609  }
1610
1611  /*
1612    hide type attribute
1613  */
1614  if(strcmp(current->value.element.attrs[currentAtt].name,TYPENAME) == 0
1615     && isDataNode(current)){
1616    xmlHandle->stack[stackPtr].currentAttribute++;
1617    return NXXgetnextattr(fid,pName,iLength,iType);
1618  }
1619
1620  strcpy(pName,current->value.element.attrs[currentAtt].name);
1621  attVal = current->value.element.attrs[currentAtt].value;
1622  nx_type = translateTypeCode((char *)attVal);
1623  if(nx_type < 0 || strcmp(pName,TYPENAME) == 0){
1624    /*
1625      no type == NX_CHAR
1626    */
1627    *iLength = strlen(attVal);
1628    *iType = NX_CHAR;
1629  } else {
1630    *iLength = 1;
1631    *iType = nx_type;
1632  }
1633
1634  xmlHandle->stack[stackPtr].currentAttribute++;
1635  return NX_OK;
1636}
1637/*-------------------------------------------------------------------------*/
1638extern  NXstatus  NXXinitattrdir(NXhandle fid){
1639  pXMLNexus xmlHandle = NULL;
1640  int stackPtr;
1641
1642  xmlHandle = (pXMLNexus)fid;
1643  assert(xmlHandle);
1644
1645  stackPtr = xmlHandle->stackPointer;
1646  xmlHandle->stack[stackPtr].currentAttribute = 0;
1647  return NX_OK;
1648}
1649/*-------------------------------------------------------------------------*/
1650NXstatus  NXXgetgroupinfo (NXhandle fid, int *iN, 
1651                                        NXname pName, NXname pClass){
1652  pXMLNexus xmlHandle = NULL;
1653  mxml_node_t *node = NULL, *child = NULL;
1654  mxml_node_t *current = NULL;
1655  const char *nameAtt = NULL;
1656  int childCount;
1657
1658  xmlHandle = (pXMLNexus)fid;
1659  assert(xmlHandle);
1660
1661  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
1662    NXReportError("No group open");
1663    return NX_ERROR;
1664  } 
1665  current = xmlHandle->stack[xmlHandle->stackPointer].current;
1666
1667  nameAtt = mxmlElementGetAttr(current,"name");
1668  if(nameAtt !=  NULL){
1669    strcpy(pName,nameAtt);
1670  }
1671  strcpy(pClass,current->value.element.name);
1672
1673/* count all child nodes, but need to ignore DATA_NODE_NAME and
1674 * descend into DIMS_NODE_NAME
1675 */
1676  childCount = 0;
1677  node = current->child;
1678  while(node != NULL)
1679  {
1680        if (!strcmp(node->value.element.name, DATA_NODE_NAME))
1681        {
1682            ;   /* names also exist in DIMS_NODE_NAME so do nothing here */
1683        }
1684        else if (!strcmp(node->value.element.name, DIMS_NODE_NAME))
1685        {
1686            child = node->child;
1687            while(child != NULL)
1688            {
1689                /* not sure why this check is needed, but you double count otherwise */
1690                if (child->type == MXML_ELEMENT) 
1691                {
1692                    childCount++;
1693                }
1694                child = child->next;
1695            }
1696        }
1697        else
1698        {
1699            childCount++;
1700        }
1701        node = node->next;
1702  }
1703  *iN = childCount;
1704  return NX_OK;
1705}
1706/*----------------------------------------------------------------------*/
1707NXstatus  NXXgetattrinfo (NXhandle fid, int *iN){
1708  pXMLNexus xmlHandle = NULL;
1709  mxml_node_t *current = NULL;
1710  int stackPtr, skip;
1711
1712  xmlHandle = (pXMLNexus)fid;
1713  assert(xmlHandle);
1714
1715  stackPtr = xmlHandle->stackPointer;
1716
1717  current = xmlHandle->stack[stackPtr].current;
1718
1719  /*
1720    hide type and group name attributes
1721  */
1722  skip=0;
1723  if(isDataNode(current)) {
1724    /* data nodes may have type */
1725    if(mxmlElementGetAttr(current,TYPENAME) != NULL) skip=1;
1726  } else {
1727    /* group nodes (except root) have name */
1728    if(mxmlElementGetAttr(current,"name") != NULL) skip=1;
1729  }
1730  *iN = current->value.element.num_attrs - skip;
1731  return NX_OK;
1732}
1733/*================= Linking functions =================================*/
1734static int countPathChars(mxml_node_t *path[], int stackPtr){
1735  int count = 1;
1736  const char *name = NULL;
1737
1738  while(stackPtr >= 0) {
1739    if(isDataNode(path[stackPtr])){
1740      count += strlen(path[stackPtr]->value.element.name);
1741    } else {
1742      name = mxmlElementGetAttr(path[stackPtr],"name");
1743      if(name != NULL){
1744        count += strlen(name);
1745      }
1746    }
1747    stackPtr--;
1748    count += 1;
1749  }
1750  return count;
1751}
1752/*-------------------------------------------------------------------*/
1753static char *buildPathString(mxml_node_t *path[], int stackPtr){
1754  int count = 0;
1755  const char *name = NULL;
1756  char *pathString = NULL;
1757
1758  count = countPathChars(path,stackPtr);
1759  pathString = (char *)malloc((count+10)*sizeof(char));
1760  if(pathString == NULL){
1761    return NULL;
1762  }
1763  memset(pathString,0,(count+10)*sizeof(char));
1764
1765  while(stackPtr >= 0) {
1766    if(isDataNode(path[stackPtr])){
1767      strcat(pathString,"/");
1768      strcat(pathString,path[stackPtr]->value.element.name);
1769    } else {
1770      name = mxmlElementGetAttr(path[stackPtr],"name");
1771      if(name != NULL){
1772        strcat(pathString,"/");
1773        strcat(pathString,name);
1774      }
1775    }
1776    stackPtr--;
1777  }
1778  return pathString;
1779}
1780/*--------------------------------------------------------------------*/
1781static char *findLinkPath(mxml_node_t *node){
1782  mxml_node_t **path = NULL;
1783  int stackPtr;
1784  mxml_node_t *current = NULL;
1785  char *result = NULL;
1786
1787  path = (mxml_node_t **)malloc(NXMAXSTACK*sizeof(mxml_node_t *));
1788  if(path == NULL){
1789    NXReportError("ERROR: out of memory following link path");
1790    return NULL;
1791  }
1792  memset(path,0,NXMAXSTACK*sizeof(mxml_node_t *));
1793
1794  /*
1795    first path:  walk up the tree untill NXroot is found
1796  */
1797  current = node;
1798  stackPtr = 0;
1799  while(current != NULL && 
1800        strcmp(current->value.element.name,"NXroot") != 0){
1801    path[stackPtr] = current;
1802    stackPtr++;
1803    current = current->parent;
1804  }
1805  stackPtr--;
1806
1807  /*
1808    path now contains the nodes to the root node in reverse order.
1809    From this build the path string
1810  */
1811  result = buildPathString(path,stackPtr);
1812  free(path);
1813  return result;
1814}
1815/*--------------------------------------------------------------------*/
1816NXstatus  NXXgetdataID (NXhandle fid, NXlink* sRes){
1817  pXMLNexus xmlHandle = NULL;
1818  mxml_node_t *current = NULL;
1819  char *linkPath = NULL;
1820
1821  xmlHandle = (pXMLNexus)fid;
1822  assert(xmlHandle);
1823
1824  if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
1825    return NX_ERROR;
1826  } 
1827  current = xmlHandle->stack[xmlHandle->stackPointer].current;
1828 
1829  linkPath = findLinkPath(current);
1830  if(!linkPath){
1831    NXReportError("Failed to allocate link path string");
1832    return NX_ERROR;
1833  }
1834  strncpy(sRes->targetPath,linkPath,1023);
1835  free(linkPath);
1836  return NX_OK;
1837}
1838/*--------------------------------------------------------------------*/
1839NXstatus  NXXgetgroupID (NXhandle fid, NXlink* sRes){
1840  pXMLNexus xmlHandle = NULL;
1841  mxml_node_t *current = NULL;
1842  char *linkPath = NULL;
1843
1844  xmlHandle = (pXMLNexus)fid;
1845  assert(xmlHandle);
1846
1847  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
1848    NXReportError("No group open");
1849    return NX_ERROR;
1850  } 
1851  current = xmlHandle->stack[xmlHandle->stackPointer].current;
1852
1853  if(xmlHandle->stackPointer == 0){
1854    return NX_ERROR;
1855  }
1856
1857  linkPath = findLinkPath(current);
1858  if(!linkPath){
1859    NXReportError("Failed to allocate link path string");
1860    return NX_ERROR;
1861  }
1862  strncpy(sRes->targetPath,linkPath,1023);
1863  free(linkPath);
1864  return NX_OK;
1865}
1866
1867/*-----------------------------------------------------------------------*/
1868  NXstatus  NXXprintlink (NXhandle fid, NXlink* sLink)
1869  {
1870    pXMLNexus xmlHandle = NULL;
1871    xmlHandle = (pXMLNexus)fid;
1872    assert(xmlHandle);
1873
1874    printf("XML link: target=\"%s\"\n", sLink->targetPath);
1875    return NX_OK;
1876  }
1877 
1878/*-----------------------------------------------------------------------*/
1879NXstatus  NXXmakelink (NXhandle fid, NXlink* sLink){
1880  pXMLNexus xmlHandle = NULL;
1881  mxml_node_t *current = NULL, *linkNode = NULL;
1882  mxml_node_t *linkedNode = NULL;
1883
1884  xmlHandle = (pXMLNexus)fid;
1885  assert(xmlHandle);
1886
1887  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
1888    NXReportError("No group to link to open");
1889    return NX_ERROR;
1890  } 
1891  current = xmlHandle->stack[xmlHandle->stackPointer].current;
1892  linkNode = mxmlNewElement(current,"NAPIlink");
1893  if(!linkNode){
1894    NXReportError("Failed to allocate new link element");
1895    return NX_ERROR;
1896  }
1897  mxmlElementSetAttr(linkNode,"target",sLink->targetPath);
1898  linkedNode = getLinkTarget(xmlHandle,sLink->targetPath);
1899  if(linkedNode != NULL){
1900    mxmlElementSetAttr(linkedNode,"target",sLink->targetPath);
1901  }
1902  return NX_OK;
1903}
1904 
1905/*-----------------------------------------------------------------------*/
1906NXstatus  NXXmakenamedlink (NXhandle fid, CONSTCHAR *name, NXlink* sLink){
1907  pXMLNexus xmlHandle = NULL;
1908  mxml_node_t *current = NULL, *linkNode = NULL;
1909  mxml_node_t *linkedNode = NULL;
1910  char buffer[256];
1911
1912  xmlHandle = (pXMLNexus)fid;
1913  assert(xmlHandle);
1914  if (!validNXName(name, 0))
1915  {
1916    sprintf(buffer, "ERROR: invalid characters in link name \"%s\"", name);
1917    NXReportError(buffer);
1918    return NX_ERROR;
1919  }
1920
1921  if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
1922    NXReportError("No group to link to open");
1923    return NX_ERROR;
1924  } 
1925  current = xmlHandle->stack[xmlHandle->stackPointer].current;
1926  linkNode = mxmlNewElement(current,"NAPIlink");
1927  if(!linkNode){
1928    NXReportError("Failed to allocate new link element");
1929    return NX_ERROR;
1930  }
1931  mxmlElementSetAttr(linkNode,"target",sLink->targetPath);
1932  mxmlElementSetAttr(linkNode,"name",name);
1933  linkedNode = getLinkTarget(xmlHandle,sLink->targetPath);
1934  if(linkedNode != NULL){
1935    mxmlElementSetAttr(linkedNode,"target",sLink->targetPath);
1936  }
1937  return NX_OK;
1938}
1939/*----------------------------------------------------------------------*/
1940NXstatus  NXXsameID (NXhandle fileid, NXlink* pFirstID, 
1941                                  NXlink* pSecondID){
1942  if(strcmp(pFirstID->targetPath,pSecondID->targetPath) == 0) {
1943    return NX_OK;
1944  } else {
1945    return NX_ERROR;
1946  }
1947}
1948/*--------------------------------------------------------------------*/
1949int  NXXcompress(NXhandle fid, int comp){
1950  /* that will throw an exception in the Java API, errors have to be fatal */
1951  /* NXReportError("NXcompress is deprecated, IGNORED"); */
1952  return NX_OK;
1953}
1954/*----------------------------------------------------------------------*/
1955void NXXassignFunctions(pNexusFunction fHandle){
1956      fHandle->nxclose=NXXclose;
1957          fHandle->nxreopen=NULL;
1958      fHandle->nxflush=NXXflush;
1959      fHandle->nxmakegroup=NXXmakegroup;
1960      fHandle->nxopengroup=NXXopengroup;
1961      fHandle->nxclosegroup=NXXclosegroup;
1962      fHandle->nxmakedata64=NXXmakedata64;
1963      fHandle->nxcompmakedata64=NXXcompmakedata64;
1964      fHandle->nxcompress=NXXcompress;
1965      fHandle->nxopendata=NXXopendata;
1966      fHandle->nxclosedata=NXXclosedata;
1967      fHandle->nxputdata=NXXputdata;
1968      fHandle->nxputattr=NXXputattr;
1969      fHandle->nxputslab64=NXXputslab64;   
1970      fHandle->nxgetdataID=NXXgetdataID;
1971      fHandle->nxmakelink=NXXmakelink;
1972      fHandle->nxmakenamedlink=NXXmakenamedlink;
1973      fHandle->nxgetdata=NXXgetdata;
1974      fHandle->nxgetinfo64=NXXgetinfo64;
1975      fHandle->nxgetnextentry=NXXgetnextentry;
1976      fHandle->nxgetslab64=NXXgetslab64;
1977      fHandle->nxgetnextattr=NXXgetnextattr;
1978      fHandle->nxgetattr=NXXgetattr;
1979      fHandle->nxgetattrinfo=NXXgetattrinfo;
1980      fHandle->nxgetgroupID=NXXgetgroupID;
1981      fHandle->nxgetgroupinfo=NXXgetgroupinfo;
1982      fHandle->nxsameID=NXXsameID;
1983      fHandle->nxinitgroupdir=NXXinitgroupdir;
1984      fHandle->nxinitattrdir=NXXinitattrdir;
1985      fHandle->nxsetnumberformat=NXXsetnumberformat;
1986      fHandle->nxprintlink=NXXprintlink;
1987      fHandle->nxnativeexternallink=NULL;
1988}
1989
1990
1991
1992#endif /*NXXML*/
Note: See TracBrowser for help on using the repository browser.