460b9539 |
1 | /* |
2 | * This file is part of DisOrder. |
3 | * Copyright (C) 2004, 2005 Richard Kettlewell |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, but |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
18 | * USA |
19 | */ |
20 | |
21 | #include <config.h> |
22 | #include "types.h" |
23 | |
24 | #include <string.h> |
25 | #include <stdio.h> |
26 | |
27 | #include "mem.h" |
28 | #include "kvp.h" |
29 | #include "log.h" |
30 | #include "vector.h" |
31 | #include "hex.h" |
32 | #include "sink.h" |
33 | |
34 | int urldecode(struct sink *sink, const char *ptr, size_t n) { |
35 | int c, d1, d2; |
36 | |
37 | while(n-- > 0) { |
38 | switch(c = *ptr++) { |
39 | case '%': |
40 | if((d1 = unhexdigit(ptr[0])) == -1 |
41 | || (d2 = unhexdigit(ptr[1])) == -1) |
42 | return -1; |
43 | c = d1 * 16 + d2; |
44 | ptr += 2; |
45 | n -= 2; |
46 | break; |
47 | case '+': |
48 | c = ' '; |
49 | break; |
50 | default: |
51 | break; |
52 | } |
53 | if(sink_writec(sink,c) < 0) |
54 | return -1; |
55 | } |
56 | return 0; |
57 | } |
58 | |
59 | static char *decode(const char *ptr, size_t n) { |
60 | struct dynstr d; |
61 | struct sink *s; |
62 | |
63 | dynstr_init(&d); |
64 | s = sink_dynstr(&d); |
65 | if(urldecode(s, ptr, n)) |
66 | return 0; |
67 | dynstr_terminate(&d); |
68 | return d.vec; |
69 | } |
70 | |
71 | struct kvp *kvp_urldecode(const char *ptr, size_t n) { |
72 | struct kvp *kvp, **kk = &kvp, *k; |
73 | const char *q, *r, *top = ptr + n, *next; |
74 | |
75 | while(ptr < top) { |
76 | *kk = k = xmalloc(sizeof *k); |
77 | if(!(q = memchr(ptr, '=', top - ptr))) |
78 | break; |
79 | if(!(k->name = decode(ptr, q - ptr))) break; |
80 | if((r = memchr(ptr, '&', top - ptr))) |
81 | next = r + 1; |
82 | else |
83 | next = r = top; |
84 | if(r < q) |
85 | break; |
86 | if(!(k->value = decode(q + 1, r - (q + 1)))) break; |
87 | kk = &k->next; |
88 | ptr = next; |
89 | } |
90 | *kk = 0; |
91 | return kvp; |
92 | } |
93 | |
94 | int urlencode(struct sink *sink, const char *s, size_t n) { |
95 | unsigned char c; |
96 | |
97 | while(n > 0) { |
98 | c = *s++; |
99 | n--; |
100 | switch(c) { |
101 | default: |
102 | if((c >= '0' && c <= '9') |
103 | || (c >= 'a' && c <= 'z') |
104 | || (c >= 'A' && c <= 'Z')) { |
105 | /* RFC2396 2.3 unreserved characters */ |
106 | case '-': |
107 | case '_': |
108 | case '.': |
109 | case '!': |
110 | case '~': |
111 | case '*': |
112 | case '\'': |
113 | case '(': |
114 | case ')': |
115 | /* additional unreserved characters */ |
116 | case '/': |
117 | if(sink_writec(sink, c) < 0) |
118 | return -1; |
119 | } else |
120 | if(sink_printf(sink, "%%%02x", (unsigned int)c) < 0) |
121 | return -1; |
122 | } |
123 | } |
124 | return 0; |
125 | } |
126 | |
127 | const char *urlencodestring(const char *s) { |
128 | struct dynstr d; |
129 | |
130 | dynstr_init(&d); |
131 | urlencode(sink_dynstr(&d), s, strlen(s)); |
132 | dynstr_terminate(&d); |
133 | return d.vec; |
134 | } |
135 | |
136 | char *kvp_urlencode(const struct kvp *kvp, size_t *np) { |
137 | struct dynstr d; |
138 | struct sink *sink; |
139 | |
140 | dynstr_init(&d); |
141 | sink = sink_dynstr(&d); |
142 | while(kvp) { |
143 | urlencode(sink, kvp->name, strlen(kvp->name)); |
144 | dynstr_append(&d, '='); |
145 | urlencode(sink, kvp->value, strlen(kvp->value)); |
146 | if((kvp = kvp->next)) |
147 | dynstr_append(&d, '&'); |
148 | |
149 | } |
150 | dynstr_terminate(&d); |
151 | if(np) |
152 | *np = d.nvec; |
153 | return d.vec; |
154 | } |
155 | |
156 | int kvp_set(struct kvp **kvpp, const char *name, const char *value) { |
157 | struct kvp *k, **kk; |
158 | |
159 | for(kk = kvpp; (k = *kk) && strcmp(name, k->name); kk = &k->next) |
160 | ; |
161 | if(k) { |
162 | if(value) { |
163 | if(strcmp(k->value, value)) { |
164 | k->value = xstrdup(value); |
165 | return 1; |
166 | } else |
167 | return 0; |
168 | } else { |
169 | *kk = k->next; |
170 | return 1; |
171 | } |
172 | } else { |
173 | if(value) { |
174 | *kk = k = xmalloc(sizeof *k); |
175 | k->name = xstrdup(name); |
176 | k->value = xstrdup(value); |
177 | return 1; |
178 | } else |
179 | return 0; |
180 | } |
181 | } |
182 | |
183 | const char *kvp_get(const struct kvp *kvp, const char *name) { |
184 | for(;kvp && strcmp(kvp->name, name); kvp = kvp->next) |
185 | ; |
186 | return kvp ? kvp->value : 0; |
187 | } |
188 | |
189 | /* |
190 | Local Variables: |
191 | c-basic-offset:2 |
192 | comment-column:40 |
193 | End: |
194 | */ |