#include #include #include #include #include "sds.h" /*@@ @file sds.c @date Wed Feb 26 20:05:00 1996 @author John Shalf @desc The SDS routines are a wrapper for the HDF SD interface that allows you to refer to files by name instead of explicitly opening them and refering to them by fileID. This file contain all of the source code that implements these wrappers. @enddesc @includes sds.h @seeheader sds.h @version 1.0 @@*/ static int32 DefaultNumberType=DFNT_FLOAT32; static int32 nfiles=0,maxfiles=54; /* Need to set the default NumberType!!!! */ typedef struct fileID { char componentname[128]; char filename[256]; char sds_name[MAX_NC_NAME]; /* to keep track of SDS name internally */ int32 id,sds_id,sdsnumber,nsds,nattrib,numbertype; int32 accessflags; clock_t lastaccess; /* in clock ticks. Uses clock(). CLOCKS_PER_SEC */ struct fileID *next; }fileID; static fileID *files=NULL; /*@@ @routine deactivateOldFiles @date Wed Feb 28 15:37:43 1996 @desc Finds the filesID's with longest time since last reference and deactivates the worst 1/8 of them to free up some file descriptors. @enddesc @seeroutine SDSdeactivate SDSreactivate getFileID @calledby NewFileID @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ static void deactivateOldFiles() { fileID *tmpid; int i,ntimes; clock_t *worst_times; ntimes=maxfiles>>3; /* Ok, divide by 8 */ ntimes=ntimes?ntimes:1; /* make sure its >0 */ /* It was the best of times... it was the worst of times... */ worst_times=(clock_t *)calloc(ntimes,sizeof(clock_t)); /* first search for the top-1/8 longest times since last access */ for(tmpid=files;tmpid;tmpid=tmpid->next){ clock_t t=tmpid->lastaccess; if(tmpid->id<0) continue; for(i=0;inext) if(tmpid->id && tmpid->lastaccess<=worst_times[ntimes-1]) SDSdeactivate(tmpid->filename); /* deactivate it */ free(worst_times); } /*@@ @routine NewFileID @date Wed Feb 28 15:37:43 1996 @desc Creates a new fileID structure, opens the file and initializes all of the structure elements. @enddesc @calledby SDSopen getFileID @calls deactivateOldFiles @par name @pdesc Name of the HDF file to open or create @ptype char* @endpar @par access @pdesc Access mode for the file (uses ANSI C access modes) @ptype char* @pvalues "r","w","rw","w+","ra" @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ fileID *NewFileID(char *name,char *access) { fileID *id=(fileID *)calloc(sizeof(fileID),1); strcpy(id->componentname,name); strcpy(id->filename,name); /* make certain that there are enough file descriptors around */ if(nfiles==maxfiles){ /* gotta deactivate a few */ int ofls=nfiles; deactivateOldFiles(); /* JMS KLUDGE */ /*fprintf(stderr,"NewFileID: deactivate old files->%u to %u\n",ofls,nfiles);*/ } else{ /* JMS KLUDGE */ /*fprintf(stderr,"NewFileID: plenty of files free->%u\n",nfiles);*/ } /* open SDS */ if(*access=='r'){ if(access[1]=='w'){ id->id=SDstart(id->filename,id->accessflags=DFACC_RDWR); if(id->id<0){ /* kludge around HDF bug (or misfeature) */ /* If open RDWR fails, then need to create file by opening with DFACC_CREATE */ id->id=SDstart(id->filename,id->accessflags=DFACC_CREATE); } SDfileinfo(id->id,&(id->nsds),&(id->nattrib)); id->sdsnumber=0; /* end of file */ if(id->accessflags!=DFACC_CREATE) id->sds_id=SDselect(id->id,0); /* goto first */ else id->sds_id=-1; } else if (access[1]=='a' || access[1]=='+') { id->id=SDstart(id->filename,id->accessflags=DFACC_RDWR); nfiles++; if(id->id<0){ /* kludge around HDF bug */ /* If open RDWR fails, then need to create file by opening with DFACC_CREATE */ id->id=SDstart(id->filename,id->accessflags=DFACC_CREATE); } SDfileinfo(id->id,&(id->nsds),&(id->nattrib)); id->sdsnumber=id->nsds; /* end of file */ if(id->accessflags!=DFACC_CREATE) id->sds_id=SDselect(id->id,id->sdsnumber); /* goto last */ else id->sds_id=-1; } else { id->id=SDstart(id->filename,id->accessflags=DFACC_RDONLY); SDfileinfo(id->id,&(id->nsds),&(id->nattrib)); id->sdsnumber=0; /* end of file */ id->sds_id=SDselect(id->id,id->sdsnumber); /* means, need to create */ } } else if(*access=='w'){ if(access[1]=='\0'){ id->id=SDstart(id->filename,id->accessflags=DFACC_CREATE); id->sdsnumber=id->nsds=0; /* end of file */ id->sds_id=-1; /* means, need to create */ } else{ id->id=SDstart(id->filename,id->accessflags=DFACC_ALL); SDfileinfo(id->id,&(id->nsds),&(id->nattrib)); id->sdsnumber=id->nsds; id->sds_id=SDselect(id->id,id->sdsnumber); /* goto last */ } } if(id->id >= 0) nfiles++; /* it has been opened successfully */ id->lastaccess=clock(); id->numbertype=DefaultNumberType; id->next=files; files=id; return id; } /*@@ @routine findIDbyComponent @date Wed Feb 28 20:37:43 1996 @desc Finds a File ID given the name of the component that the file contains. This is to support a user interface style in which the componentnames can be used as alias for the actual filename. @enddesc @par name @pdesc Name of the component. @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ fileID *findIDbyComponent(name) char *name; { fileID *id; for(id=files;id!=NULL;id=id->next) if(!strcmp(name,id->componentname)) break; return id; } /*@@ @routine findIDbyFilename @date Wed Feb 28 20:37:43 1996 @desc Finds a File ID given the name of the component that the file contains. This is to support a user interface style in which the componentnames can be used as alias for the actual filename. @enddesc @calledby SDSopen SDSclose SDSdeactivate SDSreactivate getFileID @par name @pdesc Name of the HDF file. @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ fileID *findIDbyFilename(name) char *name; { fileID *id; for(id=files;id!=NULL;id=id->next) if(!strcmp(name,id->filename)) break; return id; } /*@@ @routine removeFileID @date Wed Feb 28 20:37:43 1996 @desc Remove a file ID reference and free associated memory. It does not close the HDF file if is left open though. @enddesc @calledby SDSclose getFileID @par name @pdesc Name of the file. @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ void removeFileID(filename) char *filename; { fileID *id,*lastid; for(lastid=0,id=files;id;lastid=id,id=id->next) { if(!strcmp(id->filename,filename)){ if(!lastid){ files=id->next; } else { lastid->next=id->next; } free(id); } } } /*@@ @routine SDScomputeSize @date Wed Feb 28 15:37:43 1996 @desc Computes the Size in bytes required to store a dataset based on its dimensions and datatype. @enddesc @seeroutine SDSgetDims SDSreadData @par rank @pdesc Number of dimensions in the dataset @ptype int32 @endpar @par dims @pdesc The size of each dimension in the dataset (in elements). @ptype int32* @endpar @par datatype @pdesc The HDF datatype for each element in the dataset. @ptype int32* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ long SDScomputeSize(rank,dims,datatype) int32 rank; int32 *dims; int32 datatype; { register int i,n; register long nbytes; for(nbytes=1,n=rank,i=0;inext; if(id->sds_id>=0) SDendaccess(id->sds_id); id->sds_id=-1; if(id->id>=0){ nfiles--; SDend(id->id); } id->id=-1; free(id); } files=NULL; } /*@@ @routine SDSdeactivate @date Wed Feb 28 15:37:43 1996 @desc Closes and HDF file but preserves its access state so that it can be reactivated later. Used to free up file descriptors temporarily when more files are active than there are file descriptors availible. Used for "file descriptor juggling". @enddesc @seeroutine SDSreactivate @calledby getFileID @calls findIDbyFilename @par name @pdesc Name of the HDF file @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ /* make file handle inactive (use if shortage of descriptors) */ void SDSdeactivate(filename) char *filename; { fileID *id=findIDbyFilename(filename); if(id){ if(id->sds_id) SDendaccess(id->sds_id); SDend(id->id); id->id=-1; nfiles--; if(id->accessflags==DFACC_CREATE) id->accessflags=DFACC_RDWR; /* make sure it doesn't purge the file on reactivation */ } } /*@@ @routine SDSreactivate @date Wed Feb 28 15:37:43 1996 @desc Reopens an HDF file closed by SDSdeactivate and returns it to its original state. @enddesc @seeroutine SDSdeactivate @calledby getFileID @calls findIDbyFilename @par name @pdesc Name of the HDF file @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ void SDSreactivate(filename) char *filename; { fileID *id=findIDbyFilename(filename); if(id && id->id < 0){ id->id=SDstart(filename,id->accessflags); if(id->id) nfiles++; if(id->sds_id>=0) id->sds_id=SDselect(id->id,id->sdsnumber); } } /*@@ @routine SDSclose @date Wed Feb 28 15:37:43 1996 @desc Closes an HDF file and removes its state description from memory. @enddesc @seeroutine SDSopen SDSdeactivate SDSreactivate @calls findIDbyFilename @par name @pdesc Name of the HDF file @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ void SDSclose(filename) char *filename; { fileID *id=findIDbyFilename(filename); if(id) { SDend(id->id); nfiles--; removeFileID(filename); } } /*@@ @routine getFileID @date Wed Feb 28 20:37:43 1996 @desc Checks to see if the specified file is open. If it isn't already availbile, it opens it in read-write mode. Otherwise return the existing fileID structure. @enddesc @calls findIDbyFilename @calledby SDSopen SDSflush SDSpurge SDSseek SDSseekName SDSgetIndex SDSisCoord SDSgetFileInfo SDSgetDataName SDSgetNumDatasets SDSgetDims SDSgetNT SDSsetNT SDSreadData SDSreadChunk SDSallocateDataset SDSwriteData SDSwriteChunk SDSaddAnnotation SDSgetAnnotationSize SDSgetAnnotation SDSgetNumAttribs SDSwriteAttrib SDSreadAttrib SDSfindAttribInfo SDSgetAttribInfo SDSgetDataStrs @par name @pdesc Name of the HDF file. @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ fileID *getFileID(filename) char *filename; { fileID *id=findIDbyFilename(filename); if(!id){ /* fprintf(stderr,"getFileID(): create new fid for %s\n",filename); */ id=NewFileID(filename,"rw"); } else id->lastaccess=clock(); if(id->id<0) SDSreactivate(filename); /* could be more efficient */ return id; } /*@@ @routine SDSopen @date Wed Feb 28 15:37:43 1996 @desc Opens an HDF file in specified access mode. @enddesc @seeroutine SDSclose SDSdeactivate SDSreactivate @calls findIDbyFilename NewFileID @par name @pdesc Name of the HDF file @ptype char* @endpar @par access @pdesc Access mode for the file (uses ANSI C access modes) @ptype char* @pvalues "r","w","rw","w+","ra" @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ void SDSopen(filename,access) char *filename,*access; { fileID *id=findIDbyFilename(filename); if(!id) id=NewFileID(filename,access); } /*@@ @routine SDSflush @date Wed Feb 28 15:37:43 1996 @desc Flushes the HDF file so that if a crash occurs, the contents of the file will be preserved. (currently disabled) @enddesc @seeroutine SDSclose SDSdeactivate SDSreactivate @calls findIDbyFilename SDSdeactivate SDSreactivate @par name @pdesc Name of the HDF file @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @hdate Tues March 8 @hdesc Commented out deactivate/reactivate due to file access mode problems (must fix later) @endhistory @@*/ void SDSflush(filename) char *filename; { fileID *id=findIDbyFilename(filename); if(id && id->sds_id>=0){ SDendaccess(id->sds_id); /* id->sds_id=-1; (deactivate & reactivate will fail if you do this */ SDselect(id->id,id->sdsnumber); } /* SDSdeactivate(filename); SDSreactivate(filename); */ } /*@@ @routine SDSpurge @date Wed Feb 28 15:37:43 1996 @desc Purges an HDF file, removing all of its contents. Can Use to garauntee that you are writing into a fresh HDF file since the default way SDS opens a file is Read/Write/Append mode. Potentially dangerous routine... @enddesc @calls SDSclose SDSopen @par name @pdesc Name of the HDF file @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ void SDSpurge(filename) char *filename; { SDSclose(filename); SDSopen(filename,"w"); } /*@@ @routine SDSseek @date Wed Feb 28 15:37:43 1996 @desc Allows random acces in HDF files. Moves to the sds in the file specified by setnum. @enddesc @calls getFileID @par name @pdesc Name of the HDF file @ptype char* @endpar @par setnum @pdesc Index of the dataset in the HDf file @ptype int @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ /************** Potential problem.... On seek the fileID is not properly reclaimed *************/ void SDSseek(filename,setnum) char *filename; int setnum; { fileID *id=getFileID(filename); id->sdsnumber=setnum; if(id->sds_id>=0) SDendaccess(id->sds_id); id->sds_id=SDselect(id->id,id->sdsnumber); } /*@@ @routine SDSseekName @date Wed Feb 28 15:37:43 1996 @desc Allows random acces in HDF files. Moves to the sds in the file with the name specified by "dataname". @enddesc @calls getFileID @par name @pdesc Name of the HDF file @ptype char* @endpar @par dataname @pdesc Name of the dataset in the HDf file @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSseekName(filename,dataname) char *filename,*dataname; { fileID *id=getFileID(filename); id->sdsnumber=SDnametoindex(id->id,dataname); if(id->sds_id>=0) SDendaccess(id->sds_id); id->sds_id=SDselect(id->id,id->sdsnumber); return id->sdsnumber; } /*@@ @routine SDSgetNT @date Wed Feb 28 15:37:43 1996 @desc Gets the numbertype of the current SDS. @enddesc @calls getFileID @par name @pdesc Name of the HDF file @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ /* analogue to DFSDgetDims() it gets the AMR attributes of the next SDS */ int32 SDSgetNT(filename) char *filename; { int32 numbertype,attribs,rank,dims[MAX_VAR_DIMS]; fileID *id=getFileID(filename); if(id->sds_id<0) id->sds_id=SDselect(id->id,id->sdsnumber); if(id->sds_id<0) return -1; SDgetinfo(id->sds_id,NULL,&rank,dims,&numbertype,&attribs); id->numbertype=numbertype; return numbertype; } /*@@ @routine SDSisCoord @date Wed Feb 28 15:37:43 1996 @desc Returns 1 if the current dataset is a coordinate array and false if it is not. This is a direct passthru of the function SDisCoordVar(). This function has become necessary because in order to make HDF compatible with NetCDF, the files the designers had to disable its ability to tell the difference between datasets and stored coordinates for the datasets. @enddesc @calls getFileID @par name @pdesc Name of the HDF file @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSisCoord(filename) char *filename; { fileID *id=getFileID(filename); if(id->sds_id<0) id->sds_id=SDselect(id->id,id->sdsnumber); if(id->sds_id<0) return -1; return SDiscoordvar(id->sds_id); } /*@@ @routine SDSsetNT @date Wed Feb 28 15:37:43 1996 @desc Sets the default numbertype for a particular HDF file. All further write operations will assume this numbertype until SDSsetNT is used again to select a new numbertype.

The default numbertype is DFNT_FLOAT32 (32 bit float) @enddesc @calls getFileID @par name @pdesc Name of the HDF file @ptype char* @endpar @par numbertype @pdesc Numbertype for subsequent data writes @ptype char* @pvalues DFNT_FLOAT32 (32-bit float), DFNT_FLOAT64 (64-bit float/double), DFNT_INT8 (char), DFNT_INT16 (short int), DFNT_INT32,(int), DFNT_UINT8 (unsigned char), DFNT_UNINT16 (unsigned short), DFNT_UINT32 (unsigned int), DFNT_NATIVE (if bit-OR'ed with the above, uses machine native format) @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ void SDSsetNT(filename,numbertype) char *filename; int32 numbertype; { fileID *id=getFileID(filename); id->numbertype=numbertype; } /*@@ @routine SDSgetDims @date Wed Feb 28 15:37:43 1996 @desc Reads data from an HDF file. This must be preceded by an SDSgetDims() which returns the dimensions of the data so that the user can allocate the space to read in the data. @enddesc @seeroutine SDSreadData @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par name @pdesc Name of the dataset (read from the file) @ptype char* @endpar @par rank @pdesc Number of dimension in the dataset @ptype int32 @endpar @par dims @pdesc Dimensions of the dataset @ptype int32* @endpar @par data @pdesc Pointer to the actual dataset (preallocated by the user) @ptype VOIDP @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ long SDSgetDims (filename,dataname,rank,dims) char *filename; char *dataname; int32 *rank; int32 *dims; { int32 numbertype,attribs; long status; fileID *id=getFileID(filename); if(id->sds_id>=0) SDendaccess(id->sds_id); id->sds_id=SDselect(id->id,(id->sdsnumber)++); if(id->sds_id<0) return -1; status=SDgetinfo(id->sds_id,dataname,rank,dims,&numbertype,&attribs); if(status>=0){ id->numbertype=numbertype; return SDScomputeSize(*rank,dims,numbertype); } else return -1; } /*@@ @routine SDSreadData @date Wed Feb 28 15:37:43 1996 @desc Reads data from an HDF file. This must be preceded by an SDSgetDims() which returns the dimensions of the data so that the user can allocate the space to read in the data. @enddesc @seeroutine SDSgetDims @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par dataname @pdesc Name of the dataset (read from the file) @ptype char* @endpar @par rank @pdesc Number of dimension in the dataset @ptype int32 @endpar @par dims @pdesc Dimensions of the dataset @ptype int32* @endpar @par data @pdesc Pointer to the actual dataset (preallocated by the user) @ptype VOIDP @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int SDSreadData(filename,rank,dims,data) char *filename; int32 rank,*dims; VOIDP data; { static int32 originS[5]={0,0,0,0,0},*origin; int32 natt,nt; int status; fileID *id=getFileID(filename); if(id->sds_id<0) id->sds_id=SDselect(id->id,id->sdsnumber); if(rank > 5) { origin=(int32 *)calloc(sizeof(int),rank); /* origin is zeroed */ } else origin=originS; if(id->sds_id<0) id->sds_id=SDselect(id->id,id->sdsnumber); if(id->sds_id<0) return -1; /*SDgetinfo(id->sds_id,NULL,&rank,dims,&(id->numbertype),&(id->nattrib));*/ status = SDreaddata(id->sds_id,origin,NULL,dims,data); if(origin!=originS) free(origin); if(status>=0) return SDScomputeSize(rank,dims,id->numbertype); else return -1; } /*@@ @routine SDSreadChunk @date Wed Feb 28 15:37:43 1996 @desc Reads a subsection (chunk) of data from a selected dataset. You can specify any origin, stride, and region- of-interest within the total size of the dataset. A dataset must have been selected by an SDSgetDims() which returns the total dimensions of the data. Once selected though, it can be followed by any number of reads. @enddesc @seeroutine SDSgetDims @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par rank @pdesc Number of dimension in the dataset @ptype int32 @endpar @par dims @pdesc Dimensions of the dataset to read @ptype int32* @endpar @par origin @pdesc Origin of the read within the dataset @ptype int32* @endpar @par stride @pdesc Stride of the read in each dimension @ptype int32* @endpar @par data @pdesc Pointer to the actual dataset (preallocated by the user) @ptype VOIDP @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version need to eliminate chunk reading inefficiency. Basically, it needs to re-read the chunkname on every cycle which results in a lot of unneccessary seeking. To optimize, will need to store the sds name internally and only get it again if its a different sds. Either that or just separate readNamedChunk from this one. @hdate Tues Mar 8 @hauthor @hdesc Eliminated "name" from parameter list. Depends on SDSgetDims to read the name now. @endhistory @@*/ int SDSreadChunk(filename,rank,dims, origin,stride,data) char *filename; int32 rank,*dims; int32 *origin,*stride; VOIDP data; { static int32 originS[5]={0,0,0,0,0}; int32 natt,nt; int status; char name[MAX_NC_NAME]; fileID *id=getFileID(filename); if(!origin){ if(rank > 5) { origin=(int32 *)calloc(sizeof(int),rank); /* origin is zeroed */ } else origin=originS; } if(id->sds_id<0){ id->sds_id=SDselect(id->id,id->sdsnumber); if(id->sds_id<0) return -1; SDgetinfo(id->sds_id,name,&rank,dims,&(id->numbertype),&(id->nattrib)); } status = SDreaddata(id->sds_id,origin,stride,dims,data); if(origin!=originS) free(origin); return status; } /*@@ @routine SDSgetFileInfo @date Wed Feb 28 15:37:43 1996 @desc Gets information relevant to the entire file. Namely the number datasets contained in the file as well as the number of attributes associated with the file. @enddesc @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par nsds @pdesc Number of datasets (sds's) in the hdf file @ptype int32* @endpar @par nattrib @pdesc Number of netcdf attributes for the file @ptype int32* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ void SDSgetFileInfo (filename,nsds,nattrib) char *filename; int32 *nsds; int32 *nattrib; { fileID *id=getFileID(filename); if(nsds) *nsds=id->nsds; if(nattrib) *nattrib=id->nattrib; } /*@@ @routine SDSgetDataName @date Wed Feb 28 15:37:43 1996 @desc Gets the name of the current dataset @enddesc @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par dataname @pdesc Name of the current dataset @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @hdate Tues June 11 29:30:57 1996 @hauthor John Shalf @hdesc Corrected bug whereby rank was passed as a literal instead of a pointer to SDgetinfo @endhistory @@*/ int32 SDSgetDataName (filename,name) char *filename; char *name; { int32 status; int32 rank,dims[MAX_NC_DIMS]; fileID *id=getFileID(filename); if(id->sds_id<0) id->sds_id=SDselect(id->id,id->sdsnumber); if(id->sds_id<0) return -1; status=SDgetinfo(id->sds_id,name,&rank,dims, &(id->numbertype), &(id->nattrib)); return status; } /*@@ @routine SDSgetIndex @date Wed Feb 28 15:37:43 1996 @desc Returns the index of the current dataset @enddesc @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSgetIndex (filename) char *filename; { fileID *id=getFileID(filename); return id->sdsnumber; } /*@@ @routine SDSgetDataStrs @date Wed Feb 28 15:37:43 1996 @desc Retrieves the data strings associated with the current dataset. @enddesc @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par label @pdesc Label of the current dataset @ptype char* @endpar @par units @pdesc Units of the current dataset (ie. meters, millibars, foot-pounds) @ptype char* @endpar @par format @pdesc Format of the current dataset @ptype char* @endpar @par coordsys @pdesc Coordinate system for the current dataset. @ptype char* @endpar @par maxlen @pdesc Maximum length of a string the variables can receive. @ptype int32 @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSgetDataStrs (filename,label,units,format,coordsys,maxlen) char *filename,*label,*units,*format,*coordsys; int maxlen; { fileID *id=getFileID(filename); if(id->sds_id<0) id->sds_id=SDselect(id->id,id->sdsnumber); if(id->sds_id<0) return -1; return SDgetdatastrs(id->sds_id,label,units,format,coordsys,maxlen); } /*@@ @routine SDSgetNumDatasets @date Wed Feb 28 15:37:43 1996 @desc Returns the number of SDS's in the current dataset @enddesc @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSgetNumDatasets (filename) char *filename; { fileID *id=getFileID(filename); return id->nsds; } /*@@ @routine SDSallocateDataset @date Wed Feb 28 15:37:43 1996 @desc Creates and reserves a dataset to receive data in chunks. Use in conjunction with SDSwriteChunk. @enddesc @seeroutine SDSwriteChunk @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par dataname @pdesc Name of the SDS @ptype char* @endpar @par rank @pdesc Number of dimensions for the dataset @ptype char* @endpar @par dims @pdesc The maximum dimension sizes for the dataset (can be SD_UNLIMITED in any dimension to allow the space availible to automatically grow as you write chunks) @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSallocateDataset(filename,dataname,rank,dims) char *filename,*dataname; int32 rank,*dims; { static int32 originS[5]={0,0,0,0,0}; int status; fileID *id=getFileID(filename); if(id->accessflags==DFACC_RDONLY) return -1; /* cant write to this file */ if(id->sds_id>=0) SDendaccess(id->sds_id); /* may no longer be a valid operation */ id->sds_id=SDcreate(id->id,dataname,id->numbertype,rank,dims); if(id->sds_id>=0) (id->nsds)++; return id->sdsnumber=SDreftoindex(id->id,SDidtoref(id->sds_id)); } /*@@ @routine SDSwriteChunk @date Wed Feb 28 15:37:43 1996 @desc Writes a chunk of data to an sds with any stride, origin, and dimension so long as the chunk falls within the bounds of the dataset reserved with SDSallocateDataset(). If any of the dimensions were declared SD_UNLIMITED for size, then the size of the chunk is only constrained by system and file size limits. @enddesc @seeroutine SDSallocateDataset @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par rank @pdesc Number of dimensions for the dataset @ptype char* @endpar @par dims @pdesc The maximum dimension sizes for the dataset (can be SD_UNLIMITED in any dimension to allow the space availible to automatically grow as you write chunks) @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int SDSwriteChunk (filename,rank,dims, origin,stride,data) char *filename; int32 rank,*dims; int32 *origin,*stride; VOIDP data; { static int32 originS[5]={0,0,0,0,0}; int status; fileID *id=getFileID(filename); if(id->accessflags==DFACC_RDONLY) return -1; /* cant write to this file */ if(!origin){ if(rank > 5) { origin=(int32 *)calloc(sizeof(int32),rank); /* origin is zeroed */ } else origin=originS; } if(id->sds_id<0) return -1; /* have to reserve the chunk first!! */ /* if(id->sds_id<0) only create if it doesn't already exist id->sds_id=SDcreate(id->id,id->dataname,id->numbertype,rank,dims); */ if(id->sds_id>=0) (id->nsds)++; id->sdsnumber=SDreftoindex(id->id,SDidtoref(id->sds_id)); status=SDwritedata(id->sds_id,origin,stride,dims,data); /* SDendaccess(id->sds_id); (might append annotation) */ if(origin!=originS) free(origin); return status; } /*@@ @routine SDSwriteData @date Wed Feb 28 15:37:43 1996 @desc Writes a chunk of data to an sds with any stride, origin, and dimension so long as the chunk falls within the bounds of the dataset reserved with SDSallocateDataset(). If any of the dimensions were declared SD_UNLIMITED for size, then the size of the chunk is only constrained by system and file size limits. @enddesc @seeroutine SDSreadData SDSsetNT() @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par dataname @pdesc Name for the dataset @ptype char* @endpar @par rank @pdesc Number of dimensions for the dataset @ptype char* @endpar @par dims @pdesc The maximum dimension sizes for the dataset @ptype char* @endpar @par data @pdesc Pointer to the dataset to write. Default type is DFNT_FLOAT32 (32-bit float). This default can be changed using SDSsetNT(). @ptype VOIDP @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int SDSwriteData (filename,dataname,rank,dims,data) char *filename,*dataname; int32 rank,*dims; VOIDP data; { static int32 originS[5]={0,0,0,0,0},*origin; int status; fileID *id=getFileID(filename); if(id->accessflags==DFACC_RDONLY) return -1; /* cant write to this file */ if(id->sds_id>=0) SDendaccess(id->sds_id); if(rank > 5) { origin=(int32 *)calloc(sizeof(int32),rank); /* origin is zeroed */ } else origin=originS; id->sds_id=SDcreate(id->id,dataname,id->numbertype,rank,dims); if(id->sds_id>=0) (id->nsds)++; id->sdsnumber=SDreftoindex(id->id,SDidtoref(id->sds_id)); status=SDwritedata(id->sds_id,origin,NULL,dims,data); /* SDendaccess(id->sds_id); (might append annotation) */ if(origin!=originS) free(origin); return status; } /*@@ @routine SDSgetAnnotationSize @date Wed Feb 28 15:37:43 1996 @desc Returns the size of the current annotation attached to the current dataset @enddesc @seeroutine SDSgetAnnotation @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSgetAnnotationSize(filename) char *filename; { int32 ref; fileID *id=getFileID(filename); if(id->accessflags==DFACC_RDONLY) return -1; /* cant write to this file */ if(id->sds_id<0) id->sds_id=SDselect(id->id,id->sdsnumber); ref=SDidtoref(id->sds_id); return DFANgetlablen(id->filename,DFTAG_NDG,ref); } /*@@ @routine SDSgetAnnotation @date Wed Feb 28 15:37:43 1996 @desc Returns the size of the current annotation attached to the current dataset. @enddesc @seeroutine SDSgetAnnotationSize SDSaddAnnotation @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par annotation @pdesc buffer to store the annotation in @ptype char* @endpar @par maxlen @pdesc Maximum length of the annotation (ie. the buffer size) @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSgetAnnotation(filename,annotation,maxlen) char *filename; char *annotation; int32 maxlen; { int32 ref; fileID *id=getFileID(filename); if(id->accessflags==DFACC_RDONLY) return -1; /* cant write to this file */ if(id->sds_id<0) id->sds_id=SDselect(id->id,id->sdsnumber); ref=SDidtoref(id->sds_id); return DFANgetlabel(id->filename,DFTAG_NDG,ref,annotation,maxlen); } /*@@ @routine SDSaddAnnotation @date Wed Feb 28 15:37:43 1996 @desc Adds a text string annotation to the currently selected SDS @enddesc @seeroutine SDSgetAnnotation SDSgetAnnotationSize @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par annotation @pdesc buffer to store the annotation in @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSaddAnnotation(filename,annotation) char *filename; char *annotation; { int32 ref; fileID *id=getFileID(filename); if(id->accessflags==DFACC_RDONLY) return -1; /* cant write to this file */ if(id->sds_id<0) id->sds_id=SDselect(id->id,id->sdsnumber); ref=SDidtoref(id->sds_id); return DFANputlabel(id->filename,DFTAG_NDG,ref,annotation); } /*@@ @routine SDSgetNumAttribs @date Wed Feb 28 15:37:43 1996 @desc Returns the number of attributes associated with the current dataset. The attributes can be retreived by name (if you already know which attributes you are looking for) or by index (if you want to step through them in order). Returns an error if no SDS is currently selected. @enddesc @seeroutine SDSreadAttrib SDSfindAttribInfo SDSgetAttribInfo @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSgetNumAttribs(filename) char *filename; { int nattribs; fileID *id=getFileID(filename); if(id->sds_id>=0) return id->nattrib; else return -1; /* or should it return 0???? */ } /*@@ @routine SDSwriteAttrib @date Wed Feb 28 15:37:43 1996 @desc Writes an attribute associated with the current SDS to the HDF file. The attribute can be referred to by its name or by its index when read back in. @enddesc @seeroutine SDSreadAttrib SDSfindAttribInfo SDSgetAttribInfo SDSgetNumAttribs @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par attribname @pdesc Name of the attribute. @ptype char* @endpar @par numbertype @pdesc Numbertype of the attribute @pvalues DFNT_FLOAT32 (32-bit float), DFNT_FLOAT64 (64-bit float/double), DFNT_INT8 (char), DFNT_INT16 (short int), DFNT_INT32,(int), DFNT_UINT8 (unsigned char), DFNT_UNINT16 (unsigned short), DFNT_UINT32 (unsigned int), DFNT_NATIVE (if bit-OR'ed with the above, uses machine native format) @ptype int32 @endpar @par nelements @pdesc Number of elements (of the type specified by the numbertype param) to store in the attribute. @ptype int32 @endpar @par buffer @pdesc Pointer to the attribute data. @ptype VOIDP @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSwriteAttrib(filename,attribname,numbertype,nelements,buffer) char *filename; char *attribname; int32 numbertype; int32 nelements; VOIDP buffer; { int32 ref; fileID *id=getFileID(filename); if(id->accessflags==DFACC_RDONLY) return -1; /* cant write to this file */ if(id->sds_id<0) return -1; /* needs to be existing writeable SDS ? */ /* id->sds_id=SDselect(id->id,id->sdsnumber); if(id->sds_id<0) return -1; */ return SDsetattr(id->sds_id,attribname,numbertype,nelements,buffer); } /*@@ @routine SDSreadAttrib @date Wed Feb 28 15:37:43 1996 @desc Reads the attribute with the specified "attribname" associated with the current SDS to the HDF file. If there is no attribute by that name, it returns 0. If an attribute is found by that name, it returns the number of elements read. The attribute can be referred to by its name or by its index when read back in.

If you want to pre-allocate the buffer to match the size of the attribute being read in, then you should use SDSfindAttribInfo() or SDSgetAttribInfo() to get the exact size of the data contained in the attribute before reading. If the size of the buffer is smaller than the amount of data that needs to be read, the read will be truncated to fit into the buffer.

If the stored data is a character string and the returned size==the size of your buffer, you will need to null terminate the buffer yourself after it is returned. @enddesc @seeroutine SDSwriteAttrib SDSfindAttribInfo SDSgetAttribInfo SDSgetNumAttribs @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par attribname @pdesc Name of the attribute. @ptype char* @endpar @par nelements @pdesc The maximimum number of elements that can be read by the from the attribute (ie. the size of the buffer). @ptype int32 @endpar @par buffer @pdesc Pointer to the attribute data. @ptype VOIDP @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSreadAttrib(filename,attribname,nelements,buffer) char *filename; char *attribname; int32 nelements; VOIDP buffer; { int status; int32 ref; int index; int32 nt,count,rtval; fileID *id=getFileID(filename); if(id->sds_id<0) id->sds_id=SDselect(id->id,id->sdsnumber); if(id->sds_id<0) return -1; index=SDfindattr(id->sds_id,attribname); /* Check to make sure the number of elements in the attribute is less than the number of elements in the buffer */ status=SDattrinfo(id->sds_id,index,attribname,&nt,&count); if(status<0) return status; if(count>nelements){ char *tmpdata=(char *)malloc(count*DFKNTsize(nt)); rtval=SDreadattr(id->sds_id,index,tmpdata); bcopy(tmpdata,buffer,DFKNTsize(nt)*nelements); free(tmpdata); /* if(nt==DFNT_INT8){ might be a string, so null terminate buffer[nelements-1]='\0'; }*/ } else rtval=SDreadattr(id->sds_id,index,buffer); return (rtval>=0)?count:rtval; } /*@@ @routine SDSfindAttribInfo @date Wed Feb 28 15:37:43 1996 @desc Finds the named attribute associated with the current dataset by name and retrieves information about it. It will return -1 if no attribute with that name is found. @enddesc @seeroutine SDSreadAttrib SDSgetAttribInfo SDSgetAttribInfo SDSgetNumAttribs @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par attribname @pdesc Name of the attribute. @ptype char* @endpar @par numbertype @pdesc Storage in which to return the numbertype of the attribute @pvalues DFNT_FLOAT32 (32-bit float), DFNT_FLOAT64 (64-bit float/double), DFNT_INT8 (char), DFNT_INT16 (short int), DFNT_INT32,(int), DFNT_UINT8 (unsigned char), DFNT_UNINT16 (unsigned short), DFNT_UINT32 (unsigned int), DFNT_NATIVE (if bit-OR'ed with the above, uses machine native format) @ptype int32* @endpar @par nelements @pdesc Storage in which to return the number of elements in the attribute of the type defined by the numbertype param. @ptype int32* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSfindAttribInfo(filename,attribname,numbertype,nelements) char *filename; char *attribname; int32 *numbertype; int32 *nelements; { int32 ref; int index; fileID *id=getFileID(filename); if(id->sds_id<0) id->sds_id=SDselect(id->id,id->sdsnumber); if(id->sds_id<0) return -1; index=SDfindattr(id->sds_id,attribname); return SDattrinfo(id->sds_id,index,attribname,numbertype,nelements); } /*@@ @routine SDSgetAttribInfo @date Wed Feb 28 15:37:43 1996 @desc Allows you to get the attribute information by index instead of by name. @enddesc @seeroutine SDSreadAttrib SDSwriteAttrib SDSfindAttribInfo SDSgetNumAttribs @calls getFileID @par filename @pdesc Name of the HDF file @ptype char* @endpar @par index @pdesc Index of the attribute attached to the SDS @ptype int32 @endpar @par attribname @pdesc Storage area for name of the attribute (so that it can be returned to the user) @ptype char* @endpar @par numbertype @pdesc Storage in which to return the numbertype of the attribute @pvalues DFNT_FLOAT32 (32-bit float), DFNT_FLOAT64 (64-bit float/double), DFNT_INT8 (char), DFNT_INT16 (short int), DFNT_INT32,(int), DFNT_UINT8 (unsigned char), DFNT_UNINT16 (unsigned short), DFNT_UINT32 (unsigned int), DFNT_NATIVE (if bit-OR'ed with the above, uses machine native format) @ptype int32* @endpar @par nelements @pdesc Storage in which to return the number of elements in the attribute of the type defined by the numbertype param. @ptype int32* @endpar @history @hdate Wed Feb 28 20:38:57 1996 @hauthor John Shalf @hdesc Initial Version @endhistory @@*/ int32 SDSgetAttribInfo(filename,index,attribname,numbertype,nelements) char *filename; int32 index; char *attribname; int32 *numbertype; int32 *nelements; { int32 ref; fileID *id=getFileID(filename); if(id->sds_id<0) id->sds_id=SDselect(id->id,id->sdsnumber); if(id->sds_id<0) return -1; return SDattrinfo(id->sds_id,index,attribname,numbertype,nelements); }