source: XIOS/trunk/extern/src_netcdf4/ocnode.c @ 409

Last change on this file since 409 was 409, checked in by ymipsl, 11 years ago

Add improved nectdf internal library src

YM

  • Property svn:eol-style set to native
File size: 21.7 KB
Line 
1/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
2   See the COPYRIGHT file for more information. */
3
4#include "config.h"
5#include "ocinternal.h"
6#include "ocdebug.h"
7
8static const unsigned int MAX_UINT = 0xffffffff;
9
10static OCerror occomputeskipdatar(OCstate*, OCnode*, ocoffset_t offset);
11static int mergedas1(OCnode* dds, OCnode* das);
12static int converttype(OCtype etype, char* value, char* memory);
13static char* pathtostring(OClist* path, char* separator, int usecdfname);
14static void computefullname(OCnode* node);
15
16/* Process ocnodes to fix various semantic issues*/
17void
18occomputesemantics(OClist* ocnodes)
19{
20    unsigned int i;
21    OCASSERT((ocnodes != NULL));
22    for(i=0;i<oclistlength(ocnodes);i++) {
23        OCnode* node = (OCnode*)oclistget(ocnodes,i);
24        /* set the container for dims*/
25        if(node->octype == OC_Dimension && node->dim.array != NULL) {
26            node->container = node->dim.array->container;
27        }
28    }
29}
30
31void
32occomputefullnames(OCnode* root)
33{
34    unsigned int i;
35    if(root->name != NULL) computefullname(root);
36    if(root->subnodes != NULL) { /* recurse*/
37        for(i=0;i<oclistlength(root->subnodes);i++) {
38            OCnode* node = (OCnode*)oclistget(root->subnodes,i);
39            occomputefullnames(node);
40        }
41    }
42}
43
44static void
45computefullname(OCnode* node)
46{
47    char* tmp;
48    char* fullname;
49    OClist* path;
50
51    OCASSERT((node->name != NULL));
52    path = oclistnew();
53    occollectpathtonode(node,path);
54    tmp = pathtostring(path,PATHSEPARATOR,1);
55    if(tmp == NULL) {
56        fullname = nulldup(node->name);
57    } else {
58        fullname = tmp;
59    }
60    node->fullname = fullname;
61    oclistfree(path);
62}
63
64/* Convert path to a string; leave off the dataset name*/
65static char*
66pathtostring(OClist* path, char* separator, int usecdfname)
67{
68    int slen,i,len;
69    char* pathname;
70    if(path == NULL || (len = oclistlength(path))==0) return NULL;
71    for(slen=0,i=0;i<len;i++) {
72        OCnode* node = (OCnode*)oclistget(path,i);
73        if(node->container == NULL || node->name == NULL) continue;
74        slen += strlen(node->name);
75    }
76    slen += ((len-1)*strlen(separator));
77    slen += 1;   /* for null terminator*/
78    pathname = (char*)ocmalloc(slen);
79    MEMCHECK(pathname,NULL);
80    pathname[0] = '\0';
81    for(i=0;i<len;i++) {
82        OCnode* node = (OCnode*)oclistget(path,i);
83        if(node->container == NULL || node->name == NULL) continue;
84        if(strlen(pathname) > 0) strcat(pathname,separator);
85        strcat(pathname,node->name);
86    }
87    return pathname;
88}
89
90/* Collect the set of nodes ending in "node"*/
91void
92occollectpathtonode(OCnode* node, OClist* path)
93{
94    if(node == NULL) return;
95    occollectpathtonode(node->container,path);
96    oclistpush(path,(ocelem)node);
97}
98
99OCnode*
100ocmakenode(char* name, OCtype ptype, OCnode* root)
101{
102    OCnode* cdf = (OCnode*)ocmalloc(sizeof(OCnode));
103    MEMCHECK(cdf,(OCnode*)NULL);
104    memset((void*)cdf,0,sizeof(OCnode));
105    cdf->magic = OCMAGIC;
106    cdf->name = (name?nulldup(name):NULL);
107    cdf->octype = ptype;
108    cdf->array.dimensions = NULL;
109    cdf->root = root;
110    return cdf;
111}
112
113OCattribute*
114makeattribute(char* name, OCtype ptype, OClist* values)
115{
116    OCattribute* att = (OCattribute*)ocmalloc(sizeof(OCattribute)); /* ocmalloc zeros*/
117    MEMCHECK(att,(OCattribute*)NULL);
118    att->name = nulldup(name);
119    att->etype = ptype;
120    att->nvalues = oclistlength(values);
121    att->values = NULL;
122    if(att->nvalues > 0) {
123        int i;
124        att->values = (char**)ocmalloc(sizeof(char*)*att->nvalues);
125        for(i=0;i<att->nvalues;i++)
126            att->values[i] = nulldup((char*)oclistget(values,i));
127    }
128    return att;
129}
130
131static void
132marklostattribute(OCnode* att)
133{
134    oc_log(LOGWARN,"Lost attribute: %s",att->name);
135}
136
137void*
138oclinearize(OCtype etype, unsigned int nstrings, char** strings)
139{
140    int i;
141    size_t typesize;
142    char* memp;
143    char* memory;
144
145    if(nstrings == 0) return NULL;
146    typesize = octypesize(etype);
147    memory = (char*)ocmalloc(nstrings*typesize);
148    MEMCHECK(memory,NULL);
149    memp = memory;
150    for(i=0;i<nstrings;i++) {
151        char* value = strings[i];
152        converttype(etype,value,memp);
153        memp += typesize;
154    }
155    return memory;
156}
157
158static int
159converttype(OCtype etype, char* value, char* memory)
160{
161    long iv;
162    unsigned long uiv;
163    double dv;
164    char c[1];
165    int outofrange = 0;
166#ifdef HAVE_LONG_LONG_INT
167    long long llv;
168    unsigned long long ullv;
169#endif
170
171    switch (etype) {
172    case OC_Char:
173        if(sscanf(value,"%c",c) != 1) goto fail;
174        *((char*)memory) = c[0];
175        break;
176    case OC_Byte:
177        if(sscanf(value,"%ld",&iv) != 1) goto fail;
178        else if(iv > OC_BYTE_MAX || iv < OC_BYTE_MIN) {iv = OC_BYTE_MAX; outofrange = 1;}
179        *((signed char*)memory) = (signed char)iv;
180        break;
181    case OC_UByte:
182        if(sscanf(value,"%lu",&uiv) != 1) goto fail;
183        else if(uiv > OC_UBYTE_MAX) {uiv = OC_UBYTE_MAX; outofrange = 1;}
184        *((unsigned char*)memory) = (unsigned char)uiv;
185        break;
186    case OC_Int16:
187        if(sscanf(value,"%ld",&iv) != 1) goto fail;
188        else if(iv > OC_INT16_MAX || iv < OC_INT16_MIN) {iv = OC_INT16_MAX; outofrange = 1;}
189        *((signed short*)memory) = (signed short)iv;
190        break;
191    case OC_UInt16:
192        if(sscanf(value,"%lu",&uiv) != 1) goto fail;
193        else if(uiv > OC_UINT16_MAX) {uiv = OC_UINT16_MAX; outofrange = 1;}
194        *((unsigned short*)memory) = (unsigned short)uiv;
195        break;
196    case OC_Int32:
197        if(sscanf(value,"%ld",&iv) != 1) goto fail;
198        else if(iv > OC_INT32_MAX || iv < OC_INT32_MIN) {iv = OC_INT32_MAX; outofrange = 1;}
199        *((signed int*)memory) = (signed int)iv;
200        break;
201    case OC_UInt32:
202        if(sscanf(value,"%lu",&uiv) != 1) goto fail;
203        else if(uiv > OC_UINT32_MAX) {uiv = OC_UINT32_MAX; outofrange = 1;}
204        *((unsigned char*)memory) = (unsigned int)uiv;
205        break;
206#ifdef HAVE_LONG_LONG_INT
207    case OC_Int64:
208        if(sscanf(value,"%lld",&llv) != 1) goto fail;
209        /*else if(iv > OC_INT64_MAX || iv < OC_INT64_MIN) goto fail;*/
210        *((signed long long*)memory) = (signed long long)llv;
211        break;
212    case OC_UInt64:
213        if(sscanf(value,"%llu",&ullv) != 1) goto fail;
214        *((unsigned long long*)memory) = (unsigned long long)ullv;
215        break;
216#endif
217    case OC_Float32:
218        if(sscanf(value,"%lf",&dv) != 1) goto fail;
219        *((float*)memory) = (float)dv;
220        break;
221    case OC_Float64:
222        if(sscanf(value,"%lf",&dv) != 1) goto fail;
223        *((double*)memory) = (double)dv;
224        break;
225    case OC_String: case OC_URL:
226        *((char**)memory) = nulldup(value);
227        break;
228    default:
229        goto fail;
230    }
231    if(outofrange)
232        oc_log(LOGWARN,"converttype range failure: %d: %s",etype,value);
233    return 1;
234fail:
235    oc_log(LOGERR,"converttype bad value: %d: %s",etype,value);
236    return 0;
237}
238
239
240void
241ocfreeroot(OCnode* root)
242{
243    OCtree* tree;
244    OCstate* state;
245    int i;
246
247    if(root == NULL || root->tree == NULL) return;
248
249    tree = root->tree;
250    /* Remove the root from the state->trees list */
251    state = tree->state;
252    for(i=0;i<oclistlength(state->trees);i++) {
253        OCnode* node = (OCnode*)oclistget(state->trees,i);
254        if(root == node)
255            oclistremove(state->trees,i);
256    }
257    /* Note: it is ok if state->trees does not contain this root */   
258    ocfreetree(tree);
259}
260
261void
262ocfreetree(OCtree* tree)
263{
264    if(tree == NULL) return;
265    ocfreenodes(tree->nodes);
266    ocfree(tree->constraint);
267    ocfree(tree->text);
268    if(tree->data.xdrs != NULL) {
269        xxdr_free(tree->data.xdrs);
270    }
271    ocfree(tree->data.filename); /* may be null */
272    if(tree->data.file != NULL) fclose(tree->data.file);
273    ocfree(tree->data.memory);
274    ocfree(tree);
275}
276
277void
278ocfreenodes(OClist* nodes)
279{
280    unsigned int i,j;
281    for(i=0;i<oclistlength(nodes);i++) {
282        OCnode* node = (OCnode*)oclistget(nodes,i);
283        ocfree(node->name);
284        ocfree(node->fullname);
285        while(oclistlength(node->att.values) > 0) {
286            char* value = (char*)oclistpop(node->att.values);
287            ocfree(value);
288        }
289        while(oclistlength(node->attributes) > 0) {
290            OCattribute* attr = (OCattribute*)oclistpop(node->attributes);
291            ocfree(attr->name);
292            /* If the attribute type is string, then we need to free them*/
293            if(attr->etype == OC_String || attr->etype == OC_URL) {
294                char** strings = (char**)attr->values;
295                for(j=0;j<attr->nvalues;j++) {ocfree(*strings); strings++;}
296            }
297            ocfree(attr->values);
298            ocfree(attr);
299        }
300        if(node->array.dimensions != NULL) oclistfree(node->array.dimensions);
301        if(node->subnodes != NULL) oclistfree(node->subnodes);
302        if(node->att.values != NULL) oclistfree(node->att.values);
303        if(node->attributes != NULL) oclistfree(node->attributes);
304        ocfree(node);
305    }
306    oclistfree(nodes);
307}
308
309/*
310In order to be as compatible as possible with libdap,
311we try to use the same algorithm for DAS->DDS matching.
312As described there, the algorithm is as follows.
313    If the [attribute] name contains one or
314    more field separators then look for a [DDS]variable whose
315    name matches exactly. If the name contains no field separators then
316    the look first in the top level [of the DDS] and then in all subsequent
317    levels and return the first occurrence found. In general, this
318    searches constructor types in the order in which they appear
319    in the DDS, but there is no requirement that it do so.
320
321    Note: If a dataset contains two constructor types which have field names
322    that are the same (say point.x and pair.x) one should use fully qualified
323    names to get each of those variables.
324*/
325
326int
327ocddsdasmerge(OCstate* state, OCnode* dasroot, OCnode* ddsroot)
328{
329    OClist* dasglobals = oclistnew();
330    OClist* dasnodes = oclistnew();
331    OClist* varnodes = oclistnew();
332    OClist* ddsnodes;
333    unsigned int i,j;
334
335    if(dasroot->tree == NULL || dasroot->tree->dxdclass != OCDAS)
336        return OCTHROW(OC_EINVAL);
337    if(ddsroot->tree == NULL || (ddsroot->tree->dxdclass != OCDDS
338        && ddsroot->tree->dxdclass != OCDATADDS))
339        return OCTHROW(OC_EINVAL);
340
341    ddsnodes = ddsroot->tree->nodes;
342
343    /* 1. collect all the relevant DAS nodes;
344          namely those that contain at least one
345          attribute value.
346          Simultaneously look for potential ambiguities
347          if found; complain but continue: result are indeterminate.
348          also collect globals separately*/
349    for(i=0;i<oclistlength(dasroot->tree->nodes);i++) {
350        OCnode* das = (OCnode*)oclistget(dasroot->tree->nodes,i);
351        int hasattributes = 0;
352        if(das->octype == OC_Attribute) continue; /* ignore these for now*/
353        if(das->name == NULL || das->att.isglobal) {
354            oclistpush(dasglobals,(ocelem)das);
355            continue;
356        }
357        for(j=0;j<oclistlength(das->subnodes);j++) {
358            OCnode* subnode = (OCnode*)oclistget(das->subnodes,j);
359            if(subnode->octype == OC_Attribute) {hasattributes = 1; break;}
360        }
361        if(hasattributes) {
362            /* Look for previously collected nodes with same name*/
363            for(j=0;j<oclistlength(dasnodes);j++) {
364                OCnode* das2 = (OCnode*)oclistget(dasnodes,j);
365                if(das->name == NULL || das2->name == NULL) continue;
366                if(strcmp(das->name,das2->name)==0) {
367                    oc_log(LOGWARN,"oc_mergedas: potentially ambiguous DAS name: %s",das->name);
368                }
369            }
370            oclistpush(dasnodes,(ocelem)das);
371        }
372    }
373
374    /* 2. collect all the leaf DDS nodes (of type OC_Primitive)*/
375    for(i=0;i<oclistlength(ddsnodes);i++) {
376        OCnode* dds = (OCnode*)oclistget(ddsnodes,i);
377        if(dds->octype == OC_Primitive) oclistpush(varnodes,(ocelem)dds);
378    }
379
380    /* 3. For each das node, locate matching DDS node(s) and attach
381          attributes to the DDS node(s).
382          Match means:
383          1. DAS->fullname :: DDS->fullname
384          2. DAS->name :: DDS->fullname (support DAS names with embedded '.'
385          3. DAS->name :: DDS->name
386    */
387    for(i=0;i<oclistlength(dasnodes);i++) {
388        OCnode* das = (OCnode*)oclistget(dasnodes,i);
389        for(j=0;j<oclistlength(varnodes);j++) {
390            OCnode* dds = (OCnode*)oclistget(varnodes,j);
391            if(strcmp(das->fullname,dds->fullname)==0
392               || strcmp(das->name,dds->fullname)==0
393               || strcmp(das->name,dds->name)==0) {
394                mergedas1(dds,das);
395                /* remove from dasnodes list*/
396                oclistset(dasnodes,i,(ocelem)NULL);
397            }
398        }
399    }
400
401    /* 4. If there are attributes left, then complain about them being lost.*/
402    for(i=0;i<oclistlength(dasnodes);i++) {
403        OCnode* das = (OCnode*)oclistget(dasnodes,i);
404        if(das != NULL) marklostattribute(das);
405    }
406
407    /* 5. Assign globals*/
408    for(i=0;i<oclistlength(dasglobals);i++) {
409        OCnode* das = (OCnode*)oclistget(dasglobals,i);
410        mergedas1(ddsroot,das);
411    }
412    /* cleanup*/
413    oclistfree(dasglobals);
414    oclistfree(dasnodes);
415    oclistfree(varnodes);
416    return OCTHROW(OC_NOERR);
417}
418
419static int
420mergedas1(OCnode* dds, OCnode* das)
421{
422    unsigned int i;
423    int stat = OC_NOERR;
424    if(das == NULL) return OC_NOERR; /* nothing to do */
425    if(dds->attributes == NULL) dds->attributes = oclistnew();
426    /* assign the simple attributes in the das set to this dds node*/
427    for(i=0;i<oclistlength(das->subnodes);i++) {
428        OCnode* attnode = (OCnode*)oclistget(das->subnodes,i);
429        if(attnode->octype == OC_Attribute) {
430            OCattribute* att = makeattribute(attnode->name,
431                                                attnode->etype,
432                                                attnode->att.values);
433            oclistpush(dds->attributes,(ocelem)att);
434        }
435    }
436    return OCTHROW(stat);
437}
438
439
440
441#ifdef OCIGNORE
442
443int
444ocddsdasmerge(OCstate* state, OCnode* ddsroot, OCnode* dasroot)
445{
446    int i,j;
447    int stat = OC_NOERR;
448    OClist* globals = oclistnew();
449    if(dasroot == NULL) return OCTHROW(stat);
450    /* Start by looking for global attributes*/
451    for(i=0;i<oclistlength(dasroot->subnodes);i++) {
452        OCnode* node = (OCnode*)oclistget(dasroot->subnodes,i);
453        if(node->att.isglobal) {
454            for(j=0;j<oclistlength(node->subnodes);j++) {
455                OCnode* attnode = (OCnode*)oclistget(node->subnodes,j);
456                Attribute* att = makeattribute(attnode->name,
457                                                attnode->etype,
458                                                attnode->att.values);
459                oclistpush(globals,(ocelem)att);
460            }
461        }
462    }
463    ddsroot->attributes = globals;
464    /* Now try to match subnode names with attribute set names*/
465    for(i=0;i<oclistlength(dasroot->subnodes);i++) {
466        OCnode* das = (OCnode*)oclistget(dasroot->subnodes,i);
467        int match = 0;
468        if(das->att.isglobal) continue;
469        if(das->octype == OC_Attributeset) {
470            for(j=0;j<oclistlength(ddsroot->subnodes) && !match;j++) {
471                OCnode* dds = (OCnode*)oclistget(ddsroot->subnodes,j);
472                if(strcmp(das->name,dds->name) == 0) {
473                    match = 1;
474                    stat = mergedas1(dds,das);
475                    if(stat != OC_NOERR) break;
476                }
477            }
478        }
479        if(!match) {marklostattribute(das);}
480    }
481    if(stat == OC_NOERR) ddsroot->attributed = 1;
482    return OCTHROW(stat);
483}
484
485/* Merge das attributes into the dds node*/
486
487static int
488mergedas1(OCnode* dds, OCnode* das)
489{
490    int i,j;
491    int stat = OC_NOERR;
492    if(dds->attributes == NULL) dds->attributes = oclistnew();
493    /* assign the simple attributes in the das set to this dds node*/
494    for(i=0;i<oclistlength(das->subnodes);i++) {
495        OCnode* attnode = (OCnode*)oclistget(das->subnodes,i);
496        if(attnode->octype == OC_Attribute) {
497            Attribute* att = makeattribute(attnode->name,
498                                                attnode->etype,
499                                                attnode->att.values);
500            oclistpush(dds->attributes,(ocelem)att);
501        }
502    }
503    /* Try to merge any enclosed sets with subnodes of dds*/
504    for(i=0;i<oclistlength(das->subnodes);i++) {
505        OCnode* dasnode = (OCnode*)oclistget(das->subnodes,i);
506        int match = 0;
507        if(dasnode->octype == OC_Attribute) continue; /* already dealt with above*/
508        for(j=0;j<oclistlength(dds->subnodes) && !match;j++) {
509            OCnode* ddsnode = (OCnode*)oclistget(dds->subnodes,j);
510            if(strcmp(dasnode->name,ddsnode->name) == 0) {
511                match = 1;
512                stat = mergedas1(ddsnode,dasnode);
513                if(stat != OC_NOERR) break;
514            }
515        }
516        if(!match) {marklostattribute(dasnode);}
517    }
518    return OCTHROW(stat);
519}
520#endif
521
522static void
523ocuncorrelate(OCnode* root)
524{
525    OCtree* tree = root->tree;
526    unsigned int i;
527    if(tree == NULL) return;
528    for(i=0;i<oclistlength(tree->nodes);i++) {
529        OCnode* node = (OCnode*)oclistget(tree->nodes,i);
530        node->datadds = NULL;
531    }       
532}
533
534static OCerror
535occorrelater(OCnode* dds, OCnode* dxd)
536{
537    int i,j;
538    OCerror ocstat = OC_NOERR;
539
540    if(dds->octype != dxd->octype) {
541        OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
542    }
543    if(dxd->name != NULL && dxd->name != NULL
544       && strcmp(dxd->name,dds->name) != 0) {
545        OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
546    } else if(dxd->name != dxd->name) { /* test NULL==NULL */
547        OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
548    }
549
550    if(dxd->array.rank != dds->array.rank) {
551        OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
552    }
553
554    dds->datadds = dxd;
555
556    switch (dds->octype) {
557    case OC_Dataset:
558    case OC_Structure:
559    case OC_Grid:
560    case OC_Sequence:
561        /* Remember: there may be fewer datadds fields than dds fields */
562        for(i=0;i<oclistlength(dxd->subnodes);i++) {
563            OCnode* dxd1 = (OCnode*)oclistget(dxd->subnodes,i);
564            for(j=0;j<oclistlength(dds->subnodes);j++) {
565                OCnode* dds1 = (OCnode*)oclistget(dds->subnodes,j);
566                if(strcmp(dxd1->name,dds1->name) == 0) {
567                    ocstat = occorrelater(dds1,dxd1);
568                    if(ocstat != OC_NOERR) {OCTHROWCHK(ocstat); goto fail;}
569                    break;
570                }
571            }
572        }
573        break;
574    case OC_Dimension:
575    case OC_Primitive:
576        break;
577    default: OCPANIC1("unexpected node type: %d",dds->octype);
578    }
579    /* Correlate the dimensions */
580    if(dds->array.rank > 0) {
581        for(i=0;i<oclistlength(dxd->subnodes);i++) {
582            OCnode* ddsdim = (OCnode*)oclistget(dds->array.dimensions,i);
583            OCnode* dxddim = (OCnode*)oclistget(dxd->array.dimensions,i);
584            ocstat = occorrelater(ddsdim,dxddim);
585            if(!ocstat) goto fail;         
586        }       
587    }
588
589fail:
590    return OCTHROW(ocstat);
591
592}
593
594OCerror
595occorrelate(OCnode* dds, OCnode* dxd)
596{
597    if(dds == NULL || dxd == NULL) return OC_EINVAL;
598    ocuncorrelate(dds);
599    return occorrelater(dds,dxd);
600}
601
602/*
603Mark cacheable those primitive String/URL typed nodes
604that are contained only in structures with rank > 0.
605*/
606void
607ocmarkcacheable(OCstate* state, OCnode* ddsroot)
608{
609    int i,j;
610#ifdef OCIGNORE
611    int ok;
612#endif
613    OClist* treenodes = ddsroot->tree->nodes;
614    OClist* path = oclistnew();
615    for(i=0;i<oclistlength(treenodes);i++) {
616        OCnode* node = (OCnode*)oclistget(treenodes,i);
617        if(node->octype != OC_Primitive) continue;
618        if(node->etype != OC_String && node->etype != OC_URL) continue;
619        /* collect node path */
620        oclistclear(path);
621        occollectpathtonode(node,path); 
622#ifdef OCIGNORE
623        ok = 1;
624#endif
625        for(j=1;j<oclistlength(path)-1;j++) {/* skip top level dataset and node itself*/
626            OCnode* pathnode = (OCnode*)oclistget(path,j);
627            if(pathnode->octype != OC_Structure
628                || pathnode->array.rank > 0) {
629#ifdef OCIGNORE
630            ok=0;
631#endif
632            break;
633            }
634        }       
635#ifdef OCIGNORE
636        if(ok) {
637            node->cache.cacheable = 1;
638            node->cache.valid = 0;
639        }
640#endif
641    }
642    oclistfree(path);
643}
644
645
646/*
647Fill in the OCnode.skip fields
648*/
649OCerror
650occomputeskipdata(OCstate* state, OCnode* ddsroot)
651{
652    OCerror stat = OC_NOERR;
653    OCASSERT(ddsroot->octype == OC_Dataset);
654    stat = occomputeskipdatar(state,ddsroot,0);   
655    return stat;
656}
657
658/* Recursive helper for computeskipdata */
659static OCerror
660occomputeskipdatar(OCstate* state, OCnode* xnode, ocoffset_t offset)
661{
662    OCerror stat = OC_NOERR;
663    int i,nfields;
664    int scalar = 0;
665    ocoffset_t instancesize = 0;
666    ocoffset_t totalsize = 0;
667
668    scalar = (xnode->array.rank == 0 ? 1 : 0);
669
670    /* Set skip count and offset*/
671    if(xnode->octype == OC_Sequence)
672        xnode->skip.count = OCINDETERMINATE;
673    else
674        xnode->skip.count = totaldimsize(xnode);
675
676    xnode->skip.offset = offset; /* possibly overridden below */
677
678    switch (xnode->octype) {
679
680    case OC_Primitive:
681        switch(xnode->etype) {
682        case OC_String: case OC_URL:
683            instancesize = OCINDETERMINATE;
684            totalsize = OCINDETERMINATE;
685            break;
686        case OC_Char: case OC_Byte: case OC_UByte:
687            if(!scalar) {/*=>packed*/
688                instancesize = octypesize(xnode->etype);
689                totalsize = instancesize * xnode->skip.count;
690                totalsize = RNDUP(totalsize);
691                totalsize += 2*XDRUNIT; /* overhead is double count */
692                break;
693            }
694            /* !packed => singleton char object */
695            /* fall thru */
696        case OC_Int16: case OC_UInt16:
697        case OC_Int32: case OC_UInt32:
698        case OC_Int64:  case OC_UInt64:
699        case OC_Float32: case OC_Float64:
700            instancesize = octypesize(xnode->etype);
701            instancesize = RNDUP(instancesize); /* make multiple of XDRUNIT */
702            totalsize = (instancesize*xnode->skip.count); /* overhead is double count */
703            if(!scalar)
704                totalsize += 2*XDRUNIT; /* overhead is double count */
705            break;
706
707        default:
708            OCPANIC("unexpected etype"); /* better not happen */
709        }
710        break;
711
712    case OC_Sequence:
713        offset = (xnode->skip.offset = OCINDETERMINATE); /* do not know field offsets for arbitrary record */
714    case OC_Dataset:
715    case OC_Grid:   
716    case OC_Structure:
717        /* Compute size of each field and sum */
718        nfields = oclistlength(xnode->subnodes);
719        instancesize = 0; /* of structure as a whole */
720        for(i=0;i<nfields;i++) {
721            OCnode* subnode = (OCnode*)oclistget(xnode->subnodes,i);
722            ocoffset_t fieldsize;
723            if(offset == OCINDETERMINATE || instancesize == OCINDETERMINATE)
724                stat = occomputeskipdatar(state,subnode,OCINDETERMINATE);
725            else 
726                stat = occomputeskipdatar(state,subnode,offset+instancesize);
727            if(stat != OC_NOERR) goto done;
728            fieldsize = subnode->skip.totalsize;
729            if(instancesize == OCINDETERMINATE || fieldsize == OCINDETERMINATE)
730                instancesize = OCINDETERMINATE;
731            else
732                instancesize += fieldsize; 
733        }
734        if(instancesize != OCINDETERMINATE) {
735            instancesize = RNDUP(instancesize); /* make multiple of XDRUNIT */
736            totalsize = (instancesize*xnode->skip.count); /* overhead is single count */
737            if(!scalar)
738                totalsize += XDRUNIT; /* overhead is single count */
739        } else {
740            totalsize = OCINDETERMINATE; 
741        }
742        if(xnode->octype == OC_Sequence) {
743            totalsize = OCINDETERMINATE;
744            offset = OCINDETERMINATE;
745        }
746        break;
747
748    default: OCPANIC("unexpected octype"); /* better not happen */
749    }
750
751    xnode->skip.offset = offset;
752    xnode->skip.instancesize = instancesize;
753    xnode->skip.totalsize = totalsize;
754
755done:
756    return stat;
757}
Note: See TracBrowser for help on using the repository browser.