/********************************************************************* * Copyright 2010, UCAR/Unidata * See netcdf/COPYRIGHT file for copying and redistribution conditions. * $Id$ * $Header$ *********************************************************************/ #include "config.h" #include "includes.h" /*Forward*/ static int nccr_walk_Group(Group*, Group*, NClist*); static int nccr_walk_Dimension(Group*, Dimension*, NClist*); static int nccr_walk_Variable(Group*, Variable*, NClist*); static int nccr_walk_Structure(Group*, Structure*, NClist*); static int nccr_walk_Attribute(Group*, Attribute*, NClist*); static int nccr_walk_EnumTypedef(Group*, EnumTypedef*, NClist*); static int nccr_walk_EnumType(Group*, EnumType*, NClist*); static void annotate(Group*, CRnode*, Sort, NClist*); static void computepathname(CRnode* leaf); static int testmagicnumber(bytes_t* packet, char* magicno, size_t* offsetp); static int testpacketsize(bytes_t* packet, size_t* offsetp); /**************************************************/ /* Define cdmremote magic numbers */ #define MAGIC_START "\x43\x44\x46\x53" /* "CDFS" */ #define MAGIC_END "\xed\xed\xde\xde" #define MAGIC_HEADER "\xad\xec\xce\xda" #define MAGIC_DATA "\xab\xec\xce\xba" #define MAGIC_ERR "\xab\xad\xba\xda" int nccr_cvtasterr(ast_err err) { switch (err) { case AST_NOERR: return NC_NOERR; case AST_EOF: return NC_EINVAL; case AST_ENOMEM: return NC_ENOMEM; case AST_EFAIL: return NC_EINVAL /*generic*/; case AST_EIO: return NC_EIO; case AST_ECURL: return NC_ECURL; default: break; } return NC_EINVAL; } int nccr_decodeheadermessage(bytes_t* packet, Header** hdrp) { int ncstat = NC_NOERR; ast_err status = AST_NOERR; ast_runtime* rt = NULL; Header* protohdr = NULL; size_t offset; bytes_t buf = *packet; /* So we can modify it */ /* Check for optional MAGIC_START */ offset = 0; testmagicnumber(&buf,MAGIC_START,&offset); buf.nbytes -= offset; buf.bytes += offset; /* Check for MAGIC_HEADER */ offset = 0; if(!testmagicnumber(&buf,MAGIC_HEADER,&offset)) { nclog(NCLOGERR,"Curl data too short: %d\n",packet->nbytes); ncstat = NC_ECURL; goto done; } buf.nbytes -= offset; buf.bytes += offset; /* pull out the packet length and verify */ offset = 0; if(!testpacketsize(&buf,&offset)) { nclog(NCLOGERR,"Curl data size mismatch\n"); THROWCHK((ncstat = NC_EINVAL)); goto done; } buf.nbytes -= offset; buf.bytes += offset; /* Now decode the buffer */ status = ast_byteio_new(AST_READ,buf.bytes,buf.nbytes,&rt); if(status != AST_NOERR) goto done; status = Header_read(rt,&protohdr); if(status != AST_NOERR) goto done; /* Verify optional MAGIC_END */ offset = 0; testmagicnumber(&buf,MAGIC_END,&offset); if(ncstat) {THROWCHK(ncstat); goto done;} status = ast_reclaim(rt); if(status != AST_NOERR) goto done; if(hdrp) *hdrp = protohdr; done: if(status) ncstat = nccr_cvtasterr(status); return ncstat; } /* Walk the Header tree to insert uid and sort capture all nodes */ static void annotate(Group* parent, CRnode* node, Sort sort, NClist* nodes) { if(nclistcontains(nodes,(ncelem)node)) return; memset((void*)node,0,sizeof(CRnode)); node->uid = nclistlength(nodes); node->sort = sort; node->group = parent; nclistpush(nodes,(ncelem)node); if(parent == NULL && node->sort == _Group) node->flags.isroot = 1; } int nccr_walk_Header(Header* hdr, NClist* nodes) { int ncstat = NC_NOERR; annotate(NULL,(CRnode*)hdr,_Header,nodes); nccr_walk_Group(NULL,hdr->root,nodes); return ncstat; } static int nccr_walk_Group(Group* parent, Group* node, NClist* nodes) { int ncstat = NC_NOERR; int i; annotate(parent,(CRnode*)node,_Group,nodes); for(i=0;idims.count;i++) { ncstat = nccr_walk_Dimension(node,node->dims.values[i],nodes); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} node->dims.values[i]->node.flags.isdecl = 1; } for(i=0;ivars.count;i++) { nccr_walk_Variable(node,node->vars.values[i],nodes); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } for(i=0;istructs.count;i++) { nccr_walk_Structure(node,node->structs.values[i],nodes); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } for(i=0;iatts.count;i++) { nccr_walk_Attribute(node,node->atts.values[i],nodes); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } for(i=0;igroups.count;i++) { nccr_walk_Group(node,node->groups.values[i],nodes); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } for(i=0;ienumTypes.count;i++) { nccr_walk_EnumTypedef(node,node->enumTypes.values[i],nodes); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } done: return ncstat; } static int nccr_walk_Dimension(Group* parent, Dimension* node, NClist* nodes) { int ncstat = NC_NOERR; annotate(parent,(CRnode*)node,_Dimension,nodes); return ncstat; } static int nccr_walk_Variable(Group* parent, Variable* node, NClist* nodes) { int ncstat = NC_NOERR; int i; annotate(parent,(CRnode*)node,_Variable,nodes); for(i=0;ishape.count;i++) { nccr_walk_Dimension(parent,node->shape.values[i],nodes); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } for(i=0;iatts.count;i++) { nccr_walk_Attribute(parent,node->atts.values[i],nodes); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } done: return ncstat; } static int nccr_walk_Structure(Group* parent, Structure* node, NClist* nodes) { int ncstat = NC_NOERR; int i; annotate(parent,(CRnode*)node,_Dimension,nodes); for(i=0;ishape.count;i++) { nccr_walk_Dimension(parent,node->shape.values[i],nodes); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } for(i=0;iatts.count;i++) { nccr_walk_Attribute(parent,node->atts.values[i],nodes); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } for(i=0;ivars.count;i++) { nccr_walk_Variable(parent,node->vars.values[i],nodes); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } for(i=0;istructs.count;i++) { nccr_walk_Structure(parent,node->structs.values[i],nodes); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } done: return ncstat; } static int nccr_walk_Attribute(Group* parent, Attribute* node, NClist* nodes) { int ncstat = NC_NOERR; annotate(parent,(CRnode*)node,_Attribute,nodes); return ncstat; } static int nccr_walk_EnumTypedef(Group* parent, EnumTypedef* node, NClist* nodes) { int ncstat = NC_NOERR; int i; annotate(parent,(CRnode*)node,_EnumTypedef,nodes); for(i=0;imap.count;i++) { nccr_walk_EnumType(parent,node->map.values[i],nodes); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } done: return ncstat; } static int nccr_walk_EnumType(Group* parent, EnumType* node, NClist* nodes) { int ncstat = NC_NOERR; annotate(parent,(CRnode*)node,_EnumType,nodes); return ncstat; } /**************************************************/ int nccr_compute_pathnames(NClist* nodes) { int ncstat = NC_NOERR; int i; /* Compute the pathname for selected nodes */ for(i=0;isort) { case _Dimension: case _Variable: case _Structure: case _EnumType: case _Group: computepathname(node); break; default: break; /* ignore */ } } return ncstat; } static void computepathname(CRnode* leaf) { int i; CRnode* node; NClist* path = nclistnew(); char* name; for(node=leaf;;) { if(node->flags.isroot) break; nclistinsert(path,0,(ncelem)node); node = (CRnode*)node->group; } leaf->pathname = NULL; for(i=0;ipathname = crpathappend(leaf->pathname,name); } nclistfree(path); done: return; } char* nccr_getname(CRnode* node) { switch(node->sort) { case _Attribute: return ((Attribute*)node)->name; case _Dimension: return ((Dimension*)node)->name.defined?((Dimension*)node)->name.value:NULL; case _Variable: return ((Variable*)node)->name; case _Structure: return ((Structure*)node)->name; case _EnumTypedef: return ((EnumTypedef*)node)->name; case _EnumType: return ((EnumType*)node)->value; case _Group: return ((Group*)node)->name; case _Header: return ""; default: return NULL; } } DataType nccr_gettype(CRnode* node) { switch(node->sort) { case _Attribute: return ((Attribute*)node)->type; case _Variable: return ((Variable*)node)->dataType; case _Structure: return ((Structure*)node)->dataType; default: return -1; } } /**************************************************/ /* Map dimension refs to matching decl; if the match sizes are different, fail. */ int nccr_map_dimensions(NClist* nodes) { int ncstat = NC_NOERR; int i; NClist* dimdecls = nclistnew(); /* Collect dimension decls */ for(i=0;isort == _Dimension && node->flags.isdecl) nclistpush(dimdecls,(ncelem)node); } /* Map dimension refs to matching decl */ for(i=0;isort) { case _Dimension: /* Map dimension references to the corresponding decl */ dim = (Dimension*)node; for(j=0;jnode.pathname,dim->node.pathname)) continue; /* Validate that these are really the same dimension */ if(classifydim(decl) == classifydim(dim)) { if(dimsize(decl) == dimsize(dim)) { node->dimdecl = (Dimension*)decl; } else goto fail; } else goto fail; } ASSERT(node->flags.isdecl || node->dimdecl != NULL); break; default: break; /* ignore */ } } nclistfree(dimdecls); return ncstat; fail: return THROW(NC_EINVALCOORDS); } /**************************************************/ /* Replace all dimension references with their corrsponding dimension decl */ void nccr_deref_dimensions(NClist* nodes) { int i,j; NClist* replaced = nclistnew(); for(i=0;isort) { case _Variable: count = ((Variable*)node)->shape.count; dimset = ((Variable*)node)->shape.values; break; case _Structure: count = ((Structure*)node)->shape.count; dimset = ((Structure*)node)->shape.values; break; default: break; } /* Do the replacement */ if(count > 0 && dimset != NULL) { for(j=0;jnode.flags.isdecl) { nclistpush(replaced,(ncelem)dimset[j]); dimset[j] = dimset[j]->node.dimdecl; } } } } /*Remove the replaced from the nodeset */ for(i=0;inbytes < magiclen) return 0; if(memcmp(packet->bytes,magicno,magiclen) != 0) return 0; offset = magiclen; if(offsetp) *offsetp = offset; return 1; } static int testpacketsize(bytes_t* packet, size_t* offsetp) { unsigned long long vlen; size_t offset = 0; size_t size; /* Extract the proposed count as a varint */ vlen = varint_decode(packet->nbytes,packet->bytes,&size); offset += size; if(vlen != (packet->nbytes-offset)) return 0; *offsetp = offset; return 1; } /**************************************************/ /* Extract the Data object and return the offset in the buffer where data starts plus its expected length. */ int nccr_decodedatamessage(bytes_t* packet, Data** datahdrp, size_t* datastart) { int ncstat = NC_NOERR; ast_err status = AST_NOERR; ast_runtime* rt = NULL; Data* datahdr = NULL; size_t delta, datahdrlen, cumoffset, pos0; bytes_t buf = *packet; cumoffset = 0; /* Check for optional MAGIC_START */ delta = 0; (void)testmagicnumber(&buf,MAGIC_START,&delta); buf.nbytes -= delta; buf.bytes += delta; cumoffset += delta; /* Check for MAGIC_DATA */ delta = 0; if(!testmagicnumber(&buf,MAGIC_DATA,&delta)) { nclog(NCLOGERR,"MAGIC_DATA not found\n"); THROWCHK((ncstat = NC_EINVAL)); goto done; } buf.nbytes -= delta; buf.bytes += delta; cumoffset += delta; /* pull out the Data Header length */ delta = 0; datahdrlen = 0; ncstat = nccr_decodedatacount(&buf,&delta,&datahdrlen); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} buf.nbytes -= delta; buf.bytes += delta; cumoffset += delta; /* Now decode the buffer; but tracking the buffer position */ status = ast_byteio_new(AST_READ,buf.bytes,buf.nbytes,&rt); if(status != AST_NOERR) goto done; /* Capture the position before reading the Data Header */ status = ast_byteio_count(rt,&pos0); if(status != AST_NOERR) goto done; /* Mark the rt with the datahdrlen */ ast_mark(rt,datahdrlen); status = Data_read(rt,&datahdr); if(status != AST_NOERR) goto done; ast_unmark(rt); /* Capture the position after reading the Data Header */ status = ast_byteio_count(rt,&delta); if(status != AST_NOERR) goto done; /* get true delta */ delta = (delta - pos0); status = ast_reclaim(rt); if(status != AST_NOERR) goto done; buf.nbytes -= delta; buf.bytes += delta; cumoffset += delta; #ifdef IGNORE /* Read the data vlen at that position */ delta = 0; ncstat = nccr_decodedatacount(&buf,&delta,datalen); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} buf.nbytes -= delta; buf.bytes += delta; cumoffset += delta; #endif if(datastart) { /* save cumulative offset */ *datastart = cumoffset; } if(datahdrp) *datahdrp = datahdr; done: if(status) ncstat = nccr_cvtasterr(status); return ncstat; } int nccr_decodedatacount(bytes_t* buf, size_t* offsetp, size_t* countp) { int ncstat = NC_NOERR; ast_err status = AST_NOERR; size_t offset = *offsetp; size_t count = 0; unsigned long long vlen; /* Extract a vlen int indicating the length of the vdata */ vlen = varint_decode(buf->nbytes-offset,buf->bytes+offset,&offset); count = (size_t)vlen; /* return some values */ if(offsetp) *offsetp = offset; if(countp) *countp = count; if(status) ncstat = nccr_cvtasterr(status); return ncstat; }