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