/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc. See the COPYRIGHT file for more information. */ #include "ocinternal.h" #include "ocdata.h" #include "ocdebug.h" const char StartOfoclist = '\x5A'; const char EndOfoclist = '\xA5'; extern int oc_invert_xdr_double; #define LOCALMEMMAX 1024 /* Skip arbitrary dimensioned instance; handles dimensioning.*/ int ocskip(OCnode* node, XDR* xdrs) { unsigned int i,j,rank; int stat = OC_NOERR; unsigned int xdrcount; unsigned int len; switch (node->octype) { case OC_Primitive: /* handle non-uniform types separately*/ if(node->etype == OC_String || node->etype == OC_URL) { rank = node->array.rank; xdrcount = 1; if(rank > 0 && !xdr_u_int(xdrs,&xdrcount)) return xdrerror(); len = xdrcount; for(i=0;i do a direct skip*/ OCASSERT((node->dap.arraysize > 0 && node->dap.instancesize > 0)); if(node->array.rank > 0) { if(!xdr_skip(xdrs,node->dap.arraysize)) return xdrerror(); } else { if(!xdr_skip(xdrs,node->dap.instancesize)) return xdrerror(); } } break; case OC_Grid: OCASSERT((node->array.rank == 0)); if(node->dap.instancesize > 0) { /* do a direct skip*/ if(!xdr_skip(xdrs,node->dap.arraysize)) return xdrerror(); break; } else { /* Non-uniform size*/ /* Walk array and maps*/ for(j=0;jsubnodes);j++) { OCnode* field = (OCnode*)oclistget(node->subnodes,j); stat = ocskip(field,xdrs); if(stat != OC_NOERR) {THROWCHK(stat); break;} } if(stat != OC_NOERR) {THROWCHK(stat); break;} } break; case OC_Dataset: OCASSERT((node->array.rank == 0)); /* fall-thru*/ case OC_Structure: if(node->dap.instancesize > 0) { /* do a direct skip*/ if(!xdr_skip(xdrs,node->dap.arraysize)) return xdrerror(); } else { /* Non-uniform size, we have to skip element by element*/ rank = node->array.rank; xdrcount = 1; if(rank > 0 && !xdr_u_int(xdrs,&xdrcount)) return xdrerror(); for(i=0;isubnodes);j++) { OCnode* field = (OCnode*)oclistget(node->subnodes,j); stat = ocskip(field,xdrs); if(stat != OC_NOERR) {THROWCHK(stat); break;} } if(stat != OC_NOERR) {THROWCHK(stat); break;} } } break; case OC_Sequence: /* not uniform, so walk record by record*/ OCASSERT((node->array.rank == 0)); for(;;) { /* pick up the sequence record begin marker*/ char tmp[sizeof(unsigned int)]; /* extract the tag byte*/ if(!xdr_opaque(xdrs,tmp,sizeof(tmp))) return xdrerror(); if(tmp[0] == StartOfoclist) { /* Walk each member field*/ for(j=0;jsubnodes);j++) { OCnode* member = (OCnode*)oclistget(node->subnodes,j); stat = ocskip(member,xdrs); if(stat != OC_NOERR) {THROWCHK(stat); break;} } } else if(tmp[0] == EndOfoclist) { break; /* we are done with the this sequence instance*/ } else { oc_log(LOGERR,"missing/invalid begin/end record marker\n"); stat = OC_EINVALCOORDS; {THROWCHK(stat); break;} } if(stat != OC_NOERR) {THROWCHK(stat); break;} } break; default: OCPANIC1("oc_move: encountered unexpected node type: %x",node->octype); break; } return THROW(stat); } /* Skip arbitrary single instance; except for primitives Assumes that parent will handle arrays of compound instances or records of compound instances of this node type Specifically, all array counts have been absorbed by some parent caller.*/ int ocskipinstance(OCnode* node, XDR* xdrs) { unsigned int i; int stat = OC_NOERR; unsigned int xdrcount; #if 0 unsigned int j,rank; switch (node->octype) { case OC_Dataset: case OC_Grid: OCASSERT((node->array.rank == 0)); stat = ocskip(node,xdrs); break; case OC_Sequence: /* instance is essentially same a structure */ case OC_Structure: if(node->dap.instancesize > 0) { /* do a direct skip*/ if(!xdr_skip(xdrs,node->dap.instancesize)) return xdrerror(); } else { /* Non-uniform size, we have to skip field by field*/ /* Walk each structure/sequence field*/ for(j=0;jsubnodes);j++) { OCnode* field = (OCnode*)oclistget(node->subnodes,j); stat = ocskip(field,xdrs); if(stat != OC_NOERR) break; } if(stat != OC_NOERR) break; } break; case OC_Primitive: if(node->etype == OC_String || node->etype == OC_URL) { if(!xdr_u_int(xdrs,&xdrcount)) return xdrerror(); if(!xdr_skip(xdrs,xdrcount)) return xdrerror(); } else { OCASSERT((node->dap.instancesize > 0)); if(!xdr_skip(xdrs,node->dap.instancesize)) return xdrerror(); } break; default: OCPANIC1("oc_move: encountered unexpected node type: %x",node->octype); break; } #else if(node->dap.instancesize > 0) { /* do a direct skip*/ if(!xdr_skip(xdrs,node->dap.instancesize)) return xdrerror(); } else if(node->octype == OC_Primitive) { OCASSERT((node->etype == OC_String || node->etype == OC_URL)); if(!xdr_u_int(xdrs,&xdrcount)) return xdrerror(); if(!xdr_skip(xdrs,xdrcount)) return xdrerror(); } else { /* Non-uniform size Grid/Sequence/Structure/Dataset;*/ /* we have to skip field by field*/ for(i=0;isubnodes);i++) { OCnode* field = (OCnode*)oclistget(node->subnodes,i); stat = ocskip(field,xdrs); if(stat != OC_NOERR) break; } } #endif return THROW(stat); } /* 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. */ int ocxdrread(XDR* xdrs, char* memory, size_t memsize, int packed, OCtype octype, unsigned int start, size_t count) { int stat = OC_NOERR; unsigned int i; size_t elemsize = octypesize(octype); char* localmem = NULL; char* startmem = NULL; size_t totalsize; size_t xdrsize; unsigned int xdrckp = xdr_getpos(xdrs); /* validate memory space*/ totalsize = elemsize*count; if(memsize < totalsize) return THROW(OC_EINVAL); /* Handle packed data specially*/ /* WARNING: assumes that the initial count has been read*/ if(packed) { char tmp[LOCALMEMMAX]; unsigned int readsize = start+count; if(readsize <= LOCALMEMMAX) /* avoid malloc/free for common case*/ localmem = tmp; else { localmem = (char*)ocmalloc(readsize); MEMCHECK(localmem,OC_ENOMEM); } if(!xdr_opaque(xdrs,(char*)localmem,readsize)) return xdrerror(); memcpy((void*)memory,(void*)(localmem+start),count); if(readsize > LOCALMEMMAX) ocfree(localmem); if(!xdr_setpos(xdrs,xdrckp)) return xdrerror(); /* revert to beginning*/ return THROW(OC_NOERR); } /* Not packed: extract count items; use xdr_opaque to speed up*/ if(octype == OC_String || octype == OC_URL) { /* do nothing here; handle below*/ } else if(octype == OC_Float64 || octype == OC_UInt64 || octype == OC_Int64) { unsigned int* p; xdrsize = 2*(start+count)*BYTES_PER_XDR_UNIT; localmem = (char*)ocmalloc(xdrsize); startmem = localmem+(2*start*BYTES_PER_XDR_UNIT); MEMCHECK(localmem,OC_ENOMEM); if(!xdr_opaque(xdrs,(char*)localmem,xdrsize)) return xdrerror(); if(!oc_network_order) { for(p=(unsigned int*)startmem,i=0;i<2*count;i++,p++) { unsigned int swap = *p; swapinline(*p,swap); } } } else { unsigned int* p; xdrsize = (start+count)*BYTES_PER_XDR_UNIT; localmem = (char*)ocmalloc(xdrsize); MEMCHECK(localmem,OC_ENOMEM); startmem = localmem+(start*BYTES_PER_XDR_UNIT); if(!xdr_opaque(xdrs,(char*)localmem,xdrsize)) return xdrerror(); if(!oc_network_order) { for(p=(unsigned int*)startmem,i=0;ioctype != OC_Sequence) return THROW(OC_EINVAL); /* checkpoint the xdr position*/ xdroffset = xdr_getpos(xdrs); for(;;) { unsigned int i; /* pick up the sequence record begin marker*/ char tmp[sizeof(unsigned int)]; /* extract the tag byte*/ if(!xdr_opaque(xdrs,tmp,sizeof(tmp))) return xdrerror(); if(tmp[0] == StartOfoclist) { /* Walk each member field*/ for(i=0;isubnodes);i++) { OCnode* member = (OCnode*)oclistget(node->subnodes,i); stat = ocskip(member,xdrs); if(stat != OC_NOERR) break; } nrecords++; } else if(tmp[0] == EndOfoclist) { break; /* we are done with the this sequence instance*/ } else { oc_log(LOGERR,"missing/invalid begin/end record marker\n"); stat = OC_EINVALCOORDS; break; } if(stat != OC_NOERR) break; } /* move to checkpoint position*/ if(!xdr_setpos(xdrs,xdroffset)) return xdrerror(); if(nrecordsp != NULL) *nrecordsp = nrecords; return THROW(stat); }