1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174 |
- /* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
- See the COPYRIGHT file for more information. */
- #include "config.h"
- #include "ocinternal.h"
- #include "occontent.h"
- #include "ocdebug.h"
- /* Mnemonic*/
- #define ISPACKED 1
- /* Define the skipstate flags */
- #ifdef OCDEBUG
- typedef enum Skipstate {
- SKIPFIELDS = 1, /* skip instance without leading tag or arraycount */
- SKIPINSTANCE = 2, /*skip leading sequence tag or array counts */
- SKIPWHOLE = 4 /* skip complete object */
- } Skipstate;
- #else
- #define SKIPFIELDS 1 /* skip instance without leading tag or arraycount */
- #define SKIPINSTANCE 2 /*skip leading sequence tag or array counts */
- #define SKIPWHOLE 4 /* skip complete object */
- #endif
- /* Forward*/
- static OCmode modetransition(OCnode*,OCmode);
- static int ocgetsequencetag(XXDR* xdrs);
- static int ocskipcounts(XXDR* xdrs, OCnode*, off_t expected);
- static int ocarrayith(OCstate*, OCcontent*, OCcontent*, size_t);
- static int ocsequenceith(OCstate*, OCcontent*, OCcontent*, size_t);
- static int ocfieldith(OCstate*, OCcontent*, OCcontent*, size_t);
- static size_t ocarraycount(OCstate*, struct OCcontent*);
- static size_t ocsequencecount(OCstate*, struct OCcontent*);
- static size_t ocfieldcount(OCstate*, struct OCcontent*);
- static size_t ocprimcount(OCstate*, struct OCcontent*);
- static OCcontent* occlearcontent(struct OCstate* state, OCcontent* content);
- #ifdef OCDEBUG
- static void
- report(size_t memsize, char* memory)
- {
- #ifdef OCIGNORE
- switch(memsize) {
- case 1:
- oc_log(LOGNOTE,"reading xdr: %lu bytes = |%2x|",(unsigned long)memsize,memory[0]);
- break;
- case 4:
- oc_log(LOGNOTE,"reading xdr: %lu bytes = |%4lu|",(unsigned long)memsize,*(unsigned int*)memory);
- break;
- case 8:
- oc_log(LOGNOTE,"reading xdr: %lu bytes = |%8lu|",(unsigned long)memsize,*(unsigned long long*)memory);
- break;
- default:
- oc_log(LOGNOTE,"reading xdr: %lu bytes",(unsigned long)memsize);
- break;
- }
- oc_log(LOGNOTE,"reading xdr: %lu bytes",(unsigned long)memsize);
- #endif
- }
- static char*
- modestring(OCmode mode)
- {
- switch(mode) {
- case OCFIELDMODE: return "FIELD";
- case OCSEQUENCEMODE: return "SEQUENCE";
- case OCARRAYMODE: return "ARRAY";
- case OCPRIMITIVEMODE: return "PRIMITIVE";
- case OCNULLMODE: return "NULL";
- case OCEMPTYMODE: return "EMPTY";
- }
- return "?";
- }
- void
- octrace1(char* proc, OCstate* state, OCcontent* content, int start, int count)
- {
- unsigned long pos = xxdr_getpos(content->tree->data.xdrs);
- fprintf(stderr,"trace: %s mode=%s node=%s (%s)",
- proc,modestring(content->mode),content->node->fullname,
- octypetostring(content->node->octype));
- if(content->packed)
- fprintf(stderr," packed=%d",content->packed);
- if(count >= 0)
- fprintf(stderr," start=%lu count=%lu",
- (unsigned long)start,(unsigned long)count);
- else
- fprintf(stderr," index=%lu",(unsigned long)start);
- fprintf(stderr," xdrs.pos=%lu",pos);
- fprintf(stderr,"\n");
- if(content->cache.valid) {
- fprintf(stderr,"\tcache{index=%lu maxindex=%lu offset=%lu}\n",
- (unsigned long)content->cache.index,
- (unsigned long)content->cache.maxindex,
- (unsigned long)content->cache.offset);
- }
- fflush(stderr);
- }
- void
- octrace(char* proc, OCstate* state, OCcontent* content, int index)
- {
- octrace1(proc,state,content,index,-1);
- }
- #else
- #define octrace(proc,state,content,index)
- #define octrace1(proc,state,content,start,count)
- #define report(memsize,memory)
- #endif /*OCDEBUG*/
- OCmode
- ocgetmode(OCcontent* content)
- {
- return (content == NULL ? OCNULLMODE : content->mode);
- }
- OCcontent*
- ocnewcontent(OCstate* state)
- {
- OCcontent* content;
- if(state == NULL) return NULL;
- content = state->contentlist;
- /* Search for an unused content node*/
- while(content != NULL && content->mode != OCEMPTYMODE) {
- content = content->next;
- }
- if(content == NULL) {
- content = (OCcontent*)ocmalloc(sizeof(OCcontent));
- MEMCHECK(content,(OCcontent*)NULL);
- content->magic = OCMAGIC;
- content->next = state->contentlist;
- state->contentlist = content;
- }
- return occlearcontent(state,content);
- }
- void
- ocfreecontent(OCstate* state, OCcontent* content)
- {
- if(content != NULL) {content->mode = OCEMPTYMODE;}
- }
- static OCcontent*
- occlearcontent(struct OCstate* state, OCcontent* content)
- {
- /* save fields that should not be cleared */
- unsigned int magic = content->magic;
- OCcontent* next = content->next;
- memset((void*)content,sizeof(OCcontent),0);
- /* set/restore non-null fields */
- content->magic = magic;
- content->next = next;
- content->state = state;
- content->mode = OCNULLMODE;
- return content;
- }
- static OCcontent*
- ocsetcontent(OCcontent* childcontent, OCcontent* parent, OCnode* node, int packed)
- {
- childcontent->state = parent->state;
- childcontent->cache.valid = 0;
- childcontent->node = node;
- childcontent->tree = node->root->tree;
- childcontent->mode = modetransition(node,parent->mode);
- childcontent->packed = packed;
- return childcontent;
- }
- #ifdef OCIGNORE
- static OCcontent*
- occlonecontent(OCstate* state, OCcontent* content)
- {
- OCcontent* clone = ocnewcontent(state);
- clone->mode = content->mode;
- clone->node = content->node;
- clone->cache = content->indexcache;
- return clone;
- }
- #endif
- OCerror
- ocdataith(OCstate* state, OCcontent* parent, size_t index, OCcontent* child)
- {
- OCerror ocerr = OC_NOERR;
- switch (parent->mode) {
- case OCARRAYMODE:
- ocerr = ocarrayith(state,parent,child,index);
- break;
- case OCSEQUENCEMODE:
- ocerr = ocsequenceith(state,parent,child,index);
- break;
- case OCFIELDMODE:
- ocerr = ocfieldith(state,parent,child,index);
- break;
- default: return OC_EINVAL;
- }
- if(ocerr == OC_EDATADDS)
- ocdataddsmsg(state,parent->tree);
- return ocerr;
- }
- OCerror
- ocdatacount(OCstate* state, OCcontent* current, size_t* sizep)
- {
- OCerror ocerr = OC_NOERR;
- size_t count = 0;
- switch(current->mode) {
- case OCARRAYMODE:
- count = ocarraycount(state,current);
- break;
- case OCSEQUENCEMODE:
- count = ocsequencecount(state,current);
- break;
- case OCFIELDMODE:
- count = ocfieldcount(state,current);
- break;
- case OCPRIMITIVEMODE:
- count = ocprimcount(state,current);
- break;
- default:
- return OC_EINVAL;
- }
- current->cache.maxindex = ocmax(count,current->cache.maxindex);
- if(sizep) *sizep = count;
- return ocerr;
- }
- OCerror
- ocrootdata(OCstate* state, OCnode* root, OCcontent* content)
- {
- OCtree* tree;
- if(state == NULL || root == NULL || content == NULL)
- return OCTHROW(OC_EINVAL);
- if(root->tree == NULL) return OCTHROW(OC_EINVAL);
- tree = root->tree;
- if(tree->dxdclass != OCDATADDS) return OCTHROW(OC_ENODATA);
- if(tree->nodes == NULL) return OCTHROW(OC_EINVAL);
- if(tree->data.xdrs == NULL)
- return OCTHROW(OC_EXDR);
- occlearcontent(state,content);
- content->mode = OCFIELDMODE;
- content->node = root;
- content->tree = tree;
- content->cache.index = 0;
- content->cache.maxindex = oclistlength(content->node->subnodes);
- content->cache.offset = 0;
- content->cache.valid = 1;
- return OCTHROW(OC_NOERR);
- }
- /* Remember: we are operating wrt the datadds count, not the dds count */
- static OCerror
- ocarrayith(OCstate* state, OCcontent* content, OCcontent* elemcontent, size_t index)
- {
- unsigned int i;
- int stat = OC_NOERR;
- XXDR* xdrs;
- int packed, scalar;
- OCtype etype,octype;
- OCnode* node;
- int startindex = 0;
- octrace("ocarrayith", state, content, index);
- if(state == NULL || content == NULL) return OCTHROW(OC_EINVAL);
- if(content->mode != OCARRAYMODE) return OCTHROW(OC_EINVAL);
- etype = content->node->etype;
- octype = content->node->octype;
- node = content->node;
- scalar = (node->array.rank == 0 ? 1 : 0);
- packed = (!scalar && octype == OC_Primitive &&
- (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
- xdrs = content->tree->data.xdrs;
- if(xdrs == NULL) return OCTHROW(OC_EXDR);
- if(!content->cache.valid) {
- content->cache.index = 0; /* because we will have to walk to index'th data */
- content->cache.maxindex = totaldimsize(node);
- content->cache.valid = 1;
- /* skip past the initial counts, if any */
- if(!scalar) {
- if(!ocskipcounts(xdrs,node,node->skip.count)) return OCTHROW(OC_EDATADDS);
- }
- /* checkpoint xdr position */
- content->cache.offset = xxdr_getpos(xdrs);
- }
- /* move to the checkpoint position */
- startindex = content->cache.index;
- if(!xxdr_setpos(xdrs,content->cache.offset)) return xdrerror();
- /* skip to the index'th item */
- if(packed) {
- content->cache.index = 0; /* keep at beginning */
- } else {
- for(i=startindex;i<index;i++) {
- stat = ocskipinstance(node,xdrs,SKIPINSTANCE,NULL);
- if(stat != OC_NOERR) return OCTHROW(stat);
- }
- content->cache.index = index; /* now we are at the index'th item */
- }
- /* update cache */
- content->cache.index = index;
- content->cache.offset = xxdr_getpos(xdrs);
- /* set up the content for the current item in the array */
- ocsetcontent(elemcontent,content,node,packed); /*keep same node */
- if (index == content->cache.maxindex) {
- /* mark eod */
- elemcontent->mode = OCNULLMODE;
- }
- return OCTHROW(stat);
- }
- static int
- ocsequenceith(OCstate* state, OCcontent* content, OCcontent* structcontent, size_t index)
- {
- unsigned int i;
- int stat = OC_NOERR;
- XXDR* xdrs;
- OCtype octype,etype;
- int packed,scalar;
- OCnode* node = content->node;
- int startindex, tag;
- octrace("ocsequenceith", state, content, index);
- if(state == NULL || content == NULL) goto einval;
- if(content->mode != OCSEQUENCEMODE) goto einval;
- if(node->octype != OC_Sequence) goto einval;
- octype = node->octype;
- etype = node->etype;
- scalar = (node->array.rank == 0 ? 1 : 0);
- packed = (!scalar && octype == OC_Primitive &&
- (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
- xdrs = content->tree->data.xdrs;
- if(xdrs == NULL) goto exdr;
- if(!content->cache.valid) {
- content->cache.valid = 1;
- content->cache.index = 0;
- content->cache.maxindex = 0;
- content->cache.offset = xxdr_getpos(xdrs);
- }
- /* move to checkpoint position*/
- startindex = content->cache.index;
- if(!xxdr_setpos(xdrs,content->cache.offset)) goto exdr;
- /* Walk past the first (index-1) records */
- for(tag=StartOfSequence,i=startindex;i<index;i++) {
- /* skip instance, including tag, but leave xdr at next tag */
- stat = ocskipinstance(node,xdrs,SKIPINSTANCE,&tag);
- if(stat != OC_NOERR) goto done;
- if(tag == EndOfSequence)
- break;
- if(tag != StartOfSequence) {
- oc_log(LOGERR,"missing/invalid begin/end record marker\n");
- goto einvalcoords;
- }
- }
- if(stat != OC_NOERR) goto done;
- /* update cache; should be pointing to index'th record tag */
- content->cache.index = index;
- content->cache.maxindex = ocmax(index,content->cache.index);
- /* this is a bit (too) tricky */
- /* move to point to fields */
- tag = ocgetsequencetag(xdrs);
- if(tag == EndOfSequence) {
- /* point past end of sequence */
- content->cache.offset = xxdr_getpos(xdrs);
- } else {/*tag == StartOfSequence*/
- /* point to (next) start of sequence */
- content->cache.offset = xxdr_getpos(xdrs) - XDRUNIT;
- }
- /* at this point, xdrs should point unconditionally
- past the index'th tag */
- /* Set state of new content: keep same node */
- ocsetcontent(structcontent,content,node,packed);
- if(tag == EndOfSequence) {
- /* mark eod */
- structcontent->mode = OCNULLMODE;
- }
- done:
- return OCTHROW(stat);
- einval:
- stat = OC_EINVAL;
- goto done;
- exdr:
- stat = OC_EXDR;
- goto done;
- einvalcoords:
- stat = OC_EINVALCOORDS;
- goto done;
- }
- /*
- The ocfieldcontent procedure has to deal with the fact
- that the dap constraints may have removed some fields
- from the datadds and hence some fields may have no
- representation in the xdr data (or compiled data).
- Assume that xdr points to start of 0th field.
- */
- static int
- ocfieldith(OCstate* state, OCcontent* content, OCcontent* fieldcontent, size_t index)
- {
- unsigned int i;
- int stat = OC_NOERR;
- XXDR* xdrs;
- OCtype octype,etype;
- int packed;
- int isscalar;
- OCnode* node;
- int startindex;
- octrace("ocfieldith", state, content, index);
- if(state == NULL || content == NULL) return OCTHROW(OC_EINVAL);
- if(content->mode != OCFIELDMODE) return OCTHROW(OC_EINVAL);
- node = content->node;
- octype = node->octype;
- etype = node->etype;
- isscalar = (node->array.rank == 0 ? 1 : 0);
- packed = (!isscalar && octype == OC_Primitive
- && (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
- xdrs = content->tree->data.xdrs;
- if(xdrs == NULL) return OCTHROW(OC_EXDR);
- if(!content->cache.valid) {
- content->cache.index = 0;
- content->cache.maxindex = oclistlength(node->subnodes);
- content->cache.valid = 1;
- /* checkpoint xdr position */
- content->cache.offset = xxdr_getpos(xdrs);
- }
- /* move to the checkpoint position */
- startindex = content->cache.index;
- if(!xxdr_setpos(xdrs,content->cache.offset)) return xdrerror();
- switch (octype) {
- case OC_Sequence: /* assume xdrs points past sequence tag */
- case OC_Grid: /* Note that the Grid array is field 0 and the maps are 1..nsubnodes*/
- case OC_Dataset:
- case OC_Structure:
- /* walk to (i-1)'th field */
- for(i=startindex;i<index;i++) { /* walk field by field */
- OCnode* ithfield = (OCnode*)oclistget(node->subnodes,i);
- stat = ocskipinstance(ithfield,xdrs,SKIPWHOLE,NULL);
- if(stat != OC_NOERR) return OCTHROW(stat);
- }
- break;
- default: return OCTHROW(OC_EINVAL);
- }
- /* update cache */
- content->cache.index = index;
- content->cache.offset = xxdr_getpos(xdrs);
- /* Set state of new content: node changes to field node */
- ocsetcontent(fieldcontent,content,
- (OCnode*)oclistget(node->subnodes,index),
- packed);
- if(index >= content->cache.maxindex) {
- /* mark eod */
- fieldcontent->mode = OCNULLMODE;
- }
- return OCTHROW(stat);
- }
- /*
- In order to actually extract data,
- one must move to the specific primitive typed
- field containing the data of interest by using
- ocfieldcontent().
- Then, oc_getcontent() is invoked to extract
- some subsequence of items from the field.
- Note that oc_getcontent() will also work for scalars,
- but the start must be zero and the count must be one.
- */
- int
- ocgetcontent(OCstate* state, OCcontent* content, void* memory, size_t memsize,
- size_t start, size_t count)
- {
- int stat = OC_NOERR;
- XXDR* xdrs;
- OCtype etype, octype;
- int isscalar, packed;
- size_t elemsize, totalsize;
- OCnode* node = content->node;
- octrace1("ocgetcontent", state, content, start, count);
- if(state == NULL || content == NULL || memory == NULL)
- {OCTHROWCHK(stat=OC_EINVAL); goto done;}
- if(content->mode != OCPRIMITIVEMODE || node->octype != OC_Primitive)
- {OCTHROWCHK(stat=OC_EINVAL); goto done;}
- octype = node->octype;
- etype = node->etype;
- isscalar = (node->array.rank == 0);
- packed = (!isscalar && octype == OC_Primitive
- && (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
- if(isscalar && (start != 0 || count != 1))
- {OCTHROWCHK(stat=OC_EINVALCOORDS); goto done;}
- /* validate memory space*/
- elemsize = octypesize(etype);
- totalsize = elemsize*count;
- if(memsize < totalsize) return OCTHROW(OC_EINVAL);
- xdrs = content->tree->data.xdrs;
- if(xdrs == NULL) return OCTHROW(OC_EXDR);
- /* Need to setup the cache */
- if(!content->cache.valid) {
- content->cache.valid = 1;
- content->cache.index = 0;
- content->cache.maxindex = totaldimsize(content->node);
- if(!ocskipcounts(xdrs,content->node,content->cache.maxindex))
- return OCTHROW(OC_EXDR);
- content->cache.offset = xxdr_getpos(xdrs);
- }
- if(content->cache.valid && content->cache.maxindex < (start+count))
- return OCTHROW(OC_ENODATA);
- /* utilize the cache */
- if(!xxdr_setpos(xdrs,content->cache.offset)) return OCTHROW(OC_EXDR);
- /* Extract the data */
- stat = ocxdrread(content,xdrs,(char*)memory,memsize,start,count);
- #ifdef OCDEBUG
- report(memsize,memory+start);
- #endif
- /* Update the cache */
- if(!packed) {
- content->cache.index = (start+count);
- content->cache.offset = xxdr_getpos(xdrs);
- }
- done:
- return OCTHROW(stat);
- }
- static size_t
- ocfieldcount(OCstate* state, OCcontent* content)
- {
- OCnode* node = content->node;
- size_t count;
- OCASSERT((node != NULL));
- count = oclistlength(node->subnodes);
- return count;
- }
- static size_t
- ocarraycount(OCstate* state, OCcontent* content)
- {
- unsigned int count;
- OCnode* node = content->node;
- OCASSERT((node != NULL));
- OCASSERT((content->mode == OCARRAYMODE));
- count = totaldimsize(node);
- #ifdef VERIFY
- if(node->array.rank > 0) {
- off_t checkpoint;
- XXDR* xdrs;
- unsigned int xdrcount;
- /* verify against xdr */
- xdrs = content->tree->data.xdrs;
- OCASSERT((xdrs != NULL));
- /* checkpoint current location */
- checkpoint = xxdr_getpos(xdrs);
- /* extract the count*/
- if(!xxdr_uint(xdrs,&xdrcount)) return 0;
- if(xdrcount != count) return 0;
- /* return to checkpoint position*/
- if(!xxdr_setpos(xdrs,checkpoint)) return 0;
- }
- #endif /*VERIFY*/
- return (size_t)count;
- }
- /* Counting records actually requires walking the xdr packet
- so it is not necessarily cheap*/
- static size_t
- ocsequencecount(OCstate* state, OCcontent* content)
- {
- size_t count;
- OCnode* node = content->node;
- XXDR* xdrs;
- off_t checkpoint;
- OCASSERT((node != NULL));
- OCASSERT((node->octype == OC_Sequence));
- OCASSERT((content->mode == OCSEQUENCEMODE));
- xdrs = content->tree->data.xdrs;
- OCASSERT((xdrs != NULL));
- /* checkpoint location */
- checkpoint = xxdr_getpos(xdrs);
- for(count=0;;count++) {
- int tag;
- OCerror stat = ocskipinstance(node,xdrs,SKIPINSTANCE,&tag);
- if(stat != OC_NOERR) {count = 0; break;}
- if(tag == EndOfSequence) {
- break; /* done with the count*/
- } else if(tag != StartOfSequence) {
- oc_log(LOGERR,"missing/invalid begin/end record marker\n");
- return 0;
- }
- }
- /* move back to checkpoint position*/
- if(!xxdr_setpos(xdrs,checkpoint)) return 0;
- return count;
- }
- static size_t
- ocprimcount(OCstate* state, OCcontent* content)
- {
- unsigned int count;
- OCnode* node = content->node;
- OCASSERT((node != NULL));
- OCASSERT((content->mode == OCPRIMITIVEMODE));
- count = totaldimsize(node);
- #ifdef VERIFY
- if(node->array.rank > 0) {
- off_t checkpoint;
- XXDR* xdrs;
- unsigned int xdrcount;
- /* verify against xdr */
- xdrs = content->tree->data.xdrs;
- OCASSERT((xdrs != NULL));
- /* checkpoint current location */
- checkpoint = xxdr_getpos(xdrs);
- /* extract the count*/
- if(!xxdr_uint(xdrs,&xdrcount)) return 0;
- if(xdrcount != count) return 0;
- /* return to checkpoint position*/
- if(!xxdr_setpos(xdrs,checkpoint)) return 0;
- }
- #endif /*VERIFY*/
- return (size_t)count;
- }
- static OCmode
- modetransition(OCnode* node, OCmode srcmode)
- {
- OCmode newmode = OCNULLMODE;
- switch (srcmode) {
- case OCARRAYMODE:
- switch (node->octype) {
- case OC_Sequence:
- newmode = OCSEQUENCEMODE;
- break;
- case OC_Grid:
- case OC_Structure:
- newmode = OCFIELDMODE;
- break;
- default:
- break;
- }
- break;
- case OCSEQUENCEMODE:
- switch (node->octype) {
- default:
- newmode = OCFIELDMODE;
- break;
- }
- break;
- case OCFIELDMODE:
- switch (node->octype) {
- case OC_Sequence:
- case OC_Grid:
- case OC_Structure:
- newmode = OCARRAYMODE;
- break;
- case OC_Primitive:
- newmode = OCPRIMITIVEMODE;
- break;
- default:
- break;
- }
- break;
- case OCPRIMITIVEMODE:
- case OCNULLMODE:
- case OCEMPTYMODE:
- default:
- newmode = OCNULLMODE;
- break;
- }
- if(newmode == OCNULLMODE)
- OCPANIC1("No defined mode transition: %d",(int)srcmode);
- return newmode;
- }
- /* get the presumed current sequence tag */
- static int
- ocgetsequencetag(XXDR* xdrs)
- {
- char tag[XDRUNIT];
- if(!xxdr_getbytes(xdrs,tag,sizeof(tag))) return 0;
- return tag[0];
- }
- static int
- ocskipcounts(XXDR* xdrs, OCnode* node, off_t expected)
- {
- if(node->array.rank == 0) return 1; /* simple scalar */
- #ifdef VERIFY
- unsigned int xdrcount0,xdrcount1;
- /* Collect the dimension count from the xdr data packet*/
- if(!xxdr_uint(xdrs,&xdrcount0)) OCGOTO(shortxdr);
- if(expected >= 0 && xdrcount0 != expected) return 0;
- /* pull out redundant second count*/
- /* (note that String/URL do not have redundant count)*/
- if(node->octype == OC_Primitive
- && node->etype != OC_String && node->etype != OC_URL) {
- if(!xxdr_uint(xdrs,&xdrcount1)) return 0;
- if(xdrcount0 != xdrcount1) return 0;
- }
- #else
- /* skip the counts */
- expected = expected; /*shut up compiler*/
- if(node->octype == OC_Primitive
- && node->etype != OC_String && node->etype != OC_URL) {
- if(!xxdr_skip(xdrs,2*XDRUNIT)) return 0;
- } else {
- if(!xxdr_skip(xdrs,XDRUNIT)) return 0;
- }
- #endif
- return 1;
- }
- /**************************************************/
- /* Moved ocdata.c here */
- /**************************************************/
- const char StartOfSequence = '\x5A';
- const char EndOfSequence = '\xA5';
- static int ocerrorstring(XXDR* xdrs);
- #define LOCALMEMMAX 1024
- /*
- Skip arbitrary object based on its octype
- and a state
- Cases:
- octype Skip State actions
- -------------------------------------------
- Structure
- |Grid
- |DataSet SKIPINSTANCE Skip single instance
- |SKIPFIELDS
- SKIPWHOLE Skip array of instances
- including leading counts
- Sequence SKIPFIELDS Skip single record
- (assume leading tag already skipped)
- SKIPINSTANCE Skip single record
- (including leading tag)
-
- SKIPWHOLE Skip all records
- including leading tags
- and trailing end marker
- Primitive <any> Skip whole primitive array
- including leading counts
- Notes:
- 1. unlisted combinations are not legal/possible.
- 2. assume that xxdr_getpos is properly positioned.
- 3. If octype is OC_Sequence, tagp will be set with the
- last tag encountered.
- */
- OCerror
- ocskipinstance(OCnode* node, XXDR* xdrs, int state, int* tagp)
- {
- int i,tag;
- int stat = OC_NOERR;
- /* Support switch on combination of octype X state to simply code */
- #define CASE(octype,state) ((octype)<<3 | state)
- switch (CASE(node->octype,state)) {
- case CASE(OC_Dataset,SKIPINSTANCE):
- case CASE(OC_Grid,SKIPINSTANCE):
- case CASE(OC_Structure,SKIPINSTANCE):
- case CASE(OC_Dataset,SKIPFIELDS):
- case CASE(OC_Grid,SKIPFIELDS):
- case CASE(OC_Structure,SKIPFIELDS):
- case CASE(OC_Sequence,SKIPFIELDS): /* NOTE this special case */
- if(node->skip.instancesize != OCINDETERMINATE) {
- if(!xxdr_skip(xdrs,node->skip.instancesize)) OCGOTO(shortxdr);
- } else {/* skip field by field */
- for(i=0;i<oclistlength(node->subnodes);i++) {
- OCnode* field = (OCnode*)oclistget(node->subnodes,i);
- stat = ocskipinstance(field, xdrs, SKIPWHOLE,NULL);
- if(stat != OC_NOERR) {OCTHROWCHK(stat); goto done;}
- }
- }
- break;
- case CASE(OC_Dataset,SKIPWHOLE):
- case CASE(OC_Grid,SKIPWHOLE):
- case CASE(OC_Structure,SKIPWHOLE):
- OCASSERT(node->skip.count != OCINDETERMINATE);
- if(node->skip.totalsize != OCINDETERMINATE) {
- if(!xxdr_skip(xdrs,node->skip.totalsize)) goto badxdr;
- } else {/* skip each instance */
- if(node->array.rank > 0) {
- if(!ocskipcounts(xdrs,node,node->skip.count)) goto badxdr;
- for(i=0;i<node->skip.count;i++) {
- stat = ocskipinstance(node, xdrs, SKIPFIELDS,NULL);
- if(stat != OC_NOERR) {OCTHROWCHK(stat); goto done;}
- }
- } else { /* scalar */
- stat = ocskipinstance(node, xdrs, SKIPINSTANCE,NULL);
- if(stat != OC_NOERR) {OCTHROWCHK(stat); goto done;}
- }
- }
- break;
- case CASE(OC_Sequence,SKIPINSTANCE): /* Skip record including tag */
- tag = ocgetsequencetag(xdrs); /* always read the tag */
- if(tagp) *tagp = tag;
- if(tag == StartOfSequence) { /* skip record fields */
- stat = ocskipinstance(node, xdrs, SKIPFIELDS,NULL);
- if(stat != OC_NOERR) {OCTHROWCHK(stat); break;}
- } /* let caller handle */
- break;
-
- case CASE(OC_Sequence,SKIPWHOLE): /* Skip multiple records including tags */
- for(i=0;;i++) {
- stat = ocskipinstance(node, xdrs, SKIPINSTANCE, &tag);
- if(stat != OC_NOERR) {OCTHROWCHK(stat); break;}
- if(tag == EndOfSequence) break; /* done */
- if(tag != StartOfSequence) goto badxdr; /* malformed */
- }
- break;
- case CASE(OC_Primitive,SKIPWHOLE):
- case CASE(OC_Primitive,SKIPINSTANCE):
- case CASE(OC_Primitive,SKIPFIELDS):
- OCASSERT(node->skip.count != OCINDETERMINATE);
- if(node->skip.totalsize != OCINDETERMINATE) {
- /* skip directly past it */
- if(!xxdr_skip(xdrs,node->skip.totalsize)) goto badxdr;
- } else {/* Walk instance by instance */
- if(state == SKIPWHOLE) {
- /* read the counts */
- if(!ocskipcounts(xdrs,node,node->skip.count))
- goto badxdr;
- }
- OCASSERT(node->etype == OC_String || node->etype == OC_URL);
- /* get the count */
- for(i=0;i<node->skip.count;i++) {
- /* read and skip the string */
- unsigned int len;
- /* read string size */
- if(!xxdr_uint(xdrs,&len)) OCGOTO(shortxdr);
- /* round up to next XDRUNIT and skip string contents */
- len = RNDUP(len);
- if(!xxdr_skip(xdrs,(size_t)len)) OCGOTO(shortxdr);
- }
- }
- break;
- default:
- OCPANIC2("ocskipinstance: encountered unexpected node type or state: %d,%d",
- node->octype,state);
- break;
- }
- done:
- return OCTHROW(stat);
- shortxdr:
- oc_log(LOGERR,"short xdr packet");
- stat = OC_EXDR;
- goto done;
- badxdr:
- oc_log(LOGERR,"malformed xdr packet");
- stat = OC_EXDR;
- goto done;
- }
- /*
- Extract data from the xdr packet into a chunk of memory.
- Normally, it is assumed that we are (at least virtually)
- "at" a single instance in the xdr packet; which we read.
- Virtually because for packed data, we need to point to
- the beginning of the packed data and use the index to indicate
- which packed element to get. Assume that in any case,
- any leading counts have been passed.
- */
- OCerror
- ocxdrread(OCcontent* content, XXDR* xdrs, char* memory, size_t memsize,
- ocindex_t start, ocindex_t count)
- {
- int stat = OC_NOERR;
- unsigned int i;
- size_t elemsize;
- size_t readsize;
- size_t skipsize;
- char localmem[LOCALMEMMAX];
- char* srcmem;
- unsigned int* p;
- int packed;
- int scalar;
- OCtype octype,etype;
- ocindex_t localstart = start; /* will change if node is cacheing */
- OCnode* node;
- node = content->node;
- octype = node->octype;
- etype = node->etype;
- elemsize = octypesize(etype);
- scalar = (node->array.rank == 0 ? 1 : 0);
- /* check if the data is packed*/
- packed = (octype == OC_Primitive && !scalar
- && (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
-
- /* validate memory space*/
- if(memsize < elemsize*count) return OCTHROW(OC_EINVAL);
- #ifdef OCIGNORE
- if(!scalar && (!node->cache.cacheable || !node->cache.valid)) {
- unsigned int xdrcount0,xdrcount1;
- /* assume xdr position is correct */
- /* Read leading double count if ! scalar*/
- if(!xxdr_uint(xdrs,&xdrcount0)) OCGOTO(shortxdr);
- if(!xxdr_uint(xdrs,&xdrcount1)) OCGOTO(shortxdr);
- if(xdrcount0 != xdrcount1) return OCTHROW(OC_EXDR);
- if(xdrcount0 < start+count) OCGOTO(shortxdr);
- }
- #endif
-
- /* Handle packed data specially*/
- if(packed) {
- readsize = count*1; /* |OC_(Char,Byte,UByte)| == 1 */
- skipsize = start*1; /* |OC_(Char,Byte,UByte)| == 1 */
- /* skip to start of what we want to read */
- if(!xxdr_skip(xdrs,skipsize)) OCGOTO(shortxdr);
- /* read data, keeping xdrs on XDRUNIT boundary */
- if(!xxdr_opaque(xdrs,memory,readsize))
- OCGOTO(shortxdr);
- return OCTHROW(OC_NOERR);
- }
- /* Not packed */
- #ifdef OCIGNORE
- /* If this (primitive) object is cacheable and is valid cache,
- then modify start and set the xdr position accordingly
- */
- if(node->cache.cacheable && node->cache.valid) {
- if(node->cache.index <= start) {
- localstart -= node->cache.index;
- if(!xxdr_setpos(xdrs,node->cache.offset)) return xdrerror();
- }
- }
- #endif
- /* Compute how much to skip based on the content's cache index */
- localstart = start - content->cache.index;
- if(localstart < 0) localstart = 0;
- /* extract count items; use xxdr_getbytes to speed up*/
- srcmem = memory;
- switch (etype) {
- case OC_Float64: case OC_Int64: case OC_UInt64:
- readsize = count*2*XDRUNIT;
- skipsize = localstart*2*XDRUNIT;
- /* skip to start of what we want to read */
- if(!xxdr_skip(xdrs,skipsize)) OCGOTO(shortxdr);
- if(!xxdr_opaque(xdrs,(char*)srcmem,readsize)) OCGOTO(shortxdr);
- if(etype == OC_Float64) {
- double* dp;
- for(dp=(double*)srcmem,i=0;i<count;i++,dp++) {
- double swap;
- xxdrntohdouble((char*)dp,&swap);
- *dp = swap;
- }
- } else if(!xxdr_network_order) {
- unsigned long long* llp;
- for(llp=(unsigned long long*)srcmem,i=0;i<count;i++,p++) {
- swapinline64(llp);
- }
- }
- break;
- case OC_String: case OC_URL: {
- /* Read string by string */
- char* s = NULL;
- char** pmem = (char**)srcmem;
- /* First skip to the starting string */
- for(i=0;i<localstart;i++) {
- unsigned int slen;
- if(!xxdr_uint(xdrs,&slen)) OCGOTO(shortxdr);
- slen = RNDUP(slen);
- if(!xxdr_skip(xdrs,slen)) OCGOTO(shortxdr);
- }
- /* Read count strings */
- for(i=0;i<count;i++) {
- off_t slen;
- /* xxdr_string will always alloc the space */
- if(!xxdr_string(xdrs,&s,&slen))
- OCGOTO(shortxdr);
- pmem[i] = s;
- }
- } break;
- case OC_Char: case OC_Byte: case OC_UByte:
- case OC_Int16: case OC_UInt16:
- /* We need to store the xdr data locally until we can convert it out
- because elemsize < sizeof(int) */
- srcmem = localmem;
- if(count*elemsize > sizeof(localmem)) {
- srcmem = (char*)ocmalloc(count*sizeof(unsigned int));
- if(srcmem == NULL) {stat = OCTHROW(OC_ENOMEM); goto done;}
- }
- /* fall thru */
- case OC_Int32: case OC_UInt32:
- case OC_Float32:
- readsize = (count)*XDRUNIT;
- skipsize = (localstart)*XDRUNIT;
- if(!xxdr_skip(xdrs,skipsize)) OCGOTO(shortxdr);
- if(!xxdr_opaque(xdrs,(char*)srcmem,readsize)) OCGOTO(shortxdr);
- if(!xxdr_network_order) {
- for(p=(unsigned int*)srcmem,i=0;i<count;i++,p++) {
- swapinline32(p);
- }
- }
- break;
- default: OCPANIC("unexpected etype"); break;
- }
- /* Convert memory to right format */
- switch (etype) {
- case OC_Char: case OC_Byte: case OC_UByte: {
- char* pmem = (char*)memory;
- p = (unsigned int*)srcmem;
- for(i=0;i<count;i++) {
- unsigned int tmp = *p++;
- *pmem++ = (unsigned char)tmp;
- }
- } break;
- case OC_Int16: case OC_UInt16: {
- unsigned short* pmem = (unsigned short*)memory;
- p = (unsigned int*)srcmem;
- for(i=0;i<count;i++) {
- unsigned int tmp = *p++;
- *pmem++ = (unsigned short)tmp;
- }
- } break;
- default:
- break; /* already handled above */
- }
- /* set cache */
- content->cache.index = start + count; /* should be our current index */
- content->cache.offset = xxdr_getpos(xdrs); /* should be our current position */
- done:
- return OCTHROW(stat);
- shortxdr:
- content->cache.valid = 0; /* no longer valid */
- if(!ocerrorstring(xdrs))
- oc_log(LOGERR,"DAP DATADDS packet is apparently too short");
- stat = OCTHROW(OC_EDATADDS);
- goto done;
- }
- int
- occountrecords(OCnode* node, XXDR* xdrs, size_t* nrecordsp)
- {
- int stat = OC_NOERR;
- size_t nrecords = 0;
- if(node->octype != OC_Sequence) return OCTHROW(OC_EINVAL);
- /* checkpoint the xdr position*/
- for(nrecords=0;;nrecords++) {
- int tag = 0;
- stat = ocskipinstance(node,xdrs,SKIPINSTANCE,&tag);
- if(stat != OC_NOERR) break;
- if(tag == EndOfSequence) break;
- if(tag != StartOfSequence) {
- oc_log(LOGERR,"missing/invalid begin/end record marker\n");
- stat = OC_EINVALCOORDS;
- break;
- }
- if(stat != OC_NOERR) break;
- }
- if(nrecordsp != NULL) *nrecordsp = nrecords;
- return OCTHROW(stat);
- }
- #define tag "Error {\n"
- static int
- ocerrorstring(XXDR* xdrs)
- {
- /* Check to see if the xdrs contains "Error {\n'; assume it is at the beginning of data */
- off_t avail = xxdr_getavail(xdrs);
- char* data = (char*)malloc(avail);
- if(!xxdr_setpos(xdrs,0)) return 0;
- if(!xxdr_opaque(xdrs,data,avail)) return 0;
- /* check for error tag at front */
- if(ocstrncmp(data,tag,sizeof(tag))==0) {
- char* p;
- if((p=strchr(data,'}')) != NULL) *(++p)='\0';
- oc_log(LOGERR,"Server error: %s",data);
- /* Since important, report to stderr as well */
- fprintf(stderr,"Server error: %s",data);
- return 1;
- }
- return 0;
- }
|