source: XIOS/dev/dev_olga/extern/src_netcdf4/occontent.c @ 1620

Last change on this file since 1620 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: 32.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 "occontent.h"
7#include "ocdebug.h"
8
9/* Mnemonic*/
10#define ISPACKED 1
11
12/* Define the skipstate flags */
13#ifdef OCDEBUG
14typedef enum Skipstate {
15SKIPFIELDS = 1, /* skip instance without leading tag or arraycount */
16SKIPINSTANCE = 2, /*skip leading sequence tag or array counts */
17SKIPWHOLE = 4 /* skip complete object */
18} Skipstate;
19#else
20#define SKIPFIELDS      1 /* skip instance without leading tag or arraycount */
21#define SKIPINSTANCE    2 /*skip leading sequence tag or array counts */
22#define SKIPWHOLE       4 /* skip complete object */
23#endif
24
25/* Forward*/
26static OCmode modetransition(OCnode*,OCmode);
27static int ocgetsequencetag(XXDR* xdrs);
28static int ocskipcounts(XXDR* xdrs, OCnode*, off_t expected);
29
30static int ocarrayith(OCstate*, OCcontent*, OCcontent*, size_t);
31static int ocsequenceith(OCstate*, OCcontent*, OCcontent*, size_t);
32static int ocfieldith(OCstate*, OCcontent*, OCcontent*, size_t);
33
34static size_t ocarraycount(OCstate*, struct OCcontent*);
35static size_t ocsequencecount(OCstate*, struct OCcontent*);
36static size_t ocfieldcount(OCstate*, struct OCcontent*);
37static size_t ocprimcount(OCstate*, struct OCcontent*);
38
39static OCcontent* occlearcontent(struct OCstate* state, OCcontent* content);
40
41
42#ifdef OCDEBUG
43static void
44report(size_t memsize, char* memory)
45{
46#ifdef OCIGNORE
47    switch(memsize) {
48    case 1:
49        oc_log(LOGNOTE,"reading xdr: %lu bytes = |%2x|",(unsigned long)memsize,memory[0]);
50        break;
51    case 4:
52        oc_log(LOGNOTE,"reading xdr: %lu bytes = |%4lu|",(unsigned long)memsize,*(unsigned int*)memory);
53        break;
54    case 8:
55        oc_log(LOGNOTE,"reading xdr: %lu bytes = |%8lu|",(unsigned long)memsize,*(unsigned long long*)memory);
56        break;
57    default:
58        oc_log(LOGNOTE,"reading xdr: %lu bytes",(unsigned long)memsize);
59        break;
60    }   
61    oc_log(LOGNOTE,"reading xdr: %lu bytes",(unsigned long)memsize);
62#endif
63}
64
65static char*
66modestring(OCmode mode)
67{
68    switch(mode) {
69    case OCFIELDMODE: return "FIELD";
70    case OCSEQUENCEMODE: return "SEQUENCE";
71    case OCARRAYMODE: return "ARRAY";
72    case OCPRIMITIVEMODE: return "PRIMITIVE";
73    case OCNULLMODE: return "NULL";
74    case OCEMPTYMODE: return "EMPTY";
75    }
76    return "?";
77}
78
79void
80octrace1(char* proc, OCstate* state, OCcontent* content, int start, int count)
81{
82    unsigned long pos = xxdr_getpos(content->tree->data.xdrs);
83    fprintf(stderr,"trace: %s mode=%s node=%s (%s)",
84            proc,modestring(content->mode),content->node->fullname,
85            octypetostring(content->node->octype));
86    if(content->packed)
87        fprintf(stderr," packed=%d",content->packed);
88    if(count >= 0)
89        fprintf(stderr," start=%lu count=%lu",
90            (unsigned long)start,(unsigned long)count);
91    else
92        fprintf(stderr," index=%lu",(unsigned long)start);
93    fprintf(stderr," xdrs.pos=%lu",pos);
94    fprintf(stderr,"\n");
95    if(content->cache.valid) {
96        fprintf(stderr,"\tcache{index=%lu maxindex=%lu offset=%lu}\n",
97                (unsigned long)content->cache.index,
98                (unsigned long)content->cache.maxindex,
99                (unsigned long)content->cache.offset);
100    }
101    fflush(stderr);
102}
103
104void
105octrace(char* proc, OCstate* state, OCcontent* content, int index)
106{
107    octrace1(proc,state,content,index,-1);
108}
109
110
111#else
112#define octrace(proc,state,content,index)
113#define octrace1(proc,state,content,start,count)
114#define report(memsize,memory)
115#endif /*OCDEBUG*/
116
117OCmode
118ocgetmode(OCcontent* content)
119{
120    return (content == NULL ? OCNULLMODE : content->mode);
121}
122
123OCcontent*
124ocnewcontent(OCstate* state)
125{
126    OCcontent* content;
127    if(state == NULL) return NULL;
128    content = state->contentlist;
129    /* Search for an unused content node*/
130    while(content != NULL && content->mode != OCEMPTYMODE) {
131        content = content->next;
132    }
133    if(content == NULL) {
134        content = (OCcontent*)ocmalloc(sizeof(OCcontent));
135        MEMCHECK(content,(OCcontent*)NULL);
136        content->magic = OCMAGIC;
137        content->next = state->contentlist;
138        state->contentlist = content;
139    }
140    return occlearcontent(state,content);
141}
142
143void
144ocfreecontent(OCstate* state, OCcontent* content)
145{
146    if(content != NULL) {content->mode = OCEMPTYMODE;}
147}
148
149static OCcontent*
150occlearcontent(struct OCstate* state, OCcontent* content)
151{
152    /* save fields that should not be cleared */
153    unsigned int magic = content->magic;
154    OCcontent* next = content->next;
155    memset((void*)content,sizeof(OCcontent),0);
156    /* set/restore non-null fields */
157    content->magic = magic;
158    content->next = next;
159    content->state = state;
160    content->mode = OCNULLMODE;
161    return content;
162}
163
164static OCcontent*
165ocsetcontent(OCcontent* childcontent, OCcontent* parent, OCnode* node, int packed)
166{
167    childcontent->state = parent->state;
168    childcontent->cache.valid = 0;
169    childcontent->node = node;
170    childcontent->tree = node->root->tree;
171    childcontent->mode = modetransition(node,parent->mode);
172    childcontent->packed = packed;
173    return childcontent;
174}
175
176#ifdef OCIGNORE
177static OCcontent*
178occlonecontent(OCstate* state, OCcontent* content)
179{
180    OCcontent* clone = ocnewcontent(state);
181    clone->mode = content->mode;
182    clone->node = content->node;
183    clone->cache = content->indexcache;
184    return clone;
185}
186#endif
187
188OCerror
189ocdataith(OCstate* state, OCcontent* parent, size_t index, OCcontent* child)
190{
191    OCerror ocerr = OC_NOERR;
192    switch (parent->mode) {
193    case OCARRAYMODE:
194        ocerr = ocarrayith(state,parent,child,index);
195        break;
196    case OCSEQUENCEMODE:
197        ocerr = ocsequenceith(state,parent,child,index);
198        break;
199    case OCFIELDMODE:
200        ocerr = ocfieldith(state,parent,child,index);
201        break;
202    default: return OC_EINVAL;
203    }
204    if(ocerr == OC_EDATADDS)
205        ocdataddsmsg(state,parent->tree);
206    return ocerr;
207}
208
209OCerror
210ocdatacount(OCstate* state, OCcontent* current, size_t* sizep)
211{
212    OCerror ocerr = OC_NOERR;
213    size_t count = 0;
214    switch(current->mode) {
215    case OCARRAYMODE:
216        count = ocarraycount(state,current);
217        break;
218    case OCSEQUENCEMODE:
219        count = ocsequencecount(state,current);
220        break;
221    case OCFIELDMODE:
222        count = ocfieldcount(state,current);
223        break;
224    case OCPRIMITIVEMODE:
225        count = ocprimcount(state,current);       
226        break;
227    default: 
228        return OC_EINVAL;
229    }
230    current->cache.maxindex = ocmax(count,current->cache.maxindex);
231    if(sizep) *sizep = count;
232    return ocerr;
233}
234
235OCerror
236ocrootdata(OCstate* state, OCnode* root, OCcontent* content)
237{
238    OCtree* tree;
239    if(state == NULL || root == NULL || content == NULL)
240        return OCTHROW(OC_EINVAL);
241    if(root->tree == NULL) return OCTHROW(OC_EINVAL);
242    tree = root->tree;
243    if(tree->dxdclass != OCDATADDS) return OCTHROW(OC_ENODATA);
244    if(tree->nodes == NULL) return OCTHROW(OC_EINVAL);
245    if(tree->data.xdrs == NULL)
246        return OCTHROW(OC_EXDR);
247
248    occlearcontent(state,content);
249    content->mode = OCFIELDMODE;
250    content->node = root;
251    content->tree = tree;
252
253    content->cache.index = 0;
254    content->cache.maxindex = oclistlength(content->node->subnodes);
255    content->cache.offset = 0;
256    content->cache.valid = 1;
257
258    return OCTHROW(OC_NOERR);
259}
260
261/* Remember: we are operating wrt the datadds count, not the dds count */
262static OCerror
263ocarrayith(OCstate* state, OCcontent* content, OCcontent* elemcontent, size_t index)
264{
265    unsigned int i;
266    int stat = OC_NOERR;
267    XXDR* xdrs;
268    int packed, scalar;
269    OCtype etype,octype;
270    OCnode* node;
271    int startindex = 0;
272
273    octrace("ocarrayith", state, content, index);
274
275    if(state == NULL || content == NULL) return OCTHROW(OC_EINVAL);
276    if(content->mode != OCARRAYMODE) return OCTHROW(OC_EINVAL);
277
278    etype = content->node->etype;
279    octype = content->node->octype;
280    node = content->node;
281    scalar = (node->array.rank == 0 ? 1 : 0);
282    packed = (!scalar && octype == OC_Primitive &&
283              (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
284
285    xdrs = content->tree->data.xdrs;
286    if(xdrs == NULL) return OCTHROW(OC_EXDR);
287
288    if(!content->cache.valid) {
289        content->cache.index = 0; /* because we will have to walk to index'th data */
290        content->cache.maxindex = totaldimsize(node);
291        content->cache.valid = 1;
292        /* skip past the initial counts, if any */
293        if(!scalar) {
294            if(!ocskipcounts(xdrs,node,node->skip.count)) return OCTHROW(OC_EDATADDS);
295        }
296        /* checkpoint xdr position */
297        content->cache.offset = xxdr_getpos(xdrs);
298    }
299
300    /* move to the checkpoint position */
301    startindex = content->cache.index;
302    if(!xxdr_setpos(xdrs,content->cache.offset)) return xdrerror();
303
304    /* skip to the index'th item */
305    if(packed) {
306        content->cache.index = 0; /* keep at beginning */
307    } else {
308        for(i=startindex;i<index;i++) {
309            stat = ocskipinstance(node,xdrs,SKIPINSTANCE,NULL);
310            if(stat != OC_NOERR) return OCTHROW(stat);
311        }
312        content->cache.index = index; /* now we are at the index'th item */
313    }
314
315    /* update cache */
316    content->cache.index = index;
317    content->cache.offset = xxdr_getpos(xdrs);
318
319    /* set up the content for the current item in the array */
320    ocsetcontent(elemcontent,content,node,packed); /*keep same node */
321    if (index == content->cache.maxindex) {
322        /* mark eod */
323        elemcontent->mode = OCNULLMODE; 
324    }
325
326    return OCTHROW(stat);
327}
328
329static int
330ocsequenceith(OCstate* state, OCcontent* content, OCcontent* structcontent, size_t index)
331{
332    unsigned int i;
333    int stat = OC_NOERR;
334    XXDR* xdrs;
335    OCtype octype,etype;
336    int packed,scalar;
337    OCnode* node = content->node;
338    int startindex, tag;
339
340    octrace("ocsequenceith", state, content, index);
341
342    if(state == NULL || content == NULL) goto einval;
343    if(content->mode != OCSEQUENCEMODE) goto einval;
344    if(node->octype != OC_Sequence) goto einval;
345
346    octype = node->octype;
347    etype = node->etype;
348    scalar = (node->array.rank == 0 ? 1 : 0);
349    packed = (!scalar && octype == OC_Primitive &&
350              (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
351
352    xdrs = content->tree->data.xdrs;
353    if(xdrs == NULL) goto exdr;
354
355    if(!content->cache.valid) {
356        content->cache.valid = 1;
357        content->cache.index = 0;
358        content->cache.maxindex = 0;
359        content->cache.offset = xxdr_getpos(xdrs);
360    }
361
362    /* move to checkpoint position*/
363    startindex = content->cache.index;
364    if(!xxdr_setpos(xdrs,content->cache.offset)) goto exdr;
365
366    /* Walk past the first (index-1) records */
367    for(tag=StartOfSequence,i=startindex;i<index;i++) {
368        /* skip instance, including tag, but leave xdr at next tag */
369        stat = ocskipinstance(node,xdrs,SKIPINSTANCE,&tag);
370        if(stat != OC_NOERR) goto done;
371        if(tag == EndOfSequence)
372            break;
373        if(tag != StartOfSequence) {
374            oc_log(LOGERR,"missing/invalid begin/end record marker\n");
375            goto einvalcoords;
376        }
377    }
378    if(stat != OC_NOERR) goto done;
379
380    /* update cache; should be pointing to index'th record tag */
381    content->cache.index = index;
382    content->cache.maxindex = ocmax(index,content->cache.index);
383
384    /* this is a bit (too) tricky */
385    /* move to point to fields */
386    tag = ocgetsequencetag(xdrs);
387    if(tag == EndOfSequence) {
388        /* point past end of sequence */
389        content->cache.offset = xxdr_getpos(xdrs);
390    } else {/*tag == StartOfSequence*/
391        /* point to (next) start of sequence */
392        content->cache.offset = xxdr_getpos(xdrs) - XDRUNIT;
393    }
394    /* at this point, xdrs should point unconditionally
395       past the index'th tag */
396
397    /* Set state of new content: keep same node */
398    ocsetcontent(structcontent,content,node,packed);
399    if(tag == EndOfSequence) {
400        /* mark eod */
401        structcontent->mode = OCNULLMODE;       
402    }
403done:
404    return OCTHROW(stat);
405einval:
406    stat = OC_EINVAL;
407    goto done;
408exdr:
409    stat = OC_EXDR;
410    goto done;
411einvalcoords:
412    stat = OC_EINVALCOORDS;
413    goto done;
414}
415
416/*
417The ocfieldcontent procedure has to deal with the fact
418that the dap constraints may have removed some fields
419from the datadds and hence some fields may have no
420representation in the xdr data (or compiled data).
421Assume that xdr points to start of 0th field.
422*/
423static int
424ocfieldith(OCstate* state, OCcontent* content, OCcontent* fieldcontent, size_t index)
425{
426    unsigned int i;
427    int stat = OC_NOERR;
428    XXDR* xdrs;
429    OCtype octype,etype;
430    int packed;
431    int isscalar;
432    OCnode* node;
433    int startindex;
434
435    octrace("ocfieldith", state, content, index);
436
437    if(state == NULL || content == NULL) return OCTHROW(OC_EINVAL);
438    if(content->mode != OCFIELDMODE) return OCTHROW(OC_EINVAL);
439
440    node = content->node;
441    octype = node->octype;
442    etype = node->etype;
443    isscalar = (node->array.rank == 0 ? 1 : 0);
444    packed = (!isscalar && octype == OC_Primitive
445              && (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
446
447    xdrs = content->tree->data.xdrs;
448    if(xdrs == NULL) return OCTHROW(OC_EXDR);
449
450    if(!content->cache.valid) {
451        content->cache.index = 0;
452        content->cache.maxindex = oclistlength(node->subnodes);
453        content->cache.valid = 1;
454        /* checkpoint xdr position */
455        content->cache.offset = xxdr_getpos(xdrs);
456    }
457
458    /* move to the checkpoint position */
459    startindex = content->cache.index;
460    if(!xxdr_setpos(xdrs,content->cache.offset)) return xdrerror();
461
462    switch (octype) {
463    case OC_Sequence: /* assume xdrs points past sequence tag */
464    case OC_Grid: /* Note that the Grid array is field 0 and the maps are 1..nsubnodes*/
465    case OC_Dataset:
466    case OC_Structure:
467        /* walk to (i-1)'th field */
468        for(i=startindex;i<index;i++) { /* walk field by field */
469            OCnode* ithfield = (OCnode*)oclistget(node->subnodes,i);
470            stat = ocskipinstance(ithfield,xdrs,SKIPWHOLE,NULL);
471            if(stat != OC_NOERR) return OCTHROW(stat);
472        }
473        break;
474
475    default: return OCTHROW(OC_EINVAL);
476    }
477
478    /* update cache */
479    content->cache.index = index;
480    content->cache.offset = xxdr_getpos(xdrs);
481    /* Set state of new content: node changes to field node */
482    ocsetcontent(fieldcontent,content,
483                     (OCnode*)oclistget(node->subnodes,index),
484                     packed);
485    if(index >= content->cache.maxindex) {
486        /* mark eod */
487        fieldcontent->mode = OCNULLMODE;       
488    }
489
490    return OCTHROW(stat);
491}
492
493/*
494In order to actually extract data,
495one must move to the specific primitive typed
496field containing the data of interest by using
497ocfieldcontent().
498Then, oc_getcontent() is invoked to extract
499some subsequence of items from the field.
500Note that oc_getcontent() will also work for scalars,
501but the start must be zero and the count must be one.
502*/
503
504int
505ocgetcontent(OCstate* state, OCcontent* content, void* memory, size_t memsize,
506                 size_t start, size_t count)
507{
508    int stat = OC_NOERR;
509    XXDR* xdrs;
510    OCtype etype, octype;
511    int isscalar, packed;
512    size_t elemsize, totalsize;
513    OCnode* node = content->node;
514
515    octrace1("ocgetcontent", state, content, start, count);
516
517    if(state == NULL || content == NULL || memory == NULL)
518        {OCTHROWCHK(stat=OC_EINVAL); goto done;}
519    if(content->mode != OCPRIMITIVEMODE || node->octype != OC_Primitive)
520        {OCTHROWCHK(stat=OC_EINVAL); goto done;}
521
522    octype = node->octype;
523    etype = node->etype;
524
525    isscalar = (node->array.rank == 0);
526    packed = (!isscalar && octype == OC_Primitive
527              && (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
528
529    if(isscalar && (start != 0 || count != 1))
530        {OCTHROWCHK(stat=OC_EINVALCOORDS); goto done;}
531
532    /* validate memory space*/
533    elemsize = octypesize(etype);
534    totalsize = elemsize*count;
535    if(memsize < totalsize) return OCTHROW(OC_EINVAL);
536
537    xdrs = content->tree->data.xdrs;
538    if(xdrs == NULL) return OCTHROW(OC_EXDR);
539
540    /* Need to setup the cache */
541    if(!content->cache.valid) {
542        content->cache.valid = 1;
543        content->cache.index = 0;
544        content->cache.maxindex = totaldimsize(content->node);
545        if(!ocskipcounts(xdrs,content->node,content->cache.maxindex))
546            return OCTHROW(OC_EXDR);
547        content->cache.offset = xxdr_getpos(xdrs);
548    }
549
550    if(content->cache.valid && content->cache.maxindex < (start+count))
551        return OCTHROW(OC_ENODATA);
552
553    /* utilize the cache */
554    if(!xxdr_setpos(xdrs,content->cache.offset)) return OCTHROW(OC_EXDR);
555
556    /* Extract the data */
557    stat = ocxdrread(content,xdrs,(char*)memory,memsize,start,count);
558
559#ifdef OCDEBUG
560    report(memsize,memory+start);
561#endif
562
563    /* Update the cache */
564    if(!packed) {
565        content->cache.index = (start+count);
566        content->cache.offset = xxdr_getpos(xdrs);
567    }
568
569done:
570    return OCTHROW(stat);
571}
572
573static size_t
574ocfieldcount(OCstate* state, OCcontent* content)
575{
576    OCnode* node = content->node;
577    size_t count;
578    OCASSERT((node != NULL));
579    count = oclistlength(node->subnodes);
580    return count;
581}
582
583static size_t
584ocarraycount(OCstate* state, OCcontent* content)
585{
586    unsigned int count;
587    OCnode* node = content->node;
588
589    OCASSERT((node != NULL));
590    OCASSERT((content->mode == OCARRAYMODE));
591
592    count = totaldimsize(node);
593
594#ifdef VERIFY
595    if(node->array.rank > 0) {
596        off_t checkpoint;
597        XXDR* xdrs;
598        unsigned int xdrcount;
599        /* verify against xdr */
600        xdrs = content->tree->data.xdrs;
601        OCASSERT((xdrs != NULL));
602        /* checkpoint current location */
603        checkpoint = xxdr_getpos(xdrs);
604        /* extract the count*/
605        if(!xxdr_uint(xdrs,&xdrcount)) return 0;
606        if(xdrcount != count) return 0;
607        /* return to checkpoint position*/
608        if(!xxdr_setpos(xdrs,checkpoint)) return 0;
609    }
610#endif /*VERIFY*/
611    return (size_t)count;
612}
613
614/* Counting records actually requires walking the xdr packet
615   so it is not necessarily cheap*/
616static size_t
617ocsequencecount(OCstate* state, OCcontent* content)
618{
619    size_t count;
620    OCnode* node = content->node;
621    XXDR* xdrs;
622    off_t checkpoint;
623
624    OCASSERT((node != NULL));
625    OCASSERT((node->octype == OC_Sequence));
626    OCASSERT((content->mode == OCSEQUENCEMODE));
627
628    xdrs = content->tree->data.xdrs;
629    OCASSERT((xdrs != NULL));
630
631    /* checkpoint location */
632    checkpoint = xxdr_getpos(xdrs);
633
634    for(count=0;;count++) {
635        int tag;
636        OCerror stat = ocskipinstance(node,xdrs,SKIPINSTANCE,&tag);
637        if(stat != OC_NOERR) {count = 0; break;}
638        if(tag == EndOfSequence) {
639            break; /* done with the count*/
640        } else if(tag != StartOfSequence) {
641            oc_log(LOGERR,"missing/invalid begin/end record marker\n");
642            return 0;
643        }
644    }
645
646    /* move back to checkpoint position*/
647    if(!xxdr_setpos(xdrs,checkpoint)) return 0;
648
649    return count;
650}
651
652static size_t
653ocprimcount(OCstate* state, OCcontent* content)
654{
655    unsigned int count;
656    OCnode* node = content->node;
657
658    OCASSERT((node != NULL));
659    OCASSERT((content->mode == OCPRIMITIVEMODE));
660
661    count = totaldimsize(node);
662
663#ifdef VERIFY
664    if(node->array.rank > 0) {
665        off_t checkpoint;
666        XXDR* xdrs;
667        unsigned int xdrcount;
668        /* verify against xdr */
669        xdrs = content->tree->data.xdrs;
670        OCASSERT((xdrs != NULL));
671        /* checkpoint current location */
672        checkpoint = xxdr_getpos(xdrs);
673        /* extract the count*/
674        if(!xxdr_uint(xdrs,&xdrcount)) return 0;
675        if(xdrcount != count) return 0;
676        /* return to checkpoint position*/
677        if(!xxdr_setpos(xdrs,checkpoint)) return 0;
678    }
679#endif /*VERIFY*/
680    return (size_t)count;
681}
682
683static OCmode
684modetransition(OCnode* node, OCmode srcmode)
685{
686    OCmode  newmode = OCNULLMODE;
687    switch (srcmode) {
688    case OCARRAYMODE:
689        switch (node->octype) {
690        case OC_Sequence:
691            newmode = OCSEQUENCEMODE;
692            break;
693        case OC_Grid:
694        case OC_Structure:
695            newmode = OCFIELDMODE;
696            break;
697        default:
698            break;
699        }
700        break;
701
702    case OCSEQUENCEMODE:
703        switch (node->octype) {
704        default:
705            newmode = OCFIELDMODE;
706            break;
707        }
708        break;
709
710    case OCFIELDMODE:
711        switch (node->octype) {
712        case OC_Sequence:
713        case OC_Grid:
714        case OC_Structure:
715            newmode = OCARRAYMODE;
716            break;
717        case OC_Primitive:
718            newmode = OCPRIMITIVEMODE;
719            break;
720        default:
721            break;
722        }
723        break;
724
725    case OCPRIMITIVEMODE:
726    case OCNULLMODE:
727    case OCEMPTYMODE:
728    default:
729        newmode = OCNULLMODE;
730        break;
731    }
732    if(newmode == OCNULLMODE)
733        OCPANIC1("No defined mode transition: %d",(int)srcmode);
734    return newmode;
735}
736
737/* get the presumed current sequence tag */
738static int
739ocgetsequencetag(XXDR* xdrs)
740{
741    char tag[XDRUNIT];
742    if(!xxdr_getbytes(xdrs,tag,sizeof(tag))) return 0;
743    return tag[0];
744}
745
746static int
747ocskipcounts(XXDR* xdrs, OCnode* node, off_t expected)
748{
749    if(node->array.rank == 0) return 1; /* simple scalar */
750#ifdef VERIFY
751    unsigned int xdrcount0,xdrcount1;
752    /* Collect the dimension count from the xdr data packet*/
753    if(!xxdr_uint(xdrs,&xdrcount0)) OCGOTO(shortxdr);
754    if(expected >= 0 && xdrcount0 != expected) return 0;
755    /* pull out redundant second count*/
756    /* (note that String/URL do not have redundant count)*/
757    if(node->octype == OC_Primitive
758       && node->etype != OC_String && node->etype != OC_URL) {
759        if(!xxdr_uint(xdrs,&xdrcount1)) return 0;
760        if(xdrcount0 != xdrcount1) return 0;
761    }
762#else
763    /* skip the counts */
764    expected = expected; /*shut up compiler*/
765    if(node->octype == OC_Primitive
766       && node->etype != OC_String && node->etype != OC_URL) {
767        if(!xxdr_skip(xdrs,2*XDRUNIT)) return 0;
768    } else {
769        if(!xxdr_skip(xdrs,XDRUNIT)) return 0;
770    }
771#endif
772    return 1;
773}
774
775/**************************************************/
776/* Moved ocdata.c here */
777/**************************************************/
778
779const char StartOfSequence = '\x5A';
780const char EndOfSequence = '\xA5';
781
782static int ocerrorstring(XXDR* xdrs);
783
784#define LOCALMEMMAX 1024
785
786/*
787Skip arbitrary object based on its octype
788and a state
789
790Cases:
791
792octype          Skip State      actions
793-------------------------------------------
794Structure
795  |Grid
796  |DataSet      SKIPINSTANCE    Skip single instance
797                  |SKIPFIELDS
798                SKIPWHOLE       Skip array of instances
799                                including leading counts
800
801Sequence        SKIPFIELDS      Skip single record
802                                (assume leading tag already skipped)
803                SKIPINSTANCE    Skip single record
804                                (including leading tag)
805                                                   
806                SKIPWHOLE       Skip all records
807                                including leading tags
808                                and trailing end marker
809
810Primitive       <any>           Skip whole primitive array
811                                including leading counts
812
813Notes:
8141. unlisted combinations are not legal/possible.
8152. assume that xxdr_getpos is properly positioned.
8163. If octype is OC_Sequence, tagp will be set with the
817   last tag encountered.
818*/
819
820OCerror
821ocskipinstance(OCnode* node, XXDR* xdrs, int state, int* tagp)
822{
823    int i,tag;
824    int stat = OC_NOERR;
825
826/* Support switch on combination of octype X state to simply code */
827#define CASE(octype,state) ((octype)<<3 | state)
828
829    switch (CASE(node->octype,state)) {
830
831    case CASE(OC_Dataset,SKIPINSTANCE):
832    case CASE(OC_Grid,SKIPINSTANCE):
833    case CASE(OC_Structure,SKIPINSTANCE):
834
835    case CASE(OC_Dataset,SKIPFIELDS):
836    case CASE(OC_Grid,SKIPFIELDS):
837    case CASE(OC_Structure,SKIPFIELDS):
838    case CASE(OC_Sequence,SKIPFIELDS): /* NOTE this special case */
839        if(node->skip.instancesize != OCINDETERMINATE) {
840            if(!xxdr_skip(xdrs,node->skip.instancesize)) OCGOTO(shortxdr);
841        } else {/* skip field by field */
842            for(i=0;i<oclistlength(node->subnodes);i++) {
843                OCnode* field = (OCnode*)oclistget(node->subnodes,i);
844                stat = ocskipinstance(field, xdrs, SKIPWHOLE,NULL);
845                if(stat != OC_NOERR) {OCTHROWCHK(stat); goto done;}
846            }
847        }
848        break;
849
850    case CASE(OC_Dataset,SKIPWHOLE):
851    case CASE(OC_Grid,SKIPWHOLE):
852    case CASE(OC_Structure,SKIPWHOLE):
853        OCASSERT(node->skip.count != OCINDETERMINATE);
854        if(node->skip.totalsize != OCINDETERMINATE) {
855            if(!xxdr_skip(xdrs,node->skip.totalsize)) goto badxdr;
856        } else {/* skip each instance */
857            if(node->array.rank > 0) {
858                if(!ocskipcounts(xdrs,node,node->skip.count)) goto badxdr;
859                for(i=0;i<node->skip.count;i++) {
860                    stat = ocskipinstance(node, xdrs, SKIPFIELDS,NULL);
861                    if(stat != OC_NOERR) {OCTHROWCHK(stat); goto done;}
862                }
863            } else { /* scalar */
864                stat = ocskipinstance(node, xdrs, SKIPINSTANCE,NULL);
865                if(stat != OC_NOERR) {OCTHROWCHK(stat); goto done;}
866            }
867        }
868        break;
869
870    case CASE(OC_Sequence,SKIPINSTANCE): /* Skip record including tag */
871        tag = ocgetsequencetag(xdrs); /* always read the tag */
872        if(tagp) *tagp = tag;
873        if(tag == StartOfSequence) { /* skip record fields */
874            stat = ocskipinstance(node, xdrs, SKIPFIELDS,NULL);
875            if(stat != OC_NOERR) {OCTHROWCHK(stat); break;}
876        } /* let caller handle */
877        break;
878       
879    case CASE(OC_Sequence,SKIPWHOLE): /* Skip multiple records including tags */
880        for(i=0;;i++) {
881            stat = ocskipinstance(node, xdrs, SKIPINSTANCE, &tag);
882            if(stat != OC_NOERR) {OCTHROWCHK(stat); break;}
883            if(tag == EndOfSequence) break; /* done */
884            if(tag != StartOfSequence) goto badxdr; /* malformed */
885        }
886        break;
887
888    case CASE(OC_Primitive,SKIPWHOLE):
889    case CASE(OC_Primitive,SKIPINSTANCE):
890    case CASE(OC_Primitive,SKIPFIELDS):
891        OCASSERT(node->skip.count != OCINDETERMINATE);
892        if(node->skip.totalsize != OCINDETERMINATE) {
893            /* skip directly past it */
894            if(!xxdr_skip(xdrs,node->skip.totalsize)) goto badxdr;
895        } else {/* Walk instance by instance */
896            if(state == SKIPWHOLE) {
897                /* read the counts */
898                if(!ocskipcounts(xdrs,node,node->skip.count))
899                    goto badxdr;
900            }
901            OCASSERT(node->etype == OC_String || node->etype == OC_URL);
902            /* get the count */
903            for(i=0;i<node->skip.count;i++) {
904                /* read and skip the string */
905                unsigned int len;
906                /* read string size */
907                if(!xxdr_uint(xdrs,&len)) OCGOTO(shortxdr);
908                /* round up to next XDRUNIT and skip string contents */
909                len = RNDUP(len);
910                if(!xxdr_skip(xdrs,(size_t)len)) OCGOTO(shortxdr);
911            }
912        }
913        break;
914
915        default:
916            OCPANIC2("ocskipinstance: encountered unexpected node type or state: %d,%d",
917                        node->octype,state);
918            break;
919    }
920done:
921    return OCTHROW(stat);
922shortxdr:
923    oc_log(LOGERR,"short xdr packet");
924    stat = OC_EXDR;
925    goto done;
926badxdr:
927    oc_log(LOGERR,"malformed xdr packet");
928    stat = OC_EXDR;
929    goto done;
930}
931
932/*
933Extract data from the xdr packet into a chunk of memory.
934Normally, it is assumed that we are (at least virtually)
935"at" a single instance in the xdr packet; which we read.
936Virtually because for packed data, we need to point to
937the beginning of the packed data and use the index to indicate
938which packed element to get. Assume that in any case,
939any leading counts have been passed.
940*/
941OCerror
942ocxdrread(OCcontent* content, XXDR* xdrs, char* memory, size_t memsize,
943          ocindex_t start, ocindex_t count)
944{
945    int stat = OC_NOERR;
946    unsigned int i;
947    size_t elemsize;
948    size_t readsize;
949    size_t skipsize;
950    char localmem[LOCALMEMMAX];
951    char* srcmem;   
952    unsigned int* p;
953    int packed;
954    int scalar;
955    OCtype octype,etype;
956    ocindex_t localstart = start; /* will change if node is cacheing */
957    OCnode* node;
958
959    node = content->node;
960    octype = node->octype;
961    etype = node->etype;
962
963    elemsize = octypesize(etype);
964
965    scalar = (node->array.rank == 0 ? 1 : 0);
966
967    /* check if the data is packed*/
968    packed = (octype == OC_Primitive && !scalar
969              && (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
970         
971    /* validate memory space*/
972    if(memsize < elemsize*count) return OCTHROW(OC_EINVAL);
973
974#ifdef OCIGNORE
975    if(!scalar && (!node->cache.cacheable || !node->cache.valid)) {
976        unsigned int xdrcount0,xdrcount1;
977        /* assume xdr position is correct */
978        /* Read leading double count if ! scalar*/
979        if(!xxdr_uint(xdrs,&xdrcount0)) OCGOTO(shortxdr);
980        if(!xxdr_uint(xdrs,&xdrcount1)) OCGOTO(shortxdr);
981        if(xdrcount0 != xdrcount1) return OCTHROW(OC_EXDR);
982        if(xdrcount0 < start+count) OCGOTO(shortxdr);
983    }
984#endif
985 
986    /* Handle packed data specially*/
987    if(packed) {
988        readsize = count*1; /* |OC_(Char,Byte,UByte)| == 1 */
989        skipsize = start*1; /* |OC_(Char,Byte,UByte)| == 1 */
990        /* skip to start of what we want to read */
991        if(!xxdr_skip(xdrs,skipsize)) OCGOTO(shortxdr);
992        /* read data, keeping xdrs on XDRUNIT boundary */
993        if(!xxdr_opaque(xdrs,memory,readsize))
994            OCGOTO(shortxdr);
995        return OCTHROW(OC_NOERR);
996    }
997
998    /* Not packed */
999
1000#ifdef OCIGNORE
1001    /* If this (primitive) object is cacheable and is valid cache,
1002       then modify start and set the xdr position accordingly
1003    */
1004    if(node->cache.cacheable && node->cache.valid) {
1005        if(node->cache.index <= start) {
1006            localstart -= node->cache.index;
1007            if(!xxdr_setpos(xdrs,node->cache.offset)) return xdrerror();
1008        }
1009    }
1010#endif
1011
1012    /* Compute how much to skip based on the content's cache index */
1013    localstart = start - content->cache.index;
1014    if(localstart < 0) localstart = 0;
1015
1016    /* extract count items; use xxdr_getbytes to speed up*/
1017    srcmem = memory;
1018    switch (etype) {
1019    case OC_Float64: case OC_Int64: case OC_UInt64:
1020        readsize = count*2*XDRUNIT;
1021        skipsize = localstart*2*XDRUNIT;
1022        /* skip to start of what we want to read */
1023        if(!xxdr_skip(xdrs,skipsize)) OCGOTO(shortxdr);
1024        if(!xxdr_opaque(xdrs,(char*)srcmem,readsize)) OCGOTO(shortxdr);
1025        if(etype == OC_Float64) {
1026            double* dp;
1027            for(dp=(double*)srcmem,i=0;i<count;i++,dp++) {
1028                double swap;
1029                xxdrntohdouble((char*)dp,&swap);
1030                *dp = swap;
1031            }
1032        } else if(!xxdr_network_order) {
1033            unsigned long long* llp;
1034            for(llp=(unsigned long long*)srcmem,i=0;i<count;i++,p++) {
1035                swapinline64(llp);
1036            }
1037        }
1038        break;
1039
1040    case OC_String: case OC_URL: {
1041        /* Read string by string */
1042        char* s = NULL;
1043        char** pmem = (char**)srcmem;
1044        /* First skip to the starting string */
1045        for(i=0;i<localstart;i++) {
1046            unsigned int slen;
1047            if(!xxdr_uint(xdrs,&slen)) OCGOTO(shortxdr);
1048            slen = RNDUP(slen);
1049            if(!xxdr_skip(xdrs,slen)) OCGOTO(shortxdr);
1050        }
1051        /* Read count strings */
1052        for(i=0;i<count;i++) {
1053            off_t slen;
1054            /* xxdr_string will always alloc the space */       
1055            if(!xxdr_string(xdrs,&s,&slen)) 
1056                OCGOTO(shortxdr);
1057            pmem[i] = s;
1058        }
1059    } break;
1060
1061
1062    case OC_Char: case OC_Byte: case OC_UByte:
1063    case OC_Int16: case OC_UInt16:
1064        /* We need to store the xdr data locally until we can convert it out
1065           because  elemsize < sizeof(int) */
1066        srcmem = localmem;
1067        if(count*elemsize > sizeof(localmem)) {
1068            srcmem = (char*)ocmalloc(count*sizeof(unsigned int));
1069            if(srcmem == NULL) {stat = OCTHROW(OC_ENOMEM); goto done;}
1070        }
1071        /* fall thru */         
1072    case OC_Int32: case OC_UInt32:
1073    case OC_Float32:
1074        readsize = (count)*XDRUNIT;
1075        skipsize = (localstart)*XDRUNIT;
1076        if(!xxdr_skip(xdrs,skipsize)) OCGOTO(shortxdr);
1077        if(!xxdr_opaque(xdrs,(char*)srcmem,readsize)) OCGOTO(shortxdr);
1078        if(!xxdr_network_order) {
1079            for(p=(unsigned int*)srcmem,i=0;i<count;i++,p++) {
1080                swapinline32(p);
1081            }
1082        }
1083        break;
1084
1085    default: OCPANIC("unexpected etype"); break;
1086    }
1087
1088    /* Convert memory to right format */
1089    switch (etype) {
1090
1091    case OC_Char: case OC_Byte: case OC_UByte: {
1092        char* pmem = (char*)memory;
1093        p = (unsigned int*)srcmem;
1094        for(i=0;i<count;i++) {
1095            unsigned int tmp = *p++;
1096            *pmem++ = (unsigned char)tmp;
1097        }
1098    } break;
1099
1100    case OC_Int16: case OC_UInt16: {
1101        unsigned short* pmem = (unsigned short*)memory;
1102        p = (unsigned int*)srcmem;
1103        for(i=0;i<count;i++) {
1104            unsigned int tmp = *p++;
1105            *pmem++ = (unsigned short)tmp;
1106        }
1107    } break;
1108
1109    default: 
1110        break; /* already handled above */
1111    }
1112
1113    /* set cache */
1114    content->cache.index = start + count; /* should be our current index */
1115    content->cache.offset = xxdr_getpos(xdrs); /* should be our current position */
1116
1117done:
1118    return OCTHROW(stat);
1119
1120shortxdr:
1121    content->cache.valid = 0; /* no longer valid */
1122    if(!ocerrorstring(xdrs))
1123        oc_log(LOGERR,"DAP DATADDS packet is apparently too short");
1124    stat = OCTHROW(OC_EDATADDS);
1125    goto done;   
1126}
1127
1128int
1129occountrecords(OCnode* node, XXDR* xdrs, size_t* nrecordsp)
1130{
1131    int stat = OC_NOERR;
1132    size_t nrecords = 0;
1133
1134    if(node->octype != OC_Sequence) return OCTHROW(OC_EINVAL);
1135    /* checkpoint the xdr position*/
1136    for(nrecords=0;;nrecords++) {
1137        int tag = 0;
1138        stat = ocskipinstance(node,xdrs,SKIPINSTANCE,&tag);
1139        if(stat != OC_NOERR) break;
1140        if(tag == EndOfSequence) break;
1141        if(tag != StartOfSequence) {
1142            oc_log(LOGERR,"missing/invalid begin/end record marker\n");
1143            stat = OC_EINVALCOORDS;
1144            break;
1145        }
1146        if(stat != OC_NOERR) break;
1147    }
1148    if(nrecordsp != NULL) *nrecordsp = nrecords;
1149    return OCTHROW(stat);
1150}
1151
1152
1153
1154#define tag "Error {\n"
1155
1156static int
1157ocerrorstring(XXDR* xdrs)
1158{
1159    /* Check to see if the xdrs contains "Error {\n'; assume it is at the beginning of data */
1160    off_t avail = xxdr_getavail(xdrs);
1161    char* data = (char*)malloc(avail);
1162    if(!xxdr_setpos(xdrs,0)) return 0;
1163    if(!xxdr_opaque(xdrs,data,avail)) return 0;
1164    /* check for error tag at front */
1165    if(ocstrncmp(data,tag,sizeof(tag))==0) {
1166        char* p;
1167        if((p=strchr(data,'}')) != NULL) *(++p)='\0';
1168        oc_log(LOGERR,"Server error: %s",data);
1169        /* Since important, report to stderr as well */
1170        fprintf(stderr,"Server error: %s",data);
1171        return 1;
1172    }
1173    return 0;
1174}
Note: See TracBrowser for help on using the repository browser.