Blame


1 5546fdd5 2022-12-23 op /*
2 62c0f697 2024-02-21 op * Copyright (c) 2022, 2024 Omar Polo <op@omarpolo.com>
3 5546fdd5 2022-12-23 op *
4 5546fdd5 2022-12-23 op * Permission to use, copy, modify, and distribute this software for any
5 5546fdd5 2022-12-23 op * purpose with or without fee is hereby granted, provided that the above
6 5546fdd5 2022-12-23 op * copyright notice and this permission notice appear in all copies.
7 5546fdd5 2022-12-23 op *
8 5546fdd5 2022-12-23 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 5546fdd5 2022-12-23 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 5546fdd5 2022-12-23 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 5546fdd5 2022-12-23 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 5546fdd5 2022-12-23 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 5546fdd5 2022-12-23 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 5546fdd5 2022-12-23 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 5546fdd5 2022-12-23 op */
16 14728991 2023-06-22 op
17 14728991 2023-06-22 op #include "compat.h"
18 5546fdd5 2022-12-23 op
19 5546fdd5 2022-12-23 op #include <ctype.h>
20 871b5bb7 2022-12-24 op #include <errno.h>
21 871b5bb7 2022-12-24 op #include <stddef.h>
22 5546fdd5 2022-12-23 op #include <stdint.h>
23 a2785a57 2022-12-26 op #include <stdio.h>
24 5546fdd5 2022-12-23 op #include <stdlib.h>
25 5546fdd5 2022-12-23 op #include <string.h>
26 5546fdd5 2022-12-23 op
27 5546fdd5 2022-12-23 op #include "iri.h"
28 5546fdd5 2022-12-23 op
29 5546fdd5 2022-12-23 op /* TODO: URI -> IRI. accept IRI but emit always URI */
30 5546fdd5 2022-12-23 op
31 5546fdd5 2022-12-23 op static inline int
32 5546fdd5 2022-12-23 op cpstr(const char *start, const char *till, char *buf, size_t len)
33 5546fdd5 2022-12-23 op {
34 5546fdd5 2022-12-23 op size_t slen = till - start;
35 5546fdd5 2022-12-23 op
36 5546fdd5 2022-12-23 op if (slen + 1 >= len)
37 5546fdd5 2022-12-23 op return (-1);
38 5546fdd5 2022-12-23 op memcpy(buf, start, slen);
39 5546fdd5 2022-12-23 op buf[slen] = '\0';
40 5546fdd5 2022-12-23 op return (0);
41 5546fdd5 2022-12-23 op }
42 5546fdd5 2022-12-23 op
43 5546fdd5 2022-12-23 op static inline int
44 5546fdd5 2022-12-23 op unreserved(int c)
45 5546fdd5 2022-12-23 op {
46 5546fdd5 2022-12-23 op return (isalnum((unsigned char)c) ||
47 5546fdd5 2022-12-23 op c == '-' ||
48 5546fdd5 2022-12-23 op c == '.' ||
49 5546fdd5 2022-12-23 op c == '_' ||
50 5546fdd5 2022-12-23 op c == '~');
51 5546fdd5 2022-12-23 op }
52 5546fdd5 2022-12-23 op
53 5546fdd5 2022-12-23 op static inline int
54 5546fdd5 2022-12-23 op pctenc(const char *s)
55 5546fdd5 2022-12-23 op {
56 5546fdd5 2022-12-23 op const char *t = s;
57 5546fdd5 2022-12-23 op
58 5546fdd5 2022-12-23 op return (t[0] == '%' &&
59 5546fdd5 2022-12-23 op isxdigit((unsigned char)t[1]) &&
60 5546fdd5 2022-12-23 op isxdigit((unsigned char)t[2]));
61 5546fdd5 2022-12-23 op }
62 5546fdd5 2022-12-23 op
63 5546fdd5 2022-12-23 op static inline int
64 5546fdd5 2022-12-23 op sub_delims(int c)
65 5546fdd5 2022-12-23 op {
66 5546fdd5 2022-12-23 op return (c == '!' || c == '$' || c == '&' || c == '\'' ||
67 5546fdd5 2022-12-23 op c == '(' || c == ')' || c == '*' || c == '+' || c == ',' ||
68 5546fdd5 2022-12-23 op c == ';' || c == '=');
69 5546fdd5 2022-12-23 op }
70 5546fdd5 2022-12-23 op
71 5546fdd5 2022-12-23 op static inline const char *
72 5546fdd5 2022-12-23 op advance_pchar(const char *s)
73 5546fdd5 2022-12-23 op {
74 5546fdd5 2022-12-23 op if (unreserved(*s) || sub_delims(*s) || *s == ':' || *s == '@')
75 5546fdd5 2022-12-23 op return (s + 1);
76 5546fdd5 2022-12-23 op if (pctenc(s))
77 5546fdd5 2022-12-23 op return (s + 3);
78 5546fdd5 2022-12-23 op return (NULL);
79 5546fdd5 2022-12-23 op }
80 5546fdd5 2022-12-23 op
81 5546fdd5 2022-12-23 op static inline const char *
82 5546fdd5 2022-12-23 op advance_segment(const char *s)
83 5546fdd5 2022-12-23 op {
84 5546fdd5 2022-12-23 op const char *t = s;
85 5546fdd5 2022-12-23 op
86 5546fdd5 2022-12-23 op while ((t = advance_pchar(s)) != NULL)
87 5546fdd5 2022-12-23 op s = t;
88 5546fdd5 2022-12-23 op return (s);
89 5546fdd5 2022-12-23 op }
90 5546fdd5 2022-12-23 op
91 5546fdd5 2022-12-23 op static inline const char *
92 5546fdd5 2022-12-23 op advance_segment_nz(const char *s)
93 5546fdd5 2022-12-23 op {
94 5546fdd5 2022-12-23 op const char *t;
95 5546fdd5 2022-12-23 op
96 5546fdd5 2022-12-23 op if ((t = advance_pchar(s)) == NULL)
97 5546fdd5 2022-12-23 op return (NULL);
98 5546fdd5 2022-12-23 op return (advance_segment(t));
99 5546fdd5 2022-12-23 op }
100 5546fdd5 2022-12-23 op
101 5546fdd5 2022-12-23 op static inline const char *
102 5546fdd5 2022-12-23 op advance_segment_nz_nc(const char *s)
103 5546fdd5 2022-12-23 op {
104 5546fdd5 2022-12-23 op const char *t = s;
105 5546fdd5 2022-12-23 op
106 5546fdd5 2022-12-23 op for (;;) {
107 5546fdd5 2022-12-23 op if (unreserved(*t) || sub_delims(*t) || *t == '@')
108 5546fdd5 2022-12-23 op t++;
109 5546fdd5 2022-12-23 op else if (pctenc(t))
110 5546fdd5 2022-12-23 op t += 3;
111 5546fdd5 2022-12-23 op else
112 5546fdd5 2022-12-23 op break;
113 5546fdd5 2022-12-23 op }
114 5546fdd5 2022-12-23 op
115 5546fdd5 2022-12-23 op return (t != s ? t : NULL);
116 5546fdd5 2022-12-23 op }
117 5546fdd5 2022-12-23 op
118 5546fdd5 2022-12-23 op static const char *
119 5546fdd5 2022-12-23 op parse_scheme(const char *s, struct iri *iri)
120 5546fdd5 2022-12-23 op {
121 5546fdd5 2022-12-23 op const char *t = s;
122 5546fdd5 2022-12-23 op
123 5546fdd5 2022-12-23 op if (!isalpha((unsigned char)*t))
124 5546fdd5 2022-12-23 op return (NULL);
125 5546fdd5 2022-12-23 op
126 5546fdd5 2022-12-23 op while (isalnum((unsigned char)*t) ||
127 5546fdd5 2022-12-23 op *t == '+' ||
128 5546fdd5 2022-12-23 op *t == '-' ||
129 5546fdd5 2022-12-23 op *t == '.')
130 5546fdd5 2022-12-23 op t++;
131 5546fdd5 2022-12-23 op
132 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_scheme, sizeof(iri->iri_scheme)) == -1)
133 5546fdd5 2022-12-23 op return (NULL);
134 5546fdd5 2022-12-23 op
135 5546fdd5 2022-12-23 op iri->iri_flags |= IH_SCHEME;
136 5546fdd5 2022-12-23 op return (t);
137 5546fdd5 2022-12-23 op }
138 5546fdd5 2022-12-23 op
139 5546fdd5 2022-12-23 op /* userinfo is always optional */
140 5546fdd5 2022-12-23 op static const char *
141 5546fdd5 2022-12-23 op parse_uinfo(const char *s, struct iri *iri)
142 5546fdd5 2022-12-23 op {
143 5546fdd5 2022-12-23 op const char *t = s;
144 5546fdd5 2022-12-23 op
145 5546fdd5 2022-12-23 op for (;;) {
146 5546fdd5 2022-12-23 op if (unreserved(*t) || sub_delims(*t) || *t == ':')
147 5546fdd5 2022-12-23 op t++;
148 5546fdd5 2022-12-23 op else if (pctenc(t))
149 5546fdd5 2022-12-23 op t += 3;
150 5546fdd5 2022-12-23 op else
151 5546fdd5 2022-12-23 op break;
152 5546fdd5 2022-12-23 op }
153 5546fdd5 2022-12-23 op
154 5546fdd5 2022-12-23 op if (*t != '@')
155 5546fdd5 2022-12-23 op return (s);
156 5546fdd5 2022-12-23 op
157 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_uinfo, sizeof(iri->iri_uinfo)) == -1)
158 5546fdd5 2022-12-23 op return (NULL);
159 5546fdd5 2022-12-23 op iri->iri_flags |= IH_UINFO;
160 5546fdd5 2022-12-23 op return (t + 1);
161 5546fdd5 2022-12-23 op }
162 5546fdd5 2022-12-23 op
163 5546fdd5 2022-12-23 op static const char *
164 5546fdd5 2022-12-23 op parse_host(const char *s, struct iri *iri)
165 5546fdd5 2022-12-23 op {
166 5546fdd5 2022-12-23 op const char *t = s;
167 5546fdd5 2022-12-23 op
168 5546fdd5 2022-12-23 op /*
169 5546fdd5 2022-12-23 op * cheating a bit by relaxing and merging the rule for
170 5546fdd5 2022-12-23 op * IPv6address and IPvFuture and by merging IPv4address and
171 5546fdd5 2022-12-23 op * reg-name.
172 5546fdd5 2022-12-23 op */
173 5546fdd5 2022-12-23 op
174 5546fdd5 2022-12-23 op if (*t == '[') {
175 5546fdd5 2022-12-23 op while (*t && *t != ']')
176 5546fdd5 2022-12-23 op ++t;
177 5546fdd5 2022-12-23 op if (*t == '\0')
178 5546fdd5 2022-12-23 op return (NULL);
179 5546fdd5 2022-12-23 op t++;
180 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_host, sizeof(iri->iri_host)) == -1)
181 5546fdd5 2022-12-23 op return (NULL);
182 5546fdd5 2022-12-23 op iri->iri_flags |= IH_HOST;
183 5546fdd5 2022-12-23 op return (t);
184 5546fdd5 2022-12-23 op }
185 5546fdd5 2022-12-23 op
186 5546fdd5 2022-12-23 op for (;;) {
187 5546fdd5 2022-12-23 op if (unreserved(*t) || sub_delims(*t))
188 5546fdd5 2022-12-23 op t++;
189 5546fdd5 2022-12-23 op else if (pctenc(t))
190 5546fdd5 2022-12-23 op t += 3;
191 5546fdd5 2022-12-23 op else
192 5546fdd5 2022-12-23 op break;
193 5546fdd5 2022-12-23 op }
194 5546fdd5 2022-12-23 op
195 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_host, sizeof(iri->iri_host)) == -1)
196 5546fdd5 2022-12-23 op return (NULL);
197 5546fdd5 2022-12-23 op iri->iri_flags |= IH_HOST;
198 5546fdd5 2022-12-23 op return (t);
199 5546fdd5 2022-12-23 op }
200 5546fdd5 2022-12-23 op
201 5546fdd5 2022-12-23 op static const char *
202 5546fdd5 2022-12-23 op parse_port(const char *s, struct iri *iri)
203 5546fdd5 2022-12-23 op {
204 5546fdd5 2022-12-23 op const char *t = s;
205 5546fdd5 2022-12-23 op const char *errstr;
206 5546fdd5 2022-12-23 op
207 5546fdd5 2022-12-23 op while (isdigit((unsigned char)*t))
208 5546fdd5 2022-12-23 op t++;
209 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_portstr, sizeof(iri->iri_portstr)) == -1)
210 5546fdd5 2022-12-23 op return (NULL);
211 5546fdd5 2022-12-23 op iri->iri_port = strtonum(iri->iri_portstr, 1, UINT16_MAX, &errstr);
212 5546fdd5 2022-12-23 op if (errstr)
213 5546fdd5 2022-12-23 op return (NULL);
214 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PORT;
215 5546fdd5 2022-12-23 op return (t);
216 5546fdd5 2022-12-23 op }
217 5546fdd5 2022-12-23 op
218 5546fdd5 2022-12-23 op static const char *
219 5546fdd5 2022-12-23 op parse_authority(const char *s, struct iri *iri)
220 5546fdd5 2022-12-23 op {
221 5546fdd5 2022-12-23 op const char *t;
222 5546fdd5 2022-12-23 op
223 5546fdd5 2022-12-23 op if ((t = parse_uinfo(s, iri)) == NULL)
224 5546fdd5 2022-12-23 op return (NULL);
225 5546fdd5 2022-12-23 op
226 5546fdd5 2022-12-23 op if ((t = parse_host(t, iri)) == NULL)
227 5546fdd5 2022-12-23 op return (NULL);
228 5546fdd5 2022-12-23 op
229 5546fdd5 2022-12-23 op if (*t == ':')
230 870edfb9 2022-12-25 op return (parse_port(t + 1, iri));
231 5546fdd5 2022-12-23 op
232 5546fdd5 2022-12-23 op return (t);
233 5546fdd5 2022-12-23 op }
234 5546fdd5 2022-12-23 op
235 5546fdd5 2022-12-23 op static const char *
236 5546fdd5 2022-12-23 op parse_path_abempty(const char *s, struct iri *iri)
237 5546fdd5 2022-12-23 op {
238 5546fdd5 2022-12-23 op const char *t = s;
239 5546fdd5 2022-12-23 op
240 5546fdd5 2022-12-23 op while (*t == '/')
241 5546fdd5 2022-12-23 op t = advance_segment(t + 1);
242 5546fdd5 2022-12-23 op
243 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_path, sizeof(iri->iri_path)) == -1)
244 5546fdd5 2022-12-23 op return (NULL);
245 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
246 5546fdd5 2022-12-23 op return (t);
247 5546fdd5 2022-12-23 op }
248 5546fdd5 2022-12-23 op
249 5546fdd5 2022-12-23 op static const char *
250 5546fdd5 2022-12-23 op parse_path_absolute(const char *s, struct iri *iri)
251 5546fdd5 2022-12-23 op {
252 5546fdd5 2022-12-23 op const char *t;
253 5546fdd5 2022-12-23 op
254 5546fdd5 2022-12-23 op if (*s != '/')
255 5546fdd5 2022-12-23 op return (NULL);
256 5546fdd5 2022-12-23 op
257 5546fdd5 2022-12-23 op if ((t = advance_segment_nz(s + 1)) == NULL)
258 91ef5ab4 2024-01-22 op t = s + 1;
259 91ef5ab4 2024-01-22 op else {
260 91ef5ab4 2024-01-22 op while (*t == '/')
261 91ef5ab4 2024-01-22 op t = advance_segment(t + 1);
262 91ef5ab4 2024-01-22 op }
263 5546fdd5 2022-12-23 op
264 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_path, sizeof(iri->iri_path)) == -1)
265 5546fdd5 2022-12-23 op return (NULL);
266 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
267 5546fdd5 2022-12-23 op return (t);
268 5546fdd5 2022-12-23 op }
269 5546fdd5 2022-12-23 op
270 5546fdd5 2022-12-23 op static const char *
271 5546fdd5 2022-12-23 op parse_path_rootless(const char *s, struct iri *iri)
272 5546fdd5 2022-12-23 op {
273 5546fdd5 2022-12-23 op const char *t;
274 5546fdd5 2022-12-23 op
275 5546fdd5 2022-12-23 op if ((t = advance_segment_nz(s)) == NULL)
276 5546fdd5 2022-12-23 op return (NULL);
277 5546fdd5 2022-12-23 op
278 5546fdd5 2022-12-23 op while (*t == '/')
279 5546fdd5 2022-12-23 op t = advance_segment(t + 1);
280 5546fdd5 2022-12-23 op
281 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_path, sizeof(iri->iri_path)) == -1)
282 5546fdd5 2022-12-23 op return (NULL);
283 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
284 5546fdd5 2022-12-23 op return (t);
285 5546fdd5 2022-12-23 op }
286 5546fdd5 2022-12-23 op
287 5546fdd5 2022-12-23 op static const char *
288 5546fdd5 2022-12-23 op parse_path_noscheme(const char *s, struct iri *iri)
289 5546fdd5 2022-12-23 op {
290 5546fdd5 2022-12-23 op const char *t;
291 5546fdd5 2022-12-23 op
292 5546fdd5 2022-12-23 op if ((t = advance_segment_nz_nc(s)) == NULL)
293 5546fdd5 2022-12-23 op return (NULL);
294 5546fdd5 2022-12-23 op
295 5546fdd5 2022-12-23 op while (*t == '/')
296 5546fdd5 2022-12-23 op t = advance_segment(t + 1);
297 5546fdd5 2022-12-23 op
298 5546fdd5 2022-12-23 op if (cpstr(s, t, iri->iri_path, sizeof(iri->iri_path)) == -1)
299 5546fdd5 2022-12-23 op return (NULL);
300 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
301 5546fdd5 2022-12-23 op return (t);
302 5546fdd5 2022-12-23 op }
303 5546fdd5 2022-12-23 op
304 5546fdd5 2022-12-23 op static const char *
305 5546fdd5 2022-12-23 op parse_path_empty(const char *s, struct iri *iri)
306 5546fdd5 2022-12-23 op {
307 5546fdd5 2022-12-23 op iri->iri_path[0] = '\0';
308 5546fdd5 2022-12-23 op iri->iri_flags |= IH_PATH;
309 5546fdd5 2022-12-23 op return (s);
310 5546fdd5 2022-12-23 op }
311 5546fdd5 2022-12-23 op
312 5546fdd5 2022-12-23 op static const char *
313 5546fdd5 2022-12-23 op parse_hier(const char *s, struct iri *iri)
314 5546fdd5 2022-12-23 op {
315 5546fdd5 2022-12-23 op const char *t;
316 5546fdd5 2022-12-23 op
317 5546fdd5 2022-12-23 op if (!strncmp(s, "//", 2)) {
318 5546fdd5 2022-12-23 op if ((t = parse_authority(s + 2, iri)) == NULL)
319 5546fdd5 2022-12-23 op return (NULL);
320 5546fdd5 2022-12-23 op return (parse_path_abempty(t, iri));
321 5546fdd5 2022-12-23 op }
322 5546fdd5 2022-12-23 op
323 5546fdd5 2022-12-23 op if ((t = parse_path_absolute(s, iri)) != NULL)
324 5546fdd5 2022-12-23 op return (t);
325 5546fdd5 2022-12-23 op
326 5546fdd5 2022-12-23 op if ((t = parse_path_rootless(s, iri)) != NULL)
327 5546fdd5 2022-12-23 op return (t);
328 5546fdd5 2022-12-23 op
329 5546fdd5 2022-12-23 op return (parse_path_empty(s, iri));
330 5546fdd5 2022-12-23 op }
331 5546fdd5 2022-12-23 op
332 5546fdd5 2022-12-23 op static const char *
333 5546fdd5 2022-12-23 op parse_relative(const char *s, struct iri *iri)
334 5546fdd5 2022-12-23 op {
335 5546fdd5 2022-12-23 op const char *t = s;
336 5546fdd5 2022-12-23 op
337 5546fdd5 2022-12-23 op if (!strncmp(s, "//", 2)) {
338 5546fdd5 2022-12-23 op if ((t = parse_authority(s + 2, iri)) == NULL)
339 5546fdd5 2022-12-23 op return (NULL);
340 5546fdd5 2022-12-23 op return (parse_path_abempty(t, iri));
341 5546fdd5 2022-12-23 op }
342 5546fdd5 2022-12-23 op
343 5546fdd5 2022-12-23 op if ((t = parse_path_absolute(s, iri)) != NULL)
344 5546fdd5 2022-12-23 op return (t);
345 5546fdd5 2022-12-23 op
346 5546fdd5 2022-12-23 op if ((t = parse_path_noscheme(s, iri)) != NULL)
347 5546fdd5 2022-12-23 op return (t);
348 5546fdd5 2022-12-23 op
349 5546fdd5 2022-12-23 op return (parse_path_empty(s, iri));
350 5546fdd5 2022-12-23 op }
351 5546fdd5 2022-12-23 op
352 5546fdd5 2022-12-23 op static const char *
353 7bcbb606 2022-12-26 op parse_qf(const char *s, int flag, struct iri *iri, char *buf, size_t bufsize)
354 5546fdd5 2022-12-23 op {
355 5546fdd5 2022-12-23 op const char *n, *t = s;
356 5546fdd5 2022-12-23 op
357 5546fdd5 2022-12-23 op for (;;) {
358 5546fdd5 2022-12-23 op if ((n = advance_pchar(t)) != NULL)
359 5546fdd5 2022-12-23 op t = n;
360 5546fdd5 2022-12-23 op else if (*t == '/' || *t == '?')
361 5546fdd5 2022-12-23 op t++;
362 5546fdd5 2022-12-23 op else
363 5546fdd5 2022-12-23 op break;
364 5546fdd5 2022-12-23 op }
365 5546fdd5 2022-12-23 op
366 7bcbb606 2022-12-26 op if (cpstr(s, t, buf, bufsize) == -1)
367 5546fdd5 2022-12-23 op return (NULL);
368 7bcbb606 2022-12-26 op iri->iri_flags |= flag;
369 5546fdd5 2022-12-23 op return (t);
370 5546fdd5 2022-12-23 op }
371 5546fdd5 2022-12-23 op
372 5546fdd5 2022-12-23 op static int
373 5546fdd5 2022-12-23 op parse_uri(const char *s, struct iri *iri)
374 5546fdd5 2022-12-23 op {
375 6d091826 2022-12-26 op iri->iri_flags = 0;
376 6d091826 2022-12-26 op
377 5546fdd5 2022-12-23 op if ((s = parse_scheme(s, iri)) == NULL)
378 5546fdd5 2022-12-23 op return (-1);
379 5546fdd5 2022-12-23 op
380 5546fdd5 2022-12-23 op if (*s != ':')
381 5546fdd5 2022-12-23 op return (-1);
382 5546fdd5 2022-12-23 op
383 5546fdd5 2022-12-23 op if ((s = parse_hier(s + 1, iri)) == NULL)
384 5546fdd5 2022-12-23 op return (-1);
385 5546fdd5 2022-12-23 op
386 7bcbb606 2022-12-26 op if (*s == '?') {
387 7bcbb606 2022-12-26 op s = parse_qf(s + 1, IH_QUERY, iri, iri->iri_query,
388 7bcbb606 2022-12-26 op sizeof(iri->iri_query));
389 7bcbb606 2022-12-26 op if (s == NULL)
390 7bcbb606 2022-12-26 op return (-1);
391 7bcbb606 2022-12-26 op }
392 5546fdd5 2022-12-23 op
393 7bcbb606 2022-12-26 op if (*s == '#') {
394 7bcbb606 2022-12-26 op s = parse_qf(s + 1, IH_FRAGMENT, iri, iri->iri_fragment,
395 7bcbb606 2022-12-26 op sizeof(iri->iri_fragment));
396 7bcbb606 2022-12-26 op if (s == NULL)
397 7bcbb606 2022-12-26 op return (-1);
398 7bcbb606 2022-12-26 op }
399 a165601e 2022-12-25 op
400 a165601e 2022-12-25 op if (*s == '\0')
401 5546fdd5 2022-12-23 op return (0);
402 5546fdd5 2022-12-23 op
403 5546fdd5 2022-12-23 op return (-1);
404 5546fdd5 2022-12-23 op }
405 5546fdd5 2022-12-23 op
406 5546fdd5 2022-12-23 op static int
407 5546fdd5 2022-12-23 op parse_relative_ref(const char *s, struct iri *iri)
408 5546fdd5 2022-12-23 op {
409 5546fdd5 2022-12-23 op if ((s = parse_relative(s, iri)) == NULL)
410 5546fdd5 2022-12-23 op return (-1);
411 5546fdd5 2022-12-23 op
412 7bcbb606 2022-12-26 op if (*s == '?') {
413 7bcbb606 2022-12-26 op s = parse_qf(s + 1, IH_QUERY, iri, iri->iri_query,
414 7bcbb606 2022-12-26 op sizeof(iri->iri_query));
415 7bcbb606 2022-12-26 op if (s == NULL)
416 7bcbb606 2022-12-26 op return (-1);
417 7bcbb606 2022-12-26 op }
418 5546fdd5 2022-12-23 op
419 7bcbb606 2022-12-26 op if (*s == '#') {
420 7bcbb606 2022-12-26 op s = parse_qf(s + 1, IH_FRAGMENT, iri, iri->iri_fragment,
421 7bcbb606 2022-12-26 op sizeof(iri->iri_fragment));
422 7bcbb606 2022-12-26 op if (s == NULL)
423 7bcbb606 2022-12-26 op return (-1);
424 7bcbb606 2022-12-26 op }
425 a165601e 2022-12-25 op
426 a165601e 2022-12-25 op if (*s == '\0')
427 5546fdd5 2022-12-23 op return (0);
428 5546fdd5 2022-12-23 op
429 5546fdd5 2022-12-23 op return (-1);
430 5546fdd5 2022-12-23 op }
431 5546fdd5 2022-12-23 op
432 5546fdd5 2022-12-23 op static int
433 5546fdd5 2022-12-23 op parse(const char *s, struct iri *iri)
434 5546fdd5 2022-12-23 op {
435 5546fdd5 2022-12-23 op iri->iri_flags = 0;
436 5546fdd5 2022-12-23 op
437 5546fdd5 2022-12-23 op if (s == NULL)
438 5546fdd5 2022-12-23 op return (0);
439 5546fdd5 2022-12-23 op
440 5546fdd5 2022-12-23 op if (parse_uri(s, iri) == -1) {
441 5546fdd5 2022-12-23 op iri->iri_flags = 0;
442 5546fdd5 2022-12-23 op if (parse_relative_ref(s, iri) == -1)
443 5546fdd5 2022-12-23 op return (-1);
444 5546fdd5 2022-12-23 op }
445 5546fdd5 2022-12-23 op
446 5546fdd5 2022-12-23 op return (0);
447 5546fdd5 2022-12-23 op }
448 5546fdd5 2022-12-23 op
449 51762770 2022-12-24 op static inline void
450 51762770 2022-12-24 op lowerify(char *s)
451 51762770 2022-12-24 op {
452 51762770 2022-12-24 op for (; *s; ++s)
453 51762770 2022-12-24 op *s = tolower((unsigned char)*s);
454 51762770 2022-12-24 op }
455 51762770 2022-12-24 op
456 5546fdd5 2022-12-23 op static void
457 5546fdd5 2022-12-23 op cpfields(struct iri *dest, const struct iri *src, int flags)
458 5546fdd5 2022-12-23 op {
459 5546fdd5 2022-12-23 op if (flags & IH_SCHEME) {
460 5546fdd5 2022-12-23 op dest->iri_flags |= IH_SCHEME;
461 5546fdd5 2022-12-23 op if (src->iri_flags & IH_SCHEME)
462 5546fdd5 2022-12-23 op memcpy(dest->iri_scheme, src->iri_scheme,
463 5546fdd5 2022-12-23 op sizeof(dest->iri_scheme));
464 51762770 2022-12-24 op lowerify(dest->iri_scheme);
465 5546fdd5 2022-12-23 op }
466 5546fdd5 2022-12-23 op if (flags & IH_UINFO) {
467 997b9cd0 2022-12-24 op if (src->iri_flags & IH_UINFO) {
468 5546fdd5 2022-12-23 op memcpy(dest->iri_uinfo, src->iri_uinfo,
469 5546fdd5 2022-12-23 op sizeof(dest->iri_uinfo));
470 997b9cd0 2022-12-24 op dest->iri_flags |= IH_UINFO;
471 997b9cd0 2022-12-24 op }
472 5546fdd5 2022-12-23 op }
473 5546fdd5 2022-12-23 op if (flags & IH_HOST) {
474 5546fdd5 2022-12-23 op dest->iri_flags |= IH_HOST;
475 5546fdd5 2022-12-23 op if (src->iri_flags & IH_HOST)
476 5546fdd5 2022-12-23 op memcpy(dest->iri_host, src->iri_host,
477 5546fdd5 2022-12-23 op sizeof(dest->iri_host));
478 51762770 2022-12-24 op lowerify(dest->iri_host);
479 5546fdd5 2022-12-23 op }
480 5546fdd5 2022-12-23 op if (flags & IH_PORT) {
481 997b9cd0 2022-12-24 op if (src->iri_flags & IH_PORT) {
482 5546fdd5 2022-12-23 op dest->iri_port = src->iri_port;
483 e3278842 2022-12-26 op memcpy(dest->iri_portstr, src->iri_portstr,
484 e3278842 2022-12-26 op sizeof(dest->iri_portstr));
485 997b9cd0 2022-12-24 op dest->iri_flags |= IH_PORT;
486 997b9cd0 2022-12-24 op }
487 5546fdd5 2022-12-23 op }
488 5546fdd5 2022-12-23 op if (flags & IH_PATH) {
489 5546fdd5 2022-12-23 op dest->iri_flags |= IH_PATH;
490 5546fdd5 2022-12-23 op if (src->iri_flags & IH_PATH)
491 5546fdd5 2022-12-23 op memcpy(dest->iri_path, src->iri_path,
492 5546fdd5 2022-12-23 op sizeof(dest->iri_path));
493 5546fdd5 2022-12-23 op }
494 5546fdd5 2022-12-23 op if (flags & IH_QUERY) {
495 997b9cd0 2022-12-24 op if (src->iri_flags & IH_QUERY) {
496 997b9cd0 2022-12-24 op dest->iri_flags |= IH_QUERY;
497 5546fdd5 2022-12-23 op memcpy(dest->iri_query, src->iri_query,
498 5546fdd5 2022-12-23 op sizeof(dest->iri_query));
499 a165601e 2022-12-25 op }
500 a165601e 2022-12-25 op }
501 a165601e 2022-12-25 op if (flags & IH_FRAGMENT) {
502 a165601e 2022-12-25 op if (src->iri_flags & IH_FRAGMENT) {
503 a165601e 2022-12-25 op dest->iri_flags |= IH_FRAGMENT;
504 a165601e 2022-12-25 op memcpy(dest->iri_fragment, src->iri_fragment,
505 a165601e 2022-12-25 op sizeof(dest->iri_fragment));
506 997b9cd0 2022-12-24 op }
507 5546fdd5 2022-12-23 op }
508 5546fdd5 2022-12-23 op }
509 5546fdd5 2022-12-23 op
510 871b5bb7 2022-12-24 op static inline int
511 d2d73a09 2022-12-26 op remove_dot_segments(char *buf, ptrdiff_t bufsize)
512 5546fdd5 2022-12-23 op {
513 d2d73a09 2022-12-26 op char *p, *q;
514 5546fdd5 2022-12-23 op
515 d2d73a09 2022-12-26 op p = q = buf;
516 871b5bb7 2022-12-24 op while (*p && (q - buf < bufsize)) {
517 8b2b06b5 2022-12-25 op if (p[0] == '/' && p[1] == '.' &&
518 8b2b06b5 2022-12-25 op (p[2] == '/' || p[2] == '\0')) {
519 871b5bb7 2022-12-24 op p += 2;
520 8b2b06b5 2022-12-25 op if (*p != '/')
521 8b2b06b5 2022-12-25 op *q++ = '/';
522 8b2b06b5 2022-12-25 op } else if (p[0] == '/' && p[1] == '.' && p[2] == '.' &&
523 871b5bb7 2022-12-24 op (p[3] == '/' || p[3] == '\0')) {
524 871b5bb7 2022-12-24 op p += 3;
525 8b2b06b5 2022-12-25 op while (q > buf && *--q != '/')
526 871b5bb7 2022-12-24 op continue;
527 8b2b06b5 2022-12-25 op if (*p != '/' && (q > buf && q[-1] != '/'))
528 8b2b06b5 2022-12-25 op *q++ = '/';
529 8b2b06b5 2022-12-25 op } else
530 871b5bb7 2022-12-24 op *q++ = *p++;
531 871b5bb7 2022-12-24 op }
532 8b2b06b5 2022-12-25 op if ((*p == '\0') && (q - buf < bufsize)) {
533 871b5bb7 2022-12-24 op *q = '\0';
534 871b5bb7 2022-12-24 op return (0);
535 871b5bb7 2022-12-24 op }
536 871b5bb7 2022-12-24 op
537 871b5bb7 2022-12-24 op errno = ENAMETOOLONG;
538 871b5bb7 2022-12-24 op return (-1);
539 871b5bb7 2022-12-24 op }
540 871b5bb7 2022-12-24 op
541 871b5bb7 2022-12-24 op static inline int
542 69942b73 2022-12-26 op mergepath(char *buf, size_t bufsize, int abs, const char *base, const char *r)
543 5546fdd5 2022-12-23 op {
544 69942b73 2022-12-26 op const char *s;
545 871b5bb7 2022-12-24 op
546 69942b73 2022-12-26 op if (base == NULL || *base == '\0')
547 69942b73 2022-12-26 op base = "/";
548 69942b73 2022-12-26 op if (r == NULL || *r == '\0')
549 69942b73 2022-12-26 op r = "/";
550 871b5bb7 2022-12-24 op
551 69942b73 2022-12-26 op if (bufsize == 0)
552 69942b73 2022-12-26 op return (-1);
553 69942b73 2022-12-26 op buf[0] = '\0';
554 871b5bb7 2022-12-24 op
555 69942b73 2022-12-26 op if (abs && (*base == '\0' || !strcmp(base, "/"))) {
556 69942b73 2022-12-26 op if (*r == '/')
557 69942b73 2022-12-26 op r++;
558 69942b73 2022-12-26 op strlcpy(buf, "/", bufsize);
559 69942b73 2022-12-26 op strlcat(buf, r, bufsize);
560 871b5bb7 2022-12-24 op return (0);
561 871b5bb7 2022-12-24 op }
562 871b5bb7 2022-12-24 op
563 69942b73 2022-12-26 op if ((s = strrchr(base, '/')) != NULL) {
564 69942b73 2022-12-26 op cpstr(base, s + 1, buf, bufsize);
565 69942b73 2022-12-26 op if (*r == '/')
566 69942b73 2022-12-26 op r++;
567 871b5bb7 2022-12-24 op }
568 69942b73 2022-12-26 op if (strlcat(buf, r, bufsize) >= bufsize) {
569 871b5bb7 2022-12-24 op errno = ENAMETOOLONG;
570 871b5bb7 2022-12-24 op return (-1);
571 871b5bb7 2022-12-24 op }
572 871b5bb7 2022-12-24 op
573 871b5bb7 2022-12-24 op return (0);
574 5546fdd5 2022-12-23 op }
575 5546fdd5 2022-12-23 op
576 5546fdd5 2022-12-23 op int
577 5546fdd5 2022-12-23 op iri_parse(const char *base, const char *str, struct iri *iri)
578 5546fdd5 2022-12-23 op {
579 5546fdd5 2022-12-23 op static struct iri ibase, iparsed;
580 5546fdd5 2022-12-23 op
581 5546fdd5 2022-12-23 op memset(iri, 0, sizeof(*iri));
582 5546fdd5 2022-12-23 op
583 5546fdd5 2022-12-23 op if (base == NULL) {
584 5546fdd5 2022-12-23 op ibase.iri_flags = 0;
585 f5bc8482 2022-12-24 op if (parse_uri(str, &iparsed) == -1) {
586 f5bc8482 2022-12-24 op errno = EINVAL;
587 5546fdd5 2022-12-23 op return (-1);
588 f5bc8482 2022-12-24 op }
589 5546fdd5 2022-12-23 op } else {
590 f5bc8482 2022-12-24 op if (parse_uri(base, &ibase) == -1 ||
591 f5bc8482 2022-12-24 op parse(str, &iparsed) == -1) {
592 f5bc8482 2022-12-24 op errno = EINVAL;
593 5546fdd5 2022-12-23 op return (-1);
594 f5bc8482 2022-12-24 op }
595 5546fdd5 2022-12-23 op }
596 5546fdd5 2022-12-23 op
597 a165601e 2022-12-25 op cpfields(iri, &iparsed, IH_FRAGMENT);
598 a165601e 2022-12-25 op
599 5546fdd5 2022-12-23 op if (iparsed.iri_flags & IH_SCHEME) {
600 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, iparsed.iri_flags);
601 d2d73a09 2022-12-26 op remove_dot_segments(iri->iri_path, sizeof(iri->iri_path));
602 5546fdd5 2022-12-23 op return (0);
603 5546fdd5 2022-12-23 op }
604 5546fdd5 2022-12-23 op
605 5546fdd5 2022-12-23 op cpfields(iri, &ibase, IH_SCHEME);
606 5546fdd5 2022-12-23 op
607 5546fdd5 2022-12-23 op if (iparsed.iri_flags & IH_HOST) {
608 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, IH_AUTHORITY|IH_PATH|IH_QUERY);
609 d2d73a09 2022-12-26 op remove_dot_segments(iri->iri_path, sizeof(iri->iri_path));
610 5546fdd5 2022-12-23 op return (0);
611 5546fdd5 2022-12-23 op }
612 5546fdd5 2022-12-23 op
613 5546fdd5 2022-12-23 op cpfields(iri, &ibase, IH_AUTHORITY);
614 5546fdd5 2022-12-23 op
615 5546fdd5 2022-12-23 op if ((iparsed.iri_flags & IH_PATH) && *iparsed.iri_path == '\0') {
616 5546fdd5 2022-12-23 op cpfields(iri, &ibase, IH_PATH);
617 5546fdd5 2022-12-23 op if (iparsed.iri_flags & IH_QUERY)
618 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, IH_QUERY);
619 5546fdd5 2022-12-23 op else
620 5546fdd5 2022-12-23 op cpfields(iri, &ibase, IH_QUERY);
621 5546fdd5 2022-12-23 op return (0);
622 5546fdd5 2022-12-23 op }
623 5546fdd5 2022-12-23 op
624 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, IH_QUERY);
625 5cb6cd4d 2022-12-24 op if ((iparsed.iri_flags & IH_PATH) && *iparsed.iri_path == '/')
626 5546fdd5 2022-12-23 op cpfields(iri, &iparsed, IH_PATH);
627 5546fdd5 2022-12-23 op else {
628 5546fdd5 2022-12-23 op if (!(ibase.iri_flags & IH_PATH))
629 5546fdd5 2022-12-23 op ibase.iri_path[0] = '\0';
630 5546fdd5 2022-12-23 op if (!(iparsed.iri_flags & IH_PATH))
631 5546fdd5 2022-12-23 op iparsed.iri_path[0] = '\0';
632 69942b73 2022-12-26 op if (mergepath(iri->iri_path, sizeof(iri->iri_path),
633 69942b73 2022-12-26 op ibase.iri_flags & IH_AUTHORITY, ibase.iri_path,
634 69942b73 2022-12-26 op iparsed.iri_path) == -1)
635 f5bc8482 2022-12-24 op return (-1);
636 69942b73 2022-12-26 op iri->iri_flags |= IH_PATH;
637 5546fdd5 2022-12-23 op }
638 d2d73a09 2022-12-26 op if (remove_dot_segments(iri->iri_path, sizeof(iri->iri_path)) == -1)
639 f5bc8482 2022-12-24 op return (-1);
640 5546fdd5 2022-12-23 op return (0);
641 5546fdd5 2022-12-23 op }
642 5546fdd5 2022-12-23 op
643 5546fdd5 2022-12-23 op int
644 d59fad58 2022-12-24 op iri_unparse(const struct iri *i, char *buf, size_t buflen)
645 5546fdd5 2022-12-23 op {
646 c6432d39 2024-02-21 op int need_ss, have_path, need_s;
647 c6432d39 2024-02-21 op int r;
648 d59fad58 2022-12-24 op
649 e2089110 2024-02-21 op /* file is a quirky scheme */
650 e2089110 2024-02-21 op need_ss = (i->iri_flags & IH_AUTHORITY) ||
651 e2089110 2024-02-21 op !strcmp(i->iri_scheme, "file");
652 c6432d39 2024-02-21 op have_path = i->iri_flags & IH_PATH;
653 c6432d39 2024-02-21 op need_s = have_path && (i->iri_flags & IH_AUTHORITY) &&
654 c6432d39 2024-02-21 op i->iri_path[0] != '/';
655 d59fad58 2022-12-24 op
656 c6432d39 2024-02-21 op r = snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
657 c6432d39 2024-02-21 op (i->iri_flags & IH_SCHEME) ? i->iri_scheme : "",
658 c6432d39 2024-02-21 op (i->iri_flags & IH_SCHEME) ? ":" : "",
659 c6432d39 2024-02-21 op need_ss ? "//" : "",
660 c6432d39 2024-02-21 op (i->iri_flags & IH_UINFO) ? i->iri_uinfo : "",
661 c6432d39 2024-02-21 op (i->iri_flags & IH_UINFO) ? "@" : "",
662 c6432d39 2024-02-21 op (i->iri_flags & IH_HOST) ? i->iri_host : "",
663 c6432d39 2024-02-21 op (i->iri_flags & IH_PORT) ? ":" : "",
664 c6432d39 2024-02-21 op (i->iri_flags & IH_PORT) ? i->iri_portstr : "",
665 c6432d39 2024-02-21 op need_s ? "/" : "",
666 c6432d39 2024-02-21 op have_path ? i->iri_path : "",
667 c6432d39 2024-02-21 op (i->iri_flags & IH_QUERY) ? "?" : "",
668 c6432d39 2024-02-21 op (i->iri_flags & IH_QUERY) ? i->iri_query : "",
669 c6432d39 2024-02-21 op (i->iri_flags & IH_FRAGMENT) ? "#" : "",
670 c6432d39 2024-02-21 op (i->iri_flags & IH_FRAGMENT) ? i->iri_fragment : "");
671 c6432d39 2024-02-21 op if (r < 0 || (size_t)r >= buflen) {
672 c6432d39 2024-02-21 op errno = ENOBUFS;
673 c6432d39 2024-02-21 op return (-1);
674 d59fad58 2022-12-24 op }
675 d59fad58 2022-12-24 op
676 d59fad58 2022-12-24 op return (0);
677 5546fdd5 2022-12-23 op }
678 5546fdd5 2022-12-23 op
679 5546fdd5 2022-12-23 op int
680 5546fdd5 2022-12-23 op iri_human(const struct iri *iri, char *buf, size_t buflen)
681 5546fdd5 2022-12-23 op {
682 5546fdd5 2022-12-23 op memset(buf, 0, buflen);
683 5546fdd5 2022-12-23 op return (-1);
684 5546fdd5 2022-12-23 op }
685 5546fdd5 2022-12-23 op
686 5546fdd5 2022-12-23 op int
687 1cbd9b61 2024-01-16 op iri_setport(struct iri *iri, const char *portstr)
688 1cbd9b61 2024-01-16 op {
689 1cbd9b61 2024-01-16 op const char *errstr;
690 1cbd9b61 2024-01-16 op int port;
691 1cbd9b61 2024-01-16 op
692 1cbd9b61 2024-01-16 op port = strtonum(portstr, 1, UINT16_MAX, &errstr);
693 1cbd9b61 2024-01-16 op if (errstr)
694 1cbd9b61 2024-01-16 op return (-1);
695 1cbd9b61 2024-01-16 op
696 1cbd9b61 2024-01-16 op snprintf(iri->iri_portstr, sizeof(iri->iri_portstr), "%d", port);
697 1cbd9b61 2024-01-16 op iri->iri_port = port;
698 1cbd9b61 2024-01-16 op return (0);
699 1cbd9b61 2024-01-16 op }
700 1cbd9b61 2024-01-16 op
701 1cbd9b61 2024-01-16 op int
702 a2785a57 2022-12-26 op iri_setquery(struct iri *iri, const char *p)
703 5546fdd5 2022-12-23 op {
704 a2785a57 2022-12-26 op ptrdiff_t bufsize;
705 a2785a57 2022-12-26 op int r;
706 21fc67ae 2022-12-26 op char *buf, *q, tmp[4];
707 a2785a57 2022-12-26 op
708 a2785a57 2022-12-26 op buf = q = iri->iri_query;
709 a2785a57 2022-12-26 op bufsize = sizeof(iri->iri_query);
710 a2785a57 2022-12-26 op while (*p && (q - buf < bufsize)) {
711 1a69f471 2024-01-13 op if (unreserved(*p) || sub_delims(*p) || *p == ':' ||
712 1a69f471 2024-01-13 op *p == '@' || *p == '/' || *p == '?') {
713 1a69f471 2024-01-13 op *q++ = *p++;
714 1a69f471 2024-01-13 op continue;
715 a2785a57 2022-12-26 op }
716 1a69f471 2024-01-13 op
717 1a69f471 2024-01-13 op if (q - buf >= bufsize - 3)
718 1a69f471 2024-01-13 op goto err;
719 1a69f471 2024-01-13 op r = snprintf(tmp, sizeof(tmp), "%%%02X", (int)*p);
720 1a69f471 2024-01-13 op if (r < 0 || (size_t)r > sizeof(tmp))
721 1a69f471 2024-01-13 op return (-1);
722 1a69f471 2024-01-13 op *q++ = tmp[0];
723 1a69f471 2024-01-13 op *q++ = tmp[1];
724 1a69f471 2024-01-13 op *q++ = tmp[2];
725 1a69f471 2024-01-13 op p++;
726 a2785a57 2022-12-26 op }
727 a2785a57 2022-12-26 op if ((*p == '\0') && (q - buf < bufsize)) {
728 a2785a57 2022-12-26 op iri->iri_flags |= IH_QUERY;
729 a2785a57 2022-12-26 op *q = '\0';
730 a2785a57 2022-12-26 op return (0);
731 a2785a57 2022-12-26 op }
732 a2785a57 2022-12-26 op
733 a2785a57 2022-12-26 op err:
734 a2785a57 2022-12-26 op errno = ENOBUFS;
735 5546fdd5 2022-12-23 op return (-1);
736 62c0f697 2024-02-21 op }
737 62c0f697 2024-02-21 op
738 62c0f697 2024-02-21 op int
739 62c0f697 2024-02-21 op iri_urlescape(const char *path, char *buf, size_t len)
740 62c0f697 2024-02-21 op {
741 62c0f697 2024-02-21 op const char *hex = "0123456789abcdef";
742 62c0f697 2024-02-21 op const uint8_t *p = path;
743 62c0f697 2024-02-21 op
744 62c0f697 2024-02-21 op while (*p) {
745 62c0f697 2024-02-21 op if (len == 0)
746 62c0f697 2024-02-21 op break;
747 62c0f697 2024-02-21 op
748 62c0f697 2024-02-21 op if (unreserved(*p) || sub_delims(*p) ||
749 62c0f697 2024-02-21 op *p == ':' || *p == '@' ||
750 62c0f697 2024-02-21 op *p == '/') {
751 62c0f697 2024-02-21 op *buf++ = *p++;
752 62c0f697 2024-02-21 op len--;
753 62c0f697 2024-02-21 op continue;
754 62c0f697 2024-02-21 op }
755 62c0f697 2024-02-21 op
756 62c0f697 2024-02-21 op if (len < 3)
757 62c0f697 2024-02-21 op break;
758 62c0f697 2024-02-21 op *buf++ = '%';
759 62c0f697 2024-02-21 op *buf++ = hex[*p >> 4];
760 62c0f697 2024-02-21 op *buf++ = hex[*p & 0xf];
761 62c0f697 2024-02-21 op len -= 3;
762 62c0f697 2024-02-21 op p++;
763 62c0f697 2024-02-21 op }
764 62c0f697 2024-02-21 op
765 62c0f697 2024-02-21 op if (len == 0 || *p)
766 62c0f697 2024-02-21 op return (-1);
767 62c0f697 2024-02-21 op
768 62c0f697 2024-02-21 op *buf = '\0';
769 62c0f697 2024-02-21 op return (0);
770 62c0f697 2024-02-21 op }
771 62c0f697 2024-02-21 op
772 62c0f697 2024-02-21 op int
773 62c0f697 2024-02-21 op iri_urlunescape(const char *str, char *buf, size_t len)
774 62c0f697 2024-02-21 op {
775 62c0f697 2024-02-21 op char t[3];
776 62c0f697 2024-02-21 op unsigned long l;
777 62c0f697 2024-02-21 op
778 62c0f697 2024-02-21 op t[2] = '\0';
779 62c0f697 2024-02-21 op
780 62c0f697 2024-02-21 op while (*str) {
781 62c0f697 2024-02-21 op if (len == 0)
782 62c0f697 2024-02-21 op return (-1);
783 62c0f697 2024-02-21 op
784 62c0f697 2024-02-21 op if (*str != '%') {
785 62c0f697 2024-02-21 op *buf++ = *str++;
786 62c0f697 2024-02-21 op len--;
787 62c0f697 2024-02-21 op continue;
788 62c0f697 2024-02-21 op }
789 62c0f697 2024-02-21 op
790 62c0f697 2024-02-21 op if (!isxdigit((unsigned char)str[1]) ||
791 62c0f697 2024-02-21 op !isxdigit((unsigned char)str[2]))
792 62c0f697 2024-02-21 op return (-1);
793 62c0f697 2024-02-21 op
794 62c0f697 2024-02-21 op t[0] = str[1];
795 62c0f697 2024-02-21 op t[1] = str[2];
796 62c0f697 2024-02-21 op
797 62c0f697 2024-02-21 op /* we know it's a proper number and will fit a char */
798 62c0f697 2024-02-21 op l = strtol(t, NULL, 16);
799 62c0f697 2024-02-21 op *buf++ = (unsigned char)l;
800 62c0f697 2024-02-21 op len--;
801 62c0f697 2024-02-21 op str += 3;
802 62c0f697 2024-02-21 op }
803 62c0f697 2024-02-21 op
804 62c0f697 2024-02-21 op if (len == 0)
805 62c0f697 2024-02-21 op return (-1);
806 62c0f697 2024-02-21 op *buf = '\0';
807 62c0f697 2024-02-21 op return (0);
808 5546fdd5 2022-12-23 op }