No more manifest files
[yaz-moved-to-github.git] / src / uri.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 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] = odr_strdupn(o, path, cp - path);
157         path = cp;
158         if (*path == '=')
159         {
160             size_t i = 0;
161             char *ret;
162             path++;
163             for (cp = path; *cp && *cp != '&'; cp++)
164                 ;
165             (*val)[no] = ret = (char *) odr_malloc(o, cp - path + 1);
166             while (*path && *path != '&')
167             {
168                 size_t l = 3;
169                 ret[i++] = decode_uri_char(path, &l);
170                 path += l;
171             }
172             ret[i] = '\0';
173         }
174         else
175             (*val)[no] = odr_strdup(o, "");
176     }
177     (*name)[no] = 0;
178     (*val)[no] = 0;
179     return no;
180 }
181
182
183 /*
184  * Local variables:
185  * c-basic-offset: 4
186  * c-file-style: "Stroustrup"
187  * indent-tabs-mode: nil
188  * End:
189  * vim: shiftwidth=4 tabstop=8 expandtab
190  */
191