source: trunk/src/napi4.c @ 1822

Revision 1792, 54.5 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  NeXus - Neutron & X-ray Common Data Format
3 
4  Application Program Interface (HDF4) Routines
5 
6  Copyright (C) 1997-2006 Mark Koennecke, Przemek Klosowski
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Lesser General Public
10  License as published by the Free Software Foundation; either
11  version 2 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public
19  License along with this library; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21             
22  For further information, see <http://www.nexusformat.org>
23 
24  $Id$
25
26----------------------------------------------------------------------------*/
27
28#ifdef HDF4
29
30#include <stdlib.h>
31#include <assert.h>
32#include <string.h>
33#include <time.h>
34
35#include "napi.h"
36#include "napi4.h"
37
38extern  void *NXpData;
39
40  typedef struct __NexusFile {
41    struct iStack {
42      int32 *iRefDir;
43      int32 *iTagDir;
44      int32 iVref;
45      int32 __iStack_pad;               
46      int iNDir;
47      int iCurDir;
48    } iStack[NXMAXSTACK];
49    struct iStack iAtt;
50    int32 iVID;
51    int32 iSID;
52    int32 iCurrentVG;
53    int32 iCurrentSDS;
54    int iNXID;
55    int iStackPtr;
56    char iAccess[2];
57  } NexusFile, *pNexusFile;
58   /*-------------------------------------------------------------------*/
59
60  static pNexusFile NXIassert(NXhandle fid)
61  {
62    pNexusFile pRes;
63 
64    assert(fid != NULL);
65    pRes = (pNexusFile)fid;
66    assert(pRes->iNXID == NXSIGNATURE);
67    return pRes;
68  }
69  /*----------------------------------------------------------------------*/
70static int findNapiClass(pNexusFile pFile, int groupRef, NXname nxclass)
71{
72  NXname classText, linkClass;
73  int32 tags[2], attID, linkID, groupID;
74
75  groupID = Vattach(pFile->iVID,groupRef,"r");
76  Vgetclass(groupID, classText);
77  if(strcmp(classText,"NAPIlink") != 0)
78  {
79    /* normal group */
80    strcpy(nxclass,classText);
81    Vdetach(groupID);
82    return groupRef;
83  }
84  else 
85  {
86    /* code for linked renamed groups */
87    attID = Vfindattr(groupID,"NAPIlink");
88    if(attID >= 0)
89    {
90      Vgetattr(groupID,attID, tags);
91      linkID = Vattach(pFile->iVID,tags[1],"r");
92      Vgetclass(linkID, linkClass);
93      Vdetach(groupID);
94      Vdetach(linkID);
95      strcpy(nxclass,linkClass);
96      return tags[1];
97    } 
98    else
99    {
100      /* this allows for finding the NAPIlink group in NXmakenamedlink */
101      strcpy(nxclass,classText);
102      Vdetach(groupID);
103      return groupRef;
104    }
105  } 
106}
107  /* --------------------------------------------------------------------- */
108
109  static int32 NXIFindVgroup (pNexusFile pFile, CONSTCHAR *name, CONSTCHAR *nxclass)
110  {
111    int32 iNew, iRef, iTag;
112    int iN, i;
113    int32 *pArray = NULL;
114    NXname pText;
115 
116    assert (pFile != NULL);
117 
118    if (pFile->iCurrentVG == 0) { /* root level */
119      /* get the number and ID's of all lone Vgroups in the file */
120      iN = Vlone (pFile->iVID, NULL, 0);
121      if(iN == 0) {
122         return NX_EOD;
123      }
124      pArray = (int32 *) malloc (iN * sizeof (int32));
125      if (!pArray) {
126        NXReportError( "ERROR: out of memory in NXIFindVgroup");
127        return NX_EOD;
128      }
129      Vlone (pFile->iVID, pArray, iN);
130 
131      /* loop and check */
132      for (i = 0; i < iN; i++) {
133        iNew = Vattach (pFile->iVID, pArray[i], "r");
134        Vgetname (iNew, pText);
135        Vdetach(iNew);
136        if (strcmp (pText, name) == 0) {
137          pArray[i] = findNapiClass(pFile,pArray[i],pText);
138          if (strcmp (pText, nxclass) == 0) {
139            /* found ! */
140            iNew = pArray[i];
141            free (pArray);
142            return iNew;
143          }
144        }
145      }
146      /* nothing found */
147      free (pArray);
148      return NX_EOD;
149    } else {                      /* case in Vgroup */
150      iN = Vntagrefs (pFile->iCurrentVG);
151      for (i = 0; i < iN; i++) {
152        Vgettagref (pFile->iCurrentVG, i, &iTag, &iRef);
153        if (iTag == DFTAG_VG) {
154          iNew = Vattach (pFile->iVID, iRef, "r");
155          Vgetname (iNew, pText);
156          Vdetach(iNew);
157          if (strcmp (pText, name) == 0) {
158            iRef = findNapiClass(pFile,iRef, pText);
159            if (strcmp (pText, nxclass) == 0) {
160              return iRef;
161            }
162          }
163        }
164      }                           /* end for */
165    }                             /* end else */
166    /* not found */
167    return NX_EOD;
168  }
169 
170  /*----------------------------------------------------------------------*/ 
171
172  static int32 NXIFindSDS (NXhandle fid, CONSTCHAR *name)
173  {
174    pNexusFile self;
175    int32 iNew, iRet, iTag, iRef;
176    int32 i, iN, iA, iD1, iD2;
177    NXname pNam;
178    int32 iDim[H4_MAX_VAR_DIMS];
179 
180    self = NXIassert (fid);
181 
182    /* root level search */
183    if (self->iCurrentVG == 0) {
184      i = SDfileinfo (self->iSID, &iN, &iA);
185      if (i < 0) {
186        NXReportError( "ERROR: failure to read file information");
187        return NX_EOD;
188      }
189      for (i = 0; i < iN; i++) {
190        iNew = SDselect (self->iSID, i);
191        SDgetinfo (iNew, pNam, &iA, iDim, &iD1, &iD2);
192        if (strcmp (pNam, name) == 0) {
193          iRet = SDidtoref (iNew);
194          SDendaccess (iNew);
195          return iRet;
196        } else {
197          SDendaccess (iNew);
198        }
199      }
200      /* not found */
201      return NX_EOD;
202    }
203    /* end root level */
204    else {                        /* search in a Vgroup */
205      iN = Vntagrefs (self->iCurrentVG);
206      for (i = 0; i < iN; i++) {
207        Vgettagref (self->iCurrentVG, i, &iTag, &iRef);
208        /* we are now writing using DFTAG_NDG, but need others for backward compatability */
209        if ((iTag == DFTAG_SDG) || (iTag == DFTAG_NDG) || (iTag == DFTAG_SDS)) {
210          iNew = SDreftoindex (self->iSID, iRef);
211          iNew = SDselect (self->iSID, iNew);
212          SDgetinfo (iNew, pNam, &iA, iDim, &iD1, &iD2);
213          if (strcmp (pNam, name) == 0) {
214            SDendaccess (iNew);
215            return iRef;
216          }
217          SDendaccess (iNew);
218        }
219      }                           /* end for */
220    }                             /* end Vgroup */
221    /* we get here, only if nothing found */
222    return NX_EOD;
223  }
224 
225  /*----------------------------------------------------------------------*/
226
227  static int NXIInitDir (pNexusFile self)
228  {
229    int i;
230    int32 iTag, iRef;
231    int iStackPtr;
232 
233  /*
234   * Note: the +1 to various malloc() operations is to avoid a
235   *  malloc(0), which is an error on some operating systems
236   */
237    iStackPtr = self->iStackPtr;
238    if (self->iCurrentVG == 0 &&
239        self->iStack[iStackPtr].iRefDir == NULL) {        /* root level */
240      /* get the number and ID's of all lone Vgroups in the file */
241      self->iStack[iStackPtr].iNDir = Vlone (self->iVID, NULL, 0);
242      self->iStack[iStackPtr].iRefDir = 
243          (int32 *) malloc (self->iStack[iStackPtr].iNDir * sizeof (int32) + 1);
244      if (!self->iStack[iStackPtr].iRefDir) {
245        NXReportError( "ERROR: out of memory in NXIInitDir");
246        return NX_EOD;
247      }
248      Vlone (self->iVID,
249             self->iStack[self->iStackPtr].iRefDir,
250             self->iStack[self->iStackPtr].iNDir);
251    } else {
252      /* Vgroup level */
253      self->iStack[iStackPtr].iNDir = Vntagrefs (self->iCurrentVG);
254      self->iStack[iStackPtr].iRefDir =
255        (int32 *) malloc (self->iStack[iStackPtr].iNDir * sizeof (int32) + 1);
256      self->iStack[iStackPtr].iTagDir =
257        (int32 *) malloc (self->iStack[iStackPtr].iNDir * sizeof (int32) + 1);
258      if ((!self->iStack[iStackPtr].iRefDir) ||
259          (!self->iStack[iStackPtr].iTagDir)) {
260        NXReportError( "ERROR: out of memory in NXIInitDir");
261        return NX_EOD;
262      }
263      for (i = 0; i < self->iStack[self->iStackPtr].iNDir; i++) {
264        Vgettagref (self->iCurrentVG, i, &iTag, &iRef);
265        self->iStack[iStackPtr].iRefDir[i] = iRef;
266        self->iStack[iStackPtr].iTagDir[i] = iTag;
267      }
268    }
269    self->iStack[iStackPtr].iCurDir = 0;
270    return 1;
271  }
272
273  /*----------------------------------------------------------------------*/
274   
275  static void NXIKillDir (pNexusFile self)
276  {
277    if (self->iStack[self->iStackPtr].iRefDir) {
278      free (self->iStack[self->iStackPtr].iRefDir);
279      self->iStack[self->iStackPtr].iRefDir = NULL;
280    }
281    if (self->iStack[self->iStackPtr].iTagDir) {
282      free (self->iStack[self->iStackPtr].iTagDir);
283      self->iStack[self->iStackPtr].iTagDir = NULL;
284    }
285    self->iStack[self->iStackPtr].iCurDir = 0;
286    self->iStack[self->iStackPtr].iNDir = 0;
287  }
288
289 
290  /*-------------------------------------------------------------------------*/
291
292  static int NXIInitAttDir (pNexusFile pFile)
293  {
294    int iRet;
295    int32 iData, iAtt, iRank, iType;
296    int32 iDim[H4_MAX_VAR_DIMS];
297    NXname pNam;
298 
299    pFile->iAtt.iCurDir = 0;
300    if (pFile->iCurrentSDS != 0) {        /* SDS level */
301      iRet = SDgetinfo (pFile->iCurrentSDS, pNam, &iRank, iDim, &iType,
302                        &iAtt);
303    } else {
304      if(pFile->iCurrentVG == 0){
305        /* global level */
306        iRet = SDfileinfo (pFile->iSID, &iData, &iAtt);
307      } else {
308        /* group attribute */
309        iRet = Vnattrs(pFile->iCurrentVG);
310        iAtt = iRet;
311      }
312    }
313    if (iRet < 0) {
314      NXReportError( "ERROR: HDF cannot read attribute numbers");
315      pFile->iAtt.iNDir = 0;
316      return NX_ERROR;
317    }
318    pFile->iAtt.iNDir = iAtt;
319    return NX_OK;
320  }
321
322  /* --------------------------------------------------------------------- */
323
324  static void NXIKillAttDir (pNexusFile self)
325  {
326    if (self->iAtt.iRefDir) {
327      free (self->iAtt.iRefDir);
328      self->iAtt.iRefDir = NULL;
329    }
330    if (self->iAtt.iTagDir) {
331      free (self->iAtt.iTagDir);
332      self->iAtt.iTagDir = NULL;
333    }
334    self->iAtt.iCurDir = 0;
335    self->iAtt.iNDir = 0;
336  }
337/*------------------------------------------------------------------*/
338  static void NXIbuildPath(pNexusFile pFile, char *buffer, int bufLen)
339  {
340    int i;
341    int32 groupID, iA, iD1, iD2, iDim[H4_MAX_VAR_DIMS];
342    NXname pText;
343
344    buffer[0] = '\0';
345    for(i = 1; i <= pFile->iStackPtr; i++){
346      strncat(buffer,"/",bufLen-strlen(buffer));
347      groupID = Vattach(pFile->iVID,pFile->iStack[i].iVref, "r");
348      if (groupID != -1)
349      {
350          if (Vgetname(groupID, pText) != -1) {
351              strncat(buffer,pText,bufLen-strlen(buffer));
352          } else {
353              NXReportError( "ERROR: NXIbuildPath cannot get vgroup name");
354          }
355          Vdetach(groupID);
356      }
357      else
358      {
359          NXReportError( "ERROR: NXIbuildPath cannot attach to vgroup");
360      }
361    }
362    if(pFile->iCurrentSDS != 0){
363      if (SDgetinfo(pFile->iCurrentSDS,pText,&iA,iDim,&iD1,&iD2) != -1) {
364          strncat(buffer,"/",bufLen-strlen(buffer));
365          strncat(buffer,pText,bufLen-strlen(buffer));
366      }
367      else
368      {
369          NXReportError( "ERROR: NXIbuildPath cannot read SDS");
370      }
371    }
372  } 
373  /* ----------------------------------------------------------------------
374 
375                          Definition of NeXus API
376
377   ---------------------------------------------------------------------*/
378
379
380   NXstatus  NX4open(CONSTCHAR *filename, NXaccess am, 
381                                  NXhandle* pHandle)
382  {
383    pNexusFile pNew = NULL;
384    char pBuffer[512];
385    char *time_puffer = NULL;
386    char HDF_VERSION[64];
387    uint32 lmajor, lminor, lrelease;
388    int32 am1=0;
389 
390    *pHandle = NULL;
391
392    /* mask off any options for now */
393    am = (NXaccess)(am & NXACCMASK_REMOVEFLAGS);
394    /* map Nexus NXaccess types to HDF4 types */
395    if (am == NXACC_CREATE) {
396      am1 = DFACC_CREATE;
397    } else if (am == NXACC_CREATE4) {
398      am1 = DFACC_CREATE;
399    } else if (am == NXACC_READ) { 
400      am1 = DFACC_READ;
401    } else if (am == NXACC_RDWR) {
402      am1 = DFACC_RDWR;
403    }   
404    /* get memory */
405    pNew = (pNexusFile) malloc (sizeof (NexusFile));
406    if (!pNew) {
407      NXReportError( "ERROR: no memory to create File datastructure");
408      return NX_ERROR;
409    }
410    memset (pNew, 0, sizeof (NexusFile));
411
412#if WRITE_OLD_IDENT     /* not used at moment */
413/*
414 * write something that can be used by OLE
415 */
416   
417    if (am == NXACC_CREATE || am == NXACC_CREATE4) {
418      if ( (file_id = Hopen(filename, am1, 0)) == -1 ) {
419        sprintf (pBuffer, "ERROR: cannot open file_a: %s", filename);
420        NXReportError( pBuffer);
421        free (pNew);
422        return NX_ERROR;
423      }
424      an_id = ANstart(file_id);
425      ann_id = ANcreatef(an_id, AN_FILE_LABEL); /* AN_FILE_DESC */
426      ANwriteann(ann_id, "NeXus", 5);
427      ANendaccess(ann_id);
428      ANend(an_id);
429      if (Hclose(file_id) == -1) {
430        sprintf (pBuffer, "ERROR: cannot close file: %s", filename);
431        NXReportError( pBuffer);
432        free (pNew);
433        return NX_ERROR;
434      }
435      am = NXACC_RDWR;
436    }
437#endif /* WRITE_OLD_IDENT */
438
439    /* start SDS interface */
440    pNew->iSID = SDstart (filename, am1);
441    if (pNew->iSID <= 0) {
442      sprintf (pBuffer, "ERROR: cannot open file_b: %s", filename);
443      NXReportError( pBuffer);
444      free (pNew);
445      return NX_ERROR;
446    }
447/*
448 * need to create global attributes         file_name file_time NeXus_version
449 * at some point for new files
450 */
451    if (am != NXACC_READ) {
452      if (SDsetattr(pNew->iSID, "NeXus_version", DFNT_CHAR8, strlen(NEXUS_VERSION), NEXUS_VERSION) < 0) {
453          NXReportError( "ERROR: HDF failed to store NeXus_version attribute ");
454          return NX_ERROR;
455      }
456      Hgetlibversion(&lmajor, &lminor, &lrelease, HDF_VERSION); 
457      if (SDsetattr(pNew->iSID, "HDF_version", DFNT_CHAR8, strlen(HDF_VERSION), HDF_VERSION) < 0) {
458          NXReportError( "ERROR: HDF failed to store HDF_version attribute ");
459          return NX_ERROR;
460      }
461    }
462
463    time_puffer = NXIformatNeXusTime();
464    if (am == NXACC_CREATE || am == NXACC_CREATE4) {
465      if (SDsetattr(pNew->iSID, "file_name", DFNT_CHAR8, strlen(filename), (char*)filename) < 0) {
466        NXReportError( "ERROR: HDF failed to store file_name attribute ");
467        return NX_ERROR;
468      }
469      if(time_puffer != NULL){
470        if (SDsetattr(pNew->iSID, "file_time", DFNT_CHAR8, 
471                      strlen(time_puffer), time_puffer) < 0) {
472          NXReportError( 
473                          "ERROR: HDF failed to store file_time attribute ");
474          free(time_puffer);
475          return NX_ERROR;
476        }
477      }
478    }
479    if (time_puffer != NULL) {
480        free(time_puffer);
481    }
482
483    /*
484     * Otherwise we try to create the file two times which makes HDF
485     * Throw up on us.
486     */
487    if (am == NXACC_CREATE || am == NXACC_CREATE4) {
488      am = NXACC_RDWR;
489      am1 = DFACC_RDWR;
490    }
491
492    /* Set Vgroup access mode */
493    if (am == NXACC_READ) {
494      strcpy(pNew->iAccess,"r");
495    } else {
496      strcpy(pNew->iAccess,"w");
497    }
498 
499    /* start Vgroup API */
500   
501    pNew->iVID = Hopen(filename, am1, 100);
502    if (pNew->iVID <= 0) {
503      sprintf (pBuffer, "ERROR: cannot open file_c: %s", filename);
504      NXReportError( pBuffer);
505      free (pNew);
506      return NX_ERROR;
507    }
508    Vstart (pNew->iVID);
509    pNew->iNXID = NXSIGNATURE;
510    pNew->iStack[0].iVref = 0;    /* root! */
511 
512    *pHandle = (NXhandle)pNew;
513    return NX_OK;
514  }
515
516/*-----------------------------------------------------------------------*/
517 
518  NXstatus  NX4close (NXhandle* fid)
519  {
520    pNexusFile pFile = NULL;
521    int iRet;
522 
523    pFile = NXIassert(*fid);
524    iRet = 0;
525    /* close links into vGroups or SDS */
526    if (pFile->iCurrentVG != 0) {
527      Vdetach (pFile->iCurrentVG);
528    }
529    if (pFile->iCurrentSDS != 0) {
530      iRet = SDendaccess (pFile->iCurrentSDS);
531    }
532    if (iRet < 0) {
533      NXReportError( "ERROR: ending access to SDS");
534    }
535    /* close the SDS and Vgroup API's */
536    Vend (pFile->iVID);
537    iRet = SDend (pFile->iSID);
538    if (iRet < 0) {
539      NXReportError( "ERROR: HDF cannot close SDS interface");
540    }
541    iRet = Hclose (pFile->iVID);
542    if (iRet < 0) {
543      NXReportError( "ERROR: HDF cannot close HDF file");
544    }
545    /* release memory */
546    NXIKillDir (pFile);
547    free (pFile);
548    *fid = NULL;
549    return NX_OK;
550  } 
551
552
553/*-----------------------------------------------------------------------*/   
554
555 
556  NXstatus  NX4makegroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) 
557  {
558    pNexusFile pFile;
559    int32 iNew, iRet;
560    char pBuffer[256];
561 
562    pFile = NXIassert (fid);
563    /*
564     * Make sure that a group with the same name and nxclass does not
565     * already exist.
566     */
567    if ((iRet = NXIFindVgroup (pFile, (char*)name, nxclass)) >= 0) {
568      sprintf (pBuffer, "ERROR: Vgroup %s, class %s already exists", 
569                        name, nxclass);
570      NXReportError( pBuffer);
571      return NX_ERROR;
572    }
573 
574    /* create and configure the group */
575    iNew = Vattach (pFile->iVID, -1, "w");
576    if (iNew < 0) {
577      NXReportError( "ERROR: HDF could not create Vgroup");
578      return NX_ERROR;
579    }
580    Vsetname (iNew, name);
581    Vsetclass (iNew, nxclass);
582 
583    /* Insert it into the hierarchy, when appropriate */
584    iRet = 0;     
585    if (pFile->iCurrentVG != 0) {
586      iRet = Vinsert (pFile->iCurrentVG, iNew);
587    }
588    Vdetach (iNew);
589    if (iRet < 0) {
590      NXReportError( "ERROR: HDF failed to insert Vgroup");
591      return NX_ERROR;
592    }
593    return NX_OK;
594  }
595
596
597  /*------------------------------------------------------------------------*/
598  NXstatus  NX4opengroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass)
599  {
600    pNexusFile pFile;
601    int32 iRef;
602    char pBuffer[256];
603 
604    pFile = NXIassert (fid);
605 
606    iRef = NXIFindVgroup (pFile, (char*)name, nxclass);
607    if (iRef < 0) {
608      sprintf (pBuffer, "ERROR: Vgroup \"%s\", class \"%s\" NOT found", name, nxclass);
609      NXReportError( pBuffer);
610      return NX_ERROR;
611    }
612    /* are we at root level ? */
613    if (pFile->iCurrentVG == 0) {
614      pFile->iCurrentVG = Vattach (pFile->iVID, iRef,pFile->iAccess);
615      pFile->iStackPtr++;
616      pFile->iStack[pFile->iStackPtr].iVref = iRef;
617    } else {
618      Vdetach (pFile->iCurrentVG);
619      pFile->iStackPtr++;
620      pFile->iStack[pFile->iStackPtr].iVref = iRef;
621      pFile->iCurrentVG = Vattach (pFile->iVID,
622                                   pFile->iStack[pFile->iStackPtr].iVref,
623                                   pFile->iAccess);
624    }
625    NXIKillDir (pFile);
626    return NX_OK;
627  }
628  /* ------------------------------------------------------------------- */
629
630 
631   NXstatus  NX4closegroup (NXhandle fid)
632  {
633    pNexusFile pFile;
634 
635    pFile = NXIassert (fid);
636 
637    /* first catch the trivial case: we are at root and cannot get
638       deeper into a negative directory hierarchy (anti-directory)
639     */
640    if (pFile->iCurrentVG == 0) {
641      NXIKillDir (pFile);
642      return NX_OK;
643    } else {                      /* Sighhh. Some work to do */
644      /* close the current VG and decrement stack */
645      Vdetach (pFile->iCurrentVG);
646      NXIKillDir (pFile);
647      pFile->iStackPtr--;
648      if (pFile->iStackPtr <= 0) {        /* we hit root */
649        pFile->iStackPtr = 0;
650        pFile->iCurrentVG = 0;
651      } else {
652        /* attach to the lower Vgroup */
653        pFile->iCurrentVG = Vattach (pFile->iVID,
654                                     pFile->iStack[pFile->iStackPtr].iVref,
655                                     pFile->iAccess);
656      }
657    }
658    return NX_OK;
659  }
660 
661 
662  /* --------------------------------------------------------------------- */
663 
664  NXstatus  NX4makedata64 (NXhandle fid, CONSTCHAR *name, int datatype, int rank,
665              int64_t dimensions[])
666  {
667    pNexusFile pFile;
668    int32 iNew;
669    char pBuffer[256];
670    int i, iRet, type;
671    int32 myDim[H4_MAX_VAR_DIMS]; 
672
673    pFile = NXIassert (fid);
674     
675    if (dimensions[0] == NX_UNLIMITED)
676      {
677        dimensions[0] = SD_UNLIMITED;
678      }
679     
680    if ((iNew = NXIFindSDS (fid, name))>=0) {
681      sprintf (pBuffer, "ERROR: SDS %s already exists at this level", name);
682      NXReportError( pBuffer);
683      return NX_ERROR;
684    }
685 
686    if (datatype == NX_CHAR)
687    {
688        type=DFNT_CHAR8;
689    }
690    else if (datatype == NX_INT8)
691    {
692        type=DFNT_INT8;
693    }
694    else if (datatype == NX_UINT8)
695    {
696        type=DFNT_UINT8;
697    }
698    else if (datatype == NX_INT16)
699    {
700        type=DFNT_INT16;
701    }
702    else if (datatype == NX_UINT16)
703    {
704        type=DFNT_UINT16;
705    }
706    else if (datatype == NX_INT32)
707    {
708        type=DFNT_INT32;
709    }
710    else if (datatype == NX_UINT32)
711    {
712        type=DFNT_UINT32;
713    }
714    else if (datatype == NX_FLOAT32)
715    {
716        type=DFNT_FLOAT32;
717    }
718    else if (datatype == NX_FLOAT64)
719    {
720        type=DFNT_FLOAT64;
721    }
722    else
723    {
724      NXReportError( "ERROR: invalid type in NX4makedata");
725      return NX_ERROR;
726    }
727     
728    if (rank <= 0) {
729      sprintf (pBuffer, "ERROR: invalid rank specified for SDS %s",
730               name);
731      NXReportError( pBuffer);
732      return NX_ERROR;
733    }
734
735    /*
736      Check dimensions for consistency. The first dimension may be 0
737      thus denoting an unlimited dimension.
738    */
739    for (i = 1; i < rank; i++) {
740      if (dimensions[i] <= 0) {
741        sprintf (pBuffer,
742                 "ERROR: invalid dimension %d, value %lld given for SDS %s",
743                 i, (long long)dimensions[i], name);
744        NXReportError( pBuffer);
745        return NX_ERROR;
746      }
747    }
748
749    /* cast the dimensions array properly for non 32-bit ints */
750    for(i = 0; i < rank; i++)
751    {
752      myDim[i] = (int32)dimensions[i];
753    }
754
755
756    /* behave nicely, if there is still an SDS open */
757    if (pFile->iCurrentSDS != 0) {
758      SDendaccess (pFile->iCurrentSDS);
759      pFile->iCurrentSDS = 0;
760    }
761 
762    /* Do not allow creation of SDS's at the root level */
763    if (pFile->iCurrentVG == 0) {
764      sprintf(pBuffer, "ERROR: SDS creation at root level is not permitted");
765      NXReportError( pBuffer);
766      return NX_ERROR;
767    }
768         
769    /* dataset creation */
770    iNew = SDcreate (pFile->iSID, (char*)name, (int32)type, 
771                     (int32)rank, myDim);
772    if (iNew < 0) {
773      sprintf (pBuffer, "ERROR: cannot create SDS %s, check arguments",
774               name);
775      NXReportError( pBuffer);
776      return NX_ERROR;
777    }
778    /* link into Vgroup, if in one */
779    if (pFile->iCurrentVG != 0) {
780      iRet = Vaddtagref (pFile->iCurrentVG, DFTAG_NDG, SDidtoref (iNew));
781    }
782    iRet = SDendaccess (iNew);
783    if (iRet < 0) {
784      NXReportError( "ERROR: HDF cannot end access to SDS");
785      return NX_ERROR;
786    }
787    return NX_OK;
788  }
789 
790 
791 /* --------------------------------------------------------------------- */
792 
793   
794  NXstatus  NX4compmakedata64 (NXhandle fid, CONSTCHAR *name, int datatype, int rank,
795              int64_t dimensions[],int compress_type, int64_t chunk_size[])
796  {
797    pNexusFile pFile;
798    int32 iNew, iRet, type;
799    char pBuffer[256];
800    int i, compress_level;
801    int32 myDim[H4_MAX_VAR_DIMS]; 
802    comp_info compstruct;
803
804    pFile = NXIassert (fid);
805     
806    if (dimensions[0] == NX_UNLIMITED)
807      {
808        dimensions[0] = SD_UNLIMITED;
809      }
810     
811    if ((iNew = NXIFindSDS (fid, name))>=0) {
812      sprintf (pBuffer, "ERROR: SDS %s already exists at this level", name);
813      NXReportError( pBuffer);
814      return NX_ERROR;
815    }
816 
817    if (datatype == NX_CHAR)
818    {
819        type=DFNT_CHAR8;
820    }
821    else if (datatype == NX_INT8)
822    {
823        type=DFNT_INT8;
824    }
825    else if (datatype == NX_UINT8)
826    {
827        type=DFNT_UINT8;
828    }
829    else if (datatype == NX_INT16)
830    {
831        type=DFNT_INT16;
832    }
833    else if (datatype == NX_UINT16)
834    {
835        type=DFNT_UINT16;
836    }
837    else if (datatype == NX_INT32)
838    {
839        type=DFNT_INT32;
840    }
841    else if (datatype == NX_UINT32)
842    {
843        type=DFNT_UINT32;
844    }
845    else if (datatype == NX_FLOAT32)
846    {
847        type=DFNT_FLOAT32;
848    }
849    else if (datatype == NX_FLOAT64)
850    {
851        type=DFNT_FLOAT64;
852    }
853    else
854    {
855      NXReportError( "ERROR: invalid datatype in NX4compmakedata");
856      return NX_ERROR;
857    }
858     
859    if (rank <= 0) {
860      sprintf (pBuffer, "ERROR: invalid rank specified for SDS %s",
861               name);
862      NXReportError( pBuffer);
863      return NX_ERROR;
864    }
865
866    /*
867      Check dimensions for consistency. The first dimension may be 0
868      thus denoting an unlimited dimension.
869    */
870    for (i = 1; i < rank; i++) {
871      if (dimensions[i] <= 0) {
872        sprintf (pBuffer,
873                 "ERROR: invalid dimension %d, value %lld given for SDS %s",
874                 i, (long long)dimensions[i], name);
875        NXReportError( pBuffer);
876        return NX_ERROR;
877      }
878    }
879
880    /* cast the dimensions array properly for non 32-bit ints */
881    for(i = 0; i < rank; i++)
882    {
883      myDim[i] = (int32)dimensions[i];
884    }
885
886
887    /* behave nicely, if there is still an SDS open */
888    if (pFile->iCurrentSDS != 0) {
889      SDendaccess (pFile->iCurrentSDS);
890      pFile->iCurrentSDS = 0;
891    }
892 
893    /* Do not allow creation of SDS's at the root level */
894    if (pFile->iCurrentVG == 0) {
895      sprintf(pBuffer, "ERROR: SDS creation at root level is not permitted");
896      NXReportError( pBuffer);
897      return NX_ERROR;
898    }
899         
900    /* dataset creation */
901    iNew = SDcreate (pFile->iSID, (char*)name, (int32)type, 
902                     (int32)rank, myDim);
903    if (iNew < 0) {
904      sprintf (pBuffer, "ERROR: cannot create SDS %s, check arguments",
905               name);
906      NXReportError( pBuffer);
907      return NX_ERROR;
908    }
909     
910    /* compress SD data set */
911    compress_level = 6;
912    if( (compress_type / 100) == NX_COMP_LZW )
913    {
914        compress_level = compress_type % 100;
915        compress_type = NX_COMP_LZW;
916    }
917
918    if(compress_type == NX_COMP_LZW)
919    {
920      compstruct.deflate.level = compress_level; 
921      iRet = SDsetcompress(iNew, COMP_CODE_DEFLATE, &compstruct);
922      if (iRet < 0) 
923      {
924        NXReportError( "LZW-Compression failure!");
925        return NX_ERROR;
926      } 
927    }
928    else if (compress_type == NX_COMP_RLE)
929    {
930      iRet = SDsetcompress(iNew, COMP_CODE_RLE, &compstruct);
931      if (iRet < 0) 
932        {
933          NXReportError( "RLE-Compression failure!");
934          return NX_ERROR;
935        }   
936    }
937    else if (compress_type == NX_COMP_HUF)
938    {
939      compstruct.skphuff.skp_size = DFKNTsize(type); 
940      iRet = SDsetcompress(iNew, COMP_CODE_SKPHUFF, &compstruct);
941      if (iRet < 0) 
942        {
943          NXReportError( "HUF-Compression failure!");
944          return NX_ERROR;
945        } 
946    }
947    else if (compress_type == NX_COMP_NONE)
948    {
949      /*      */
950    }
951    else 
952    {
953      NXReportError( "Unknown compression method!");
954      return NX_ERROR; 
955    }
956    /* link into Vgroup, if in one */
957    if (pFile->iCurrentVG != 0) {
958      iRet = Vaddtagref (pFile->iCurrentVG, DFTAG_NDG, SDidtoref (iNew));
959    }
960    iRet = SDendaccess (iNew);
961    if (iRet < 0) {
962      NXReportError( "ERROR: HDF cannot end access to SDS");
963      return NX_ERROR;
964    }
965   
966    return NX_OK;
967  }
968 
969  /* --------------------------------------------------------------------- */
970
971   
972  NXstatus  NX4compress (NXhandle fid, int compress_type)
973  {
974    pNexusFile pFile;
975    int32 iRank, iAtt, iType, iRet;
976    int32 iSize[H4_MAX_VAR_DIMS];
977    comp_coder_t compress_typei = COMP_CODE_NONE;
978    NXname pBuffer;
979    char pError[512];
980    comp_info compstruct; 
981    int compress_level = 6;
982   
983    pFile = NXIassert (fid);
984 
985    /* check if there is an SDS open */
986    if (pFile->iCurrentSDS == 0) {
987      NXReportError( "ERROR: no SDS open");
988      return NX_ERROR;
989    }
990   
991    if (compress_type == NX_COMP_NONE) 
992      {
993        compress_typei = COMP_CODE_NONE;
994      }
995      else if (compress_type == NX_COMP_LZW) 
996      {
997        compress_typei = COMP_CODE_DEFLATE;
998      }
999      else if ( (compress_type / 100) == NX_COMP_LZW )
1000      {
1001        compress_typei = COMP_CODE_DEFLATE;
1002        compress_level = compress_type % 100;
1003        compress_type = NX_COMP_LZW;
1004      }
1005      else if (compress_type == NX_COMP_RLE)
1006      {
1007        compress_typei = COMP_CODE_RLE;
1008      }
1009      else if 
1010      (compress_type == NX_COMP_HUF)
1011      {
1012        compress_typei = COMP_CODE_SKPHUFF;
1013      }
1014   
1015    /* first read dimension information */
1016    SDgetinfo (pFile->iCurrentSDS, pBuffer, &iRank, iSize, &iType, &iAtt);
1017
1018    /*
1019       according to compression type initialize compression
1020       information
1021    */
1022    if(compress_type == NX_COMP_LZW)
1023    {
1024         compstruct.deflate.level = compress_level;
1025    }
1026    else if(compress_type == NX_COMP_HUF)
1027    {
1028        compstruct.skphuff.skp_size = DFKNTsize(iType);
1029    }
1030
1031    iRet = SDsetcompress(pFile->iCurrentSDS, compress_typei, &compstruct);
1032    if (iRet < 0) {
1033      sprintf (pError, "ERROR: failure to compress data to %s", pBuffer);
1034      NXReportError( pError);
1035      return NX_ERROR;
1036    }
1037    return NX_OK;
1038  } 
1039
1040  /* --------------------------------------------------------------------- */
1041 
1042 
1043  NXstatus  NX4opendata (NXhandle fid, CONSTCHAR *name)
1044  {
1045    pNexusFile pFile;
1046    int32 iNew, attID, tags[2];
1047    char pBuffer[256];
1048    int iRet;
1049 
1050    pFile = NXIassert (fid);
1051 
1052    /* First find the reference number of the SDS */
1053    iNew = NXIFindSDS (fid, name);
1054    if (iNew < 0) {
1055      sprintf (pBuffer, "ERROR: SDS \"%s\" not found at this level", name);
1056      NXReportError( pBuffer);
1057      return NX_ERROR;
1058    }
1059    /* Be nice: properly close the old open SDS silently if there is
1060     * still an SDS open.
1061     */
1062    if (pFile->iCurrentSDS) {
1063      iRet = SDendaccess (pFile->iCurrentSDS);
1064      if (iRet < 0) {
1065        NXReportError( "ERROR: HDF cannot end access to SDS");
1066      }
1067    }
1068    /* clear pending attribute directories first */
1069    NXIKillAttDir (pFile);
1070
1071    /* open the SDS, thereby watching for linked SDS under a different name */
1072    iNew = SDreftoindex (pFile->iSID, iNew);
1073    pFile->iCurrentSDS = SDselect (pFile->iSID, iNew);
1074    attID = SDfindattr(pFile->iCurrentSDS,"NAPIlink");
1075    if(attID >= 0)
1076    {
1077      SDreadattr(pFile->iCurrentSDS,attID, tags);
1078      SDendaccess(pFile->iCurrentSDS);
1079      iNew = SDreftoindex (pFile->iSID, tags[1]);
1080      pFile->iCurrentSDS = SDselect (pFile->iSID, iNew);
1081    }
1082
1083    if (pFile->iCurrentSDS < 0) {
1084      NXReportError( "ERROR: HDF error opening SDS");
1085      pFile->iCurrentSDS = 0;
1086      return NX_ERROR;
1087    }
1088    return NX_OK;
1089  }
1090   
1091  /* ----------------------------------------------------------------- */
1092   
1093 
1094  NXstatus  NX4closedata (NXhandle fid)
1095  {
1096    pNexusFile pFile;
1097    int iRet;
1098 
1099    pFile = NXIassert (fid);
1100 
1101    if (pFile->iCurrentSDS != 0) {
1102      iRet = SDendaccess (pFile->iCurrentSDS);
1103      pFile->iCurrentSDS = 0;
1104      if (iRet < 0) {
1105        NXReportError( "ERROR: HDF cannot end access to SDS");
1106        return NX_ERROR;
1107      }
1108    } else {
1109      NXReportError( "ERROR: no SDS open --> nothing to do");
1110      return NX_ERROR;
1111    }
1112    NXIKillAttDir (pFile);                /* for attribute data */
1113    return NX_OK;
1114  }
1115   
1116 
1117  /* ------------------------------------------------------------------- */
1118
1119  NXstatus  NX4putdata (NXhandle fid, const void *data)
1120  {
1121    pNexusFile pFile;
1122    int32 iStart[H4_MAX_VAR_DIMS], iSize[H4_MAX_VAR_DIMS], iStride[H4_MAX_VAR_DIMS];
1123    NXname pBuffer;
1124    int32 iRank, iAtt, iType, iRet, i;
1125    char pError[512];
1126     
1127    pFile = NXIassert (fid);
1128 
1129    /* check if there is an SDS open */
1130    if (pFile->iCurrentSDS == 0) {
1131      NXReportError( "ERROR: no SDS open");
1132      return NX_ERROR;
1133    }
1134    /* first read dimension information */
1135    memset (iStart, 0, H4_MAX_VAR_DIMS * sizeof (int32));
1136    SDgetinfo (pFile->iCurrentSDS, pBuffer, &iRank, iSize, &iType, &iAtt);
1137 
1138    /* initialise stride to 1 */
1139    for (i = 0; i < iRank; i++) {
1140      iStride[i] = 1;
1141    }
1142 
1143    /* actually write */
1144    iRet = SDwritedata (pFile->iCurrentSDS, iStart, iStride, iSize, (void*)data);
1145    if (iRet < 0) {
1146      /* HEprint(stdout,0); */
1147      sprintf (pError, "ERROR: failure to write data to %s", pBuffer);
1148      NXReportError( pError);
1149      return NX_ERROR;
1150    }
1151    return NX_OK;
1152  }
1153   
1154  /* ------------------------------------------------------------------- */
1155
1156  NXstatus
1157   NX4putattr (NXhandle fid, CONSTCHAR *name, const void *data, int datalen, int iType)
1158  {
1159    pNexusFile pFile;
1160    int iRet, type;
1161 
1162    pFile = NXIassert (fid);
1163    if (iType == NX_CHAR)
1164    {
1165        type=DFNT_CHAR8;
1166    }
1167    else if (iType == NX_INT8)
1168    {
1169        type=DFNT_INT8;
1170    }
1171    else if (iType == NX_UINT8)
1172    {
1173        type=DFNT_UINT8;
1174    }
1175    else if (iType == NX_INT16)
1176    {
1177        type=DFNT_INT16;
1178    }
1179    else if (iType == NX_UINT16)
1180    {
1181        type=DFNT_UINT16;
1182    }
1183    else if (iType == NX_INT32)
1184    {
1185        type=DFNT_INT32;
1186    }
1187    else if (iType == NX_UINT32)
1188    {
1189        type=DFNT_UINT32;
1190    }
1191    else if (iType == NX_FLOAT32)
1192    {
1193        type=DFNT_FLOAT32;
1194    }
1195    else if (iType == NX_FLOAT64)
1196    {
1197        type=DFNT_FLOAT64;
1198    }
1199    else
1200    {
1201      NXReportError( "ERROR: Invalid data type for HDF attribute");
1202      return NX_ERROR;
1203    }
1204    if (pFile->iCurrentSDS != 0) {
1205      /* SDS attribute */
1206      iRet = SDsetattr (pFile->iCurrentSDS, (char*)name, (int32)type,
1207                        (int32)datalen, data);
1208    } else {
1209      if(pFile->iCurrentVG == 0){
1210        /* global attribute */
1211        iRet = SDsetattr (pFile->iSID, (char*)name, (int32)type,
1212                          (int32)datalen, data);
1213      } else {
1214        /* group attribute */
1215        iRet = Vsetattr(pFile->iCurrentVG, (char *)name, (int32) type,
1216                        (int32)datalen,data);
1217      }
1218    }
1219    iType = type;
1220    if (iRet < 0) {
1221      NXReportError( "ERROR: HDF failed to store attribute ");
1222      return NX_ERROR;
1223    }
1224    return NX_OK;
1225  }
1226 
1227   /* ------------------------------------------------------------------- */
1228
1229   
1230  NXstatus  NX4putslab64 (NXhandle fid, const void *data, const int64_t iStart[], const int64_t iSize[])
1231  {
1232    pNexusFile pFile;
1233    int iRet;
1234    int32 iStride[H4_MAX_VAR_DIMS];
1235    int32 myStart[H4_MAX_VAR_DIMS], mySize[H4_MAX_VAR_DIMS];
1236    int32 i, iRank, iType, iAtt;
1237    NXname pBuffer; 
1238 
1239 
1240    pFile = NXIassert (fid);
1241 
1242    /* check if there is an SDS open */
1243    if (pFile->iCurrentSDS == 0) {
1244      NXReportError( "ERROR: no SDS open");
1245      return NX_ERROR;
1246    }
1247    /* initialise stride to 1 */
1248    for (i = 0; i < H4_MAX_VAR_DIMS; i++) {
1249      iStride[i] = 1;
1250    }
1251
1252         SDgetinfo (pFile->iCurrentSDS, pBuffer, 
1253            &iRank, myStart, &iType, &iAtt);
1254         for(i = 0; i < iRank; i++)
1255         {
1256           myStart[i] = (int32)iStart[i];
1257           mySize[i]  = (int32)iSize[i];
1258         }
1259         /* finally write */
1260         iRet = SDwritedata (pFile->iCurrentSDS, myStart, 
1261                        iStride, mySize, (void*)data);
1262
1263
1264    /* deal with HDF errors */
1265    if (iRet < 0) {
1266      NXReportError( "ERROR: writing slab failed");
1267      return NX_ERROR;
1268    }
1269    return NX_OK;
1270  }
1271
1272 
1273  /* ------------------------------------------------------------------- */
1274
1275  NXstatus  NX4getdataID (NXhandle fid, NXlink* sRes)
1276  {
1277    pNexusFile pFile;
1278    int datalen, type = NX_CHAR;
1279
1280    pFile = NXIassert (fid);
1281 
1282    if (pFile->iCurrentSDS == 0) {
1283      sRes->iTag = NX_ERROR;
1284      return NX_ERROR;
1285    } else {
1286      sRes->iTag = DFTAG_NDG;
1287      sRes->iRef = SDidtoref (pFile->iCurrentSDS);
1288      NXMDisableErrorReporting();
1289      datalen = 1024;
1290      memset(&sRes->targetPath,0,1024);
1291      if(NX4getattr(fid,"target",&sRes->targetPath,&datalen,&type) != NX_OK)
1292      {
1293        NXIbuildPath(pFile,sRes->targetPath,1024);
1294      }
1295      NXMEnableErrorReporting();
1296      return NX_OK;
1297    }
1298    sRes->iTag = NX_ERROR;
1299    return NX_ERROR;                  /* not reached */
1300  }
1301
1302
1303  /* ------------------------------------------------------------------- */
1304
1305 
1306  NXstatus  NX4makelink (NXhandle fid, NXlink* sLink)
1307  {
1308    pNexusFile pFile;
1309    int32 dataID, type = DFNT_CHAR8, length;
1310    char name[] = "target";
1311 
1312    pFile = NXIassert (fid);
1313 
1314    if (pFile->iCurrentVG == 0) { /* root level, can not link here */
1315      return NX_ERROR;
1316    }
1317    Vaddtagref(pFile->iCurrentVG, sLink->iTag, sLink->iRef);
1318    length = strlen(sLink->targetPath);
1319    if(sLink->iTag == DFTAG_SDG || sLink->iTag == DFTAG_NDG ||
1320       sLink->iTag == DFTAG_SDS)
1321    {
1322      dataID = SDreftoindex(pFile->iSID,sLink->iRef);
1323      dataID = SDselect(pFile->iSID,dataID);
1324      SDsetattr(dataID,name,type,length,sLink->targetPath);
1325      SDendaccess(dataID);
1326    }
1327    else 
1328    {
1329      dataID = Vattach(pFile->iVID,sLink->iRef,"w");
1330      Vsetattr(dataID, (char *)name, type, (int32) length, sLink->targetPath);
1331      Vdetach(dataID);
1332    }
1333    return NX_OK;
1334  }
1335  /* ------------------------------------------------------------------- */
1336
1337 
1338  NXstatus  NX4makenamedlink (NXhandle fid, CONSTCHAR* newname, NXlink* sLink)
1339  {
1340    pNexusFile pFile;
1341    int32 dataID, type = DFNT_CHAR8, length, dataType = NX_CHAR, 
1342      rank = 1, attType = NX_INT32;
1343    int64_t iDim[1];
1344    char name[] = "target";
1345    int tags[2]; 
1346
1347    pFile = NXIassert (fid);
1348 
1349    if (pFile->iCurrentVG == 0) { /* root level, can not link here */
1350      return NX_ERROR;
1351    }
1352
1353    tags[0] = sLink->iTag;
1354    tags[1] = sLink->iRef;
1355
1356    length = strlen(sLink->targetPath); 
1357    if(sLink->iTag == DFTAG_SDG || sLink->iTag == DFTAG_NDG ||
1358       sLink->iTag == DFTAG_SDS)
1359    {
1360      iDim[0] = 1;
1361      NX4makedata64(fid,newname, dataType,rank,iDim);
1362      NX4opendata(fid,newname);
1363      NX4putattr(fid,"NAPIlink",tags, 2, attType);
1364      NX4closedata(fid); 
1365      dataID = SDreftoindex(pFile->iSID,sLink->iRef);
1366      dataID = SDselect(pFile->iSID,dataID);
1367      SDsetattr(dataID,name,type,length,sLink->targetPath);
1368      SDendaccess(dataID);
1369    } else {
1370      NX4makegroup(fid,newname,"NAPIlink");
1371      NX4opengroup(fid,newname,"NAPIlink");
1372      NX4putattr(fid,"NAPIlink",tags, 2, attType);
1373      NX4closegroup(fid);
1374      dataID = Vattach(pFile->iVID,sLink->iRef,"w");
1375      Vsetattr(dataID, (char *)name, type, (int32) length, sLink->targetPath);
1376      Vdetach(dataID);
1377    }
1378    return NX_OK;
1379  }
1380
1381  /*----------------------------------------------------------------------*/
1382 
1383  NXstatus  NX4printlink (NXhandle fid, NXlink* sLink)
1384  {
1385     NXIassert (fid);
1386     printf("HDF4 link: iTag = %ld, iRef = %ld, target=\"%s\"\n", sLink->iTag, sLink->iRef, sLink->targetPath);
1387    return NX_OK;
1388  }
1389 
1390  /*----------------------------------------------------------------------*/
1391
1392  NXstatus  NX4flush(NXhandle *pHandle)
1393  {
1394    char *pFileName, *pCopy = NULL;
1395    int access, dummy, iRet, i, iStack;
1396    pNexusFile pFile = NULL;
1397    NXaccess ac;
1398    int *iRefs = NULL;
1399
1400    pFile = NXIassert(*pHandle);
1401   
1402    /*
1403      The HDF4-API does not support a flush. We help ourselves with
1404      inquiring the name and access type of the file, closing it and
1405      opening it again. This is also the reason why this needs a pointer
1406      to the handle structure as the handle changes. The other thing we
1407      do is to store the refs of all open vGroups in a temporary array
1408      in order to recover the position in the vGroup hierarchy before the
1409      flush.
1410    */
1411    iRet = Hfidinquire(pFile->iVID,&pFileName,&access,&dummy);
1412    if (iRet < 0) {
1413      NXReportError( 
1414        "ERROR: Failed to inquire file name for HDF file");
1415      return NX_ERROR;
1416    }
1417    if(pFile->iAccess[0] == 'r') {
1418      ac = NXACC_READ;
1419    }else if(pFile->iAccess[0] == 'w') {
1420      ac = NXACC_RDWR;
1421    } else {
1422      NXReportError( 
1423        "ERROR: NX4flush failed to determine file access mode");
1424      return NX_ERROR;
1425    }
1426    pCopy = (char *)malloc((strlen(pFileName)+10)*sizeof(char));
1427    if(!pCopy) {
1428      NXReportError( 
1429        "ERROR: Failed to allocate data for filename copy");
1430      return NX_ERROR;
1431    }
1432    memset(pCopy,0,strlen(pFileName)+10);
1433    strcpy(pCopy,pFileName);     
1434   
1435    /* get refs for recovering vGroup position */
1436    iStack = 0;
1437    if(pFile->iStackPtr > 0) {
1438      iStack = pFile->iStackPtr + 1;
1439      iRefs = (int *)malloc(iStack*sizeof(int));
1440      if(!iRefs){
1441        NXReportError( 
1442        "ERROR: Failed to allocate data for hierarchy copy");
1443        return NX_ERROR;
1444      }
1445      for(i = 0; i < iStack; i++){
1446         iRefs[i] = pFile->iStack[i].iVref;
1447      }
1448    }
1449
1450    iRet = NX4close(pHandle);
1451    if(iRet != NX_OK) {
1452      return iRet;
1453    }
1454
1455    iRet = NX4open(pCopy, ac, pHandle);
1456    free(pCopy);
1457   
1458    /* return to position in vGroup hierarchy */
1459    pFile = NXIassert(*pHandle);
1460    if(iStack > 0){
1461      pFile->iStackPtr = iStack - 1;
1462      for(i = 0; i < iStack; i++){
1463        pFile->iStack[i].iVref = iRefs[i];
1464      }
1465      free(iRefs);
1466      pFile->iCurrentVG = Vattach(pFile->iVID,
1467                                  pFile->iStack[pFile->iStackPtr].iVref,
1468                                  pFile->iAccess);
1469    }
1470   
1471    return iRet;
1472  } 
1473
1474  /*-------------------------------------------------------------------------*/
1475 
1476
1477  NXstatus  NX4getnextentry (NXhandle fid, NXname name, NXname nxclass, int *datatype)
1478  {
1479    pNexusFile pFile;
1480    int iRet, iStackPtr, iCurDir;
1481    int32 iTemp, iD1, iD2, iA;
1482    int32 iDim[H4_MAX_VAR_DIMS];
1483 
1484    pFile = NXIassert (fid);
1485 
1486    iStackPtr = pFile->iStackPtr;
1487    iCurDir   = pFile->iStack[pFile->iStackPtr].iCurDir;
1488 
1489    /* first case to check for: no directory entry */
1490    if (pFile->iStack[pFile->iStackPtr].iRefDir == NULL) {
1491      iRet = NXIInitDir (pFile);
1492      if (iRet < 0) {
1493        NXReportError(
1494                        "ERROR: no memory to store directory info");
1495        return NX_EOD;
1496      }
1497    }
1498
1499    /* Next case: end of directory */
1500    if (iCurDir >= pFile->iStack[pFile->iStackPtr].iNDir) {
1501      NXIKillDir (pFile);
1502      return NX_EOD;
1503    }
1504
1505    /* Next case: we have data! supply it and increment counter */
1506    if (pFile->iCurrentVG == 0) { /* root level */
1507      iTemp = Vattach (pFile->iVID,
1508                       pFile->iStack[iStackPtr].iRefDir[iCurDir], "r");
1509      if (iTemp < 0) {
1510        NXReportError( "ERROR: HDF cannot attach to Vgroup");
1511        return NX_ERROR;
1512      }
1513      Vgetname (iTemp, name);
1514      Vdetach (iTemp);
1515      findNapiClass(pFile, pFile->iStack[pFile->iStackPtr].iRefDir[iCurDir], nxclass);
1516      *datatype = DFTAG_VG;
1517      pFile->iStack[pFile->iStackPtr].iCurDir++;
1518      return NX_OK;
1519    } else {                      /* in Vgroup */
1520      if (pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_VG) {/* Vgroup */
1521        iTemp = Vattach (pFile->iVID,
1522                         pFile->iStack[iStackPtr].iRefDir[iCurDir], "r");
1523        if (iTemp < 0) {
1524          NXReportError( "ERROR: HDF cannot attach to Vgroup");
1525          return NX_ERROR;
1526        }
1527        Vgetname (iTemp, name);
1528        Vdetach(iTemp);
1529        findNapiClass(pFile, pFile->iStack[pFile->iStackPtr].iRefDir[iCurDir], nxclass);
1530        *datatype = DFTAG_VG;
1531        pFile->iStack[pFile->iStackPtr].iCurDir++;
1532        Vdetach (iTemp);
1533        return NX_OK;
1534        /* we are now writing using DFTAG_NDG, but need others for backward compatability */
1535      } else if ((pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_SDG) ||
1536                 (pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_NDG) ||
1537                 (pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_SDS)) {
1538        iTemp = SDreftoindex (pFile->iSID,
1539                              pFile->iStack[iStackPtr].iRefDir[iCurDir]);
1540        iTemp = SDselect (pFile->iSID, iTemp);
1541        SDgetinfo (iTemp, name, &iA, iDim, &iD1, &iD2);
1542        strcpy (nxclass, "SDS");
1543        *datatype = iD1;
1544        SDendaccess (iTemp);
1545        pFile->iStack[pFile->iStackPtr].iCurDir++;
1546        return NX_OK;
1547      } else {                    /* unidentified */
1548        strcpy (name, "UNKNOWN");
1549        strcpy (nxclass, "UNKNOWN");
1550        *datatype = pFile->iStack[iStackPtr].iTagDir[iCurDir];
1551        pFile->iStack[pFile->iStackPtr].iCurDir++;
1552        return NX_OK;
1553      }
1554    }
1555    return NX_ERROR;              /* not reached */
1556  }
1557
1558
1559  /*-------------------------------------------------------------------------*/
1560
1561   
1562  NXstatus  NX4getdata (NXhandle fid, void *data)
1563  {
1564    pNexusFile pFile;
1565    int32 iStart[H4_MAX_VAR_DIMS], iSize[H4_MAX_VAR_DIMS];
1566    NXname pBuffer;
1567    int32 iRank, iAtt, iType;
1568 
1569    pFile = NXIassert (fid);
1570 
1571    /* check if there is an SDS open */
1572    if (pFile->iCurrentSDS == 0) {
1573      NXReportError( "ERROR: no SDS open");
1574      return NX_ERROR;
1575    }
1576    /* first read dimension information */
1577    memset (iStart, 0, H4_MAX_VAR_DIMS * sizeof (int32));
1578    SDgetinfo (pFile->iCurrentSDS, pBuffer, &iRank, iSize, &iType, &iAtt);
1579    /* actually read */
1580    SDreaddata (pFile->iCurrentSDS, iStart, NULL, iSize, data);
1581    return NX_OK;
1582  } 
1583 
1584  /*-------------------------------------------------------------------------*/
1585
1586  NXstatus
1587   NX4getinfo64 (NXhandle fid, int *rank, int64_t dimension[], 
1588                            int *iType)
1589  {
1590    pNexusFile pFile;
1591    NXname pBuffer;
1592    int32 iAtt, myDim[H4_MAX_VAR_DIMS], i, iRank, mType;
1593 
1594    pFile = NXIassert (fid);
1595 
1596    /* check if there is an SDS open */
1597    if (pFile->iCurrentSDS == 0) {
1598      NXReportError( "ERROR: no SDS open");
1599      return NX_ERROR;
1600    }
1601    /* read information */
1602    SDgetinfo (pFile->iCurrentSDS, pBuffer, &iRank, myDim, 
1603               &mType, &iAtt);
1604
1605    /* conversion to proper ints for the platform */ 
1606    *iType = (int)mType;
1607    *rank = (int)iRank;
1608    for(i = 0; i < iRank; i++)
1609    {
1610       dimension[i] = (int)myDim[i];
1611    }
1612    return NX_OK;
1613  }
1614 
1615   
1616  /*-------------------------------------------------------------------------*/
1617
1618 
1619  NXstatus  NX4getslab64 (NXhandle fid, void *data, const int64_t iStart[], const int64_t iSize[])
1620  {
1621    pNexusFile pFile;
1622    int32 myStart[H4_MAX_VAR_DIMS], mySize[H4_MAX_VAR_DIMS];
1623    int32 i, iRank, iType, iAtt;
1624    NXname pBuffer; 
1625
1626    pFile = NXIassert (fid);
1627 
1628    /* check if there is an SDS open */
1629    if (pFile->iCurrentSDS == 0) {
1630      NXReportError( "ERROR: no SDS open");
1631      return NX_ERROR;
1632    }
1633
1634         SDgetinfo (pFile->iCurrentSDS, pBuffer, 
1635            &iRank, myStart, &iType, &iAtt);
1636         for(i = 0; i < iRank; i++)
1637         {
1638           myStart[i] = (int32)iStart[i];
1639           mySize[i]  = (int32)iSize[i];
1640         }
1641        /* finally read  */
1642        SDreaddata (pFile->iCurrentSDS, myStart, NULL, 
1643                   mySize, data);
1644        return NX_OK;
1645  }
1646 
1647  /*-------------------------------------------------------------------------*/
1648
1649  NXstatus  NX4getnextattr (NXhandle fileid, NXname pName,
1650           int *iLength, int *iType)
1651  {
1652    pNexusFile pFile;
1653    int iRet;
1654    int32 iPType, iCount, count;
1655 
1656    pFile = NXIassert (fileid);
1657 
1658    /* first check if we have to start a new attribute search */
1659    if (pFile->iAtt.iNDir == 0) {
1660      iRet = NXIInitAttDir (pFile);
1661      if (iRet == NX_ERROR) {
1662        return NX_ERROR;
1663      }
1664    }
1665    /* are we done ? */
1666    if (pFile->iAtt.iCurDir >= pFile->iAtt.iNDir) {
1667      NXIKillAttDir (pFile);
1668      return NX_EOD;
1669    }
1670    /* well, there must be data to copy */
1671    if (pFile->iCurrentSDS == 0) {       
1672      if(pFile->iCurrentVG == 0) {
1673        /* global attribute */
1674        iRet = SDattrinfo (pFile->iSID, pFile->iAtt.iCurDir,
1675                           pName, &iPType, &iCount);
1676      }else {
1677        /* group attribute */
1678        iRet = Vattrinfo(pFile->iCurrentVG, pFile->iAtt.iCurDir,
1679                         pName, &iPType, &iCount, &count);
1680      }
1681    } else {
1682      iRet = SDattrinfo (pFile->iCurrentSDS, pFile->iAtt.iCurDir,
1683                         pName, &iPType, &iCount);
1684    }
1685    if (iRet < 0) {
1686      NXReportError( "ERROR: HDF cannot read attribute info");
1687      return NX_ERROR;
1688    }
1689    *iLength = iCount;
1690    *iType = iPType;
1691    pFile->iAtt.iCurDir++;
1692    return NX_OK;
1693  }
1694   
1695 
1696  /*-------------------------------------------------------------------------*/
1697
1698
1699  NXstatus  NX4getattr (NXhandle fid, char *name, void *data, int* datalen, int* iType)
1700  {
1701    pNexusFile pFile;
1702    int32 iNew, iType32, count;
1703    void *pData = NULL;
1704    int32 iLen, iRet;
1705    int type;
1706    char pBuffer[256];
1707    NXname pNam;
1708 
1709    type = *iType;
1710    if (type == NX_CHAR)
1711    {
1712        type=DFNT_CHAR8;
1713    }
1714    else if (type == NX_INT8)
1715    {
1716        type=DFNT_INT8;
1717    }
1718    else if (type == NX_UINT8)
1719    {
1720        type=DFNT_UINT8;
1721    }
1722    else if (type == NX_INT16)
1723    {
1724        type=DFNT_INT16;
1725    }
1726    else if (type == NX_UINT16)
1727    {
1728        type=DFNT_UINT16;
1729    }
1730    else if (type == NX_INT32)
1731    {
1732        type=DFNT_INT32;
1733    }
1734    else if (type == NX_UINT32)
1735    {
1736        type=DFNT_UINT32;
1737    }
1738    else if (type == NX_FLOAT32)
1739    {
1740        type=DFNT_FLOAT32;
1741    }
1742    else if (type == NX_FLOAT64)
1743    {
1744        type=DFNT_FLOAT64;
1745    }
1746    *datalen = (*datalen) * DFKNTsize(type);
1747    pFile = NXIassert (fid);
1748 
1749    /* find attribute */
1750    if (pFile->iCurrentSDS != 0) {
1751      /* SDS attribute */
1752      iNew = SDfindattr (pFile->iCurrentSDS, name);
1753    } else {
1754      if(pFile->iCurrentVG == 0){
1755       /* global attribute */
1756       iNew = SDfindattr (pFile->iSID, name);
1757      } else {
1758        /* group attribute */
1759        iNew = Vfindattr(pFile->iCurrentVG, name); 
1760      }
1761    }
1762    if (iNew < 0) {
1763      sprintf (pBuffer, "ERROR: attribute \"%s\" not found", name);
1764      NXReportError( pBuffer);
1765      return NX_ERROR;
1766    }
1767    /* get more info, allocate temporary data space */
1768    iType32 = (int32)type;
1769    if (pFile->iCurrentSDS != 0) {
1770      iRet = SDattrinfo (pFile->iCurrentSDS, iNew, pNam, &iType32, &iLen);
1771    } else {
1772      if(pFile->iCurrentVG == 0){
1773        iRet = SDattrinfo (pFile->iSID, iNew, pNam, &iType32, &iLen);
1774      } else {
1775        iRet = Vattrinfo(pFile->iCurrentVG,iNew,pNam,&iType32,&count,
1776                         &iLen);
1777      }
1778    }
1779    if (iRet < 0) {
1780      sprintf (pBuffer, "ERROR: HDF could not read attribute info");
1781      NXReportError( pBuffer);
1782      return NX_ERROR;
1783    }
1784    *iType = (int)iType32;
1785    iLen = iLen * DFKNTsize (*iType);
1786    if(*iType == NX_CHAR){
1787      iLen += 1;
1788    }
1789    pData = (void *) malloc (iLen);
1790    if (!pData) {
1791      NXReportError( "ERROR: allocating memory in NXgetattr");
1792      return NX_ERROR;
1793    }
1794    memset (pData, 0, iLen);
1795 
1796    /* finally read the data */
1797    if (pFile->iCurrentSDS != 0) {
1798      iRet = SDreadattr (pFile->iCurrentSDS, iNew, pData);
1799    } else {
1800      if(pFile->iCurrentVG == 0){
1801        iRet = SDreadattr (pFile->iSID, iNew, pData);
1802      } else {
1803        iRet = Vgetattr(pFile->iCurrentVG, iNew, pData);
1804      }
1805    }
1806    if (iRet < 0) {
1807      sprintf (pBuffer, "ERROR: HDF could not read attribute data");
1808      NXReportError( pBuffer);
1809      return NX_ERROR;
1810    }
1811    /* copy data to caller */
1812    memset (data, 0, *datalen);
1813    if ((*datalen <= iLen) && 
1814     (*iType == DFNT_UINT8 || *iType == DFNT_CHAR8 || *iType == DFNT_UCHAR8)) {
1815      iLen = *datalen - 1; /* this enforces NULL termination regardless of size of datalen */
1816    }
1817    memcpy (data, pData, iLen);
1818    *datalen = iLen / DFKNTsize(*iType);
1819    free (pData);
1820    return NX_OK;
1821  }
1822 
1823  /*-------------------------------------------------------------------------*/
1824
1825   
1826  NXstatus  NX4getattrinfo (NXhandle fid, int *iN)
1827  {
1828    pNexusFile pFile;
1829    int iRet;
1830    int32 iData, iAtt, iRank, iType;
1831    int32 iDim[H4_MAX_VAR_DIMS];
1832    NXname pNam;
1833 
1834    pFile = NXIassert (fid);
1835    if (pFile->iCurrentSDS != 0) {        /* SDS level */
1836      iRet = SDgetinfo (pFile->iCurrentSDS, pNam, &iRank, iDim, &iType,
1837                        &iAtt);
1838    } else {
1839      if(pFile->iCurrentVG == 0){ 
1840        /* global level */
1841        iRet = SDfileinfo (pFile->iSID, &iData, &iAtt);
1842      } else {
1843        iRet = Vnattrs(pFile->iCurrentVG);
1844        iAtt = iRet;
1845      }
1846    }
1847    if (iRet < 0) {
1848      NXReportError( "NX_ERROR: HDF cannot read attribute numbers");
1849      *iN = 0;
1850      return NX_ERROR;
1851    }
1852    *iN = iAtt;
1853    return NX_OK;
1854  }
1855 
1856  /*-------------------------------------------------------------------------*/
1857
1858  NXstatus  NX4getgroupID (NXhandle fileid, NXlink* sRes)
1859  {
1860    pNexusFile pFile;
1861 
1862    pFile = NXIassert (fileid);
1863 
1864    if (pFile->iCurrentVG == 0) {
1865      sRes->iTag = NX_ERROR;
1866      return NX_ERROR;
1867    } else {
1868      sRes->iTag = DFTAG_VG;
1869      sRes->iRef = VQueryref(pFile->iCurrentVG);
1870      NXIbuildPath(pFile,sRes->targetPath,1024);
1871      return NX_OK;
1872    }
1873    /* not reached */
1874    sRes->iTag = NX_ERROR;
1875    return NX_ERROR;
1876  }
1877
1878 /*-------------------------------------------------------------------------*/
1879
1880  NXstatus
1881   NX4getgroupinfo (NXhandle fid, int *iN, NXname pName, NXname pClass)
1882  {
1883    pNexusFile pFile;
1884 
1885    pFile = NXIassert (fid);
1886    /* check if there is a group open */
1887    if (pFile->iCurrentVG == 0) {
1888      *iN = Vlone (pFile->iVID, NULL, 0);
1889      strcpy (pName, "root");
1890      strcpy (pClass, "NXroot");
1891    }
1892    else {
1893      *iN = Vntagrefs (pFile->iCurrentVG);
1894      Vgetname (pFile->iCurrentVG, pName);
1895      Vgetclass (pFile->iCurrentVG, pClass);
1896    }
1897    return NX_OK;
1898  }
1899 
1900  /* ------------------------------------------------------------------- */
1901
1902  NXstatus  NX4sameID (NXhandle fileid, NXlink* pFirstID, NXlink* pSecondID)
1903  {
1904    NXIassert (fileid);
1905    if ((pFirstID->iTag == pSecondID->iTag) & (pFirstID->iRef == pSecondID->iRef)) {
1906       return NX_OK;
1907    } else {
1908       return NX_ERROR;
1909    }
1910  }
1911
1912  /*-------------------------------------------------------------------------*/
1913
1914 
1915  NXstatus  NX4initattrdir (NXhandle fid)
1916  {
1917    pNexusFile pFile;
1918    int iRet;
1919   
1920    pFile = NXIassert (fid);
1921    NXIKillAttDir (pFile);
1922    iRet = NXIInitAttDir (pFile);
1923    if (iRet == NX_ERROR)
1924      return NX_ERROR;
1925    return NX_OK;
1926  }
1927 
1928 
1929  /*-------------------------------------------------------------------------*/
1930 
1931 
1932  NXstatus  NX4initgroupdir (NXhandle fid)
1933  {
1934    pNexusFile pFile;
1935    int iRet;
1936   
1937    pFile = NXIassert (fid);
1938    NXIKillDir (pFile);
1939    iRet = NXIInitDir (pFile);
1940    if (iRet < 0) {
1941      NXReportError("NX_ERROR: no memory to store directory info");
1942      return NX_EOD;
1943    }
1944    return NX_OK;
1945  }
1946 
1947/*--------------------------------------------------------------------*/
1948void NX4assignFunctions(pNexusFunction fHandle)
1949{
1950      fHandle->nxclose=NX4close;
1951          fHandle->nxreopen=NULL;
1952      fHandle->nxflush=NX4flush;
1953      fHandle->nxmakegroup=NX4makegroup;
1954      fHandle->nxopengroup=NX4opengroup;
1955      fHandle->nxclosegroup=NX4closegroup;
1956      fHandle->nxmakedata64=NX4makedata64;
1957      fHandle->nxcompmakedata64=NX4compmakedata64;
1958      fHandle->nxcompress=NX4compress;
1959      fHandle->nxopendata=NX4opendata;
1960      fHandle->nxclosedata=NX4closedata;
1961      fHandle->nxputdata=NX4putdata;
1962      fHandle->nxputattr=NX4putattr;
1963      fHandle->nxputslab64=NX4putslab64;   
1964      fHandle->nxgetdataID=NX4getdataID;
1965      fHandle->nxmakelink=NX4makelink;
1966      fHandle->nxmakenamedlink=NX4makenamedlink;
1967      fHandle->nxgetdata=NX4getdata;
1968      fHandle->nxgetinfo64=NX4getinfo64;
1969      fHandle->nxgetnextentry=NX4getnextentry;
1970      fHandle->nxgetslab64=NX4getslab64;
1971      fHandle->nxgetnextattr=NX4getnextattr;
1972      fHandle->nxgetattr=NX4getattr;
1973      fHandle->nxgetattrinfo=NX4getattrinfo;
1974      fHandle->nxgetgroupID=NX4getgroupID;
1975      fHandle->nxgetgroupinfo=NX4getgroupinfo;
1976      fHandle->nxsameID=NX4sameID;
1977      fHandle->nxinitgroupdir=NX4initgroupdir;
1978      fHandle->nxinitattrdir=NX4initattrdir;
1979      fHandle->nxprintlink=NX4printlink;
1980      fHandle->nxnativeexternallink=NULL;
1981}
1982
1983#endif /*HDF4*/
Note: See TracBrowser for help on using the repository browser.