1/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
2   See the COPYRIGHT file for more information. */
3
4#include "config.h"
5#ifdef HAVE_UNISTD_H
6#include <unistd.h>
7#endif
8#ifdef HAVE_FCNTL_H
9#include <fcntl.h>
10#endif
11#ifdef HAVE_SYS_STAT_H
12#include <sys/stat.h>
13#endif
14#include <errno.h>
15
16#if defined(_WIN32) || defined(_WIN64)
17#define mode_t int
18#endif
19
20#include "ocinternal.h"
21#include "ocdebug.h"
22
23/* Order is important: longest first */
24static char* DDSdatamarks[3] = {"Data:\r\n","Data:\n",(char*)NULL};
25
26/* Not all systems have strndup, so provide one*/
27char*
28ocstrndup(const char* s, size_t len)
29{
30    char* dup;
31    if(s == NULL) return NULL;
32    dup = (char*)ocmalloc(len+1);
33    MEMCHECK(dup,NULL);
34    memcpy((void*)dup,s,len);
35    dup[len] = '\0';
36    return dup;
37}
38
39/* Do not trust strncmp semantics; this one
40   compares upto len chars or to null terminators */
41int
42ocstrncmp(const char* s1, const char* s2, size_t len)
43{
44    const char *p,*q;
45    if(s1 == s2) return 0;
46    if(s1 == NULL) return -1;
47    if(s2 == NULL) return +1;
48    for(p=s1,q=s2;len > 0;p++,q++,len--) {
49 if(*p == 0 && *q == 0) return 0; /* *p == *q == 0 */
50 if(*p != *q)
51     return (*p - *q);
52    }
53    /* 1st len chars are same */
54    return 0;
55}
56
57
58#if 0
59void
60makedimlist(OClistpathOClistdims)
61{
62    unsigned int i,j;
63    for(i=0;i<oclistlength(path);i++) {
64 OCnodenode = (OCnode*)oclistget(path,i);
65        unsigned int rank = node->array.rank;
66 for(j=0;j<rank;j++) {
67     OCnodedim = (OCnode*)oclistget(node->array.dimensions,j);
68     oclistpush(dims,(void*)dim);
69        }
70    }
71}
72#endif
73
74void
75ocfreeprojectionclause(OCprojectionclauseclause)
76{
77    if(clause->target != NULL) free(clause->target);
78    while(oclistlength(clause->indexsets) > 0) {
79 OClistslices = (OClist*)oclistpop(clause->indexsets);
80        while(oclistlength(slices) > 0) {
81     OCsliceslice = (OCslice*)oclistpop(slices);
82     if(slice != NULL) free(slice);
83 }
84        oclistfree(slices);
85    }
86    oclistfree(clause->indexsets);
87    free(clause);
88}
89
90#if 0
91void
92freeAttributes(OClistattset)
93{
94    unsigned int i,j;
95    for(i=0;i<oclistlength(attset);i++) {
96 OCattributeatt = (OCattribute*)oclistget(attset,i);
97 if(att->name != NULL) free(att->name);
98 if(att->etype == OC_String || att->etype == OC_URL) {
99     for(j=0;j<att->nvalues;j++) {
100 char* s = ((char**)att->values)[j];
101 if(s != NULL) free(s);
102     }
103 } else {
104     free(att->values);
105 }
106    }
107}
108#endif
109
110#if 0
111void
112freeOCnode(OCnodecdf, int deep)
113{
114    unsigned int i;
115    if(cdf == NULL) return;
116    if(cdf->name != NULL) free(cdf->name);
117    if(cdf->fullname != NULL) free(cdf->fullname);
118    if(cdf->attributes != NULLfreeAttributes(cdf->attributes);
119    if(cdf->subnodes != NULL) {
120 if(deep) {
121            for(i=0;i<oclistlength(cdf->subnodes);i++) {
122         OCnodenode = (OCnode*)oclistget(cdf->subnodes,i);
123 freeOCnode(node,deep);
124     }
125 }
126        oclistfree(cdf->subnodes);
127    }
128    free(cdf);
129}
130#endif
131
132int
133ocfindbod(OCbytesbuffer, size_t* bodp, size_t* ddslenp)
134{
135    unsigned int i;
136    char* content;
137    size_t len = ocbyteslength(buffer);
138    char** marks;
139
140    content = ocbytescontents(buffer);
141
142    for(marks = DDSdatamarks;*marks;marks++) {
143 char* mark = *marks;
144        size_t tlen = strlen(mark);
145        for(i=0;i<len;i++) {
146     if((i+tlen) <= len
147         && (ocstrncmp(content+i,mark,tlen)==0)) {
148        *ddslenp = i;
149         i += tlen;
150         *bodp = i;
151         return 1;
152     }
153 }
154    }
155    *ddslenp = 0;
156    *bodp = 0;
157    return 0; /* tag not found; not necessarily an error*/
158}
159
160/* Compute total # of elements if dimensioned*/
161size_t
162octotaldimsize(size_t rank, size_t* sizes)
163{
164    unsigned int i;
165    size_t count = 1;
166    for(i=0;i<rank;i++) {
167        count *= sizes[i];
168    }
169    return count;
170}
171
172size_t
173octypesize(OCtype etype)
174{
175    switch (etype) {
176    case OC_Char: return sizeof(char);
177    case OC_Byte: return sizeof(signed char);
178    case OC_UByte: return sizeof(unsigned char);
179    case OC_Int16: return sizeof(short);
180    case OC_UInt16: return sizeof(unsigned short);
181    case OC_Int32: return sizeof(int);
182    case OC_UInt32: return sizeof(unsigned int);
183    case OC_Float32: return sizeof(float);
184    case OC_Float64: return sizeof(double);
185#ifdef HAVE_LONG_LONG_INT
186    case OC_Int64: return sizeof(long long);
187    case OC_UInt64: return sizeof(unsigned long long);
188#endif
189    case OC_String: return sizeof(char*);
190    case OC_URL: return sizeof(char*);
191    default: break;     /* Ignore all others */
192    }
193    return 0;
194}
195
196char*
197octypetostring(OCtype octype)
198{
199    switch (octype) {
200    case OC_NAT:          return "OC_NAT";
201    case OC_Char:         return "OC_Char";
202    case OC_Byte:         return "OC_Byte";
203    case OC_UByte:    return "OC_UByte";
204    case OC_Int16:        return "OC_Int16";
205    case OC_UInt16:       return "OC_UInt16";
206    case OC_Int32:        return "OC_Int32";
207    case OC_UInt32:       return "OC_UInt32";
208    case OC_Int64:        return "OC_Int64";
209    case OC_UInt64:       return "OC_UInt64";
210    case OC_Float32:      return "OC_Float32";
211    case OC_Float64:      return "OC_Float64";
212    case OC_String:       return "OC_String";
213    case OC_URL:          return "OC_URL";
214    /* Non-primitives*/
215    case OC_Dataset:      return "OC_Dataset";
216    case OC_Sequence:     return "OC_Sequence";
217    case OC_Grid:         return "OC_Grid";
218    case OC_Structure:    return "OC_Structure";
219    case OC_Dimension:    return "OC_Dimension";
220    case OC_Attribute:    return "OC_Attribute";
221    case OC_Attributeset: return "OC_Attributeset";
222    case OC_Atomic:       return "OC_Atomic";
223    default: break;
224    }
225    return NULL;
226}
227
228char*
229octypetoddsstring(OCtype octype)
230{
231    switch (octype) {
232    case OC_Byte:         return "Byte";
233    case OC_Int16:        return "Int16";
234    case OC_UInt16:       return "UInt16";
235    case OC_Int32:        return "Int32";
236    case OC_UInt32:       return "UInt32";
237    case OC_Float32:      return "Float32";
238    case OC_Float64:      return "Float64";
239    case OC_String:       return "String";
240    case OC_URL:          return "Url";
241    /* Non-atomics*/
242    case OC_Dataset:      return "Dataset";
243    case OC_Sequence:     return "Sequence";
244    case OC_Grid:         return "Grid";
245    case OC_Structure:    return "Structure";
246    case OC_Dimension:    return "Dimension";
247    case OC_Attribute:    return "Attribute";
248    case OC_Attributeset: return "Attributeset";
249    case OC_Atomic:       return "Atomic";
250    default: break;
251    }
252    return "<unknown>";
253}
254
255
256OCerror
257octypeprint(OCtype etype, void* value, size_t bufsize, char* buf)
258{
259    if(buf == NULL || bufsize == 0 || value == NULL) return OC_EINVAL;
260    buf[0] = '\0';
261    switch (etype) {
262    case OC_Char:
263 snprintf(buf,bufsize,"'%c'",*(char*)value);
264 break;
265    case OC_Byte:
266 snprintf(buf,bufsize,"%d",*(signed char*)value);
267 break;
268    case OC_UByte:
269 snprintf(buf,bufsize,"%u",*(unsigned char*)value);
270 break;
271    case OC_Int16:
272 snprintf(buf,bufsize,"%d",*(short*)value);
273 break;
274    case OC_UInt16:
275 snprintf(buf,bufsize,"%u",*(unsigned short*)value);
276 break;
277    case OC_Int32:
278 snprintf(buf,bufsize,"%d",*(int*)value);
279 break;
280    case OC_UInt32:
281 snprintf(buf,bufsize,"%u",*(unsigned int*)value);
282 break;
283    case OC_Float32:
284 snprintf(buf,bufsize,"%g",*(float*)value);
285 break;
286    case OC_Float64:
287 snprintf(buf,bufsize,"%g",*(double*)value);
288 break;
289#ifdef HAVE_LONG_LONG_INT
290    case OC_Int64:
291 snprintf(buf,bufsize,"%lld",*(long long*)value);
292 break;
293    case OC_UInt64:
294 snprintf(buf,bufsize,"%llu",*(unsigned long long*)value);
295 break;
296#endif
297    case OC_String:
298    case OC_URL: {
299 char* s = *(char**)value;
300 snprintf(buf,bufsize,"\"%s\"",s);
301 } break;
302    default: break;
303    }
304    return OC_NOERR;
305}
306
307size_t
308xxdrsize(OCtype etype)
309{
310    switch (etype) {
311    case OC_Char:
312    case OC_Byte:
313    case OC_UByte:
314    case OC_Int16:
315    case OC_UInt16:
316    case OC_Int32:
317    case OC_UInt32:
318 return XDRUNIT;
319    case OC_Int64:
320    case OC_UInt64:
321 return (2*XDRUNIT);
322    case OC_Float32:
323 return XDRUNIT;
324    case OC_Float64:
325 return (2*XDRUNIT);
326    case OC_String:
327    case OC_URL:
328    default: break;
329    }
330    return 0;
331}
332
333/**************************************/
334
335char*
336ocerrstring(int err)
337{
338    if(err == 0) return "no error";
339    if(err > 0) return strerror(err);
340    switch (err) {
341 case OC_EBADID:
342     return "OC_EBADID: Not a valid ID";
343 case OC_EINVAL:
344     return "OC_EINVAL: Invalid argument";
345 case OC_EPERM:
346     return "OC_EPERM: Write to read only";
347 case OC_EINVALCOORDS:
348     return "OC_EINVALCOORDS: Index exceeds dimension bound";
349 case OC_ENOTVAR:
350     return "OC_ENOTVAR: Variable not found";
351 case OC_ECHAR:
352     return "OC_ECHAR: Attempt to convert between text & numbers";
353 case OC_EEDGE:
354     return "OC_EEDGE: Start+count exceeds dimension bound";
355 case OC_ESTRIDE:
356     return "OC_ESTRIDE: Illegal stride";
357 case OC_ENOMEM:
358     return "OC_ENOMEM: Memory allocation (malloc) failure";
359 case OC_EDIMSIZE:
360     return "OC_EDIMSIZE: Invalid dimension size";
361 case OC_EDAP:
362     return "OC_EDAP: unspecified DAP failure";
363 case OC_EXDR:
364     return "OC_EXDR: XDR failure";
365 case OC_ECURL:
366     return "OC_ECURL: unspecified libcurl failure";
367 case OC_EBADURL:
368     return "OC_EBADURL: malformed url";
369 case OC_EBADVAR:
370     return "OC_EBADVAR: no such variable";
371 case OC_EOPEN:
372     return "OC_EOPEN: temporary file open failed";
373 case OC_EIO:
374     return "OC_EIO: I/O failure";
375 case OC_ENODATA:
376     return "OC_ENODATA: Variable has no data in DAP request";
377 case OC_EDAPSVC:
378     return "OC_EDAPSVC: DAP Server error";
379 case OC_ENAMEINUSE:
380     return "OC_ENAMEINUSE: Duplicate name in DDS";
381 case OC_EDAS:
382     return "OC_EDAS: Malformed or unreadable DAS";
383 case OC_EDDS:
384     return "OC_EDDS: Malformed or unreadable DDS";
385 case OC_EDATADDS:
386     return "OC_EDATADDS: Malformed or unreadable DATADDS";
387 case OC_ERCFILE:
388     return "OC_ERCFILE: Malformed,  unreadable, or bad value in the run-time configuration file";
389 case OC_ENOFILE:
390     return "OC_ENOFILE: cannot read content of URL";
391
392 /* oc_data related errors */
393 case OC_EINDEX:
394     return "OC_EINDEX: index argument too large";
395 case OC_EBADTYPE:
396     return "OC_EBADTYPE: argument of wrong OCtype";
397
398 /* String concatenation overrun */
399 case OC_EOVERRUN:
400     return "OC_EOVERRUN: internal concatenation failed";
401
402 /* Authorization Error */
403 case OC_EAUTH:
404     return "OC_EAUTH: authorization failure";
405
406 default: break;
407    }
408    return "<unknown error code>";
409}
410
411OCerror
412ocsvcerrordata(OCstatestate, char** codep, char** msgp, long* httpp)
413{
414    if(codep) *codep = state->error.code;
415    if(msgp) *msgp = state->error.message;
416    if(httpp) *httpp = state->error.httpcode;
417    return OC_NOERR;
418}
419
420/* if we get OC_EDATADDS error, then try to capture any
421   error message and log it; assumes that in this case,
422   the datadds is not big.
423*/
424void
425ocdataddsmsg(OCstatestateOCtreetree)
426{
427#define ERRCHUNK 1024
428#define ERRFILL ' '
429#define ERRTAG "Error {"
430    int i,j;
431    size_t len;
432    XXDRxdrs;
433    char* contents;
434    off_t ckp;
435
436    if(tree == NULL) return;
437    /* get available space */
438    xdrs = tree->data.xdrs;
439    len = xxdr_length(xdrs);
440    if(len < strlen(ERRTAG))
441 return; /* no room */
442    ckp = xxdr_getpos(xdrs);
443    xxdr_setpos(xdrs,(off_t)0);
444    /* read the whole thing */
445    contents = (char*)malloc(len+1);
446    (void)xxdr_getbytes(xdrs,contents,(off_t)len);
447    contents[len] = '\0';
448    /* Look for error tag */
449    for(i=0;i<len;i++) {
450        if(ocstrncmp(contents+i,ERRTAG,strlen(ERRTAG))==0) {
451     /* log the error message */
452     /* Do a quick and dirty escape */
453     for(j=i;j<len;j++) {
454         int c = contents[i+j];
455 if(c > 0 && (c < ' ' || c >= '\177'))
456     contents[i+j] = ERRFILL;
457     }
458     oclog(OCLOGERR,"DATADDS failure, possible message: '%s'\n",
459 contents+i);
460     goto done;
461 }
462    }
463    xxdr_setpos(xdrs,ckp);
464done:
465    return;
466}
467
468/* Given some set of indices [i0][i1]...[in] (where n == rank-1)
469   and the maximum sizes, compute the linear offset
470   for set of dimension indices.
471*/
472size_t
473ocarrayoffset(size_t rank, size_t* sizes, size_t* indices)
474{
475    unsigned int i;
476    size_t count = 0;
477    for(i=0;i<rank;i++) {
478 count *= sizes[i];
479 count += indices[i];
480    }
481    return count;
482}
483
484/* Inverse of ocarrayoffset: convert linear index to a set of indices */
485void
486ocarrayindices(size_t index, size_t rank, size_t* sizes, size_t* indices)
487{
488    int i;
489    for(i=rank-1;i>=0;i--) {
490 indices[i] = index % sizes[i];
491 index = (index - indices[i]) / sizes[i];
492    }
493}
494
495/* Given some set of edge counts [i0][i1]...[in] (where n == rank-1)
496   and the maximum sizes, compute the linear offset
497   for the last edge position
498*/
499size_t
500ocedgeoffset(size_t rank, size_t* sizes, size_t* edges)
501{
502    unsigned int i;
503    size_t count = 0;
504    for(i=0;i<rank;i++) {
505 count *= sizes[i];
506 count += (edges[i]-1);
507    }
508    return count;
509}
510
511int
512ocvalidateindices(size_t rank, size_t* sizes, size_t* indices)
513{
514    int i;
515    for(i=0;i<rank;i++) {
516 if(indices[i] >= sizes[i]) return 0;
517    }
518    return 1;
519}
520
521int
522oc_ispacked(OCnodenode)
523{
524    OCtype octype = node->octype;
525    OCtype etype = node->etype;
526    int isscalar = (node->array.rank == 0);
527    int packed;
528
529    if(isscalar || octype != OC_Atomic)
530 return 0; /* is not packed */
531    packed = (etype == OC_Byte
532       || etype == OC_UByte
533              || etype == OC_Char) ? 1 : 0;
534    return packed;
535}
536
537/* Must be consistent with ocx.h.OCDT */
538#define NMODES 6
539#define MAXMODENAME 8 /*max (strlen(modestrings[i])) */
540static char* modestrings[NMODES+1] = {
541"FIELD", /* ((OCDT)(1<<0)) field of a container */
542"ELEMENT", /* ((OCDT)(1<<1)) element of a structure array */
543"RECORD", /* ((OCDT)(1<<2)) record of a sequence */
544"ARRAY", /* ((OCDT)(1<<3)) is structure array */
545"SEQUENCE", /* ((OCDT)(1<<4)) is sequence */
546"ATOMIC", /* ((OCDT)(1<<5)) is atomic leaf */
547NULL,
548};
549
550const char*
551ocdtmodestring(OCDT mode,int compact)
552{
553    static char result[1+(NMODES*(MAXMODENAME+1))]; /* hack to avoid malloc */
554    int i;
555    char* p = result;
556    result[0] = '\0';
557    if(mode == 0) {
558 if(compact) *p++ = '-';
559 else if(!occoncat(result,sizeof(result),1,"NONE"))
560     return NULL;
561    } else for(i=0;;i++) {
562 char* ms = modestrings[i];
563 if(ms == NULL) break;
564 if(!compact && i > 0)
565     if(!occoncat(result,sizeof(result),1,","))
566 return NULL;
567        if(fisset(mode,(1<<i))) {
568     if(compact) *p++ = ms[0];
569     else if(!occoncat(result,sizeof(result),1,ms))
570 return NULL;
571 }
572    }
573    /* pad compact list out to NMODES in length (+1 for null terminator) */
574    if(compact) {
575 while((p-result) < NMODES) *p++ = ' ';
576 *p = '\0';
577    }
578    return result;
579}
580
581
582/*
583Instead of using snprintf to concatenate
584multiple strings into a given target,
585provide a direct concatenator.
586So, this function concats the n argument strings
587and overwrites the contents of dst.
588Care is taken to never overrun the available
589space (the size parameter).
590Note that size is assumed to include the null
591terminator and that in the event of overrun,
592the string will have a null at dst[size-1].
593Return 0 if overrun, 1 otherwise.
594*/
595int
596occopycat(char* dst, size_t size, size_t n, ...)
597{
598    va_list args;
599    size_t avail = size - 1;
600    int i;
601    int status = 1; /* assume ok */
602    char* p = dst;
603
604    if(n == 0) {
605 if(size > 0)
606     dst[0] = '\0';
607 return (size > 0 ? 1: 0);
608    }
609
610    va_start(args,n);
611    for(i=0;i<n;i++) {
612 char* q = va_arg(args, char*);
613 for(;;) {
614     int c = *q++;
615     if(c == '\0') break;
616     if(avail == 0) {status = 0; goto done;}
617     *p++ = c;
618     avail--;
619 }
620    }
621    /* make sure we null terminate;
622       note that since avail was size-1, there
623       will always be room
624    */
625    *p = '\0';
626
627done:
628    va_end(args);
629    return status;
630}
631
632/*
633Similar to occopycat, but
634the n strings are, in effect,
635concatenated and appended to the
636current contents of dst.
637The size parameter is the total size of dst,
638including room for null terminator.
639Return 0 if overrun, 1 otherwise.
640*/
641int
642occoncat(char* dst, size_t size, size_t n, ...)
643{
644    va_list args;
645    int status = 1; /* assume ok */
646    size_t avail = 0;
647    int i;
648    char* p;
649    size_t dstused;
650    dstused = strlen(dst);
651    if(dstused >= size)
652 return 0; /* There is no room to append */
653    /* move to the end of the current contents of dst
654       and act like we are doing copycat
655    */
656    p = dst + dstused;
657    size -= dstused;
658    avail = size - 1;
659    if(n == 0) {
660 if(size > 0)
661     p[0] = '\0';
662 return (size > 0 ? 1: 0);
663    }
664
665    va_start(args,n);
666    for(i=0;i<n;i++) {
667 char* q = va_arg(args, char*);
668 for(;;) {
669     int c = *q++;
670     if(c == '\0') break;
671     if(avail == 0) {status = 0; goto done;}
672     *p++ = c;
673     avail--;
674 }
675    }
676    /* make sure we null terminate;
677       note that since avail was size-1, there
678       will always be room
679    */
680    *p = '\0';
681
682done:
683    va_end(args);
684    return status;
685}
686
687
688/**
689Wrap mktmp and return the generated name
690*/
691
692int
693ocmktmp(const char* base, char** tmpnamep)
694{
695    int fd;
696    char tmpname[OCPATHMAX+1];
697    mode_t mask;
698    if(!occopycat(tmpname,sizeof(tmpname)-1,1,base)) {
699 return OC_EOVERRUN;
700    }
701#ifdef HAVE_MKSTEMP
702    if(!occoncat(tmpname,sizeof(tmpname)-1,1,"XXXXXX")) {
703 return OC_EOVERRUN;
704    }
705    /* Note Potential problem: old versions of this function
706       leave the file in mode 0666 instead of 0600 */
707
708    mask=umask(0077);
709    fd = mkstemp(tmpname);
710    (void)umask(mask);
711#else /* !HAVE_MKSTEMP */
712    /* Need to simulate by using some kind of pseudo-random number */
713    {
714 int rno = rand();
715 char spid[7];
716 if(rno < 0) rno = -rno;
717        snprintf(spid,sizeof(spid),"%06d",rno);
718 if(!occoncat(tmpname,sizeof(tmpname)-1,1,spid)) {
719     return OC_EOVERRUN;
720        }
721#if defined(_WIN32) || defined(_WIN64)
722        fd=open(tmpname,O_RDWR|O_BINARY|O_CREAT_S_IREAD|_S_IWRITE);
723#  else
724        fd=open(tmpname,O_RDWR|O_CREAT|O_EXCLS_IRWXU);
725#  endif
726    }
727#endif /* !HAVE_MKSTEMP */
728    if(fd < 0) {
729       return OC_EOPEN;
730    } else
731 close(fd);
732    if(tmpnamep) *tmpnamep = strdup(tmpname);
733    return OC_NOERR;
734}
735
736/* merge two envv style lists */
737char**
738ocmerge(const char** list1, const char** list2)
739{
740    int l1l2;
741    char** merge;
742    const char** p;
743    for(l1=0,p=list1;*p;p++) {l1++;}
744    for(l2=0,p=list2;*p;p++) {l2++;}
745    merge = (char**)malloc(sizeof(char*)*(l1+l2+1));
746    if(merge == NULL)
747 return NULL;
748    memcpy(merge,list1,sizeof(char*)*l1);
749    memcpy(merge+l1,list2,sizeof(char*)*l2);
750    merge[l1+l2] = NULL;
751    return merge;
752}


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