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