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 | } |
---|