CCL: fix use of "term" field in sub queries
[yaz-moved-to-github.git] / src / uri.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2012 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file uri.c
7  * \brief Implements URI utilities.
8  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <stdlib.h>
14 #include <yaz/srw.h>
15 #include <yaz/matchstr.h>
16 #include <yaz/yaz-iconv.h>
17
18 static int hex_digit (int ch)
19 {
20     if (ch >= '0' && ch <= '9')
21         return ch - '0';
22     else if (ch >= 'a' && ch <= 'f')
23         return ch - 'a'+10;
24     else if (ch >= 'A' && ch <= 'F')
25         return ch - 'A'+10;
26     return -1;
27 }
28
29 static void encode_uri_char(char *dst, char ch)
30 {
31     /*  mark        = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" */
32     if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
33         (ch >= '0' && ch <= '9') || strchr("-_.!~*'(|)", ch))
34     {
35         dst[0] = ch;
36         dst[1] = '\0';
37     }
38     else
39     {
40         dst[0] = '%';
41         sprintf(dst+1, "%02X", (unsigned char ) ch);
42     }
43 }
44
45 void yaz_encode_uri_component(char *dst, const char *uri)
46 {
47     for (; *uri; uri++)
48     {
49         encode_uri_char(dst, *uri);
50         dst += strlen(dst);
51     }
52     *dst = '\0';
53 }
54
55 static unsigned char decode_uri_char(const char *path, size_t *len)
56 {
57     unsigned char ch;
58     if (*path == '+')
59     {
60         ch = ' ';
61         *len = 1;
62     }
63     else if (*path == '%' && *len >= 3)
64     {
65         int d1 = hex_digit(path[1]);
66         int d2 = hex_digit(path[2]);
67         if (d1 >= 0 && d2 >= 0)
68         {
69             ch = d1 * 16 + d2;
70             *len = 3;
71         }
72         else
73         {
74             ch = *path;
75             *len = 1;
76         }
77     }
78     else
79     {
80         ch = *path;
81         *len = 1;
82     }
83     return ch;
84 }
85
86 void yaz_decode_uri_component(char *dst, const char *uri, size_t len)
87 {
88     while (len)
89     {
90         size_t sz = len;
91         *dst++ = decode_uri_char(uri, &sz);
92         uri += sz;
93         len = len - sz;
94     }
95     *dst = '\0';
96 }
97
98 void yaz_array_to_uri(char **path, ODR o, char **name, char **value)
99 {
100     size_t i, szp = 0, sz = 1;
101     for(i = 0; name[i]; i++)
102         sz += strlen(name[i]) + 3 + strlen(value[i]) * 3;
103     *path = (char *) odr_malloc(o, sz);
104     
105     for(i = 0; name[i]; i++)
106     {
107         size_t ilen;
108         if (i)
109             (*path)[szp++] = '&';
110         ilen = strlen(name[i]);
111         memcpy(*path+szp, name[i], ilen);
112         szp += ilen;
113         (*path)[szp++] = '=';
114
115         yaz_encode_uri_component(*path + szp, value[i]);
116         szp += strlen(*path + szp);
117     }
118     (*path)[szp] = '\0';
119 }
120
121 int yaz_uri_to_array(const char *path, ODR o, char ***name, char ***val)
122 {
123     int no = 2;
124     const char *cp;
125     *name = 0;
126     if (*path == '?')
127         path++;
128     if (!*path)
129         return 0;
130     cp = path;
131     while ((cp = strchr(cp, '&')))
132     {
133         cp++;
134         no++;
135     }
136     *name = (char **) odr_malloc(o, no * sizeof(char*));
137     *val = (char **) odr_malloc(o, no * sizeof(char*));
138
139     for (no = 0; *path; no++)
140     {
141         while (*path == '&')
142             path++;
143         if (!*path)
144             break;
145
146         for (cp = path; *cp && *cp != '=' && *cp != '&'; cp++)
147             ;
148
149         (*name)[no] = (char *) odr_malloc(o, (cp-path)+1);
150         memcpy((*name)[no], path, cp-path);
151         (*name)[no][cp-path] = '\0';
152
153         path = cp;
154         if (*path == '=')
155         {
156             size_t i = 0;
157             char *ret;
158             path++;
159             for (cp = path; *cp && *cp != '&'; cp++)
160                 ;
161             (*val)[no] = ret = (char *) odr_malloc(o, cp - path + 1);
162             while (*path && *path != '&')
163             {
164                 size_t l = 3;
165                 ret[i++] = decode_uri_char(path, &l);
166                 path += l;
167             }
168             ret[i] = '\0';
169         }
170         else
171             (*val)[no] = odr_strdup(o, "");
172     }
173     (*name)[no] = 0;
174     (*val)[no] = 0;
175     return no;
176 }
177
178 char *yaz_uri_val(const char *path, const char *name, ODR o)
179 {
180     size_t nlen = strlen(name);
181     if (*path != '?')
182         return 0;
183     path++;
184     while (path && *path)
185     {
186         const char *p1 = strchr(path, '=');
187         if (!p1)
188             break;
189         if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
190         {
191             size_t i = 0;
192             char *ret;
193             
194             path = p1 + 1;
195             p1 = strchr(path, '&');
196             if (!p1)
197                 p1 = strlen(path) + path;
198             ret = (char *) odr_malloc(o, p1 - path + 1);
199             while (*path && *path != '&')
200             {
201                 size_t l = 3;
202                 ret[i++] = decode_uri_char(path, &l);
203                 path += l;
204             }
205             ret[i] = '\0';
206             return ret;
207         }
208         path = strchr(p1, '&');
209         if (path)
210             path++;
211     }
212     return 0;
213 }
214
215 /*
216  * Local variables:
217  * c-basic-offset: 4
218  * c-file-style: "Stroustrup"
219  * indent-tabs-mode: nil
220  * End:
221  * vim: shiftwidth=4 tabstop=8 expandtab
222  */
223