NeXus  4.4.3
 All Data Structures Files Functions Variables Typedefs Macros Pages
nxio.c
Go to the documentation of this file.
1 
27 #include <nxconfig.h>
28 
29 #ifdef WITH_MXML
30 
31 #include <mxml.h>
32 #include <assert.h>
33 #include "napi.h"
34 #include "nxio.h"
35 #include "nxdataset.h"
36 #include "napiconfig.h"
37 
38 /* fix for mxml-2.3 */
39 #ifndef MXML_WRAP
40 #define MXML_WRAP 79
41 #endif
42 
43 #ifdef _MSC_VER
44 #define snprintf _snprintf
45 #endif /* _MSC_VER */
46 
47 /* #define TESTMAIN 1 */
48 /*=================== type code handling ================================= */
49 typedef struct {
50  char name[30];
51  char format[30];
52  int nx_type;
53 }type_code;
54 
55 #define NTYPECODE 11
56 static type_code typecode[NTYPECODE];
57 /*-----------------------------------------------------------------------*/
59  type_code myCode;
60 
61  strcpy(myCode.name,"NX_FLOAT32");
62  strcpy(myCode.format,"%12.4f");
63  myCode.nx_type = NX_FLOAT32;
64  typecode[0] = myCode;
65 
66  strcpy(myCode.name,"NX_FLOAT64");
67  strcpy(myCode.format,"%16.5f");
68  myCode.nx_type = NX_FLOAT64;
69  typecode[1] = myCode;
70 
71  strcpy(myCode.name,"NX_INT8");
72  strcpy(myCode.format,"%5d");
73  myCode.nx_type = NX_INT8;
74  typecode[2] = myCode;
75 
76  strcpy(myCode.name,"NX_UINT8");
77  strcpy(myCode.format,"%5d");
78  myCode.nx_type = NX_UINT8;
79  typecode[3] = myCode;
80 
81  strcpy(myCode.name,"NX_INT16");
82  strcpy(myCode.format,"%8d");
83  myCode.nx_type = NX_INT16;
84  typecode[4] = myCode;
85 
86  strcpy(myCode.name,"NX_UINT16");
87  strcpy(myCode.format,"%8d");
88  myCode.nx_type = NX_UINT16;
89  typecode[5] = myCode;
90 
91  strcpy(myCode.name,"NX_INT32");
92  strcpy(myCode.format,"%12d");
93  myCode.nx_type = NX_INT32;
94  typecode[6] = myCode;
95 
96  strcpy(myCode.name,"NX_UINT32");
97  strcpy(myCode.format,"%12d");
98  myCode.nx_type = NX_UINT32;
99  typecode[7] = myCode;
100 
101  strcpy(myCode.name,"NX_INT64");
102  strcpy(myCode.format,"%24lld");
103  myCode.nx_type = NX_INT64;
104  typecode[8] = myCode;
105 
106  strcpy(myCode.name,"NX_UINT64");
107  strcpy(myCode.format,"%24llu");
108  myCode.nx_type = NX_UINT64;
109  typecode[9] = myCode;
110 
111  strcpy(myCode.name,"NX_CHAR");
112  strcpy(myCode.format,"%c");
113  myCode.nx_type = NX_CHAR;
114  typecode[10] = myCode;
115 }
116 /*----------------------------------------------------------------------*/
117 void setNumberFormat(int nx_type, char *format){
118  int i;
119 
120  for(i = 0; i < NTYPECODE; i++){
121  if(typecode[i].nx_type == nx_type){
122  strncpy(typecode[i].format,format,29);
123  }
124  }
125 }
126 /*------------------------------------------------------------------*/
127 static void getNumberFormat(int nx_type, char format[30]){
128  int i;
129 
130  for(i = 0; i < NTYPECODE; i++){
131  if(typecode[i].nx_type == nx_type){
132  strncpy(format,typecode[i].format,29);
133  }
134  }
135 }
136 /*----------------------------------------------------------------*/
137 void getNumberText(int nx_type, char *typestring, int typeLen){
138  int i;
139 
140  for(i = 0; i < NTYPECODE; i++){
141  if(typecode[i].nx_type == nx_type){
142  strncpy(typestring,typecode[i].name,typeLen);
143  }
144  }
145 }
146 /*
147  * 'mxml_add_char()' - Add a character to a buffer, expanding as needed.
148  * copied here from mxml-file.c to achieve compatibility with mxml-2.1
149  * standard
150  */
151 
152 static int /* O - 0 on success, -1 on error */
153 myxml_add_char(int ch, /* I - Character to add */
154  char **bufptr, /* IO - Current position in buffer */
155  char **buffer, /* IO - Current buffer */
156  size_t *bufsize) /* IO - Current buffer size */
157 {
158  char *newbuffer; /* New buffer value */
159 
160 
161  if (*bufptr >= (*buffer + *bufsize - 4))
162  {
163  /*
164  * Increase the size of the buffer...
165  */
166 
167  if (*bufsize < 1024)
168  {
169  (*bufsize) *= 2;
170  }
171  else
172  {
173  (*bufsize) *= 3;
174  (*bufsize) /= 2;
175  }
176 
177  newbuffer = (char *)malloc(*bufsize*sizeof(char));
178  if(!newbuffer){
179  free(*buffer);
180 
181  mxml_error("Unable to expand string buffer to %d bytes!", *bufsize);
182 
183  return (-1);
184  }
185  memset(newbuffer,0,*bufsize*sizeof(char));
186  memcpy(newbuffer,*buffer,*bufptr - *buffer);
187  free(*buffer);
188 
189  *bufptr = newbuffer + (*bufptr - *buffer);
190  *buffer = newbuffer;
191  }
192 
193  if (ch < 128)
194  {
195  /*
196  * Single byte ASCII...
197  */
198 
199  *(*bufptr)++ = ch;
200  }
201  else if (ch < 2048)
202  {
203  /*
204  * Two-byte UTF-8...
205  */
206 
207  *(*bufptr)++ = 0xc0 | (ch >> 6);
208  *(*bufptr)++ = 0x80 | (ch & 0x3f);
209  }
210  else if (ch < 65536)
211  {
212  /*
213  * Three-byte UTF-8...
214  */
215 
216  *(*bufptr)++ = 0xe0 | (ch >> 12);
217  *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
218  *(*bufptr)++ = 0x80 | (ch & 0x3f);
219  }
220  else
221  {
222  /*
223  * Four-byte UTF-8...
224  */
225 
226  *(*bufptr)++ = 0xf0 | (ch >> 18);
227  *(*bufptr)++ = 0x80 | ((ch >> 12) & 0x3f);
228  *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
229  *(*bufptr)++ = 0x80 | (ch & 0x3f);
230  }
231 
232  return (0);
233 }
234 /*------------------------------------------------------------------*/
235 extern char *stptok(char *s, char *tok, size_t toklen, char *brk);
236 /*=====================================================================
237  actual stuff for implementing the callback functions
238  =====================================================================*/
239 
240 /*
241  * if passed NX_CHAR, then returns dimension of -1 and the caller
242  * needs to do a strlen() or equivalent
243  */
244 void analyzeDim(const char *typeString, int *rank,
245  int64_t *iDim, int *type){
246  char dimString[132];
247  char dim[20];
248  const char *dimStart, *dimEnd;
249  char* dimTemp;
250  int myRank;
251 
252  if(strchr(typeString,(int)'[') == NULL){
253  *rank = 1;
254  switch(*type){
255  case NX_INT8:
256  case NX_UINT8:
257  case NX_INT16:
258  case NX_UINT16:
259  case NX_INT32:
260  case NX_UINT32:
261  case NX_INT64:
262  case NX_UINT64:
263  case NX_FLOAT32:
264  case NX_FLOAT64:
265  iDim[0] = 1;
266  break;
267  case NX_CHAR:
268  iDim[0] = -1; /* length unknown, caller needs to determine later */
269  break;
270  default:
271  mxml_error("ERROR: (analyzeDim) unknown type code %d for typeString %s", *type, typeString);
272  break;
273  }
274  } else {
275  /*
276  we have to determine rank and the dims.
277  Start by extracting the dimension string.
278  */
279  dimStart = strchr(typeString,(int)'[') + 1;
280  dimEnd = strchr(typeString,(int)']');
281  if(!dimStart || !dimEnd) {
282  mxml_error("ERROR: malformed dimension string in %s",typeString);
283  return;
284  }
285  if((dimEnd - dimStart) > 131){
286  mxml_error("ERROR: run away dimension definition in %s",typeString);
287  return;
288  }
289  memset(dimString,0,132);
290  memcpy(dimString,dimStart,(dimEnd-dimStart)*sizeof(char));
291  dimTemp = stptok(dimString,dim,19,",");
292  myRank = 0;
293  while(dimTemp != NULL){
294  iDim[myRank] = atoi(dim);
295  dimTemp = stptok(dimTemp,dim,19,",");
296  myRank++;
297  }
298  *rank = myRank;
299  }
300 }
301 /*--------------------------------------------------------------------*/
302 int translateTypeCode(const char *code, const char* term){
303  int i, result = -1;
304  char test_str[80];
305 
306  for(i = 0; i < NTYPECODE; i++){
307  snprintf(test_str, sizeof(test_str)-1, "%s%s", typecode[i].name, term);
308  if(strncmp(code, test_str, strlen(test_str)) == 0){
309  result = typecode[i].nx_type;
310  break;
311  }
312  }
313  return result;
314 }
315 
316 /*
317  * This is used to locate an Idims node from the new style table data layout
318  */
319 static mxml_node_t* findDimsNode(mxml_node_t *node)
320 {
321  mxml_node_t *tnode = NULL;
322  const char* name = node->value.element.name;
323  if ( (node->parent != NULL) && !strcmp(node->parent->value.element.name, DATA_NODE_NAME) )
324  {
325  tnode = mxmlFindElement(node->parent->parent, node->parent->parent, DIMS_NODE_NAME, NULL, NULL, MXML_DESCEND_FIRST);
326  if (tnode != NULL)
327  {
328  tnode = mxmlFindElement(tnode,tnode,name,NULL,NULL,MXML_DESCEND_FIRST);
329  }
330  }
331  return tnode;
332 }
333 
334 /*---------------------------------------------------------------------*/
335 /*return 1 if in table mode , 0 if not */
336 static void analyzeDataType(mxml_node_t *parent, int *rank, int *type,
337  int64_t *iDim){
338  const char *typeString;
339  mxml_node_t* tnode;
340  int nx_type = -1;
341  int table_mode = 0;
342 
343  *rank = 1;
344  *type = NX_CHAR;
345  iDim[0] = -1;
346 
347  /*
348  get the type attribute. No attribute means: plain text
349  */
350  tnode = findDimsNode(parent);
351  if (tnode != NULL)
352  {
353  table_mode = 1;
354  parent = tnode;
355  }
356  typeString = mxmlElementGetAttr(parent,TYPENAME);
357  if(typeString == NULL){
358  return;
359  }
360 
361  nx_type = translateTypeCode((char *)typeString, "");
362 
363  /*
364  assign type
365  */
366  if(nx_type == -1){
367  mxml_error(
368  "ERROR: %s is an invalid NeXus type, I try to continue but may fail",
369  typeString);
370  *type =NX_CHAR;
371  return;
372  }
373 
374  *type = nx_type;
375 
376  analyzeDim(typeString, rank, iDim, type);
377  if (table_mode)
378  {
379  *rank = 1;
380  iDim[0] = 1;
381  }
382  return;
383 }
384 /*-------------------------------------------------------------------*/
385 void destroyDataset(void *data){
386  if(data != NULL){
387  dropNXDataset((pNXDS)data);
388  }
389 }
390 /*-------------------------------------------------------------------*/
391 static char *getNextNumber(char *pStart, char pNumber[80]){
392  int charCount = 0;
393  pNumber[0] = '\0';
394 
395  /* advance to first digit */
396  while(isspace(*pStart) && *pStart != '\0'){
397  pStart++;
398  }
399  if(*pStart == '\0'){
400  return NULL;
401  }
402 
403  /* copy */
404  while(!isspace(*pStart) && *pStart != '\0' && charCount < 78){
405  pNumber[charCount] = *pStart;
406  pStart++;
407  charCount++;
408  }
409  pNumber[charCount] = '\0';
410  return pStart;
411 }
412 /*--------------------------------------------------------------------*/
413 mxml_type_t nexusTypeCallback(mxml_node_t *parent){
414  const char *typeString;
415 
416  if(strstr(parent->value.element.name,"?xml") != NULL ||
417  !strncmp(parent->value.element.name,"NX",2) ||
418  !strcmp(parent->value.element.name,DATA_NODE_NAME) ||
419  !strcmp(parent->value.element.name,DIMS_NODE_NAME)){
420  return MXML_ELEMENT;
421  } else {
422  /* data nodes do not habe TYPENAME in table style but are always CUSTOM */
423  if (parent->parent != NULL && !strcmp(parent->parent->value.element.name, DATA_NODE_NAME))
424  {
425  return MXML_CUSTOM;
426  }
427  if (parent->parent != NULL && !strcmp(parent->parent->value.element.name, DIMS_NODE_NAME))
428  {
429  return MXML_OPAQUE;
430  }
431  typeString = mxmlElementGetAttr(parent,TYPENAME);
432  if(typeString == NULL){
433  /*
434  MXML_TEXT seems more appropriate here. But mxml hacks text into
435  single words which is not what NeXus wants.
436  */
437  return MXML_OPAQUE;
438  } else{
439  if(strstr(typeString,"NX_CHAR") != NULL){
440  return MXML_OPAQUE;
441  } else {
442  return MXML_CUSTOM;
443  }
444  }
445  }
446 }
447 /*----------------------------------------------------------------------*/
448 int nexusLoadCallback(mxml_node_t *node, const char *buffer){
449  mxml_node_t *parent = NULL;
450  int rank, type;
451  int64_t iDim[NX_MAXRANK];
452  char pNumber[80], *pStart;
453  long address, maxAddress;
454  pNXDS dataset = NULL;
455 
456  parent = node->parent;
457  analyzeDataType(parent,&rank,&type,iDim);
458  if(iDim[0] == -1 || !strcmp(parent->parent->value.element.name, DIMS_NODE_NAME)){
459  iDim[0] = strlen(buffer);
460  node->value.custom.data = strdup(buffer);
461  node->value.custom.destroy = free;
462  return 0;
463  } else {
464  node->value.custom.data = createNXDataset(rank,type,iDim);
465  dataset = (pNXDS)node->value.custom.data;
466  if(dataset == NULL){
467  mxml_error("Failed to allocate custom dataset");
468  return 1;
469  }
470  node->value.custom.destroy = destroyDataset;
471  }
472 
473  /*
474  load data
475  */
476  pStart = (char *)buffer;
477  maxAddress = getNXDatasetLength(dataset);
478  address = 0;
479  while( (pStart = getNextNumber(pStart,pNumber)) != NULL &&
480  address < maxAddress){
481  putNXDatasetValueAt(dataset,address,atof(pNumber));
482  address++;
483  }
484 
485  return 0;
486 }
487 /*---------------------------------------------------------------------*/
488 static void stringIntoBuffer(char **buffer, char **bufPtr, size_t *bufSize,
489  char *string){
490  size_t i;
491 
492  for(i = 0; i < strlen(string); i++){
493  myxml_add_char(string[i],bufPtr,buffer,bufSize);
494  }
495 }
496 /*--------------------------------------------------------------------*/
497 static void formatNumber(double value, char *txt, int txtLen,
498  char *format, int type){
499  switch(type){
500  case NX_INT8:
501  case NX_UINT8:
502  case NX_INT16:
503  case NX_UINT16:
504  case NX_INT32:
505  case NX_UINT32:
506  snprintf(txt,txtLen,format,(int)value);
507  break;
508  case NX_INT64:
509  snprintf(txt,txtLen,format,(int64_t)value);
510  break;
511  case NX_UINT64:
512  snprintf(txt,txtLen,format,(uint64_t)value);
513  break;
514  case NX_FLOAT32:
515  case NX_FLOAT64:
516  snprintf(txt,txtLen,format,value);
517  break;
518  default:
519  /*assert(0); something is very wrong here */
520  printf("Problem\n");
521  break;
522  }
523 }
524 /*--------------------------------------------------------------------*/
525 static int countDepth(mxml_node_t *node){
526  int count = 0;
527  mxml_node_t *cur;
528 
529  cur = node;
530  while(cur != NULL){
531  count++;
532  cur = cur->parent;
533  }
534  count--;
535  return count;
536 }
537 /*---------------------------------------------------------------------*/
538 char *nexusWriteCallback(mxml_node_t *node){
539  int type, col;
540  char pNumber[80], indent[80], format[30];
541  char *buffer, *bufPtr;
542  pNXDS dataset;
543  int currentLen, table_style = 0;
544  size_t i, bufsize, length;
545  int is_definition = 0;
546  /* this is set by nxconvert when making a definiton */
547  is_definition = (getenv("NX_IS_DEFINITION") != NULL);
548 
549  if (!strcmp(node->parent->parent->value.element.name, DATA_NODE_NAME))
550  {
551  table_style = 1;
552  }
553  /*
554  allocate output buffer
555  */
556  buffer = (char *)malloc(1024*sizeof(char));
557  if(buffer == NULL){
558  mxml_error("Unable to allocate buffer");
559  return NULL;
560  }
561  memset(buffer,0,1024);
562  bufPtr = buffer;
563  bufsize = 1024;
564 
565  dataset = (pNXDS)node->value.custom.data;
566 
567  /*
568  prepare indentation level
569  */
570  col = countDepth(node)*2;
571  memset(indent,0,80);
572  for(i = 0; i < col; i++){
573  indent[i] = ' ';
574  }
575 
576  /*
577  get dataset info
578  */
579  type = getNXDatasetType(dataset);
580  if (is_definition) {
581  length = 1;
582  } else {
583  length = getNXDatasetLength(dataset);
584  }
585  if(dataset->format != NULL){
586  strcpy(format,dataset->format);
587  } else {
588  getNumberFormat(type,format);
589  }
590 
591  /*
592  actually get the data out
593  */
594  if (table_style)
595  {
596  for(i = 0; i < length; i++){
597  formatNumber(getNXDatasetValueAt(dataset,i),pNumber,79,format,type);
598  stringIntoBuffer(&buffer,&bufPtr,&bufsize,pNumber);
599  }
600  }
601  else
602  {
603  currentLen = col;
604  myxml_add_char('\n',&bufPtr,&buffer,&bufsize);
605  stringIntoBuffer(&buffer,&bufPtr,&bufsize,indent);
606  for(i = 0; i < length; i++){
607  formatNumber(getNXDatasetValueAt(dataset,i),pNumber,79,format,type);
608  if(currentLen + strlen(pNumber) > MXML_WRAP){
609  /*
610  wrap line
611  */
612  myxml_add_char('\n',&bufPtr,&buffer,&bufsize);
613  stringIntoBuffer(&buffer,&bufPtr,&bufsize,indent);
614  currentLen = col;
615  }
616  stringIntoBuffer(&buffer,&bufPtr,&bufsize,pNumber);
617  myxml_add_char(' ',&bufPtr,&buffer,&bufsize);
618  currentLen += strlen(pNumber) + 1;
619  }
620  }
621  myxml_add_char('\0',&bufPtr,&buffer,&bufsize);
622  return (char *)buffer;
623 }
624 /*------------------------------------------------------------------*/
625 int isDataNode(mxml_node_t *node){
626  if(mxmlElementGetAttr(node,"name") != NULL){
627  return 0;
628  }
629  if(strcmp(node->value.element.name,"NXroot") == 0){
630  return 0;
631  }
632  if(strcmp(node->value.element.name,DIMS_NODE_NAME) == 0){
633  return 0;
634  }
635  if(strcmp(node->value.element.name,DATA_NODE_NAME) == 0){
636  return 0;
637  }
638  if(strcmp(node->value.element.name,"NAPIlink") == 0){
639  return 0;
640  }
641  return 1;
642 }
643 /*--------------------------------------------------------------------*/
644 static int isTextData(mxml_node_t *node){
645  const char *attr = NULL;
646 
647  if(!isDataNode(node)){
648  return 0;
649  }
650  /*
651  test datasets
652  */
653  attr = mxmlElementGetAttr(node,TYPENAME);
654  if(attr == NULL){
655  return 1;
656  }
657  if(strstr(attr,"NX_CHAR") != NULL){
658  return 1;
659  } else {
660  return 0;
661  }
662 }
663 /*---------------------------------------------------------------------*/
664 
665 /*
666  * note: not reentrant or thead safe; returns pointer to static storage
667  */
668 const char *NXwhitespaceCallback(mxml_node_t *node, int where){
669  static char *indent = NULL;
670  int len;
671 
672  if(strstr(node->value.element.name,"?xml") != NULL){
673  return NULL;
674  }
675  if (node->parent != NULL && !strcmp(node->parent->value.element.name, DATA_NODE_NAME))
676  {
677  return NULL;
678  }
679  if (where == MXML_WS_BEFORE_CLOSE && !strcmp(node->value.element.name, DATA_NODE_NAME))
680  {
681  return NULL;
682  }
683 
684  if(isTextData(node)){
685  if(where == MXML_WS_BEFORE_OPEN){
686  len = countDepth(node)*2 + 2;
687  if (indent != NULL)
688  {
689  free(indent);
690  indent = NULL;
691  }
692  indent = (char *)malloc(len*sizeof(char));
693  if(indent != NULL){
694  memset(indent,' ',len);
695  indent[0]= '\n';
696  indent[len-1] = '\0';
697  return (const char*)indent;
698  }
699  }
700  return NULL;
701  }
702 
703  if(where == MXML_WS_BEFORE_OPEN || where == MXML_WS_BEFORE_CLOSE){
704  len = countDepth(node)*2 + 2;
705  if (indent != NULL)
706  {
707  free(indent);
708  indent = NULL;
709  }
710  indent = (char *)malloc(len*sizeof(char));
711  if(indent != NULL){
712  memset(indent,' ',len);
713  indent[0]= '\n';
714  indent[len-1] = '\0';
715  return (const char*)indent;
716  }
717  }
718  return NULL;
719 }
720 /*-----------------------------------------------------------------------*/
721 #ifdef TESTMAIN
722 #include <stdio.h>
723 
724 int main(int argc, char *argv[]){
725  mxml_node_t *root = NULL;
726  FILE *f;
727 
728  mxmlSetCustomHandlers(nexusLoadCallback, nexusWriteCallback);
730 
731  /*
732  read test
733  */
734  f = fopen("dmc.xml","r");
735  root = mxmlLoadFile(NULL,f,nexusTypeCallback);
736  fclose(f);
737 
738  /*
739  write test
740  */
741  setNumberFormat(NX_INT32,"%8d");
742  setNumberFormat(NX_FLOAT32,"%8.2f");
743  f = fopen("dmc2.xml","w");
744  mxmlSaveFile(root,f,NXwhitespaceCallback);
745  fclose(f);
746 
747 }
748 #endif
749 
750 
751 #endif /*NXXML*/
int putNXDatasetValueAt(pNXDS dataset, int64_t address, double value)
Definition: nxdataset.c:281
int getNXDatasetType(pNXDS dataset)
Definition: nxdataset.c:131
void dropNXDataset(pNXDS dataset)
Definition: nxdataset.c:89
#define NX_INT64
Definition: nxdataset.h:47
pNXDS createNXDataset(int rank, int typecode, int64_t dim[])
Definition: nxdataset.c:36
mxml_type_t nexusTypeCallback(mxml_node_t *parent)
void analyzeDim(const char *typeString, int *rank, int64_t *iDim, int *type)
char * nexusWriteCallback(mxml_node_t *node)
void initializeNumberFormats()
#define NX_INT8
Definition: nxdataset.h:41
int isDataNode(mxml_node_t *node)
void setNumberFormat(int dataType, char *formatString)
char * format
Definition: nxdataset.h:22
#define NX_FLOAT64
Definition: nxdataset.h:40
#define NX_UINT8
Definition: nxdataset.h:42
double getNXDatasetValueAt(pNXDS dataset, int64_t address)
Definition: nxdataset.c:194
#define DATA_NODE_NAME
Definition: nxio.h:33
int nexusLoadCallback(mxml_node_t *node, const char *buffer)
#define NX_FLOAT32
Definition: nxdataset.h:39
int translateTypeCode(const char *code, const char *term)
void getNumberText(int nx_type, char *typestring, int typeLen)
void destroyDataset(void *data)
#define NX_MAXRANK
Definition: nxdataset.h:51
#define TYPENAME
This file contains functions necessary to perform XML-I/O for NeXus with the mxml-library.
Definition: nxio.h:30
#define NX_UINT16
Definition: nxdataset.h:44
char * stptok(const char *s, char *tok, size_t toklen, char *brk)
Definition: stptok.c:17
#define DIMS_NODE_NAME
Definition: nxio.h:32
#define NX_CHAR
Definition: nxdataset.h:49
#define NX_UINT64
Definition: nxdataset.h:48
#define NX_UINT32
Definition: nxdataset.h:46
const char * NXwhitespaceCallback(mxml_node_t *node, int where)
#define NX_INT32
Definition: nxdataset.h:45
int getNXDatasetLength(pNXDS dataset)
Definition: nxdataset.c:141
#define NX_INT16
Definition: nxdataset.h:43