/* Extract data for a netcdf variable that has a string dimension. */ static int extractstring( NCDAPCOMMON* nccomm, Getvara* xgetvar, CDFnode* xnode, DCEsegment* segment, size_t dimindex, /*notused*/ OClink conn, OCdatanode currentcontent, struct NCMEMORY* memory ) { NCerror ncstat = NC_NOERR; OCerror ocstat = OC_NOERR; int i; size_t rank0; NClist* strings = NULL; Dapodometer* odom = NULL; ASSERT(xnode->etype == NC_STRING || xnode->etype == NC_URL); /* Compute rank minus string dimension */ rank0 = nclistlength(xnode->array.dimset0); /* keep whole extracted strings stored in an NClist */ strings = nclistnew(); if(rank0 == 0) {/*=> scalar*/ char* value = NULL; ocstat = oc_data_readscalar(conn,currentcontent,sizeof(value),&value); if(ocstat != OC_NOERR) goto done; nclistpush(strings,(void*)value); } else { /* Use the odometer to walk to the appropriate fields*/ odom = dapodom_fromsegment(segment,0,rank0); while(dapodom_more(odom)) { char* value = NULL; ocstat = oc_data_readn(conn,currentcontent,odom->index,1,sizeof(value),&value); if(ocstat != OC_NOERR) goto done; nclistpush(strings,(void*)value); dapodom_next(odom); } dapodom_free(odom); } /* Get each string in turn, slice it by applying the string dimm and store in user supplied memory */ for(i=0;i<nclistlength(strings);i++) { char* s = (char*)nclistget(strings,i); slicestring(conn,s,&segment->slices[rank0],memory); free(s); } nclistfree(strings); done: if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat); return THROW(ncstat); }
/* We are at a primitive variable or scalar that has no string dimensions. Extract the data. (This is way too complicated) */ static int extract( NCDAPCOMMON* nccomm, Getvara* xgetvar, CDFnode* xnode, DCEsegment* segment, size_t dimindex,/*notused*/ OClink conn, OCdatanode currentcontent, struct NCMEMORY* memory ) { OCerror ocstat = OC_NOERR; NCerror ncstat = NC_NOERR; size_t count,rank0; Dapodometer* odom = NULL; size_t externtypesize; size_t interntypesize; int requireconversion; char value[16]; ASSERT((segment != NULL)); requireconversion = conversionrequired(xgetvar->dsttype,xnode->etype); ASSERT(xgetvar->cache != NULL); externtypesize = nctypesizeof(xgetvar->dsttype); interntypesize = nctypesizeof(xnode->etype); rank0 = nclistlength(xnode->array.dimset0); #ifdef DEBUG2 fprintf(stderr,"moveto: primitive: segment=%s", dcetostring((DCEnode*)segment)); fprintf(stderr," iswholevariable=%d",xgetvar->cache->wholevariable); fprintf(stderr,"\n"); #endif if(rank0 == 0) {/* scalar */ char* mem = (requireconversion?value:memory->next); ASSERT(externtypesize <= sizeof(value)); /* Read the whole scalar directly into memory */ ocstat = oc_data_readscalar(conn,currentcontent,externtypesize,mem); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} if(requireconversion) { /* convert the value to external type */ ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } memory->next += (externtypesize); } else if(xgetvar->cache->wholevariable) {/* && rank0 > 0 */ /* There are multiple cases, assuming no conversion required. 1) client is asking for whole variable => start=0, count=totalsize, stride=1 => read whole thing at one shot 2) client is asking for non-strided subset and edges are maximal => start=x, count=y, stride=1 => read whole subset at one shot 3) client is asking for strided subset or edges are not maximal => start=x, count=y, stride=s => we have to use odometer on leading prefix. If conversion required, then read one-by-one */ int safeindex = dcesafeindex(segment,0,rank0); assert(safeindex >= 0 && safeindex <= rank0); if(!requireconversion && safeindex == 0) { /* can read whole thing */ size_t internlen; count = dcesegmentsize(segment,0,rank0); /* how many to read */ internlen = interntypesize*count; /* Read the whole variable directly into memory.*/ ocstat = oc_data_readn(conn,currentcontent,dap_zero,count,internlen,memory->next); /* bump memory pointer */ memory->next += internlen; if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} } else if(!requireconversion && safeindex > 0 && safeindex < rank0) { size_t internlen; /* We need to build an odometer for the unsafe prefix of the slices */ odom = dapodom_fromsegment(segment,0,safeindex); count = dcesegmentsize(segment,safeindex,rank0); /* read in count chunks */ internlen = interntypesize*count; while(dapodom_more(odom)) { ocstat = oc_data_readn(conn,currentcontent,odom->index,count,internlen,memory->next); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} memory->next += internlen; dapodom_next(odom); } dapodom_free(odom); } else { /* Cover following cases, all of which require reading values one-by-one: 1. requireconversion 2. !requireconversion but safeindex == rank0 =>no safe indices Note that in case 2, we will do a no-op conversion. */ odom = dapodom_fromsegment(segment,0,rank0); while(dapodom_more(odom)) { char value[16]; /* Big enough to hold any numeric value */ ocstat = oc_data_readn(conn,currentcontent,odom->index,1,interntypesize,value); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} memory->next += (externtypesize); dapodom_next(odom); } dapodom_free(odom); } } else { /* !xgetvar->cache->wholevariable && rank0 > 0 */ /* This is the case where the constraint was applied by the server, so we just read it in, possibly with conversion */ if(requireconversion) { /* read one-by-one */ odom = dapodom_fromsegment(segment,0,rank0); while(dapodom_more(odom)) { char value[16]; /* Big enough to hold any numeric value */ ocstat = oc_data_readn(conn,currentcontent,odom->index,1,interntypesize,value); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} memory->next += (externtypesize); dapodom_next(odom); } dapodom_free(odom); } else {/* Read straight to memory */ size_t internlen; count = dcesegmentsize(segment,0,rank0); /* how many to read */ internlen = interntypesize*count; ocstat = oc_data_readn(conn,currentcontent,dap_zero,count,internlen,memory->next); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} } } done: return THROW(ncstat); }
static NCerror movetor(NCDAPCOMMON* nccomm, OCdatanode currentcontent, NClist* path, int depth, /* depth is position in segment list*/ Getvara* xgetvar, size_t dimindex, /* dimindex is position in xgetvar->slices*/ struct NCMEMORY* memory, NClist* segments) { OCerror ocstat = OC_NOERR; NCerror ncstat = NC_NOERR; OClink conn = nccomm->oc.conn; CDFnode* xnode = (CDFnode*)nclistget(path,depth); OCdatanode reccontent = NULL; OCdatanode dimcontent = NULL; OCdatanode fieldcontent = NULL; Dapodometer* odom = NULL; int hasstringdim = 0; DCEsegment* segment; OCDT mode; /* Note that we use depth-1 because the path contains the DATASET but the segment list does not */ segment = (DCEsegment*)nclistget(segments,depth-1); /*may be NULL*/ if(xnode->etype == NC_STRING || xnode->etype == NC_URL) hasstringdim = 1; /* Get the mode */ mode = oc_data_mode(conn,currentcontent); #ifdef DEBUG2 fprintf(stderr,"moveto: nctype=%d depth=%d dimindex=%d mode=%s", xnode->nctype, depth,dimindex,oc_data_modestring(mode)); fprintf(stderr," segment=%s hasstringdim=%d\n", dcetostring((DCEnode*)segment),hasstringdim); #endif switch (xnode->nctype) { #if 0 #define OCDT_FIELD ((OCDT)(1)) /* field of a container */ #define OCDT_ELEMENT ((OCDT)(2)) /* element of a structure array */ #define OCDT_RECORD ((OCDT)(4)) /* record of a sequence */ #define OCDT_ARRAY ((OCDT)(8)) /* is structure array */ #define OCDT_SEQUENCE ((OCDT)(16)) /* is sequence */ #define OCDT_ATOMIC ((OCDT)(32)) /* is atomic leaf */ #endif default: goto done; case NC_Grid: case NC_Dataset: case NC_Structure: /* Separate out the case where structure is dimensioned */ if(oc_data_indexable(conn,currentcontent)) { /* => dimensioned structure */ /* The current segment should reflect the proper parts of the nc_get_vara argument */ /* Create odometer for this structure's part of the projection */ odom = dapodom_fromsegment(segment,0,segment->rank); while(dapodom_more(odom)) { /* Compute which instance to move to*/ ocstat = oc_data_ithelement(conn,currentcontent, odom->index,&dimcontent); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} ASSERT(oc_data_indexed(conn,dimcontent)); ncstat = movetor(nccomm,dimcontent, path,depth,/*keep same depth*/ xgetvar,dimindex+segment->rank, memory,segments); dapodom_next(odom); } dapodom_free(odom); } else {/* scalar instance */ ncstat = movetofield(nccomm,currentcontent,path,depth,xgetvar,dimindex,memory,segments); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} } break; case NC_Sequence: if(fIsSet(mode,OCDT_SEQUENCE)) { ASSERT((xnode->attachment != NULL)); ASSERT((segment != NULL)); ASSERT((segment->rank == 1)); /* Build an odometer for walking the sequence, however, watch out for the case when the user set a limit and that limit is not actually reached in this request. */ /* By construction, this sequence represents the first (and only) dimension of this segment */ odom = dapodom_fromsegment(segment,0,1); while(dapodom_more(odom)) { size_t recordindex = dapodom_count(odom); ocstat = oc_data_ithrecord(conn,currentcontent, recordindex,&reccontent); if(ocstat != OC_NOERR) { if(ocstat == OC_EINDEX) ocstat = OC_EINVALCOORDS; THROWCHK(ocstat); goto done; } ncstat = movetor(nccomm,reccontent, path,depth, xgetvar,dimindex+1, memory,segments); if(ncstat != OC_NOERR) {THROWCHK(ncstat); goto done;} dapodom_next(odom); } } else if(fIsSet(mode,OCDT_RECORD)) { /* Treat like structure */ /* currentcontent points to the record instance */ ncstat = movetofield(nccomm,currentcontent,path,depth,xgetvar,dimindex,memory,segments); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} } break; case NC_Atomic: if(hasstringdim) ncstat = extractstring(nccomm, xgetvar, xnode, segment, dimindex, conn, currentcontent, memory); else ncstat = extract(nccomm, xgetvar, xnode, segment, dimindex, conn, currentcontent, memory); break; } done: oc_data_free(conn,dimcontent); oc_data_free(conn,fieldcontent); oc_data_free(conn,reccontent); if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat); return THROW(ncstat); }