[409] | 1 | /********************************************************************* |
---|
| 2 | * Copyright 1993, UCAR/Unidata |
---|
| 3 | * See netcdf/COPYRIGHT file for copying and redistribution conditions. |
---|
| 4 | * $Header: /upc/share/CVS/netcdf-3/libncdap3/getvara3.c,v 1.44 2010/05/27 21:34:08 dmh Exp $ |
---|
| 5 | *********************************************************************/ |
---|
| 6 | |
---|
| 7 | #include "ncdap3.h" |
---|
| 8 | #include "dapodom.h" |
---|
| 9 | #include "dapdump.h" |
---|
| 10 | #include "ncd3dispatch.h" |
---|
| 11 | |
---|
| 12 | |
---|
| 13 | #define NEWVARM |
---|
| 14 | |
---|
| 15 | /* Define a tracker for memory to support*/ |
---|
| 16 | /* the concatenation*/ |
---|
| 17 | |
---|
| 18 | struct NCMEMORY { |
---|
| 19 | void* memory; |
---|
| 20 | char* next; /* where to store the next chunk of data*/ |
---|
| 21 | }; |
---|
| 22 | |
---|
| 23 | /* Forward:*/ |
---|
| 24 | static NCerror moveto(NCDAPCOMMON*, Getvara*, CDFnode* dataroot, void* memory); |
---|
| 25 | static NCerror movetor(NCDAPCOMMON*, OCdata currentcontent, |
---|
| 26 | NClist* path, int depth, |
---|
| 27 | Getvara*, int dimindex, |
---|
| 28 | struct NCMEMORY*, NClist* segments); |
---|
| 29 | |
---|
| 30 | static int findfield(CDFnode* node, CDFnode* subnode); |
---|
| 31 | static int wholeslicepoint(Dapodometer* odom); |
---|
| 32 | static NCerror removepseudodims(DCEprojection* proj); |
---|
| 33 | |
---|
| 34 | static int extract(NCDAPCOMMON*, Getvara*, CDFnode*, DCEsegment*, OClink, OCdata, struct NCMEMORY*); |
---|
| 35 | static int extractstring(NCDAPCOMMON*, Getvara*, CDFnode*, DCEsegment*, OClink, OCdata, struct NCMEMORY*); |
---|
| 36 | |
---|
| 37 | /** |
---|
| 38 | 1. We build the projection to be sent to the server aka |
---|
| 39 | the fetch constraint. We want the server do do as much work |
---|
| 40 | as possible, so we send it a url with a fetch constraint |
---|
| 41 | that is the merge of the url constraint with the vara |
---|
| 42 | constraint. |
---|
| 43 | |
---|
| 44 | The url constraint, if any, is the one that was provided |
---|
| 45 | in the url specified in nc_open(). |
---|
| 46 | |
---|
| 47 | The vara constraint is the one formed from the arguments |
---|
| 48 | (start, count, stride) provided to the call to nc_get_vara(). |
---|
| 49 | |
---|
| 50 | There are some exceptions to the formation of the fetch constraint. |
---|
| 51 | In all cases, the fetch constraint will use any URL selections, |
---|
| 52 | but will use different fetch projections. |
---|
| 53 | a. URL is unconstrainable (e.g. file://...): |
---|
| 54 | fetchprojection = null => fetch whole dataset |
---|
| 55 | b. The target variable (as specified in nc_get_vara()) |
---|
| 56 | is already in the cache and is whole variable. |
---|
| 57 | fetchprojection = N.A. since variable is in the cache |
---|
| 58 | c. Vara is requesting part of a variable but NCF_WHOLEVAR flag is set. |
---|
| 59 | fetchprojection = unsliced vara variable => fetch whole variable |
---|
| 60 | d. Vara is requesting part of a variable and NCF_WHOLEVAR flag is not set. |
---|
| 61 | fetchprojection = sliced vara variable => fetch part variable |
---|
| 62 | |
---|
| 63 | 2. At this point, all or part of the target variable is available in the cache. |
---|
| 64 | |
---|
| 65 | 3. We build a projection to walk (guide) the use of the oc |
---|
| 66 | data procedures in extract the required data from the cache. |
---|
| 67 | For cases a,b,c: |
---|
| 68 | walkprojection = merge(urlprojection,varaprojection) |
---|
| 69 | For case d: |
---|
| 70 | walkprojection = varaprojection without slicing. |
---|
| 71 | This means we need only extract the complete contents of the cache. |
---|
| 72 | Notice that this will not necessarily be a direct memory to |
---|
| 73 | memory copy because the dap encoding still needs to be |
---|
| 74 | interpreted. For this case, we derive a walk projection |
---|
| 75 | from the vara projection that will properly access the cached data. |
---|
| 76 | This walk projection shifts the merged projection so all slices |
---|
| 77 | start at 0 and have a stride of 1. |
---|
| 78 | |
---|
| 79 | */ |
---|
| 80 | |
---|
| 81 | NCerror |
---|
| 82 | nc3d_getvarx(int ncid, int varid, |
---|
| 83 | const size_t *startp, |
---|
| 84 | const size_t *countp, |
---|
| 85 | const ptrdiff_t* stridep, |
---|
| 86 | void *data, |
---|
| 87 | nc_type dsttype0) |
---|
| 88 | { |
---|
| 89 | NCerror ncstat = NC_NOERR; |
---|
| 90 | OCerror ocstat = OC_NOERR; |
---|
| 91 | int i; |
---|
| 92 | NC* drno; |
---|
| 93 | NC* substrate; |
---|
| 94 | NCDAPCOMMON* dapcomm; |
---|
| 95 | CDFnode* cdfvar; /* cdf node mapping to var*/ |
---|
| 96 | NClist* varnodes; |
---|
| 97 | nc_type dsttype; |
---|
| 98 | Getvara* varainfo = NULL; |
---|
| 99 | CDFnode* xtarget = NULL; /* target in DATADDS */ |
---|
| 100 | CDFnode* target = NULL; /* target in constrained DDS */ |
---|
| 101 | DCEprojection* varaprojection = NULL; |
---|
| 102 | NCcachenode* cachenode = NULL; |
---|
| 103 | size_t localcount[NC_MAX_VAR_DIMS]; |
---|
| 104 | NClist* ncdimsall; |
---|
| 105 | size_t ncrank; |
---|
| 106 | NClist* vars = NULL; |
---|
| 107 | DCEconstraint* fetchconstraint = NULL; |
---|
| 108 | DCEprojection* fetchprojection = NULL; |
---|
| 109 | DCEprojection* walkprojection = NULL; |
---|
| 110 | int state; |
---|
| 111 | #define FETCHWHOLE 1 /* fetch whole data set */ |
---|
| 112 | #define FETCHVAR 2 /* fetch whole variable */ |
---|
| 113 | #define FETCHPART 4 /* fetch constrained variable */ |
---|
| 114 | #define CACHED 8 /* whole variable is already in the cache */ |
---|
| 115 | |
---|
| 116 | ncstat = NC_check_id(ncid, (NC**)&drno); |
---|
| 117 | if(ncstat != NC_NOERR) goto fail; |
---|
| 118 | dapcomm = (NCDAPCOMMON*)drno->dispatchdata; |
---|
| 119 | |
---|
| 120 | ncstat = NC_check_id(drno->substrate, (NC**)&substrate); |
---|
| 121 | if(ncstat != NC_NOERR) goto fail; |
---|
| 122 | |
---|
| 123 | /* Locate var node via varid */ |
---|
| 124 | varnodes = dapcomm->cdf.varnodes; |
---|
| 125 | for(i=0;i<nclistlength(varnodes);i++) { |
---|
| 126 | CDFnode* node = (CDFnode*)nclistget(varnodes,i); |
---|
| 127 | if(node->array.basevar == NULL |
---|
| 128 | && node->nctype == NC_Primitive |
---|
| 129 | && node->ncid == varid) { |
---|
| 130 | cdfvar = node; |
---|
| 131 | break; |
---|
| 132 | } |
---|
| 133 | } |
---|
| 134 | |
---|
| 135 | ASSERT((cdfvar != NULL)); |
---|
| 136 | |
---|
| 137 | /* Get the dimension info */ |
---|
| 138 | ncdimsall = cdfvar->array.dimsetall; |
---|
| 139 | ncrank = nclistlength(ncdimsall); |
---|
| 140 | |
---|
| 141 | #ifdef DEBUG |
---|
| 142 | { |
---|
| 143 | int i; |
---|
| 144 | fprintf(stderr,"getvarx: %s",cdfvar->ncfullname); |
---|
| 145 | for(i=0;i<ncrank;i++) |
---|
| 146 | fprintf(stderr,"[%ld:%ld:%ld]", |
---|
| 147 | (long)startp[i], |
---|
| 148 | (long)countp[i], |
---|
| 149 | (long)stridep[i] |
---|
| 150 | ); |
---|
| 151 | fprintf(stderr,"\n"); |
---|
| 152 | } |
---|
| 153 | #endif |
---|
| 154 | |
---|
| 155 | /* Fill in missing arguments */ |
---|
| 156 | if(startp == NULL) |
---|
| 157 | startp = nc_sizevector0; |
---|
| 158 | |
---|
| 159 | if(countp == NULL) { |
---|
| 160 | /* Accumulate the dimension sizes */ |
---|
| 161 | for(i=0;i<ncrank;i++) { |
---|
| 162 | CDFnode* dim = (CDFnode*)nclistget(ncdimsall,i); |
---|
| 163 | localcount[i] = dim->dim.declsize; |
---|
| 164 | } |
---|
| 165 | countp = localcount; |
---|
| 166 | } |
---|
| 167 | |
---|
| 168 | if(stridep == NULL) |
---|
| 169 | stridep = nc_ptrdiffvector1; |
---|
| 170 | |
---|
| 171 | /* Validate the dimension sizes */ |
---|
| 172 | for(i=0;i<ncrank;i++) { |
---|
| 173 | CDFnode* dim = (CDFnode*)nclistget(ncdimsall,i); |
---|
| 174 | if(startp[i] > dim->dim.declsize |
---|
| 175 | || startp[i]+countp[i] > dim->dim.declsize) { |
---|
| 176 | ncstat = NC_EINVALCOORDS; |
---|
| 177 | goto fail; |
---|
| 178 | } |
---|
| 179 | } |
---|
| 180 | |
---|
| 181 | #ifdef DEBUG |
---|
| 182 | { |
---|
| 183 | NClist* dims = cdfvar->array.dimsetall; |
---|
| 184 | fprintf(stderr,"getvarx: %s",cdfvar->ncfullname); |
---|
| 185 | if(nclistlength(dims) > 0) {int i; |
---|
| 186 | for(i=0;i<nclistlength(dims);i++) |
---|
| 187 | fprintf(stderr,"[%lu:%lu:%lu]",(unsigned long)startp[i],(unsigned long)countp[i],(unsigned long)stridep[i]); |
---|
| 188 | fprintf(stderr," -> "); |
---|
| 189 | for(i=0;i<nclistlength(dims);i++) |
---|
| 190 | if(stridep[i]==1) |
---|
| 191 | fprintf(stderr,"[%lu:%lu]",(unsigned long)startp[i],(unsigned long)((startp[i]+countp[i])-1)); |
---|
| 192 | else |
---|
| 193 | fprintf(stderr,"[%lu:%lu:%lu]", |
---|
| 194 | (unsigned long)startp[i], |
---|
| 195 | (unsigned long)stridep[i], |
---|
| 196 | (unsigned long)(((startp[i]+countp[i])*stridep[i])-1)); |
---|
| 197 | } |
---|
| 198 | fprintf(stderr,"\n"); |
---|
| 199 | } |
---|
| 200 | #endif |
---|
| 201 | |
---|
| 202 | dsttype = (dsttype0); |
---|
| 203 | |
---|
| 204 | /* Default to using the inquiry type for this var*/ |
---|
| 205 | if(dsttype == NC_NAT) dsttype = cdfvar->externaltype; |
---|
| 206 | |
---|
| 207 | /* Validate any implied type conversion*/ |
---|
| 208 | if(cdfvar->etype != dsttype && dsttype == NC_CHAR) { |
---|
| 209 | /* The only disallowed conversion is to/from char and non-byte |
---|
| 210 | numeric types*/ |
---|
| 211 | switch (cdfvar->etype) { |
---|
| 212 | case NC_STRING: case NC_URL: |
---|
| 213 | case NC_CHAR: case NC_BYTE: case NC_UBYTE: |
---|
| 214 | break; |
---|
| 215 | default: |
---|
| 216 | return THROW(NC_ECHAR); |
---|
| 217 | } |
---|
| 218 | } |
---|
| 219 | |
---|
| 220 | ncstat = makegetvar34(dapcomm,cdfvar,data,dsttype,&varainfo); |
---|
| 221 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} |
---|
| 222 | |
---|
| 223 | state = 0; |
---|
| 224 | if(iscached(dapcomm,cdfvar,&cachenode)) { |
---|
| 225 | state = CACHED; |
---|
| 226 | ASSERT((cachenode != NULL)); |
---|
| 227 | #ifdef DEBUG |
---|
| 228 | fprintf(stderr,"var is in cache\n"); |
---|
| 229 | #endif |
---|
| 230 | /* If it is cached, then it is a whole variable but may still |
---|
| 231 | need to apply constraints during the walk */ |
---|
| 232 | ASSERT(cachenode->wholevariable); /* by construction */ |
---|
| 233 | } else if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) { |
---|
| 234 | state = FETCHWHOLE; |
---|
| 235 | } else {/* load using constraints */ |
---|
| 236 | if(FLAGSET(dapcomm->controls,NCF_WHOLEVAR)) |
---|
| 237 | state = FETCHVAR; |
---|
| 238 | else |
---|
| 239 | state = FETCHPART; |
---|
| 240 | } |
---|
| 241 | |
---|
| 242 | ASSERT(state != 0); |
---|
| 243 | |
---|
| 244 | /* Convert the start/stop/stride info into a projection */ |
---|
| 245 | ncstat = buildvaraprojection3(varainfo, |
---|
| 246 | startp,countp,stridep, |
---|
| 247 | &varaprojection); |
---|
| 248 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} |
---|
| 249 | |
---|
| 250 | fetchprojection = NULL; |
---|
| 251 | walkprojection = NULL; |
---|
| 252 | |
---|
| 253 | /* Create walkprojection as the merge of the url projections |
---|
| 254 | and the vara projection; may change in FETCHPART case below*/ |
---|
| 255 | ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections, |
---|
| 256 | varaprojection,&walkprojection); |
---|
| 257 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} |
---|
| 258 | |
---|
| 259 | #ifdef DEBUG |
---|
| 260 | fprintf(stderr,"getvarx: walkprojection: |%s|\n",dumpprojection(walkprojection)); |
---|
| 261 | #endif |
---|
| 262 | |
---|
| 263 | /* define the var list of interest */ |
---|
| 264 | vars = nclistnew(); |
---|
| 265 | nclistpush(vars,(ncelem)varainfo->target); |
---|
| 266 | |
---|
| 267 | switch (state) { |
---|
| 268 | |
---|
| 269 | case FETCHWHOLE: { |
---|
| 270 | /* buildcachenode3 will create a new cachenode and |
---|
| 271 | will also fetch the whole corresponding datadds. |
---|
| 272 | */ |
---|
| 273 | /* Build the complete constraint to use in the fetch */ |
---|
| 274 | fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT); |
---|
| 275 | /* Use no projections or selections */ |
---|
| 276 | fetchconstraint->projections = nclistnew(); |
---|
| 277 | fetchconstraint->selections = nclistnew(); |
---|
| 278 | #ifdef DEBUG |
---|
| 279 | fprintf(stderr,"getvarx: FETCHWHOLE: fetchconstraint: %s\n",dumpconstraint(fetchconstraint)); |
---|
| 280 | #endif |
---|
| 281 | ncstat = buildcachenode34(dapcomm,fetchconstraint,vars,&cachenode,0); |
---|
| 282 | fetchconstraint = NULL; /*buildcachenode34 takes control of fetchconstraint.*/ |
---|
| 283 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} |
---|
| 284 | } break; |
---|
| 285 | |
---|
| 286 | case CACHED: { |
---|
| 287 | } break; |
---|
| 288 | |
---|
| 289 | case FETCHVAR: { /* Fetch a complete single variable */ |
---|
| 290 | /* Create fetch projection as the merge of the url projections |
---|
| 291 | and the vara projection */ |
---|
| 292 | ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections, |
---|
| 293 | varaprojection,&fetchprojection); |
---|
| 294 | /* elide any sequence and string dimensions (dap servers do not allow such). */ |
---|
| 295 | ncstat = removepseudodims(fetchprojection); |
---|
| 296 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} |
---|
| 297 | |
---|
| 298 | /* Convert to a whole variable projection */ |
---|
| 299 | dcemakewholeprojection(fetchprojection); |
---|
| 300 | |
---|
| 301 | #ifdef DEBUG |
---|
| 302 | fprintf(stderr,"getvarx: FETCHVAR: fetchprojection: |%s|\n",dumpprojection(fetchprojection)); |
---|
| 303 | #endif |
---|
| 304 | |
---|
| 305 | /* Build the complete constraint to use in the fetch */ |
---|
| 306 | fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT); |
---|
| 307 | /* merged constraint just uses the url constraint selection */ |
---|
| 308 | fetchconstraint->selections = dceclonelist(dapcomm->oc.dapconstraint->selections); |
---|
| 309 | /* and the created fetch projection */ |
---|
| 310 | fetchconstraint->projections = nclistnew(); |
---|
| 311 | nclistpush(fetchconstraint->projections,(ncelem)fetchprojection); |
---|
| 312 | #ifdef DEBUG |
---|
| 313 | fprintf(stderr,"getvarx: FETCHVAR: fetchconstraint: %s\n",dumpconstraint(fetchconstraint)); |
---|
| 314 | #endif |
---|
| 315 | /* buildcachenode3 will create a new cachenode and |
---|
| 316 | will also fetch the corresponding datadds. |
---|
| 317 | */ |
---|
| 318 | ncstat = buildcachenode34(dapcomm,fetchconstraint,vars,&cachenode,0); |
---|
| 319 | fetchconstraint = NULL; /*buildcachenode34 takes control of fetchconstraint.*/ |
---|
| 320 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} |
---|
| 321 | } break; |
---|
| 322 | |
---|
| 323 | case FETCHPART: { |
---|
| 324 | /* Create fetch projection as the merge of the url projections |
---|
| 325 | and the vara projection */ |
---|
| 326 | ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections, |
---|
| 327 | varaprojection,&fetchprojection); |
---|
| 328 | /* elide any sequence and string dimensions (dap servers do not allow such). */ |
---|
| 329 | ncstat = removepseudodims(fetchprojection); |
---|
| 330 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} |
---|
| 331 | |
---|
| 332 | /* Shift the varaprojection for simple walk */ |
---|
| 333 | dcefree((DCEnode*)walkprojection) ; /* reclaim any existing walkprojection */ |
---|
| 334 | walkprojection = (DCEprojection*)dceclone((DCEnode*)varaprojection); |
---|
| 335 | dapshiftprojection(walkprojection); |
---|
| 336 | |
---|
| 337 | #ifdef DEBUG |
---|
| 338 | fprintf(stderr,"getvarx: FETCHPART: fetchprojection: |%s|\n",dumpprojection(fetchprojection)); |
---|
| 339 | #endif |
---|
| 340 | |
---|
| 341 | /* Build the complete constraint to use in the fetch */ |
---|
| 342 | fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT); |
---|
| 343 | /* merged constraint just uses the url constraint selection */ |
---|
| 344 | fetchconstraint->selections = dceclonelist(dapcomm->oc.dapconstraint->selections); |
---|
| 345 | /* and the created fetch projection */ |
---|
| 346 | fetchconstraint->projections = nclistnew(); |
---|
| 347 | nclistpush(fetchconstraint->projections,(ncelem)fetchprojection); |
---|
| 348 | #ifdef DEBUG |
---|
| 349 | fprintf(stderr,"getvarx: FETCHPART: fetchconstraint: %s\n",dumpconstraint(fetchconstraint)); |
---|
| 350 | #endif |
---|
| 351 | /* buildcachenode3 will create a new cachenode and |
---|
| 352 | will also fetch the corresponding datadds. |
---|
| 353 | */ |
---|
| 354 | ncstat = buildcachenode34(dapcomm,fetchconstraint,vars,&cachenode,0); |
---|
| 355 | fetchconstraint = NULL; /*buildcachenode34 takes control of fetchconstraint.*/ |
---|
| 356 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} |
---|
| 357 | } break; |
---|
| 358 | |
---|
| 359 | default: PANIC1("unknown fetch state: %d\n",state); |
---|
| 360 | } |
---|
| 361 | |
---|
| 362 | ASSERT(cachenode != NULL); |
---|
| 363 | |
---|
| 364 | #ifdef DEBUG |
---|
| 365 | fprintf(stderr,"cache.datadds=%s\n",dumptree(cachenode->datadds)); |
---|
| 366 | #endif |
---|
| 367 | |
---|
| 368 | /* attach DATADDS to (constrained) DDS */ |
---|
| 369 | unattach34(dapcomm->cdf.ddsroot); |
---|
| 370 | ncstat = attachsubset34(cachenode->datadds,dapcomm->cdf.ddsroot); |
---|
| 371 | if(ncstat) goto fail; |
---|
| 372 | |
---|
| 373 | /* Fix up varainfo to use the cache */ |
---|
| 374 | varainfo->cache = cachenode; |
---|
| 375 | cachenode = NULL; |
---|
| 376 | varainfo->varaprojection = walkprojection; |
---|
| 377 | walkprojection = NULL; |
---|
| 378 | |
---|
| 379 | /* Get the var correlate from the datadds */ |
---|
| 380 | target = varainfo->target; |
---|
| 381 | xtarget = target->attachment; |
---|
| 382 | if(xtarget == NULL) |
---|
| 383 | {THROWCHK(ncstat=NC_ENODATA); goto fail;} |
---|
| 384 | |
---|
| 385 | /* Switch to datadds tree space*/ |
---|
| 386 | varainfo->target = xtarget; |
---|
| 387 | ncstat = moveto(dapcomm,varainfo,varainfo->cache->datadds,data); |
---|
| 388 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;} |
---|
| 389 | |
---|
| 390 | goto ok; |
---|
| 391 | |
---|
| 392 | fail: |
---|
| 393 | if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat); |
---|
| 394 | ok: |
---|
| 395 | nclistfree(vars); |
---|
| 396 | dcefree((DCEnode*)varaprojection); |
---|
| 397 | dcefree((DCEnode*)fetchconstraint); |
---|
| 398 | freegetvara(varainfo); |
---|
| 399 | return THROW(ncstat); |
---|
| 400 | } |
---|
| 401 | |
---|
| 402 | /* Remove any pseudodimensions (sequence and string)*/ |
---|
| 403 | static NCerror |
---|
| 404 | removepseudodims(DCEprojection* proj) |
---|
| 405 | { |
---|
| 406 | int i; |
---|
| 407 | #ifdef DEBUG1 |
---|
| 408 | fprintf(stderr,"removesequencedims.before: %s\n",dumpprojection(proj)); |
---|
| 409 | #endif |
---|
| 410 | for(i=0;i<nclistlength(proj->var->segments);i++) { |
---|
| 411 | DCEsegment* seg = (DCEsegment*)nclistget(proj->var->segments,i); |
---|
| 412 | CDFnode* cdfnode = (CDFnode*)seg->annotation; |
---|
| 413 | if(cdfnode->array.seqdim != NULL) |
---|
| 414 | seg->rank = 0; |
---|
| 415 | else if(cdfnode->array.stringdim != NULL) |
---|
| 416 | seg->rank--; |
---|
| 417 | } |
---|
| 418 | #ifdef DEBUG1 |
---|
| 419 | fprintf(stderr,"removepseudodims.after: %s\n",dumpprojection(proj)); |
---|
| 420 | #endif |
---|
| 421 | return NC_NOERR; |
---|
| 422 | } |
---|
| 423 | |
---|
| 424 | static NCerror |
---|
| 425 | moveto(NCDAPCOMMON* nccomm, Getvara* xgetvar, CDFnode* xrootnode, void* memory) |
---|
| 426 | { |
---|
| 427 | OCerror ocstat = OC_NOERR; |
---|
| 428 | NCerror ncstat = NC_NOERR; |
---|
| 429 | OCconnection conn = nccomm->oc.conn; |
---|
| 430 | OCdata xrootcontent; |
---|
| 431 | OCobject ocroot; |
---|
| 432 | NClist* path = nclistnew(); |
---|
| 433 | struct NCMEMORY memstate; |
---|
| 434 | |
---|
| 435 | memstate.next = (memstate.memory = memory); |
---|
| 436 | |
---|
| 437 | /* Get the root content*/ |
---|
| 438 | ocroot = xrootnode->tree->ocroot; |
---|
| 439 | xrootcontent = oc_data_new(conn); |
---|
| 440 | ocstat = oc_data_root(conn,ocroot,xrootcontent); |
---|
| 441 | if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} |
---|
| 442 | |
---|
| 443 | /* Remember: xgetvar->target is in DATADDS tree */ |
---|
| 444 | collectnodepath3(xgetvar->target,path,WITHDATASET); |
---|
| 445 | ncstat = movetor(nccomm,xrootcontent, |
---|
| 446 | path,0,xgetvar,0,&memstate, |
---|
| 447 | xgetvar->varaprojection->var->segments); |
---|
| 448 | |
---|
| 449 | done: |
---|
| 450 | nclistfree(path); |
---|
| 451 | oc_data_free(conn,xrootcontent); |
---|
| 452 | if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat); |
---|
| 453 | return THROW(ncstat); |
---|
| 454 | } |
---|
| 455 | |
---|
| 456 | static NCerror |
---|
| 457 | movetor(NCDAPCOMMON* nccomm, |
---|
| 458 | OCdata currentcontent, |
---|
| 459 | NClist* path, |
---|
| 460 | int depth, /* depth is position in segment list*/ |
---|
| 461 | Getvara* xgetvar, |
---|
| 462 | int dimindex, /* dimindex is position in xgetvar->slices*/ |
---|
| 463 | struct NCMEMORY* memory, |
---|
| 464 | NClist* segments) |
---|
| 465 | { |
---|
| 466 | int i; |
---|
| 467 | OCerror ocstat = OC_NOERR; |
---|
| 468 | NCerror ncstat = NC_NOERR; |
---|
| 469 | size_t fieldindex,gridindex,rank; |
---|
| 470 | OCconnection conn = nccomm->oc.conn; |
---|
| 471 | CDFnode* xnode = (CDFnode*)nclistget(path,depth); |
---|
| 472 | OCdata reccontent = OCNULL; |
---|
| 473 | OCdata dimcontent = OCNULL; |
---|
| 474 | OCdata fieldcontent = OCNULL; |
---|
| 475 | Dapodometer* odom = OCNULL; |
---|
| 476 | OCmode currentmode = OCNULLMODE; |
---|
| 477 | CDFnode* xnext; |
---|
| 478 | int hasstringdim = 0; |
---|
| 479 | size_t dimoffset; |
---|
| 480 | DCEsegment* segment; |
---|
| 481 | int newdepth; |
---|
| 482 | int caching = FLAGSET(nccomm->controls,NCF_CACHE); |
---|
| 483 | int unconstrainable = FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE); |
---|
| 484 | |
---|
| 485 | /* Note that we use depth-1 because the path contains the DATASET |
---|
| 486 | but the segment list does not */ |
---|
| 487 | segment = (DCEsegment*)nclistget(segments,depth-1); /*may be NULL*/ |
---|
| 488 | if(xnode->etype == NC_STRING || xnode->etype == NC_URL) hasstringdim = 1; |
---|
| 489 | |
---|
| 490 | ocstat = oc_data_mode(conn,currentcontent,¤tmode); |
---|
| 491 | |
---|
| 492 | #ifdef DEBUG2 |
---|
| 493 | fprintf(stderr,"moveto: nctype=%d currentmode=%d depth=%d dimindex=%d", |
---|
| 494 | xnode->nctype, currentmode, depth,dimindex); |
---|
| 495 | fprintf(stderr," segment=%s hasstringdim=%d\n", |
---|
| 496 | dcetostring((DCEnode*)segment),hasstringdim); |
---|
| 497 | #endif |
---|
| 498 | |
---|
| 499 | /* Switch on the combination of nctype and mode */ |
---|
| 500 | #define CASE(nc1,nc2) (nc1*1024+nc2) |
---|
| 501 | |
---|
| 502 | /* This must be consistent with the oc mode transition function */ |
---|
| 503 | switch (CASE(xnode->nctype,currentmode)) { |
---|
| 504 | |
---|
| 505 | default: |
---|
| 506 | PANIC2("Illegal combination: nctype=%d mode=%d", |
---|
| 507 | (int)xnode->nctype,(int)currentmode); |
---|
| 508 | break; |
---|
| 509 | |
---|
| 510 | case CASE(NC_Sequence,OCFIELDMODE): |
---|
| 511 | case CASE(NC_Dataset,OCFIELDMODE): |
---|
| 512 | case CASE(NC_Grid,OCFIELDMODE): |
---|
| 513 | case CASE(NC_Structure,OCFIELDMODE): |
---|
| 514 | /* currentcontent points to the grid/dataset/structure instance */ |
---|
| 515 | xnext = (CDFnode*)nclistget(path,depth+1); |
---|
| 516 | ASSERT((xnext != NULL)); |
---|
| 517 | fieldindex = findfield(xnode,xnext); |
---|
| 518 | /* If the next node is a virtual node, then |
---|
| 519 | we need to effectively |
---|
| 520 | ignore it and use the appropriate subnode. |
---|
| 521 | If the next node is a structuregrid node, then |
---|
| 522 | use it as is. |
---|
| 523 | */ |
---|
| 524 | if(xnext->virtual) { |
---|
| 525 | CDFnode* xgrid = xnext; |
---|
| 526 | xnext = (CDFnode*)nclistget(path,depth+2); /* real node */ |
---|
| 527 | gridindex = fieldindex; |
---|
| 528 | fieldindex = findfield(xgrid,xnext); |
---|
| 529 | fieldindex += gridindex; |
---|
| 530 | newdepth = depth+2; |
---|
| 531 | } else { |
---|
| 532 | newdepth = depth+1; |
---|
| 533 | } |
---|
| 534 | fieldcontent = oc_data_new(conn); |
---|
| 535 | ocstat = oc_data_ith(conn,currentcontent,fieldindex,fieldcontent); |
---|
| 536 | if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;} |
---|
| 537 | ncstat = movetor(nccomm,fieldcontent, |
---|
| 538 | path,newdepth,xgetvar,dimindex,memory, |
---|
| 539 | segments); |
---|
| 540 | break; |
---|
| 541 | |
---|
| 542 | case CASE(NC_Sequence,OCARRAYMODE): /* will actually always be scalar, but will have |
---|
| 543 | rank == 1 to account for the sequence dim */ |
---|
| 544 | case CASE(NC_Grid,OCARRAYMODE): /* will actually always be scalar */ |
---|
| 545 | case CASE(NC_Structure,OCARRAYMODE): |
---|
| 546 | /* figure out which slices refer to this node: |
---|
| 547 | dimindex upto dimindex+rank; */ |
---|
| 548 | ASSERT((segment != NULL)); |
---|
| 549 | rank = segment->rank; |
---|
| 550 | if(xnode->nctype == NC_Sequence) |
---|
| 551 | rank--; /* ignore the sequence dim */ |
---|
| 552 | if(rank == 0) { |
---|
| 553 | odom = newdapodometer1(1); |
---|
| 554 | } else if(caching || unconstrainable) { |
---|
| 555 | odom = newdapodometer(segment->slices,0,rank); |
---|
| 556 | } else { /*Since vara was projected out, build a simple odometer*/ |
---|
| 557 | odom = newsimpledapodometer(segment,rank); |
---|
| 558 | } |
---|
| 559 | while(dapodometermore(odom)) { |
---|
| 560 | OCmode mode; |
---|
| 561 | /* Compute which instance to move to*/ |
---|
| 562 | dimoffset = dapodometercount(odom); |
---|
| 563 | dimcontent = oc_data_new(conn); |
---|
| 564 | ocstat = oc_data_ith(conn,currentcontent,dimoffset,dimcontent); |
---|
| 565 | if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;} |
---|
| 566 | ocstat = oc_data_mode(conn,dimcontent,&mode); |
---|
| 567 | ASSERT((mode == OCFIELDMODE |
---|
| 568 | || (mode == OCSEQUENCEMODE && xnode->nctype == NC_Sequence))); |
---|
| 569 | ncstat = movetor(nccomm,dimcontent, |
---|
| 570 | path,depth, |
---|
| 571 | xgetvar,dimindex+rank, |
---|
| 572 | memory,segments); |
---|
| 573 | dapodometerincr(odom); |
---|
| 574 | } |
---|
| 575 | freedapodometer(odom); |
---|
| 576 | break; |
---|
| 577 | |
---|
| 578 | case CASE(NC_Sequence,OCSEQUENCEMODE): { |
---|
| 579 | DCEslice* uslice; |
---|
| 580 | ASSERT((segment != NULL)); |
---|
| 581 | /* Get and check the corresponding sequence dimension from DDS */ |
---|
| 582 | ASSERT((xnode->attachment != NULL)); |
---|
| 583 | /* use uslice to walk the sequence; however, watch out |
---|
| 584 | for the case when the user set a limit and that limit |
---|
| 585 | is not actually reached in this request. |
---|
| 586 | */ |
---|
| 587 | /* By construction, this sequence represents the first |
---|
| 588 | (and only) dimension of this segment */ |
---|
| 589 | uslice = &segment->slices[0]; |
---|
| 590 | reccontent = oc_data_new(conn); |
---|
| 591 | for(i=uslice->first;i<uslice->stop;i+=uslice->stride) { |
---|
| 592 | OCmode eos; |
---|
| 593 | ocstat = oc_data_ith(conn,currentcontent,i,reccontent); |
---|
| 594 | if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;} |
---|
| 595 | ocstat = oc_data_mode(conn,reccontent,&eos); |
---|
| 596 | if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;} |
---|
| 597 | if(eos == OCNULLMODE) { |
---|
| 598 | /* We asked for too much */ |
---|
| 599 | ncstat = THROW(NC_EINVALCOORDS); |
---|
| 600 | goto fail; |
---|
| 601 | } |
---|
| 602 | ncstat = movetor(nccomm,reccontent, |
---|
| 603 | path,depth, |
---|
| 604 | xgetvar,dimindex+1, |
---|
| 605 | memory,segments); |
---|
| 606 | if(ncstat != OC_NOERR) {THROWCHK(ncstat); goto fail;} |
---|
| 607 | } |
---|
| 608 | } break; |
---|
| 609 | |
---|
| 610 | case CASE(NC_Primitive,OCPRIMITIVEMODE): |
---|
| 611 | if(hasstringdim) |
---|
| 612 | ncstat = extractstring(nccomm, xgetvar, xnode, segment, conn, currentcontent, memory); |
---|
| 613 | else |
---|
| 614 | ncstat = extract(nccomm, xgetvar, xnode, segment, conn, currentcontent, memory); |
---|
| 615 | break; |
---|
| 616 | |
---|
| 617 | } |
---|
| 618 | goto ok; |
---|
| 619 | |
---|
| 620 | fail: |
---|
| 621 | ok: |
---|
| 622 | oc_data_free(conn,dimcontent); |
---|
| 623 | oc_data_free(conn,fieldcontent); |
---|
| 624 | oc_data_free(conn,reccontent); |
---|
| 625 | if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat); |
---|
| 626 | return THROW(ncstat); |
---|
| 627 | } |
---|
| 628 | |
---|
| 629 | /* Determine the index in the odometer at which |
---|
| 630 | the odometer will be walking the whole subslice |
---|
| 631 | This will allow us to optimize. |
---|
| 632 | */ |
---|
| 633 | static int |
---|
| 634 | wholeslicepoint(Dapodometer* odom) |
---|
| 635 | { |
---|
| 636 | unsigned int i; |
---|
| 637 | int point; |
---|
| 638 | for(point=-1,i=0;i<odom->rank;i++) { |
---|
| 639 | ASSERT((odom->slices[i].declsize != 0)); |
---|
| 640 | if(odom->slices[i].first != 0 || odom->slices[i].stride != 1 |
---|
| 641 | || odom->slices[i].length != odom->slices[i].declsize) |
---|
| 642 | point = i; |
---|
| 643 | } |
---|
| 644 | if(point == -1) |
---|
| 645 | point = 0; /* wholevariable */ |
---|
| 646 | else if(point == (odom->rank - 1)) |
---|
| 647 | point = -1; /* no whole point */ |
---|
| 648 | else |
---|
| 649 | point += 1; /* intermediate point */ |
---|
| 650 | return point; |
---|
| 651 | } |
---|
| 652 | |
---|
| 653 | static int |
---|
| 654 | findfield(CDFnode* node, CDFnode* field) |
---|
| 655 | { |
---|
| 656 | size_t i; |
---|
| 657 | for(i=0;i<nclistlength(node->subnodes);i++) { |
---|
| 658 | CDFnode* test = (CDFnode*) nclistget(node->subnodes,i); |
---|
| 659 | if(test == field) return i; |
---|
| 660 | } |
---|
| 661 | return -1; |
---|
| 662 | } |
---|
| 663 | |
---|
| 664 | |
---|
| 665 | int |
---|
| 666 | nc3d_getvarmx(int ncid, int varid, |
---|
| 667 | const size_t *start, |
---|
| 668 | const size_t *edges, |
---|
| 669 | const ptrdiff_t* stride, |
---|
| 670 | const ptrdiff_t* map, |
---|
| 671 | void* data, |
---|
| 672 | nc_type dsttype0) |
---|
| 673 | { |
---|
| 674 | NCerror ncstat = NC_NOERR; |
---|
| 675 | int i; |
---|
| 676 | NC* drno; |
---|
| 677 | NC* substrate; |
---|
| 678 | NCDAPCOMMON* dapcomm; |
---|
| 679 | NC_var* var; |
---|
| 680 | CDFnode* cdfvar; /* cdf node mapping to var*/ |
---|
| 681 | NClist* varnodes; |
---|
| 682 | nc_type dsttype; |
---|
| 683 | size_t externsize; |
---|
| 684 | size_t dimsizes[NC_MAX_VAR_DIMS]; |
---|
| 685 | Dapodometer* odom = NULL; |
---|
| 686 | unsigned int ncrank; |
---|
| 687 | NClist* ncdims = NULL; |
---|
| 688 | size_t nelems; |
---|
| 689 | #ifdef NEWVARM |
---|
| 690 | char* localcopy; /* of whole variable */ |
---|
| 691 | #endif |
---|
| 692 | |
---|
| 693 | ncstat = NC_check_id(ncid, (NC**)&drno); |
---|
| 694 | if(ncstat != NC_NOERR) goto done; |
---|
| 695 | dapcomm = (NCDAPCOMMON*)drno->dispatchdata; |
---|
| 696 | |
---|
| 697 | ncstat = NC_check_id(drno->substrate, (NC**)&substrate); |
---|
| 698 | if(ncstat != NC_NOERR) goto done; |
---|
| 699 | var = NC_lookupvar(substrate,varid); |
---|
| 700 | if(var == NULL) {ncstat = NC_ENOTVAR; goto done;} |
---|
| 701 | |
---|
| 702 | /* Locate var node via varid */ |
---|
| 703 | varnodes = dapcomm->cdf.varnodes; |
---|
| 704 | for(i=0;i<nclistlength(varnodes);i++) { |
---|
| 705 | CDFnode* node = (CDFnode*)nclistget(varnodes,i); |
---|
| 706 | if(node->array.basevar == NULL |
---|
| 707 | && node->nctype == NC_Primitive |
---|
| 708 | && node->ncid == varid) { |
---|
| 709 | cdfvar = node; |
---|
| 710 | break; |
---|
| 711 | } |
---|
| 712 | } |
---|
| 713 | |
---|
| 714 | ASSERT((cdfvar != NULL)); |
---|
| 715 | ASSERT((strcmp(cdfvar->ncfullname,var->name->cp)==0)); |
---|
| 716 | |
---|
| 717 | if(nclistlength(cdfvar->array.dimsetplus) == 0) { |
---|
| 718 | /* The variable is a scalar; consequently, there is only one |
---|
| 719 | thing to get and only one place to put it. (Why was I |
---|
| 720 | called?) */ |
---|
| 721 | /* recurse with additional parameters */ |
---|
| 722 | return THROW(nc3d_getvarx(ncid,varid, |
---|
| 723 | NULL,NULL,NULL, |
---|
| 724 | data,dsttype0)); |
---|
| 725 | } |
---|
| 726 | |
---|
| 727 | dsttype = (dsttype0); |
---|
| 728 | |
---|
| 729 | /* Default to using the inquiry type for this var*/ |
---|
| 730 | if(dsttype == NC_NAT) dsttype = cdfvar->externaltype; |
---|
| 731 | |
---|
| 732 | /* Validate any implied type conversion*/ |
---|
| 733 | if(cdfvar->etype != dsttype && dsttype == NC_CHAR) { |
---|
| 734 | /* The only disallowed conversion is to/from char and non-byte |
---|
| 735 | numeric types*/ |
---|
| 736 | switch (cdfvar->etype) { |
---|
| 737 | case NC_STRING: case NC_URL: |
---|
| 738 | case NC_CHAR: case NC_BYTE: case NC_UBYTE: |
---|
| 739 | break; |
---|
| 740 | default: |
---|
| 741 | return THROW(NC_ECHAR); |
---|
| 742 | } |
---|
| 743 | } |
---|
| 744 | |
---|
| 745 | externsize = nctypesizeof(dsttype); |
---|
| 746 | |
---|
| 747 | /* Accumulate the dimension sizes and the total # of elements */ |
---|
| 748 | ncdims = cdfvar->array.dimsetall; |
---|
| 749 | ncrank = nclistlength(ncdims); |
---|
| 750 | |
---|
| 751 | nelems = 1; /* also Compute the number of elements being retrieved */ |
---|
| 752 | for(i=0;i<ncrank;i++) { |
---|
| 753 | CDFnode* dim = (CDFnode*)nclistget(ncdims,i); |
---|
| 754 | dimsizes[i] = dim->dim.declsize; |
---|
| 755 | nelems *= edges[i]; |
---|
| 756 | } |
---|
| 757 | |
---|
| 758 | /* Originally, this code repeatedly extracted single values |
---|
| 759 | using get_var1. In an attempt to improve performance, |
---|
| 760 | I have converted to reading the whole variable at once |
---|
| 761 | and walking it locally. |
---|
| 762 | */ |
---|
| 763 | |
---|
| 764 | #ifdef NEWVARM |
---|
| 765 | localcopy = (char*)malloc(nelems*externsize); |
---|
| 766 | |
---|
| 767 | /* We need to use the varieties of get_vars in order to |
---|
| 768 | properly do conversion to the external type |
---|
| 769 | */ |
---|
| 770 | |
---|
| 771 | switch (dsttype) { |
---|
| 772 | |
---|
| 773 | case NC_CHAR: |
---|
| 774 | ncstat = nc_get_vars_text(ncid,varid,start, edges, stride, |
---|
| 775 | (char*)localcopy); |
---|
| 776 | break; |
---|
| 777 | case NC_BYTE: |
---|
| 778 | ncstat = nc_get_vars_schar(ncid,varid,start, edges, stride, |
---|
| 779 | (signed char*)localcopy); |
---|
| 780 | break; |
---|
| 781 | case NC_SHORT: |
---|
| 782 | ncstat = nc_get_vars_short(ncid,varid, start, edges, stride, |
---|
| 783 | (short*)localcopy); |
---|
| 784 | break; |
---|
| 785 | case NC_INT: |
---|
| 786 | ncstat = nc_get_vars_int(ncid,varid,start, edges, stride, |
---|
| 787 | (int*)localcopy); |
---|
| 788 | break; |
---|
| 789 | case NC_FLOAT: |
---|
| 790 | ncstat = nc_get_vars_float(ncid,varid,start, edges, stride, |
---|
| 791 | (float*)localcopy); |
---|
| 792 | break; |
---|
| 793 | case NC_DOUBLE: |
---|
| 794 | ncstat = nc_get_vars_double(ncid,varid, start, edges, stride, |
---|
| 795 | (double*)localcopy); |
---|
| 796 | break; |
---|
| 797 | default: break; |
---|
| 798 | } |
---|
| 799 | |
---|
| 800 | odom = newdapodometer2(start,edges,stride,0,ncrank); |
---|
| 801 | |
---|
| 802 | /* Walk the local copy */ |
---|
| 803 | for(i=0;i<nelems;i++) { |
---|
| 804 | size_t voffset = dapodometervarmcount(odom,map,dimsizes); |
---|
| 805 | void* dataoffset = (void*)(((char*)data) + (externsize*voffset)); |
---|
| 806 | char* localpos = (localcopy + externsize*i); |
---|
| 807 | /* extract the indexset'th value from local copy */ |
---|
| 808 | memcpy(dataoffset,(void*)localpos,externsize); |
---|
| 809 | /* |
---|
| 810 | fprintf(stderr,"new: %lu -> %lu %f\n", |
---|
| 811 | (unsigned long)(i), |
---|
| 812 | (unsigned long)voffset, |
---|
| 813 | *(float*)localpos); |
---|
| 814 | */ |
---|
| 815 | dapodometerincr(odom); |
---|
| 816 | } |
---|
| 817 | #else |
---|
| 818 | odom = newdapodometer2(start,edges,stride,0,ncrank); |
---|
| 819 | while(dapodometermore(odom)) { |
---|
| 820 | size_t* indexset = dapodometerindices(odom); |
---|
| 821 | size_t voffset = dapodometervarmcount(odom,map,dimsizes); |
---|
| 822 | char internalmem[128]; |
---|
| 823 | char externalmem[128]; |
---|
| 824 | void* dataoffset = (void*)(((char*)data) + (externsize*voffset)); |
---|
| 825 | |
---|
| 826 | /* get the indexset'th value using variable's internal type */ |
---|
| 827 | ncstat = nc_get_var1(ncid,varid,indexset,(void*)&internalmem); |
---|
| 828 | if(ncstat != NC_NOERR) goto done; |
---|
| 829 | /* Convert to external type */ |
---|
| 830 | ncstat = dapconvert3(cdfvar->etype,dsttype,externalmem,internalmem); |
---|
| 831 | if(ncstat != NC_NOERR) goto done; |
---|
| 832 | memcpy(dataoffset,(void*)externalmem,externsize); |
---|
| 833 | /* |
---|
| 834 | fprintf(stderr,"old: %lu -> %lu %f\n", |
---|
| 835 | (unsigned long)dapodometercount(odom), |
---|
| 836 | (unsigned long)voffset, |
---|
| 837 | *(float*)externalmem); |
---|
| 838 | */ |
---|
| 839 | dapodometerincr(odom); |
---|
| 840 | } |
---|
| 841 | #endif |
---|
| 842 | |
---|
| 843 | done: |
---|
| 844 | return ncstat; |
---|
| 845 | } |
---|
| 846 | |
---|
| 847 | static int |
---|
| 848 | conversionrequired(nc_type t1, nc_type t2) |
---|
| 849 | { |
---|
| 850 | if(t1 == t2) |
---|
| 851 | return 0; |
---|
| 852 | if(nctypesizeof(t1) != nctypesizeof(t2)) |
---|
| 853 | return 1; |
---|
| 854 | /* Avoid too many cases by making t1 < t2 */ |
---|
| 855 | if(t1 > t2) {int tmp = t1; t1 = t2; t2 = tmp;} |
---|
| 856 | #undef CASE |
---|
| 857 | #define CASE(t1,t2) ((t1)<<5 | (t2)) |
---|
| 858 | switch (CASE(t1,t2)) { |
---|
| 859 | case CASE(NC_BYTE,NC_UBYTE): |
---|
| 860 | case CASE(NC_BYTE,NC_CHAR): |
---|
| 861 | case CASE(NC_CHAR,NC_UBYTE): |
---|
| 862 | case CASE(NC_SHORT,NC_USHORT): |
---|
| 863 | case CASE(NC_INT,NC_UINT): |
---|
| 864 | case CASE(NC_INT64,NC_UINT64): |
---|
| 865 | return 0; |
---|
| 866 | default: break; |
---|
| 867 | } |
---|
| 868 | return 1; |
---|
| 869 | } |
---|
| 870 | |
---|
| 871 | /* We are at a primitive variable or scalar that has no string dimensions. |
---|
| 872 | Extract the data. |
---|
| 873 | (This is way too complicated) |
---|
| 874 | */ |
---|
| 875 | static int |
---|
| 876 | extract( |
---|
| 877 | NCDAPCOMMON* nccomm, |
---|
| 878 | Getvara* xgetvar, |
---|
| 879 | CDFnode* xnode, |
---|
| 880 | DCEsegment* segment, |
---|
| 881 | OClink conn, |
---|
| 882 | OCdata currentcontent, |
---|
| 883 | struct NCMEMORY* memory |
---|
| 884 | ) |
---|
| 885 | { |
---|
| 886 | OCerror ocstat = OC_NOERR; |
---|
| 887 | NCerror ncstat = NC_NOERR; |
---|
| 888 | size_t rank; |
---|
| 889 | Dapodometer* odom = OCNULL; |
---|
| 890 | int wholepoint; |
---|
| 891 | size_t externtypesize; |
---|
| 892 | size_t interntypesize; |
---|
| 893 | char* localmemory = NULL; |
---|
| 894 | size_t odomsubsize; |
---|
| 895 | size_t internlen; |
---|
| 896 | int requireconversion; |
---|
| 897 | char value[16]; |
---|
| 898 | |
---|
| 899 | ASSERT((segment != NULL)); |
---|
| 900 | |
---|
| 901 | requireconversion = conversionrequired(xgetvar->dsttype,xnode->etype); |
---|
| 902 | |
---|
| 903 | rank = segment->rank; |
---|
| 904 | |
---|
| 905 | if(rank == 0) {/* scalar */ |
---|
| 906 | char* mem = (requireconversion?value:memory->next); |
---|
| 907 | ASSERT((segment != NULL)); |
---|
| 908 | externtypesize = nctypesizeof(xgetvar->dsttype); |
---|
| 909 | ASSERT(externtypesize <= sizeof(value)); |
---|
| 910 | /* Read the whole scalar directly into memory */ |
---|
| 911 | ocstat = oc_data_get(conn,currentcontent,mem,externtypesize,0,1); |
---|
| 912 | if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} |
---|
| 913 | if(requireconversion) { |
---|
| 914 | /* convert the value to external type */ |
---|
| 915 | ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1); |
---|
| 916 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} |
---|
| 917 | } |
---|
| 918 | memory->next += (externtypesize); |
---|
| 919 | |
---|
| 920 | } else {/* rank > 0 */ |
---|
| 921 | |
---|
| 922 | #ifdef DEBUG2 |
---|
| 923 | fprintf(stderr,"moveto: primitive: segment=%s", |
---|
| 924 | dcetostring((DCEnode*)segment)); |
---|
| 925 | fprintf(stderr," iswholevariable=%d",xgetvar->cache->wholevariable); |
---|
| 926 | fprintf(stderr,"\n"); |
---|
| 927 | #endif |
---|
| 928 | |
---|
| 929 | ASSERT(xgetvar->cache != NULL); |
---|
| 930 | if(xgetvar->cache->wholevariable) { |
---|
| 931 | odom = newdapodometer(segment->slices,0,rank); |
---|
| 932 | } else { /*!xgetvar->cache->wholevariable*/ |
---|
| 933 | odom = newsimpledapodometer(segment,rank); |
---|
| 934 | } |
---|
| 935 | /* Optimize off the use of the odometer by checking the slicing |
---|
| 936 | to see if the whole variable, or some whole subslice |
---|
| 937 | is being extracted. |
---|
| 938 | However do not do this if the external type conversion is needed |
---|
| 939 | or if the whole slice point is rank-1 (normal case anyway). |
---|
| 940 | */ |
---|
| 941 | externtypesize = nctypesizeof(xgetvar->dsttype); |
---|
| 942 | interntypesize = nctypesizeof(xnode->etype); |
---|
| 943 | wholepoint = wholeslicepoint(odom); |
---|
| 944 | if(wholepoint == -1) |
---|
| 945 | odomsubsize = 1; /* no whole point */ |
---|
| 946 | else |
---|
| 947 | odomsubsize = dapodometerspace(odom,wholepoint); |
---|
| 948 | internlen = (odomsubsize*interntypesize); |
---|
| 949 | if(requireconversion) { |
---|
| 950 | /* copy the data locally before conversion */ |
---|
| 951 | localmemory = (char*)malloc(internlen); |
---|
| 952 | } else { |
---|
| 953 | localmemory = memory->next; |
---|
| 954 | } |
---|
| 955 | |
---|
| 956 | #ifdef DEBUG2 |
---|
| 957 | fprintf(stderr,"moveto: primitive: "); |
---|
| 958 | fprintf(stderr," wholepoint=%d",wholepoint); |
---|
| 959 | fprintf(stderr,"\n"); |
---|
| 960 | #endif |
---|
| 961 | |
---|
| 962 | if(wholepoint == 0) {/* whole variable */ |
---|
| 963 | /* Read the whole n elements directly into memory.*/ |
---|
| 964 | ocstat = oc_data_get(conn,currentcontent,localmemory, |
---|
| 965 | internlen,0,odomsubsize); |
---|
| 966 | if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} |
---|
| 967 | if(requireconversion) { |
---|
| 968 | /* do conversion */ |
---|
| 969 | ncstat = dapconvert3(xnode->etype,xgetvar->dsttype, |
---|
| 970 | memory->next,localmemory,odomsubsize); |
---|
| 971 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} |
---|
| 972 | } |
---|
| 973 | memory->next += (externtypesize*odomsubsize); |
---|
| 974 | } else if(wholepoint > 0) {/* whole subslice */ |
---|
| 975 | odom->rank = wholepoint; /* truncate */ |
---|
| 976 | while(dapodometermore(odom)) { |
---|
| 977 | size_t dimoffset = dapodometercount(odom) * odomsubsize; |
---|
| 978 | ocstat = oc_data_get(conn,currentcontent,localmemory, |
---|
| 979 | internlen,dimoffset,odomsubsize); |
---|
| 980 | if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} |
---|
| 981 | if(requireconversion) { |
---|
| 982 | /* do conversion */ |
---|
| 983 | ncstat = dapconvert3(xnode->etype,xgetvar->dsttype, |
---|
| 984 | memory->next,localmemory,odomsubsize); |
---|
| 985 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} |
---|
| 986 | } |
---|
| 987 | memory->next += (externtypesize*odomsubsize); |
---|
| 988 | dapodometerincr(odom); |
---|
| 989 | } |
---|
| 990 | } else { /* Oh well, use the odometer to walk to the |
---|
| 991 | appropriate fields*/ |
---|
| 992 | while(dapodometermore(odom)) { |
---|
| 993 | char* mem = (requireconversion?value:memory->next); |
---|
| 994 | size_t dimoffset = dapodometercount(odom); |
---|
| 995 | ocstat = oc_data_get(conn,currentcontent,mem,externtypesize,dimoffset,1); |
---|
| 996 | if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} |
---|
| 997 | if(requireconversion) { |
---|
| 998 | ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1); |
---|
| 999 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} |
---|
| 1000 | } |
---|
| 1001 | memory->next += externtypesize; |
---|
| 1002 | dapodometerincr(odom); |
---|
| 1003 | } |
---|
| 1004 | } |
---|
| 1005 | freedapodometer(odom); |
---|
| 1006 | if(requireconversion) nullfree(localmemory); |
---|
| 1007 | } |
---|
| 1008 | done: |
---|
| 1009 | return THROW(ncstat); |
---|
| 1010 | } |
---|
| 1011 | |
---|
| 1012 | |
---|
| 1013 | static NCerror |
---|
| 1014 | slicestring(OCconnection conn, char* stringmem, DCEslice* slice, struct NCMEMORY* memory) |
---|
| 1015 | { |
---|
| 1016 | size_t stringlen; |
---|
| 1017 | unsigned int i; |
---|
| 1018 | NCerror ncstat = NC_NOERR; |
---|
| 1019 | char* lastchar; |
---|
| 1020 | size_t charcount; /* number of characters inserted into memory */ |
---|
| 1021 | |
---|
| 1022 | /* libnc-dap chooses to convert string escapes to the corresponding |
---|
| 1023 | character; so we do likewise. |
---|
| 1024 | */ |
---|
| 1025 | dapexpandescapes(stringmem); |
---|
| 1026 | stringlen = strlen(stringmem); |
---|
| 1027 | |
---|
| 1028 | #ifdef DEBUG2 |
---|
| 1029 | fprintf(stderr,"moveto: slicestring: string/%lu=%s\n",stringlen,stringmem); |
---|
| 1030 | fprintf(stderr,"slicestring: %lu string=|%s|\n",stringlen,stringmem); |
---|
| 1031 | fprintf(stderr,"slicestring: slice=[%lu:%lu:%lu/%lu]\n", |
---|
| 1032 | slice->first,slice->stride,slice->stop,slice->declsize); |
---|
| 1033 | #endif |
---|
| 1034 | |
---|
| 1035 | /* Stride across string; if we go past end of string, then pad*/ |
---|
| 1036 | charcount = 0; |
---|
| 1037 | for(i=slice->first;i<slice->length;i+=slice->stride) { |
---|
| 1038 | if(i < stringlen) |
---|
| 1039 | *memory->next = stringmem[i]; |
---|
| 1040 | else /* i >= stringlen*/ |
---|
| 1041 | *memory->next = NC_FILL_CHAR; |
---|
| 1042 | memory->next++; |
---|
| 1043 | charcount++; |
---|
| 1044 | } |
---|
| 1045 | lastchar = (memory->next); |
---|
| 1046 | if(charcount > 0) { |
---|
| 1047 | lastchar--; |
---|
| 1048 | } |
---|
| 1049 | |
---|
| 1050 | return THROW(ncstat); |
---|
| 1051 | } |
---|
| 1052 | |
---|
| 1053 | /* |
---|
| 1054 | Extract data for a netcdf variable that has a string dimension. |
---|
| 1055 | */ |
---|
| 1056 | static int |
---|
| 1057 | extractstring( |
---|
| 1058 | NCDAPCOMMON* nccomm, |
---|
| 1059 | Getvara* xgetvar, |
---|
| 1060 | CDFnode* xnode, |
---|
| 1061 | DCEsegment* segment, |
---|
| 1062 | OClink conn, |
---|
| 1063 | OCdata currentcontent, |
---|
| 1064 | struct NCMEMORY* memory |
---|
| 1065 | ) |
---|
| 1066 | { |
---|
| 1067 | NCerror ncstat = NC_NOERR; |
---|
| 1068 | OCerror ocstat = OC_NOERR; |
---|
| 1069 | int i; |
---|
| 1070 | size_t rank; |
---|
| 1071 | int caching = FLAGSET(nccomm->controls,NCF_CACHE); |
---|
| 1072 | int unconstrainable = FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE); |
---|
| 1073 | NClist* strings = NULL; |
---|
| 1074 | Dapodometer* odom = OCNULL; |
---|
| 1075 | |
---|
| 1076 | rank = segment->rank; |
---|
| 1077 | |
---|
| 1078 | /* A number of optimizations are possible but none is currently used. */ |
---|
| 1079 | |
---|
| 1080 | /* Use the odometer to walk to the appropriate fields*/ |
---|
| 1081 | if(rank == 1) { |
---|
| 1082 | odom = newdapodometer1(1); /* scalar case */ |
---|
| 1083 | } else if(caching || unconstrainable) { |
---|
| 1084 | odom = newdapodometer(segment->slices,0,rank-1); |
---|
| 1085 | } else { /*Since vara was projected out, build a simple odometer*/ |
---|
| 1086 | odom = newsimpledapodometer(segment,rank-1); |
---|
| 1087 | } |
---|
| 1088 | |
---|
| 1089 | /* step thru the odometer obtaining each string and storing it in an OClist */ |
---|
| 1090 | strings = nclistnew(); |
---|
| 1091 | nclistsetalloc(strings,dapodometerspace(odom,0)); /* preallocate */ |
---|
| 1092 | while(dapodometermore(odom)) { |
---|
| 1093 | char* value = NULL; |
---|
| 1094 | size_t dimoffset = dapodometercount(odom); |
---|
| 1095 | ocstat = oc_data_get(conn,currentcontent,&value,sizeof(value),dimoffset,1); |
---|
| 1096 | if(ocstat != OC_NOERR) goto done; |
---|
| 1097 | nclistpush(strings,(ncelem)value); |
---|
| 1098 | dapodometerincr(odom); |
---|
| 1099 | } |
---|
| 1100 | freedapodometer(odom); |
---|
| 1101 | /* Get each string in turn, slice it and store in user |
---|
| 1102 | supplied memory */ |
---|
| 1103 | for(i=0;i<nclistlength(strings);i++) { |
---|
| 1104 | char* s = (char*)nclistget(strings,i); |
---|
| 1105 | slicestring(conn,s,&segment->slices[rank-1],memory); |
---|
| 1106 | free(s); |
---|
| 1107 | } |
---|
| 1108 | nclistfree(strings); |
---|
| 1109 | done: |
---|
| 1110 | if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat); |
---|
| 1111 | return THROW(ncstat); |
---|
| 1112 | } |
---|