Fix left/right switch of truncation flag
[yaz-moved-to-github.git] / src / uri.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2011 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         const char *p1 = strchr(path, '=');
142         size_t i = 0;
143         char *ret;
144         if (!p1)
145             break;
146
147         (*name)[no] = (char *) odr_malloc(o, (p1-path)+1);
148         memcpy((*name)[no], path, p1-path);
149         (*name)[no][p1-path] = '\0';
150
151         path = p1 + 1;
152         p1 = strchr(path, '&');
153         if (!p1)
154             p1 = strlen(path) + path;
155         (*val)[no] = ret = (char *) odr_malloc(o, p1 - path + 1);
156         while (*path && *path != '&')
157         {
158             size_t l = 3;
159             ret[i++] = decode_uri_char(path, &l);
160             path += l;
161         }
162         ret[i] = '\0';
163
164         if (*path)
165             path++;
166     }
167     (*name)[no] = 0;
168     (*val)[no] = 0;
169     return no;
170 }
171
172 char *yaz_uri_val(const char *path, const char *name, ODR o)
173 {
174     size_t nlen = strlen(name);
175     if (*path != '?')
176         return 0;
177     path++;
178     while (path && *path)
179     {
180         const char *p1 = strchr(path, '=');
181         if (!p1)
182             break;
183         if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
184         {
185             size_t i = 0;
186             char *ret;
187             
188             path = p1 + 1;
189             p1 = strchr(path, '&');
190             if (!p1)
191                 p1 = strlen(path) + path;
192             ret = (char *) odr_malloc(o, p1 - path + 1);
193             while (*path && *path != '&')
194             {
195                 size_t l = 3;
196                 ret[i++] = decode_uri_char(path, &l);
197                 path += l;
198             }
199             ret[i] = '\0';
200             return ret;
201         }
202         path = strchr(p1, '&');
203         if (path)
204             path++;
205     }
206     return 0;
207 }
208
209 /*
210  * Local variables:
211  * c-basic-offset: 4
212  * c-file-style: "Stroustrup"
213  * indent-tabs-mode: nil
214  * End:
215  * vim: shiftwidth=4 tabstop=8 expandtab
216  */
217