source: XIOS/dev/dev_cmip6_omp/extern/src_netcdf4/ocuri.c @ 1606

Last change on this file since 1606 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: 17.2 KB
Line 
1/*********************************************************************
2 *   Copyright 2010, UCAR/Unidata
3 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 *   $Header$
5 *********************************************************************/
6
7#include "config.h"
8
9#include <stdlib.h>
10#include <string.h>
11#include <stdio.h>
12
13#include "oc.h"
14#include "ocuri.h"
15
16#define OCURIDEBUG
17
18#define LBRACKET '['
19#define RBRACKET ']'
20
21#ifndef FIX
22#define FIX(s) ((s)==NULL?"":(s))
23#endif
24
25#ifndef NILLEN
26#define NILLEN(s) ((s)==NULL?0:strlen(s))
27#endif
28
29#ifdef HAVE_STRDUP
30#  ifndef nulldup
31#  define nulldup(s) ((s)==NULL?NULL:strdup(s))
32#  endif
33#endif
34
35#ifndef HAVE_STRDUP
36static char* nulldup(char* s)
37{
38    char* dup = NULL;
39    if(s != NULL) {
40        dup = (char*)malloc(strlen(s)+1);
41        if(dup != NULL)
42            strcpy(dup,s);
43    }
44    return dup;
45}
46#endif
47
48#ifdef OCIGNORE
49/* Not all systems have strndup, so provide one*/
50static char*
51ocstrndup(const char* s, size_t len)
52{
53    char* dup;
54    if(s == NULL) return NULL;
55    dup = (char*)ocmalloc(len+1);
56    MEMCHECK(dup,NULL);
57    memcpy((void*)dup,s,len);
58    dup[len] = '\0';
59    return dup;
60}
61#endif
62
63/* Do not trust strncmp */
64static int
65ocuristrncmp(const char* s1, const char* s2, size_t len)
66{
67    const char *p,*q;
68    if(s1 == s2) return 0;
69    if(s1 == NULL) return -1;
70    if(s2 == NULL) return +1;
71    for(p=s1,q=s2;len > 0;p++,q++,len--) {
72        if(*p != *q)
73            return (*p - *q);   
74        if(*p == 0) return 0; /* *p == *q == 0 */
75    }
76    /* 1st len chars are same */
77    return 0;
78}
79
80static char* legalprotocols[] = {
81"file:",
82"http:",
83"https:",
84"ftp:",
85NULL /* NULL terminate*/
86};
87
88/* Allowable character sets for encode */
89static char* fileallow = 
90"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$&'()*+,-./:;=?@_~";
91
92static char* queryallow = 
93"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$&'()*+,-./:;=?@_~";
94
95static void ocparamfree(char** params);
96static int ocfind(char** params, const char* key);
97
98/* Do a simple uri parse: return 0 if fail, 1 otherwise*/
99int
100ocuriparse(const char* uri0, OCURI** ocurip)
101{
102    OCURI* ocuri = NULL;
103    char* uri;
104    char** pp;
105    char* p;
106    char* p1;
107    int c;
108
109    /* accumulate parse points*/
110    char* protocol = NULL;
111    char* params = NULL;
112    char* host = NULL;
113    char* port = NULL;
114    char* constraint = NULL;
115    char* user = NULL;
116    char* pwd = NULL;
117    char* file = NULL;
118
119    if(uri0 == NULL)
120        return OC_EBADURL;
121
122    ocuri = (OCURI*)calloc(1,sizeof(OCURI));
123    if(ocuri == NULL) return 0;
124
125    /* make local copy of uri */
126    uri = nulldup(uri0);
127
128    /* remove all whitespace*/
129    p = uri;
130    p1 = uri;
131    while((c=*p1++)) {if(c != ' ' && c != '\t') *p++ = c;}
132
133    p = uri;
134
135    /* break up the uri string into pieces*/
136
137    /* 1. leading bracketed parameters */
138    if(*p == LBRACKET) {
139        params = p+1;
140        /* find end of the clientparams*/
141        for(;*p;p++) {if(p[0] == RBRACKET && p[1] != LBRACKET) break;}
142        if(*p == 0) goto fail; /* malformed client params*/
143        *p = '\0'; /* leave off the trailing rbracket for now */
144        p++; /* move past the params*/
145    }
146
147    /* verify that the uri starts with an acceptable protocol*/
148    for(pp=legalprotocols;*pp;pp++) {
149        if(ocuristrncmp(p,*pp,strlen(*pp))==0) break;
150    }
151    if(*pp == NULL) goto fail; /* illegal protocol*/
152    /* save the protocol */
153    protocol = *pp;
154
155    /* 4. skip protocol */
156    p += strlen(protocol);
157
158    /* 5. skip // */
159    if(*p != '/' && *(p+1) != '/')
160        goto fail;
161    p += 2;
162
163    /* 6. Mark the end of the host section */
164    file = strchr(p,'/');
165    if(file) {
166        *file++ = '\0'; /* warning: we just overwrote the leading / */
167    } else
168        goto fail;
169
170    /* 7. extract any user:pwd */
171    p1 = strchr(p,'@');
172    if(p1) {/* Assume we have user:pwd@ */
173        *p1 = '\0';
174        user = p;
175        pwd = strchr(p,':');
176        if(!pwd) goto fail; /* malformed */
177        *pwd++ = '\0';
178        p = pwd+strlen(pwd)+1;
179    }
180
181    /* 8. extract host and port */
182    host = p;
183    port = strchr(p,':');
184    if(port) {
185        *port++ = '\0';
186    }
187
188    /* 9. Look for '?' */
189    constraint = strchr(file,'?');
190    if(constraint) {
191        *constraint++ = '\0';
192    }
193
194    /* assemble the component pieces*/
195    if(uri0 && strlen(uri0) > 0)
196        ocuri->uri = nulldup(uri0);
197    if(protocol && strlen(protocol) > 0) {
198        ocuri->protocol = nulldup(protocol);
199        /* remove trailing ':' */
200        ocuri->protocol[strlen(protocol)-1] = '\0';
201    }
202    if(user && strlen(user) > 0)
203        ocuri->user = nulldup(user);
204    if(pwd && strlen(pwd) > 0)
205        ocuri->password = nulldup(pwd);
206    if(host && strlen(host) > 0)
207        ocuri->host = nulldup(host);
208    if(port && strlen(port) > 0)
209        ocuri->port = nulldup(port);
210    if(file && strlen(file) > 0) {
211        /* Add back the leading / */
212        ocuri->file = malloc(strlen(file)+2);
213        strcpy(ocuri->file,"/");
214        strcat(ocuri->file,file);
215    }
216    if(constraint && strlen(constraint) > 0)
217        ocuri->constraint = nulldup(constraint);
218    ocurisetconstraints(ocuri,constraint);
219    if(params != NULL && strlen(params) > 0) {
220        ocuri->params = (char*)malloc(1+2+strlen(params));
221        strcpy(ocuri->params,"[");
222        strcat(ocuri->params,params);
223        strcat(ocuri->params,"]");
224    }
225
226#ifdef OCXDEBUG
227        {
228        fprintf(stderr,"ocuri:");
229        fprintf(stderr," params=|%s|",FIX(ocuri->params));
230        fprintf(stderr," protocol=|%s|",FIX(ocuri->protocol));
231        fprintf(stderr," host=|%s|",FIX(ocuri->host));
232        fprintf(stderr," port=|%s|",FIX(ocuri->port));
233        fprintf(stderr," file=|%s|",FIX(ocuri->file));
234        fprintf(stderr," constraint=|%s|",FIX(ocuri->constraint));
235        fprintf(stderr,"\n");
236    }
237#endif
238    free(uri);
239    if(ocurip != NULL) *ocurip = ocuri;
240    return 1;
241
242fail:
243    if(ocuri) ocurifree(ocuri);
244    if(uri != NULL) free(uri);
245    return 0;
246}
247
248void
249ocurifree(OCURI* ocuri)
250{
251    if(ocuri == NULL) return;
252    if(ocuri->uri != NULL) {free(ocuri->uri);}
253    if(ocuri->protocol != NULL) {free(ocuri->protocol);}
254    if(ocuri->user != NULL) {free(ocuri->user);}
255    if(ocuri->password != NULL) {free(ocuri->password);}
256    if(ocuri->host != NULL) {free(ocuri->host);}
257    if(ocuri->port != NULL) {free(ocuri->port);}
258    if(ocuri->file != NULL) {free(ocuri->file);}
259    if(ocuri->constraint != NULL) {free(ocuri->constraint);}
260    if(ocuri->projection != NULL) {free(ocuri->projection);}
261    if(ocuri->selection != NULL) {free(ocuri->selection);}
262    if(ocuri->params != NULL) {free(ocuri->params);}
263    if(ocuri->paramlist != NULL) ocparamfree(ocuri->paramlist);
264    free(ocuri);
265}
266
267/* Replace the constraints */
268void
269ocurisetconstraints(OCURI* duri,const char* constraints)
270{
271    char* proj = NULL;
272    char* select = NULL;
273    const char* p;
274
275    if(duri->constraint == NULL) free(duri->constraint);
276    if(duri->projection != NULL) free(duri->projection);
277    if(duri->selection != NULL) free(duri->selection);
278    duri->constraint = NULL;   
279    duri->projection = NULL;   
280    duri->selection = NULL;
281
282    if(constraints == NULL || strlen(constraints)==0) return;
283
284    duri->constraint = nulldup(constraints);
285    if(*duri->constraint == '?')
286        strcpy(duri->constraint,duri->constraint+1);
287
288    p = duri->constraint;
289    proj = (char*) p;
290    select = strchr(proj,'&');
291    if(select != NULL) {
292        size_t plen = (select - proj);
293        if(plen == 0) {
294            proj = NULL;
295        } else {
296            proj = (char*)malloc(plen+1);
297            memcpy((void*)proj,p,plen);
298            proj[plen] = '\0';
299        }
300        select = nulldup(select);
301    } else {
302        proj = nulldup(proj);
303        select = NULL;
304    }
305    duri->projection = proj;
306    duri->selection = select;
307}
308
309
310/* Construct a complete OC URI without the client params
311   and optionally with the constraints;
312   caller frees returned string.
313   Optionally encode the pieces.
314*/
315
316char*
317ocuribuild(OCURI* duri, const char* prefix, const char* suffix, int flags)
318{
319    size_t len = 0;
320    char* newuri;
321    char* tmpfile;
322    char* tmpsuffix;
323    char* tmpquery;
324
325    int withparams = ((flags&OCURIPARAMS)
326                        && duri->params != NULL);
327    int withuserpwd = ((flags&OCURIUSERPWD)
328                       && duri->user != NULL && duri->password != NULL);
329    int withconstraints = ((flags&OCURICONSTRAINTS)
330                           && duri->constraint != NULL);
331#ifdef NEWESCAPE
332    int encode = (flags&OCURIENCODE);
333#else
334    int encode = 0;
335#endif
336
337    if(prefix != NULL) len += NILLEN(prefix);
338    if(withparams) {
339        len += NILLEN("[]");
340        len += NILLEN(duri->params);
341    }
342    len += (NILLEN(duri->protocol)+NILLEN("://"));
343    if(withuserpwd) {
344        len += (NILLEN(duri->user)+NILLEN(duri->password)+NILLEN(":@"));
345    }
346    len += (NILLEN(duri->host));
347    if(duri->port != NULL) {
348        len += (NILLEN(":")+NILLEN(duri->port));
349    }
350   
351    tmpfile = duri->file;
352    if(encode)
353        tmpfile = ocuriencode(tmpfile,fileallow);
354    len += (NILLEN(tmpfile));
355
356    if(suffix != NULL) {
357        tmpsuffix = (char*)suffix;
358        if(encode)
359            tmpsuffix = ocuriencode(tmpsuffix,fileallow);
360        len += (NILLEN(tmpsuffix));
361    }
362
363    if(withconstraints) {
364        tmpquery = duri->constraint;
365        if(encode)
366            tmpquery = ocuriencode(tmpquery,queryallow);
367        len += (NILLEN("?")+NILLEN(tmpquery));
368    }
369
370    len += 1; /* null terminator */
371   
372    newuri = (char*)malloc(len);
373    if(newuri == NULL) return NULL;
374
375    newuri[0] = '\0';
376    if(prefix != NULL) strcat(newuri,prefix);
377    if(withparams) {
378        strcat(newuri,"[");
379        strcat(newuri,duri->params);
380        strcat(newuri,"]");
381    }
382    if(duri->protocol != NULL)
383        strcat(newuri,duri->protocol);
384    strcat(newuri,"://");
385    if(withuserpwd) {
386        strcat(newuri,duri->user);
387        strcat(newuri,":");
388        strcat(newuri,duri->password); 
389        strcat(newuri,"@");
390    }
391    if(duri->host != NULL) { /* may be null if using file: protocol */
392        strcat(newuri,duri->host);     
393    }
394    if(duri->port != NULL) {
395        strcat(newuri,":");
396        strcat(newuri,duri->port);
397    }
398
399    strcat(newuri,tmpfile);
400    if(suffix != NULL) strcat(newuri,tmpsuffix);
401    if(withconstraints) {
402        strcat(newuri,"?");
403        strcat(newuri,tmpquery);
404    }
405    return newuri;
406}
407
408/**************************************************/
409/* Parameter support */
410
411/*
412Client parameters are assumed to be
413one or more instances of bracketed pairs:
414e.g "[...][...]...".
415The bracket content in turn is assumed to be a
416comma separated list of <name>=<value> pairs.
417e.g. x=y,z=,a=b.
418If the same parameter is specifed more than once,
419then the first occurrence is used; this is so that
420is possible to forcibly override user specified
421parameters by prefixing.
422IMPORTANT: client parameter string is assumed to
423have blanks compress out.
424Returns 1 if parse suceeded, 0 otherwise;
425*/
426
427int
428ocuridecodeparams(OCURI* ocuri)
429{
430    char* cp;
431    char* cq;
432    int c;
433    int i;
434    int nparams;
435    char* params0;
436    char* params;
437    char* params1;
438    char** plist;
439
440    if(ocuri == NULL) return 0;
441    if(ocuri->params == NULL) return 1;
442
443    params0 = ocuri->params;
444
445    /* Pass 1 to replace beginning '[' and ending ']' */
446    if(params0[0] == '[') 
447        params = nulldup(params0+1);
448    else
449        params = nulldup(params0);     
450
451    if(params[strlen(params)-1] == ']')
452        params[strlen(params)-1] = '\0';
453
454    /* Pass 2 to replace "][" pairs with ','*/
455    params1 = nulldup(params);
456    cp=params; cq = params1;
457    while((c=*cp++)) {
458        if(c == RBRACKET && *cp == LBRACKET) {cp++; c = ',';}
459        *cq++ = c;
460    }
461    *cq = '\0';
462    free(params);
463    params = params1;
464
465    /* Pass 3 to break string into pieces and count # of pairs */
466    nparams=0;
467    for(cp=params;(c=*cp);cp++) {
468        if(c == ',') {*cp = '\0'; nparams++;}
469    }
470    nparams++; /* for last one */
471
472    /* plist is an env style list */
473    plist = (char**)calloc(1,sizeof(char*)*(2*nparams+1)); /* +1 for null termination */
474
475    /* Pass 4 to break up each pass into a (name,value) pair*/
476    /* and insert into the param list */
477    /* parameters of the form name name= are converted to name=""*/
478    cp = params;
479    for(i=0;i<nparams;i++) {
480        char* next = cp+strlen(cp)+1; /* save ptr to next pair*/
481        char* vp;
482        /*break up the ith param*/
483        vp = strchr(cp,'=');
484        if(vp != NULL) {*vp = '\0'; vp++;} else {vp = "";}
485        plist[2*i] = nulldup(cp);       
486        plist[2*i+1] = nulldup(vp);
487        cp = next;
488    }
489    plist[2*nparams] = NULL;
490    free(params);
491    if(ocuri->paramlist != NULL)
492        ocparamfree(ocuri->paramlist);
493    ocuri->paramlist = plist;
494    return 1;
495}
496
497const char*
498ocurilookup(OCURI* uri, const char* key)
499{
500    int i;
501    if(uri == NULL || key == NULL || uri->params == NULL) return NULL;
502    if(uri->paramlist == NULL) {
503        i = ocuridecodeparams(uri);
504        if(!i) return 0;
505    }
506    i = ocfind(uri->paramlist,key);
507    if(i >= 0)
508        return uri->paramlist[(2*i)+1];
509    return NULL;
510}
511
512int
513ocurisetparams(OCURI* uri, const char* newparams)
514{
515    if(uri == NULL) return 0;
516    if(uri->paramlist != NULL) ocparamfree(uri->paramlist);
517    uri->paramlist = NULL;
518    if(uri->params != NULL) free(uri->params);
519    uri->params = nulldup(newparams);
520    return 1;
521}
522
523/* Internal version of lookup; returns the paired index of the key */
524static int
525ocfind(char** params, const char* key)
526{
527    int i;
528    char** p;
529    for(i=0,p=params;*p;p+=2,i++) {
530        if(strcmp(key,*p)==0) return i;
531    }
532    return -1;
533}
534
535static void
536ocparamfree(char** params)
537{
538    char** p;
539    if(params == NULL) return;
540    for(p=params;*p;p+=2) {
541        free(*p);
542        if(p[1] != NULL) free(p[1]);
543    }
544    free(params);
545}
546
547#ifdef OCIGNORE
548/*
549Delete the entry.
550return value = 1 => found and deleted;
551               0 => param not found
552*/
553int
554ocparamdelete(char** params, const char* key)
555{
556    int i;
557    char** p;
558    char** q;
559    if(params == NULL || key == NULL) return 0;
560    i = ocfind(params,key);
561    if(i < 0) return 0;
562    p = params+(2*i);
563    for(q=p+2;*q;) {   
564        *p++ = *q++;
565    }
566    *p = NULL;
567    return 1;
568}
569
570static int
571oclength(char** params)
572{
573    int i = 0;
574    if(params != NULL) {
575        while(*params) {params+=2; i++;}
576    }
577    return i;
578}
579
580/*
581Insert new client param (name,value);
582return value = 1 => not already defined
583               0 => param already defined (no change)
584*/
585char**
586ocparaminsert(char** params, const char* key, const char* value)
587{
588    int i;
589    char** newp;
590    size_t len;
591    if(params == NULL || key == NULL) return 0;
592    i = ocfind(params,key);
593    if(i >= 0) return 0;
594    /* not found, append */
595    i = oclength(params);
596    len = sizeof(char*)*((2*i)+1);
597    newp = realloc(params,len+2*sizeof(char*));
598    memcpy(newp,params,len);
599    newp[2*i] = nulldup(key);
600    newp[2*i+1] = (value==NULL?NULL:nulldup(value));
601    return newp;
602}
603
604/*
605Replace new client param (name,value);
606return value = 1 => replacement performed
607               0 => key not found (no change)
608*/
609int
610ocparamreplace(char** params, const char* key, const char* value)
611{
612    int i;
613    if(params == NULL || key == NULL) return 0;
614    i = ocfind(params,key);
615    if(i < 0) return 0;
616    if(params[2*i+1] != NULL) free(params[2*i+1]);
617    params[2*i+1] = nulldup(value);
618    return 1;
619}
620#endif
621
622
623/* Provide % encoders and decoders */
624
625
626static char* hexchars = "0123456789abcdefABCDEF";
627
628static void
629toHex(unsigned int b, char hex[2])
630{
631    hex[0] = hexchars[(b >> 4) & 0xff];
632    hex[1] = hexchars[(b) & 0xff];
633}
634
635
636static unsigned int
637fromHex(int c)
638{
639    if(c >= '0' && c <= '9') return (c - '0');
640    if(c >= 'a' && c <= 'f') return (10 + (c - 'a'));
641    if(c >= 'A' && c <= 'F') return (10 + (c - 'A'));
642    return -1;
643}
644
645
646/* Return a string representing encoding of input; caller must free;
647   watch out: will encode whole string, so watch what you give it.
648   Allowable argument specifies characters that do not need escaping.
649 */
650
651char*
652ocuriencode(char* s, char* allowable)
653{
654    size_t slen;
655    char* encoded;
656    char* inptr;
657    char* outptr;
658
659    if(s == NULL) return NULL;
660
661    slen = strlen(s);
662    encoded = (char*)malloc((3*slen) + 1); /* max possible size */
663
664    for(inptr=s,outptr=encoded;*inptr;) {
665        int c = *inptr++;
666        if(c == ' ') {
667            *outptr++ = '+';
668        } else {
669            /* search allowable */
670            int c2;
671            char* a = allowable;
672            while((c2=*a++)) {
673                if(c == c2) break;
674            }
675            if(c2) {*outptr++ = c;}
676            else {
677                char hex[2];
678                toHex(c,hex);
679                *outptr++ = '%';
680                *outptr++ = hex[0];
681                *outptr++ = hex[1];
682            }
683        }
684    }
685    *outptr = '\0';
686    return encoded;
687}
688
689/* Return a string representing decoding of input; caller must free;*/
690char*
691ocuridecode(char* s)
692{
693    return ocuridecodeonly(s,NULL);
694}
695
696/* Return a string representing decoding of input only for specified
697   characters;  caller must free
698*/
699char*
700ocuridecodeonly(char* s, char* only)
701{
702    size_t slen;
703    char* decoded;
704    char* outptr;
705    char* inptr;
706    unsigned int c;
707   
708    if (s == NULL) return NULL;
709    if(only == NULL) only = "";
710
711    slen = strlen(s);
712    decoded = (char*)malloc(slen+1); /* Should be max we need */
713
714    outptr = decoded;
715    inptr = s;
716    while((c = *inptr++)) {
717        if(c == '+' && strchr(only,'+') != NULL)
718            *outptr++ = ' ';
719        else if(c == '%') {
720            /* try to pull two hex more characters */
721            if(inptr[0] != '\0' && inptr[1] != '\0'
722                && strchr(hexchars,inptr[0]) != NULL
723                && strchr(hexchars,inptr[1]) != NULL) {
724                /* test conversion */
725                int xc = (fromHex(inptr[0]) << 4) | (fromHex(inptr[1]));
726                if(strchr(only,xc) != NULL) {
727                    inptr += 2; /* decode it */
728                    c = xc;
729                }
730            }
731        }
732        *outptr++ = c;
733    }
734    *outptr = '\0';
735    return decoded;
736}
737
Note: See TracBrowser for help on using the repository browser.