mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-11-21 03:13:42 +08:00
fcecd1a2bc
effectively o(n cubed); modified to be o(n squared). 2. If the list of prefetched variables is too long, (something on the order of 400 variables), then the server may reject it. Modified code so that in the case that the set of prefetch'd vars is the in fact all variables, it does not create a long request. This does not actually solve the problem if the prefetch list is long, but not all inclusive.
832 lines
21 KiB
C
832 lines
21 KiB
C
/*********************************************************************
|
|
* Copyright 2010, UCAR/Unidata
|
|
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
|
* $Header$
|
|
*********************************************************************/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
|
|
#include "ocuri.h"
|
|
|
|
#define OCURIDEBUG
|
|
|
|
#ifdef OCURIDEBUG
|
|
static int failpoint = 0;
|
|
#define THROW(n) {failpoint=(n); goto fail;}
|
|
#else
|
|
#define THROW(n)
|
|
#endif
|
|
|
|
|
|
#define PADDING 8
|
|
|
|
#define LBRACKET '['
|
|
#define RBRACKET ']'
|
|
#define EOFCHAR '\0'
|
|
|
|
#ifndef FIX
|
|
#define FIX(s) ((s)==NULL?"NULL":(s))
|
|
#endif
|
|
|
|
#ifndef NILLEN
|
|
#define NILLEN(s) ((s)==NULL?0:strlen(s))
|
|
#endif
|
|
|
|
#ifndef nulldup
|
|
#define nulldup(s) ((s)==NULL?NULL:strdup(s))
|
|
#endif
|
|
|
|
#define terminate(p) {*(p) = EOFCHAR;}
|
|
|
|
#define endof(p) ((p)+strlen(p))
|
|
|
|
static struct OC_ProtocolInfo {
|
|
char* name;
|
|
int filelike; /* 1=>this protocol has no host, user+pwd, or port */
|
|
} legalprotocols[] = {
|
|
{"file",1},
|
|
{"http",0},
|
|
{"https",0},
|
|
{"ftp",0},
|
|
};
|
|
|
|
/* Allowable character sets for encode */
|
|
static char* fileallow =
|
|
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$&'()*+,-./:;=?@_~";
|
|
|
|
static char* queryallow =
|
|
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$&'()*+,-./:;=?@_~";
|
|
|
|
/* Forward */
|
|
static void ocparamfree(char** params);
|
|
static int ocfind(char** params, const char* key);
|
|
static void oclshift1(char* p);
|
|
static void ocrshift1(char* p);
|
|
static char* oclocate(char* p, const char* charlist);
|
|
static void ocappendparams(char* newuri, char** p);
|
|
|
|
/* Do a simple uri parse: return 0 if fail, 1 otherwise*/
|
|
int
|
|
ocuriparse(const char* uri0, OCURI** durip)
|
|
{
|
|
OCURI* duri = NULL;
|
|
char* uri = NULL;
|
|
char* p;
|
|
struct OC_ProtocolInfo* proto;
|
|
int i,nprotos;
|
|
|
|
/* accumulate parse points*/
|
|
char* protocol = NULL;
|
|
char* host = NULL;
|
|
char* port = NULL;
|
|
char* constraint = NULL;
|
|
char* user = NULL;
|
|
char* pwd = NULL;
|
|
char* file = NULL;
|
|
char* prefixparams = NULL;
|
|
char* suffixparams = NULL;
|
|
|
|
if(uri0 == NULL || strlen(uri0) == 0)
|
|
{THROW(1); goto fail;}
|
|
|
|
duri = (OCURI*)calloc(1,sizeof(OCURI));
|
|
if(duri == NULL)
|
|
{THROW(2); goto fail;}
|
|
|
|
/* save original uri */
|
|
duri->uri = nulldup(uri0);
|
|
|
|
/* make local copy of uri */
|
|
uri = (char*)malloc(strlen(uri0)+1+PADDING); /* +1 for trailing null,
|
|
+PADDING for shifting */
|
|
if(uri == NULL)
|
|
{THROW(3); goto fail;}
|
|
|
|
/* strings will be broken into pieces with intermixed '\0; characters;
|
|
first char is guaranteed to be '\0' */
|
|
|
|
duri->strings = uri;
|
|
uri++;
|
|
|
|
/* dup the incoming url */
|
|
strcpy(uri,uri0);
|
|
|
|
/* Walk the uri and do the following:
|
|
1. remove all whitespace
|
|
2. remove all '\\' (Temp hack to remove escape characters
|
|
inserted by Windows or MinGW)
|
|
*/
|
|
for(p=uri;*p;p++) {
|
|
if(*p == '\\' || *p < ' ')
|
|
oclshift1(p); /* compress out */
|
|
}
|
|
|
|
p = uri;
|
|
|
|
/* break up the uri string into big chunks: prefixparams, protocol,
|
|
host section, and the file section (i.e. remainder)
|
|
*/
|
|
|
|
/* collect any prefix bracketed parameters */
|
|
if(*p == LBRACKET) {
|
|
prefixparams = p+1;
|
|
/* find end of the clientparams; convert LB,RB to ';' */
|
|
for(;*p;p++) {
|
|
if(p[0] == RBRACKET && p[1] == LBRACKET) {
|
|
p[0] = ';';
|
|
oclshift1(p+1);
|
|
} else if(p[0] == RBRACKET && p[1] != LBRACKET)
|
|
break;
|
|
}
|
|
if(*p == 0)
|
|
{THROW(4); goto fail; /* malformed client params*/}
|
|
terminate(p); /* nul term the prefixparams (overwrites
|
|
the final RBRACKET) */
|
|
p++; /* move past the final RBRACKET */
|
|
}
|
|
|
|
/* Tag the protocol */
|
|
protocol = p;
|
|
p = strchr(p,':');
|
|
if(!p)
|
|
{THROW(5); goto fail;}
|
|
terminate(p); /*overwrite colon*/
|
|
p++; /* skip the colon */
|
|
|
|
/* verify that the uri starts with an acceptable protocol*/
|
|
nprotos = (sizeof(legalprotocols)/sizeof(struct OC_ProtocolInfo));
|
|
proto = NULL;
|
|
for(i=0;i<nprotos;i++) {
|
|
if(strcmp(protocol,legalprotocols[i].name)==0) {
|
|
proto = &legalprotocols[i];
|
|
break;
|
|
}
|
|
}
|
|
if(proto == NULL)
|
|
{THROW(6); goto fail; /* illegal protocol*/}
|
|
|
|
/* skip // */
|
|
if(p[0] != '/' && p[1] != '/')
|
|
{THROW(7); goto fail;}
|
|
p += 2;
|
|
|
|
/* If this is all we have (proto://) then fail */
|
|
if(*p == EOFCHAR)
|
|
{THROW(8); goto fail;}
|
|
|
|
/* establish the start of the file section */
|
|
if(proto->filelike) {/* everything after proto:// */
|
|
file = p;
|
|
host = NULL; /* and no host section */
|
|
} else { /*!proto->filelike => This means there should be a host section */
|
|
/* locate the end of the host section and therefore the start
|
|
of the file section */
|
|
host = p;
|
|
p = oclocate(p,"/?#");
|
|
if(p == NULL) {
|
|
file = endof(host); /* there is no file section */
|
|
} else {
|
|
ocrshift1(p); /* make room to terminate the host section
|
|
without overwriting the leading character */
|
|
terminate(p); /* terminate the host section */
|
|
file = p+1; /* +1 becauseof the shift */
|
|
}
|
|
}
|
|
|
|
/* If you shift in the code below, you must reset file beginning */
|
|
|
|
if(host != NULL) {/* Parse the host section */
|
|
/* Check for leading user:pwd@ */
|
|
p = strchr(host,'@');
|
|
if(p) {
|
|
if(p == host)
|
|
{THROW(9); goto fail; /* we have proto://@ */}
|
|
user = host;
|
|
terminate(p); /* overwrite '@' */
|
|
host = p+1; /* start of host ip name */
|
|
p = strchr(user,':');
|
|
if(p == NULL)
|
|
{THROW(10); goto fail; /* malformed */}
|
|
terminate(p); /*overwrite colon */
|
|
pwd = p+1;
|
|
}
|
|
|
|
/* extract host and port */
|
|
p = host;
|
|
p = strchr(p,':');
|
|
if(p != NULL) {
|
|
terminate(p);
|
|
p++;
|
|
port = p;
|
|
if(*port == EOFCHAR)
|
|
{THROW(11); goto fail; /* we have proto://...:/ */}
|
|
/* The port must look something like a number */
|
|
for(;*p;p++) {
|
|
if(strchr("0123456789-",*p) == NULL)
|
|
{THROW(12); goto fail; /* probably not a real port, fail */}
|
|
}
|
|
} /* else *p == NULL */
|
|
|
|
|
|
/* check for empty host section */
|
|
if(*host == EOFCHAR)
|
|
{THROW(13); goto fail;}
|
|
|
|
}
|
|
|
|
assert(file != NULL);
|
|
p = file;
|
|
|
|
/* find the end of the file section and the start of the
|
|
constraints and/or suffixparams
|
|
*/
|
|
p = oclocate(p,"?#");
|
|
if(p != NULL) { /* we have constraint and/or suffixparams */
|
|
char* fileend = p; /* save the end of the file section */
|
|
char* constraintend = NULL;
|
|
if(*p == '?')
|
|
constraint = p+1;
|
|
else
|
|
constraint = NULL;
|
|
p = strchr(p,'#'); /* may repeat effect of oclocate above */
|
|
if(p != NULL) {
|
|
constraintend = p;
|
|
suffixparams = p+1;
|
|
} else
|
|
suffixparams = NULL;
|
|
/* Ok, terminate the pieces */
|
|
terminate(fileend); /* terminate file section */
|
|
if(constraint != NULL && constraintend != NULL)
|
|
terminate(constraintend);
|
|
/* Suffix params are already terminated
|
|
since they should be the last section
|
|
of the original url
|
|
*/
|
|
}
|
|
|
|
/* check for empty sections */
|
|
if(file != NULL && *file == EOFCHAR)
|
|
file = NULL; /* empty file section */
|
|
if(constraint != NULL && *constraint == EOFCHAR)
|
|
constraint = NULL; /* empty constraint section */
|
|
if(suffixparams != NULL && *suffixparams == EOFCHAR)
|
|
suffixparams = NULL; /* empty suffixparams section */
|
|
|
|
if(suffixparams != NULL) {
|
|
/* there really are suffix params; so rebuild the suffix params */
|
|
p = suffixparams;
|
|
/* There must be brackets */
|
|
if(*p != LBRACKET)
|
|
{THROW(14); goto fail;}
|
|
suffixparams++; /* skip leading LBRACKET */
|
|
p = suffixparams;
|
|
/* convert RBRACKET LBRACKET to ';' */
|
|
for(;*p;p++) {
|
|
if(p[0] == RBRACKET && p[1] == LBRACKET) {
|
|
p[0] = ';';
|
|
oclshift1(p+1);
|
|
} else if(p[0] == RBRACKET && p[1] != LBRACKET) {
|
|
/* terminate suffixparams */
|
|
*p = EOFCHAR;
|
|
break;
|
|
}
|
|
}
|
|
if(*suffixparams == EOFCHAR)
|
|
suffixparams = NULL; /* suffixparams are empty */
|
|
}
|
|
|
|
/* do last minute empty check */
|
|
if(protocol != NULL && *protocol == EOFCHAR) protocol = NULL;
|
|
if(user != NULL && *user == EOFCHAR) user = NULL;
|
|
if(pwd != NULL && *pwd == EOFCHAR) pwd = NULL;
|
|
if(host != NULL && *host == EOFCHAR) host = NULL;
|
|
if(port != NULL && *port == EOFCHAR) port = NULL;
|
|
if(file != NULL && *file == EOFCHAR) file = NULL;
|
|
if(constraint != NULL && *constraint == EOFCHAR) constraint = NULL;
|
|
|
|
/* assemble the component pieces */
|
|
duri->protocol = protocol;
|
|
duri->user = user;
|
|
duri->password = pwd;
|
|
duri->host = host;
|
|
duri->port = port;
|
|
duri->file = file;
|
|
|
|
ocurisetconstraints(duri,constraint);
|
|
|
|
/* concat suffix and prefix params */
|
|
if(prefixparams != NULL || suffixparams != NULL) {
|
|
int plen = prefixparams ? strlen(prefixparams) : 0;
|
|
int slen = suffixparams ? strlen(suffixparams) : 0;
|
|
int space = plen + slen + 1;
|
|
/* add 1 for an extra comma if both are defined */
|
|
space++;
|
|
duri->params = (char*)malloc(space);
|
|
duri->params[0] = EOFCHAR; /* so we can use strcat */
|
|
if(plen > 0) {
|
|
strcat(duri->params,prefixparams);
|
|
if(slen > 0)
|
|
strcat(duri->params,";");
|
|
}
|
|
if(slen > 0)
|
|
strcat(duri->params,suffixparams);
|
|
}
|
|
|
|
#ifdef OCXDEBUG
|
|
{
|
|
fprintf(stderr,"duri:");
|
|
fprintf(stderr," params=|%s|",FIX(duri->params));
|
|
fprintf(stderr," protocol=|%s|",FIX(duri->protocol));
|
|
fprintf(stderr," host=|%s|",FIX(duri->host));
|
|
fprintf(stderr," port=|%s|",FIX(duri->port));
|
|
fprintf(stderr," file=|%s|",FIX(duri->file));
|
|
fprintf(stderr," constraint=|%s|",FIX(duri->constraint));
|
|
fprintf(stderr,"\n");
|
|
}
|
|
#endif
|
|
if(durip != NULL) *durip = duri; else free(duri);
|
|
return 1;
|
|
|
|
fail:
|
|
if(duri != NULL) {
|
|
ocurifree(duri);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
ocurifree(OCURI* duri)
|
|
{
|
|
if(duri == NULL) return;
|
|
if(duri->uri != NULL) {free(duri->uri);}
|
|
if(duri->params != NULL) {free(duri->params);}
|
|
if(duri->paramlist != NULL) ocparamfree(duri->paramlist);
|
|
if(duri->strings != NULL) {free(duri->strings);}
|
|
if(duri->constraint != NULL) {free(duri->constraint);}
|
|
if(duri->projection != NULL) {free(duri->projection);}
|
|
if(duri->selection != NULL) {free(duri->selection);}
|
|
free(duri);
|
|
}
|
|
|
|
/* Replace the constraints */
|
|
void
|
|
ocurisetconstraints(OCURI* duri,const char* constraints)
|
|
{
|
|
char* proj = NULL;
|
|
char* select = NULL;
|
|
const char* p;
|
|
|
|
if(duri->constraint != NULL) free(duri->constraint);
|
|
if(duri->projection != NULL) free(duri->projection);
|
|
if(duri->selection != NULL) free(duri->selection);
|
|
duri->constraint = NULL;
|
|
duri->projection = NULL;
|
|
duri->selection = NULL;
|
|
|
|
if(constraints == NULL || strlen(constraints)==0) return;
|
|
|
|
duri->constraint = nulldup(constraints);
|
|
if(*duri->constraint == '?')
|
|
oclshift1(duri->constraint);
|
|
|
|
p = duri->constraint;
|
|
proj = (char*) p;
|
|
select = strchr(proj,'&');
|
|
if(select != NULL) {
|
|
size_t plen = (select - proj);
|
|
if(plen == 0) {
|
|
proj = NULL;
|
|
} else {
|
|
proj = (char*)malloc(plen+1);
|
|
memcpy((void*)proj,p,plen);
|
|
proj[plen] = EOFCHAR;
|
|
}
|
|
select = nulldup(select);
|
|
} else {
|
|
proj = nulldup(proj);
|
|
select = NULL;
|
|
}
|
|
duri->projection = proj;
|
|
duri->selection = select;
|
|
}
|
|
|
|
|
|
/* Construct a complete OC URI.
|
|
Optionally with the constraints.
|
|
Optionally with the user parameters.
|
|
Caller frees returned string.
|
|
Optionally encode the pieces.
|
|
*/
|
|
|
|
char*
|
|
ocuribuild(OCURI* duri, const char* prefix, const char* suffix, int flags)
|
|
{
|
|
size_t len = 0;
|
|
char* newuri;
|
|
char* tmpfile;
|
|
char* tmpsuffix;
|
|
char* tmpquery;
|
|
int nparams = 0;
|
|
int paramslen = 0;
|
|
|
|
/* if both are specified, prefix has priority */
|
|
int withsuffixparams = ((flags&OCURISUFFIXPARAMS)!=0
|
|
&& duri->params != NULL);
|
|
int withprefixparams = ((flags&OCURIPREFIXPARAMS)!=0
|
|
&& duri->params != NULL);
|
|
int withuserpwd = ((flags&OCURIUSERPWD)!=0
|
|
&& duri->user != NULL && duri->password != NULL);
|
|
int withconstraints = ((flags&OCURICONSTRAINTS)!=0
|
|
&& duri->constraint != NULL);
|
|
#ifdef NEWESCAPE
|
|
int encode = (flags&OCURIENCODE);
|
|
#else
|
|
int encode = 0;
|
|
#endif
|
|
|
|
if(prefix != NULL) len += NILLEN(prefix);
|
|
len += (NILLEN(duri->protocol)+NILLEN("://"));
|
|
if(withuserpwd) {
|
|
len += (NILLEN(duri->user)+NILLEN(duri->password)+NILLEN(":@"));
|
|
}
|
|
len += (NILLEN(duri->host));
|
|
if(duri->port != NULL) {
|
|
len += (NILLEN(":")+NILLEN(duri->port));
|
|
}
|
|
|
|
tmpfile = duri->file;
|
|
if(encode)
|
|
tmpfile = ocuriencode(tmpfile,fileallow);
|
|
len += (NILLEN(tmpfile));
|
|
|
|
if(suffix != NULL) {
|
|
tmpsuffix = (char*)suffix;
|
|
if(encode)
|
|
tmpsuffix = ocuriencode(tmpsuffix,fileallow);
|
|
len += (NILLEN(tmpsuffix));
|
|
}
|
|
|
|
if(withconstraints) {
|
|
tmpquery = duri->constraint;
|
|
if(encode)
|
|
tmpquery = ocuriencode(tmpquery,queryallow);
|
|
len += (NILLEN("?")+NILLEN(tmpquery));
|
|
}
|
|
|
|
if(withprefixparams || withsuffixparams) {
|
|
char** p;
|
|
if(duri->paramlist == NULL)
|
|
if(!ocuridecodeparams(duri))
|
|
return NULL;
|
|
for(paramslen=0,nparams=0,p=duri->paramlist;*p;p++) {
|
|
nparams++;
|
|
paramslen += NILLEN(*p);
|
|
}
|
|
if(nparams % 2 == 1)
|
|
return NULL; /* malformed */
|
|
nparams = (nparams / 2);
|
|
len += paramslen;
|
|
len += 3*nparams; /* for brackets for every param plus possible = */
|
|
if(withsuffixparams)
|
|
len += strlen("#");
|
|
}
|
|
|
|
len += 1; /* null terminator */
|
|
|
|
newuri = (char*)malloc(len);
|
|
if(newuri == NULL) return NULL;
|
|
|
|
newuri[0] = EOFCHAR;
|
|
if(prefix != NULL) strcat(newuri,prefix);
|
|
if(withprefixparams) {
|
|
ocappendparams(newuri,duri->paramlist);
|
|
}
|
|
if(duri->protocol != NULL)
|
|
strcat(newuri,duri->protocol);
|
|
strcat(newuri,"://");
|
|
if(withuserpwd) {
|
|
strcat(newuri,duri->user);
|
|
strcat(newuri,":");
|
|
strcat(newuri,duri->password);
|
|
strcat(newuri,"@");
|
|
}
|
|
if(duri->host != NULL) { /* may be null if using file: protocol */
|
|
strcat(newuri,duri->host);
|
|
}
|
|
if(duri->port != NULL) {
|
|
strcat(newuri,":");
|
|
strcat(newuri,duri->port);
|
|
}
|
|
|
|
if(tmpfile != NULL) {
|
|
strcat(newuri,tmpfile);
|
|
if(suffix != NULL) strcat(newuri,tmpsuffix);
|
|
}
|
|
if(withconstraints) {
|
|
strcat(newuri,"?");
|
|
strcat(newuri,tmpquery);
|
|
}
|
|
if(withsuffixparams & !withprefixparams) {
|
|
strcat(newuri,"#");
|
|
ocappendparams(newuri,duri->paramlist);
|
|
}
|
|
return newuri;
|
|
}
|
|
|
|
static void
|
|
ocappendparams(char* newuri, char** p)
|
|
{
|
|
while(*p) {
|
|
strcat(newuri,"[");
|
|
strcat(newuri,*p++);
|
|
if(strlen(*p) > 0) {
|
|
strcat(newuri,"=");
|
|
strcat(newuri,*p);
|
|
}
|
|
p++;
|
|
strcat(newuri,"]");
|
|
}
|
|
}
|
|
|
|
/**************************************************/
|
|
/* Parameter support */
|
|
|
|
/*
|
|
In the original url, client parameters are assumed to be one
|
|
or more instances of bracketed pairs: e.g "[...][...]...".
|
|
They may occur either at the front, or suffixed after
|
|
a trailing # character After processing, the list is
|
|
converted to a semicolon separated list of the combination
|
|
of prefix and suffix parameters.
|
|
|
|
After the url is parsed, the parameter list
|
|
is converted to a semicolon separated list with all
|
|
whitespace removed.
|
|
In any case, each parameter in turn is assumed to be a
|
|
of the form <name>=<value> or [<name>].
|
|
e.g. [x=y][z][a=b][w]. If the same parameter is specified more
|
|
than once, then the first occurrence is used; this is so
|
|
that is possible to forcibly override user specified
|
|
parameters by prefixing. IMPORTANT: client parameter string
|
|
is assumed to have blanks compressed out. Returns 1 if parse
|
|
suceeded, 0 otherwise; */
|
|
|
|
int
|
|
ocuridecodeparams(OCURI* ocuri)
|
|
{
|
|
char* cp;
|
|
int i,c;
|
|
int nparams;
|
|
char* params;
|
|
char** plist;
|
|
|
|
if(ocuri == NULL) return 0;
|
|
if(ocuri->params == NULL) return 1;
|
|
|
|
params = strdup(ocuri->params); /* so we can modify */
|
|
|
|
/* Pass 1 to break string into pieces at the semicolons
|
|
and count # of pairs */
|
|
nparams=0;
|
|
for(cp=params;(c=*cp);cp++) {
|
|
if(c == ';') {*cp = EOFCHAR; nparams++;}
|
|
}
|
|
nparams++; /* for last one */
|
|
|
|
/* plist is an env style list */
|
|
plist = (char**)calloc(1,sizeof(char*)*(2*nparams+1)); /* +1 for null termination */
|
|
|
|
/* Break up each param into a (name,value) pair*/
|
|
/* and insert into the param list */
|
|
/* parameters of the form name name= are converted to name=""*/
|
|
for(cp=params,i=0;i<nparams;i++) {
|
|
char* next = cp+strlen(cp)+1; /* save ptr to next pair*/
|
|
char* vp;
|
|
/*break up the ith param*/
|
|
vp = strchr(cp,'=');
|
|
if(vp != NULL) {*vp = EOFCHAR; vp++;} else {vp = "";}
|
|
plist[2*i] = nulldup(cp);
|
|
plist[2*i+1] = nulldup(vp);
|
|
cp = next;
|
|
}
|
|
plist[2*nparams] = NULL;
|
|
free(params);
|
|
if(ocuri->paramlist != NULL)
|
|
ocparamfree(ocuri->paramlist);
|
|
ocuri->paramlist = plist;
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
ocurilookup(OCURI* uri, const char* key, const char** resultp)
|
|
{
|
|
int i;
|
|
char* value = NULL;
|
|
if(uri == NULL || key == NULL || uri->params == NULL) return 0;
|
|
if(uri->paramlist == NULL) {
|
|
i = ocuridecodeparams(uri);
|
|
if(!i) return 0;
|
|
}
|
|
i = ocfind(uri->paramlist,key);
|
|
if(i < 0)
|
|
return 0;
|
|
value = uri->paramlist[(2*i)+1];
|
|
if(resultp) *resultp = value;
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
ocurisetparams(OCURI* uri, const char* newparams)
|
|
{
|
|
if(uri == NULL) return 0;
|
|
if(uri->paramlist != NULL) ocparamfree(uri->paramlist);
|
|
uri->paramlist = NULL;
|
|
if(uri->params != NULL) free(uri->params);
|
|
uri->params = nulldup(newparams);
|
|
return 1;
|
|
}
|
|
|
|
/* Internal version of lookup; returns the paired index of the key */
|
|
static int
|
|
ocfind(char** params, const char* key)
|
|
{
|
|
int i;
|
|
char** p;
|
|
for(i=0,p=params;*p;p+=2,i++) {
|
|
if(strcmp(key,*p)==0) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static void
|
|
ocparamfree(char** params)
|
|
{
|
|
char** p;
|
|
if(params == NULL) return;
|
|
for(p=params;*p;p+=2) {
|
|
free(*p);
|
|
if(p[1] != NULL) free(p[1]);
|
|
}
|
|
free(params);
|
|
}
|
|
|
|
|
|
/* Return the ptr to the first occurrence of
|
|
any char in the list. Return NULL if no
|
|
occurrences
|
|
*/
|
|
static char*
|
|
oclocate(char* p, const char* charlist)
|
|
{
|
|
for(;*p;p++) {
|
|
if(strchr(charlist,*p) != NULL)
|
|
return p;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* Shift every char starting at p 1 place to the left */
|
|
static void
|
|
oclshift1(char* p)
|
|
{
|
|
if(p != NULL && *p != EOFCHAR) {
|
|
char* q = p++;
|
|
while((*q++=*p++));
|
|
}
|
|
}
|
|
|
|
/* Shift every char starting at p 1 place to the right */
|
|
static void
|
|
ocrshift1(char* p)
|
|
{
|
|
char cur;
|
|
cur = 0;
|
|
do {
|
|
char next = *p;
|
|
*p++ = cur;
|
|
cur = next;
|
|
} while(cur != 0);
|
|
*p = 0; /* make sure we are still null terminated */
|
|
}
|
|
|
|
|
|
/* Provide % encoders and decoders */
|
|
|
|
|
|
static char* hexchars = "0123456789abcdefABCDEF";
|
|
|
|
static void
|
|
toHex(unsigned int b, char hex[2])
|
|
{
|
|
hex[0] = hexchars[(b >> 4) & 0xff];
|
|
hex[1] = hexchars[(b) & 0xff];
|
|
}
|
|
|
|
|
|
static unsigned int
|
|
fromHex(int c)
|
|
{
|
|
if(c >= '0' && c <= '9') return (c - '0');
|
|
if(c >= 'a' && c <= 'f') return (10 + (c - 'a'));
|
|
if(c >= 'A' && c <= 'F') return (10 + (c - 'A'));
|
|
return -1;
|
|
}
|
|
|
|
|
|
/* Return a string representing encoding of input; caller must free;
|
|
watch out: will encode whole string, so watch what you give it.
|
|
Allowable argument specifies characters that do not need escaping.
|
|
*/
|
|
|
|
char*
|
|
ocuriencode(char* s, char* allowable)
|
|
{
|
|
size_t slen;
|
|
char* encoded;
|
|
char* inptr;
|
|
char* outptr;
|
|
|
|
if(s == NULL) return NULL;
|
|
|
|
slen = strlen(s);
|
|
encoded = (char*)malloc((3*slen) + 1); /* max possible size */
|
|
|
|
for(inptr=s,outptr=encoded;*inptr;) {
|
|
int c = *inptr++;
|
|
if(c == ' ') {
|
|
*outptr++ = '+';
|
|
} else {
|
|
/* search allowable */
|
|
int c2;
|
|
char* a = allowable;
|
|
while((c2=*a++)) {
|
|
if(c == c2) break;
|
|
}
|
|
if(c2) {*outptr++ = c;}
|
|
else {
|
|
char hex[2];
|
|
toHex(c,hex);
|
|
*outptr++ = '%';
|
|
*outptr++ = hex[0];
|
|
*outptr++ = hex[1];
|
|
}
|
|
}
|
|
}
|
|
*outptr = EOFCHAR;
|
|
return encoded;
|
|
}
|
|
|
|
/* Return a string representing decoding of input; caller must free;*/
|
|
char*
|
|
ocuridecode(char* s)
|
|
{
|
|
return ocuridecodeonly(s,NULL);
|
|
}
|
|
|
|
/* Return a string representing decoding of input only for specified
|
|
characters; caller must free
|
|
*/
|
|
char*
|
|
ocuridecodeonly(char* s, char* only)
|
|
{
|
|
size_t slen;
|
|
char* decoded;
|
|
char* outptr;
|
|
char* inptr;
|
|
unsigned int c;
|
|
|
|
if (s == NULL) return NULL;
|
|
if(only == NULL) only = "";
|
|
|
|
slen = strlen(s);
|
|
decoded = (char*)malloc(slen+1); /* Should be max we need */
|
|
|
|
outptr = decoded;
|
|
inptr = s;
|
|
while((c = *inptr++)) {
|
|
if(c == '+' && strchr(only,'+') != NULL)
|
|
*outptr++ = ' ';
|
|
else if(c == '%') {
|
|
/* try to pull two hex more characters */
|
|
if(inptr[0] != EOFCHAR && inptr[1] != EOFCHAR
|
|
&& strchr(hexchars,inptr[0]) != NULL
|
|
&& strchr(hexchars,inptr[1]) != NULL) {
|
|
/* test conversion */
|
|
int xc = (fromHex(inptr[0]) << 4) | (fromHex(inptr[1]));
|
|
if(strchr(only,xc) != NULL) {
|
|
inptr += 2; /* decode it */
|
|
c = xc;
|
|
}
|
|
}
|
|
}
|
|
*outptr++ = c;
|
|
}
|
|
*outptr = EOFCHAR;
|
|
return decoded;
|
|
}
|
|
|