f502f7cbde1e23d6a8de6a4c1a9d9ecf5305ae9f
[mLib] / codec / url.c
1 /* -*-c-*-
2 *
3 * Parsing and construction of url-encoded name/value pairs
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the mLib utilities library.
11 *
12 * mLib is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * mLib is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "dstr.h"
36 #include "url.h"
37
38 /*----- Main code ---------------------------------------------------------*/
39
40 /* --- @url_initenc@ --- *
41 *
42 * Arguments: @url_ectx *ctx@ = pointer to context block
43 *
44 * Returns: ---
45 *
46 * Use: Initializes a URL encoding context.
47 */
48
49 void url_initenc(url_ectx *ctx) { ctx->f = 0; }
50
51 /* --- @encode@ --- *
52 *
53 * Arguments: @url_ectx *ctx@ = encoding context
54 * @dstr *d@ = pointer to output string
55 * @const char *p@ = pointer to thing to encode
56 *
57 * Returns: ---
58 *
59 * Use: Encodes the input string into the output string.
60 */
61
62 static void encode(url_ectx *ctx, dstr *d, const char *p)
63 {
64 while (*p) {
65 switch (*p) {
66 case ' ':
67 DPUTC(d, '+');
68 break;
69 default:
70 if ((ctx->f & URLF_LAX) || isalnum((unsigned char)*p))
71 goto safe;
72 else
73 goto unsafe;
74 case '/':
75 case '~':
76 if (ctx->f & URLF_STRICT)
77 goto unsafe;
78 case '-':
79 case '.':
80 case '_':
81 safe:
82 DPUTC(d, *p);
83 break;
84 unsafe:
85 case '+':
86 case '%':
87 case '=':
88 case '&':
89 case ';':
90 dstr_putf(d, "%%%02x", *p);
91 break;
92 }
93 p++;
94 }
95 }
96
97 /* --- @url_enc@ --- *
98 *
99 * Arguments: @url_ectx *ctx@ = pointer to encoding context
100 * @dstr *d@ = pointer to output string
101 * @const char *name@ = pointer to name
102 * @const char *value@ = pointer to value
103 *
104 * Returns: ---
105 *
106 * Use: Writes an assignment between @name@ and @value@ to the
107 * output string, encoding the values properly.
108 */
109
110 void url_enc(url_ectx *ctx, dstr *d, const char *name, const char *value)
111 {
112 if (ctx->f & URLF_SEP)
113 DPUTC(d, (ctx->f & URLF_SEMI) ? ';' : '&');
114 encode(ctx, d, name);
115 DPUTC(d, '=');
116 encode(ctx, d, value);
117 DPUTZ(d);
118 ctx->f |= URLF_SEP;
119 }
120
121 /* --- @url_initdec@ --- *
122 *
123 * Arguments: @url_dctx *ctx@ = pointer to context block
124 * @const char *p@ = string to read data from
125 *
126 * Returns: ---
127 *
128 * Use: Initializes a URL decoding context.
129 */
130
131 void url_initdec(url_dctx *ctx, const char *p) { ctx->p = p; ctx->f = 0; }
132
133 /* --- @decode@ --- *
134 *
135 * Arguments: @url_dctx *ctx@ = pointer to the context
136 * @dstr *d@ = pointer to output string
137 * @const char *p@ = pointer to input data
138 * @int eq@ = whether to stop at `=' characters
139 *
140 * Returns: Pointer to next available character.
141 *
142 * Use: Does a URL decode.
143 */
144
145 static const char *decode(url_dctx *ctx, dstr *d, const char *p, int eq)
146 {
147 if (!*p)
148 return (0);
149 for (;;) {
150 switch (*p) {
151 case '=':
152 if (eq)
153 return (p);
154 goto boring;
155 case ';':
156 if (ctx->f & URLF_SEMI)
157 return (p);
158 goto boring;
159 case 0:
160 case '&':
161 return (p);
162 case '+':
163 DPUTC(d, ' ');
164 break;
165 case '%': {
166 unsigned int ch;
167 int n;
168 int x = sscanf(p + 1, "%2x%n", &ch, &n);
169 if (x == 1) {
170 DPUTC(d, ch);
171 p += n;
172 break;
173 }
174 }
175 default:
176 boring:
177 DPUTC(d, *p);
178 break;
179 }
180 p++;
181 }
182 }
183
184 /* --- @url_dec@ --- *
185 *
186 * Arguments: @url_dctx *ctx@ = pointer to decode context
187 * @dstr *n@ = pointer to output string for name
188 * @dstr *v@ = pointer to output string for value
189 *
190 * Returns: Nonzero if it read something, zero if there's nothing left
191 *
192 * Use: Decodes the next name/value pair from a urlencoded string.
193 */
194
195 int url_dec(url_dctx *ctx, dstr *n, dstr *v)
196 {
197 const char *p = ctx->p;
198 size_t l = n->len;
199
200 again:
201 if ((p = decode(ctx, n, p, 1)) == 0 || *p == 0)
202 return (0);
203 if (*p != '=') {
204 p++;
205 n->len = l;
206 goto again;
207 }
208 p++;
209 if ((p = decode(ctx, v, p, 0)) == 0)
210 return (0);
211 DPUTZ(n);
212 DPUTZ(v);
213 ctx->p = p;
214 return (1);
215 }
216
217 /*----- That's all, folks -------------------------------------------------*/