Encode record properly (recordXMLEscaping, recordPacking)
[yaz-moved-to-github.git] / src / uri.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 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         while (*cp && *cp != '=' && *cp != '&')
136         {
137             /* check that x-form names looks sane */
138             if (*cp <= ' ' || *cp >= 127)
139                 return 0;
140             cp++;
141         }
142     }
143     *name = (char **) odr_malloc(o, no * sizeof(char*));
144     *val = (char **) odr_malloc(o, no * sizeof(char*));
145
146     for (no = 0; *path; no++)
147     {
148         while (*path == '&')
149             path++;
150         if (!*path)
151             break;
152
153         for (cp = path; *cp && *cp != '=' && *cp != '&'; cp++)
154             ;
155
156         (*name)[no] = (char *) odr_malloc(o, (cp-path)+1);
157         memcpy((*name)[no], path, cp-path);
158         (*name)[no][cp-path] = '\0';
159
160         path = cp;
161         if (*path == '=')
162         {
163             size_t i = 0;
164             char *ret;
165             path++;
166             for (cp = path; *cp && *cp != '&'; cp++)
167                 ;
168             (*val)[no] = ret = (char *) odr_malloc(o, cp - path + 1);
169             while (*path && *path != '&')
170             {
171                 size_t l = 3;
172                 ret[i++] = decode_uri_char(path, &l);
173                 path += l;
174             }
175             ret[i] = '\0';
176         }
177         else
178             (*val)[no] = odr_strdup(o, "");
179     }
180     (*name)[no] = 0;
181     (*val)[no] = 0;
182     return no;
183 }
184
185 char *yaz_uri_val(const char *path, const char *name, ODR o)
186 {
187     size_t nlen = strlen(name);
188     if (*path != '?')
189         return 0;
190     path++;
191     while (path && *path)
192     {
193         const char *p1 = strchr(path, '=');
194         if (!p1)
195             break;
196         if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
197         {
198             size_t i = 0;
199             char *ret;
200
201             path = p1 + 1;
202             p1 = strchr(path, '&');
203             if (!p1)
204                 p1 = strlen(path) + path;
205             ret = (char *) odr_malloc(o, p1 - path + 1);
206             while (*path && *path != '&')
207             {
208                 size_t l = 3;
209                 ret[i++] = decode_uri_char(path, &l);
210                 path += l;
211             }
212             ret[i] = '\0';
213             return ret;
214         }
215         path = strchr(p1, '&');
216         if (path)
217             path++;
218     }
219     return 0;
220 }
221
222 /*
223  * Local variables:
224  * c-basic-offset: 4
225  * c-file-style: "Stroustrup"
226  * indent-tabs-mode: nil
227  * End:
228  * vim: shiftwidth=4 tabstop=8 expandtab
229  */
230