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#include "ocdump.h"
8
9/* Forward*/
10static OCerror ocread(OCdata*, XXDR*, char*, size_t, size_t, size_t);
11
12#ifdef OCDEBUG
13
14static void
15octrace(char* procOCstatestateOCdatadata)
16{
17    OCbytesbuffer = ocbytesnew();
18    ocdumpdatapath(state,data,buffer);
19    fprintf(stderr,"%s: %s\n",proc,ocbytescontents(buffer));
20}
21
22#else
23
24#define octrace(proc,state,data)
25#endif /*OCDEBUG*/
26
27/* Use this to attach to a data tree for a DATADDS */
28OCerror
29ocdata_getroot(OCstatestateOCnoderootOCdata** datap)
30{
31    OCdatadata;
32    assert(root->tree->dxdclass == OCDATADDS);
33    assert(root->octype == OC_Dataset);
34
35    if(root->tree->data.data == NULL)
36 return OCTHROW(OC_ENODATA);
37
38    data = root->tree->data.data;
39    if(datap) *datap = data;
40
41    octrace("attach",state,data);
42
43    return OCTHROW(OC_NOERR);
44}
45
46OCerror
47ocdata_container(OCstatestateOCdatadataOCdata** containerp)
48{
49    OCdatacontainer;
50    OCnodepattern;
51
52    OCASSERT(state != NULL);
53
54    pattern = data->pattern;
55
56    if(pattern->container == NULL)
57 return OCTHROW(OC_EBADTYPE);
58
59    container = data->container;
60    if(container == NULL)
61 return OCTHROW(OC_EBADTYPE);
62
63    if(containerp) *containerp = container;
64
65    octrace("container", statecontainer);
66
67    return OC_NOERR;
68}
69
70OCerror
71ocdata_root(OCstatestateOCdatadataOCdata** rootp)
72{
73    OCdataroot;
74    OCnodepattern;
75
76    OCASSERT(state != NULL);
77
78    pattern = data->pattern;
79    root = pattern->tree->data.data;
80    if(rootp) *rootp = root;
81
82    octrace("root", stateroot);
83
84    return OC_NOERR;
85}
86
87OCerror
88ocdata_ithfield(OCstatestateOCdatacontainer, size_t indexOCdata** fieldp)
89{
90    OCdatafield;
91    OCnodepattern;
92
93    OCASSERT(state != NULL);
94    OCASSERT(container != NULL);
95
96    pattern = container->pattern;
97
98    if(!ociscontainer(pattern->octype))
99 return OCTHROW(OC_EBADTYPE);
100
101    /* Validate index */
102    if(index >= container->ninstances)
103 return OCTHROW(OC_EINDEX);
104
105    field = container->instances[index];
106    if(fieldp) *fieldp = field;
107
108    octrace("ithfield", statefield);
109
110    return OC_NOERR;
111}
112
113OCerror
114ocdata_ithelement(OCstatestateOCdatadata, size_t* indicesOCdata** elementp)
115{
116    int stat = OC_NOERR;
117    OCdataelement;
118    OCnodepattern;
119    size_t index,rank;
120
121    OCASSERT(state != NULL);
122    OCASSERT(data != NULL);
123
124    pattern = data->pattern;
125    rank = pattern->array.rank;
126
127    /* Must be a dimensioned Structure */
128    if(pattern->octype != OC_Structure || rank == 0)
129 return OCTHROW(OC_EBADTYPE);
130
131    /* Validate indices */
132    if(!ocvalidateindices(rank,pattern->array.sizes,indices))
133 return OCTHROW(OC_EINVALCOORDS);
134
135    /* compute linearized index */
136    index = ocarrayoffset(rank,pattern->array.sizes,indices);
137
138    if(index >= data->ninstances)
139 return OCTHROW(OC_EINDEX);
140
141    element = data->instances[index];
142
143    if(elementp) *elementp = element;
144
145    octrace("ithelement", stateelement);
146
147    return OCTHROW(stat);
148}
149
150/* Move to the ith sequence record. */
151OCerror
152ocdata_ithrecord(OCstatestateOCdatadata,
153                 size_t index, /* record number */
154  OCdata** recordp
155                 )
156{
157    int stat = OC_NOERR;
158    OCdatarecord;
159    OCnodepattern;
160
161    OCASSERT(state != NULL);
162    OCASSERT(data != NULL);
163
164    pattern = data->pattern;
165
166    /* Must be a Sequence */
167    if(pattern->octype != OC_Sequence
168       || !fisset(data->datamode,OCDT_SEQUENCE))
169 return OCTHROW(OC_EBADTYPE);
170
171    /* Validate index */
172    if(index >= data->ninstances)
173 return OCTHROW(OC_EINDEX);
174
175    record = data->instances[index];
176
177    if(recordp) *recordp = record;
178
179    octrace("ithrecord", staterecord);
180
181    return OCTHROW(stat);
182}
183
184OCerror
185ocdata_position(OCstatestateOCdatadata, size_t* indices)
186{
187    OCnodepattern;
188
189    OCASSERT(state != NULL);
190    OCASSERT(data != NULL);
191    OCASSERT(indices != NULL);
192
193    pattern = data->pattern;
194    if(fisset(data->datamode,OCDT_RECORD))
195 indices[0] = data->index;
196    else if(fisset(data->datamode,OCDT_ELEMENT)) {
197 /* Transform the linearized array index into a set of indices */
198 ocarrayindices(data->index,
199                       pattern->array.rank,
200                       pattern->array.sizes,
201                       indices);
202    } else
203 return OCTHROW(OC_EBADTYPE);
204    return OCTHROW(OC_NOERR);
205}
206
207OCerror
208ocdata_recordcount(OCstatestateOCdatadata, size_t* countp)
209{
210    OCASSERT(state != NULL);
211    OCASSERT(data != NULL);
212    OCASSERT(countp != NULL);
213
214    if(data->pattern->octype != OC_Sequence
215       || !fisset(data->datamode,OCDT_SEQUENCE))
216 return OCTHROW(OC_EBADTYPE);
217
218    *countp = data->ninstances;
219
220    return OC_NOERR;
221}
222
223/**************************************************/
224/*
225In order to actually extract data, one must move to the
226specific primitive typed field containing the data of
227interest by using ocdata_fieldith().  Then this procedure
228is invoked to extract some subsequence of items from the
229field.  For scalars, the start and count are ignored.
230Note that start and count are linearized from the oc_data_read
231arguments.
232*/
233
234OCerror
235ocdata_read(OCstatestateOCdatadata, size_t start, size_t count,
236 void* memory, size_t memsize)
237
238{
239    int stat = OC_NOERR;
240    XXDRxdrs;
241    OCtype etype;
242    int isscalar;
243    size_t elemsizetotalsizecountsize;
244    OCnodepattern;
245
246    octrace("read", statedata);
247
248    assert(state != NULL);
249    assert(data != NULL);
250    assert(memory != NULL);
251    assert(memsize > 0);
252
253    pattern = data->pattern;
254    assert(pattern->octype == OC_Atomic);
255    etype = pattern->etype;
256
257    isscalar = (pattern->array.rank == 0 ? 1 : 0);
258
259    /* validate memory space*/
260    elemsize = octypesize(etype);
261    totalsize = elemsize*data->ninstances;
262    countsize = elemsize*count;
263    if(totalsize < countsize || memsize < countsize)
264 return OCTHROW(OC_EINVAL);
265
266    /* Get XXDR* */
267    xdrs = pattern->root->tree->data.xdrs;
268
269    if(isscalar) {
270        /* Extract the data */
271        stat = ocread(data,xdrs,(char*)memory,memsize,0,1);
272    } else {
273        /* Validate the start and count */
274        if(start >= data->ninstances
275           || (start+count) > data->ninstances)
276     return OCTHROW(OC_EINVALCOORDS);
277        /* Extract the data */
278        stat = ocread(data,xdrs,(char*)memory,memsize,start,count);
279    }
280
281    return OCTHROW(stat);
282}
283
284/**************************************************/
285/*
286Extract data from a leaf into memory.
287*/
288
289static OCerror
290ocread(OCdatadataXXDRxdrs, char* memory, size_t memsize, size_t start, size_t count)
291{
292    int i;
293    OCnodepattern;
294    OCtype etype;
295    off_t elemsizetotalsizexdrtotalxdrstart;
296    int scalar;
297
298    OCASSERT(data != NULL);
299    OCASSERT(memory != NULL);
300    OCASSERT(memsize > 0);
301    OCASSERT(count > 0);
302    OCASSERT((start+count) <= data->ninstances);
303
304    pattern = data->pattern;
305    etype = pattern->etype;
306    scalar = (pattern->array.rank == 0);
307
308    /* Note that for strings, xdrsize == 0 */
309    xdrtotal = count*data->xdrsize; /* amount (in xdr sizes) to read */
310    xdrstart = start*data->xdrsize; /* offset from the start of the data */
311
312    elemsize = octypesize(etype); /* wrt memory, not xdrsize */
313    totalsize = elemsize*count;
314
315    /* validate memory space*/
316    if(memsize < totalsize) return OCTHROW(OC_EINVAL);
317
318    /* copy out with appropriate byte-order conversions */
319    switch (etype) {
320
321    case OC_Int32: case OC_UInt32: case OC_Float32:
322 xxdr_setpos(xdrs,data->xdroffset+xdrstart);
323 if(!xxdr_getbytes(xdrs,memory,xdrtotal)) {OCTHROW(OC_EDATADDS); goto xdrfail;}
324 if(!xxdr_network_order) {
325     unsigned int* p;
326     for(p=(unsigned int*)memory,i=0;i<count;i++,p++) {
327 swapinline32(p);
328     }
329 }
330 break;
331
332    case OC_Int64: case OC_UInt64:
333 xxdr_setpos(xdrs,data->xdroffset+xdrstart);
334 if(!xxdr_getbytes(xdrs,memory,xdrtotal)) {OCTHROW(OC_EDATADDS); goto xdrfail;}
335 if(!xxdr_network_order) {
336     unsigned long long* llp;
337     for(llp=(unsigned long long*)memory,i=0;i<count;i++,llp++) {
338 swapinline64(llp);
339     }
340 }
341        break;
342
343    case OC_Float64:
344 xxdr_setpos(xdrs,data->xdroffset+xdrstart);
345 if(!xxdr_getbytes(xdrs,memory,xdrtotal)) {OCTHROW(OC_EDATADDS); goto xdrfail;}
346 {
347     double* dp;
348     for(dp=(double*)memory,i=0;i<count;i++,dp++) {
349 double swap;
350 xxdrntohdouble((char*)dp,&swap);
351 *dp = swap;
352     }
353 }
354 break;
355
356    /* non-packed fixed length, but memory size < xdrsize */
357    case OC_Int16: case OC_UInt16: {
358 /* In order to avoid allocating a lot of space, we do this one int at a time */
359 /* Remember also that the short is not packed, so its xdr size is twice
360           its memory size */
361        xxdr_setpos(xdrs,data->xdroffset+xdrstart);
362        if(scalar) {
363     if(!xxdr_ushort(xdrs,(unsigned short*)memory)) {OCTHROW(OC_EDATADDS); goto xdrfail;}
364 } else {
365     unsigned short* sp = (unsigned short*)memory;
366     for(i=0;i<count;i++,sp++) {
367         unsigned int tmp;
368 if(!xxdr_getbytes(xdrs,(char*)&tmp,(off_t)XDRUNIT))
369     {OCTHROW(OC_EDATADDS); goto xdrfail;}
370 /* convert from network order if necessary */
371 if(!xxdr_network_order)
372     swapinline32(&tmp);
373 /* store as unsigned short */
374 *sp = (unsigned short)tmp;
375     }
376 }
377 } break;
378
379    /* Do the byte types, packed/unpacked */
380    case OC_Byte:
381    case OC_UByte:
382    case OC_Char:
383 if(scalar) {
384     /* scalar bytes are stored in xdr as int */
385     xxdr_setpos(xdrs,data->xdroffset+xdrstart);
386     if(!xxdr_uchar(xdrs,(unsigned char*)memory)) {OCTHROW(OC_EDATADDS); goto xdrfail;}
387 } else {
388     /* the xdroffset will always be at the start of the
389               packed data, so we need to add the start count to it */
390     xxdr_setpos(xdrs,data->xdroffset+xdrstart);
391     if(!xxdr_getbytes(xdrs,memory,xdrtotal)) {OCTHROW(OC_EDATADDS); goto xdrfail;}
392 }
393 break;
394
395    /* Hard case, because strings are variable length */
396    case OC_String: case OC_URL: {
397 /* use the data->nstrings data->string fields */
398 char** sp = (char**)memory;
399 if(count > data->nstrings)
400     return OCTHROW(OC_EDATADDS);
401 for(i=0;i<count;i++,sp++) {
402     off_t len;
403     off_t offset = data->strings[start+i];
404            xxdr_setpos(xdrs,offset);
405            /* get the string */
406     if(!xxdr_string(xdrs,sp,&len))
407 {OCTHROW(OC_EDATADDS); goto xdrfail;}
408 }
409        } break;
410
411    default: OCPANIC("unexpected etype"); break;
412    }
413
414    return OC_NOERR;
415
416xdrfail:
417    oclog(OCLOGERR,"DAP DATADDS packet is apparently too short");
418    return OCTHROW(OC_EDATADDS);
419}
420


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed