/src/mhd2/src/mhd2/mhd_str.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | This file is part of libmicrohttpd |
3 | | Copyright (C) 2015-2024 Evgeny Grin (Karlson2k) |
4 | | |
5 | | GNU libmicrohttpd is free software; you can redistribute it and/or |
6 | | modify it under the terms of the GNU Lesser General Public |
7 | | License as published by the Free Software Foundation; either |
8 | | version 2.1 of the License, or (at your option) any later version. |
9 | | |
10 | | GNU libmicrohttpd is distributed in the hope that it will be useful, |
11 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | | Lesser General Public License for more details. |
14 | | |
15 | | You should have received a copy of the GNU Lesser General Public |
16 | | License along with this library; if not, write to the Free Software |
17 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
18 | | */ |
19 | | |
20 | | /** |
21 | | * @file microhttpd/mhd_str.c |
22 | | * @brief Functions implementations for string manipulating |
23 | | * @author Karlson2k (Evgeny Grin) |
24 | | */ |
25 | | |
26 | | #include "mhd_sys_options.h" |
27 | | |
28 | | #include "mhd_str.h" |
29 | | |
30 | | #include <string.h> |
31 | | |
32 | | #include "mhd_assert.h" |
33 | | #include "mhd_limits.h" |
34 | | |
35 | | #ifdef MHD_FAVOR_SMALL_CODE |
36 | | # ifdef MHD_static_inline_ |
37 | | # undef MHD_static_inline_ |
38 | | # endif /* MHD_static_inline_ */ |
39 | | /* Do not force inlining and do not use macro functions, use normal static |
40 | | functions instead. |
41 | | This may give more flexibility for size optimizations. */ |
42 | | # define MHD_static_inline_ static |
43 | | # ifndef HAVE_INLINE_FUNCS |
44 | | # define HAVE_INLINE_FUNCS 1 |
45 | | # endif /* !HAVE_INLINE_FUNCS */ |
46 | | #endif /* MHD_FAVOR_SMALL_CODE */ |
47 | | |
48 | | /* |
49 | | * Block of functions/macros that use US-ASCII charset as required by HTTP |
50 | | * standards. Not affected by current locale settings. |
51 | | */ |
52 | | |
53 | | #ifdef HAVE_INLINE_FUNCS |
54 | | |
55 | | #if 0 /* Disable unused functions. */ |
56 | | /** |
57 | | * Check whether character is lower case letter in US-ASCII |
58 | | * |
59 | | * @param c character to check |
60 | | * @return non-zero if character is lower case letter, zero otherwise |
61 | | */ |
62 | | MHD_static_inline_ MHD_FN_CONST_ bool |
63 | | isasciilower (char c) |
64 | | { |
65 | | return (c >= 'a') && (c <= 'z'); |
66 | | } |
67 | | |
68 | | |
69 | | #endif /* Disable unused functions. */ |
70 | | |
71 | | |
72 | | /** |
73 | | * Check whether character is upper case letter in US-ASCII |
74 | | * |
75 | | * @param c character to check |
76 | | * @return non-zero if character is upper case letter, zero otherwise |
77 | | */ |
78 | | MHD_static_inline_ MHD_FN_CONST_ bool |
79 | | isasciiupper (char c) |
80 | 2.15k | { |
81 | 2.15k | return (c <= 'Z') && (c >= 'A'); |
82 | 2.15k | } |
83 | | |
84 | | |
85 | | #if 0 /* Disable unused functions. */ |
86 | | /** |
87 | | * Check whether character is letter in US-ASCII |
88 | | * |
89 | | * @param c character to check |
90 | | * @return non-zero if character is letter in US-ASCII, zero otherwise |
91 | | */ |
92 | | MHD_static_inline_ MHD_FN_CONST_ bool |
93 | | isasciialpha (char c) |
94 | | { |
95 | | return isasciilower (c) || isasciiupper (c); |
96 | | } |
97 | | |
98 | | |
99 | | #endif /* Disable unused functions. */ |
100 | | |
101 | | |
102 | | /** |
103 | | * Check whether character is decimal digit in US-ASCII |
104 | | * |
105 | | * @param c character to check |
106 | | * @return non-zero if character is decimal digit, zero otherwise |
107 | | */ |
108 | | MHD_static_inline_ MHD_FN_CONST_ bool |
109 | | isasciidigit (char c) |
110 | 17.5k | { |
111 | 17.5k | return (c <= '9') && (c >= '0'); |
112 | 17.5k | } |
113 | | |
114 | | |
115 | | #if 0 /* Disable unused functions. */ |
116 | | /** |
117 | | * Check whether character is hexadecimal digit in US-ASCII |
118 | | * |
119 | | * @param c character to check |
120 | | * @return non-zero if character is decimal digit, zero otherwise |
121 | | */ |
122 | | MHD_static_inline_ MHD_FN_CONST_ bool |
123 | | isasciixdigit (char c) |
124 | | { |
125 | | return isasciidigit (c) || |
126 | | ( (c <= 'F') && (c >= 'A') ) || |
127 | | ( (c <= 'f') && (c >= 'a') ); |
128 | | } |
129 | | |
130 | | |
131 | | /** |
132 | | * Check whether character is decimal digit or letter in US-ASCII |
133 | | * |
134 | | * @param c character to check |
135 | | * @return non-zero if character is decimal digit or letter, zero otherwise |
136 | | */ |
137 | | MHD_static_inline_ MHD_FN_CONST_ bool |
138 | | isasciialnum (char c) |
139 | | { |
140 | | return isasciialpha (c) || isasciidigit (c); |
141 | | } |
142 | | |
143 | | |
144 | | #endif /* Disable unused functions. */ |
145 | | |
146 | | |
147 | | #if 0 /* Disable unused functions. */ |
148 | | /** |
149 | | * Convert US-ASCII character to lower case. |
150 | | * If character is upper case letter in US-ASCII than it's converted to lower |
151 | | * case analog. If character is NOT upper case letter than it's returned |
152 | | * unmodified. |
153 | | * |
154 | | * @param c character to convert |
155 | | * @return converted to lower case character |
156 | | */ |
157 | | MHD_static_inline_ MHD_FN_CONST_ char |
158 | | toasciilower (char c) |
159 | | { |
160 | | return isasciiupper (c) ? (char) (0x20u | (unsigned char) c) : c; |
161 | | } |
162 | | |
163 | | |
164 | | /** |
165 | | * Convert US-ASCII character to upper case. |
166 | | * If character is lower case letter in US-ASCII than it's converted to upper |
167 | | * case analog. If character is NOT lower case letter than it's returned |
168 | | * unmodified. |
169 | | * |
170 | | * @param c character to convert |
171 | | * @return converted to upper case character |
172 | | */ |
173 | | MHD_static_inline_ MHD_FN_CONST_ char |
174 | | toasciiupper (char c) |
175 | | { |
176 | | return isasciilower (c) ? (char) ((~0x20u) & (unsigned char) c) : c; |
177 | | } |
178 | | |
179 | | |
180 | | #endif /* Disable unused functions. */ |
181 | | |
182 | | |
183 | | #if defined(MHD_FAVOR_SMALL_CODE) /* Used only in mhd_str_to_uvalue_n() */ |
184 | | /** |
185 | | * Convert US-ASCII decimal digit to its value. |
186 | | * |
187 | | * @param c character to convert |
188 | | * @return value of decimal digit or -1 if @ c is not decimal digit |
189 | | */ |
190 | | MHD_static_inline_ MHD_FN_CONST_ int |
191 | | todigitvalue (char c) |
192 | | { |
193 | | if (isasciidigit (c)) |
194 | | return (unsigned char) (c - '0'); |
195 | | |
196 | | return -1; |
197 | | } |
198 | | |
199 | | |
200 | | #endif /* MHD_FAVOR_SMALL_CODE */ |
201 | | |
202 | | |
203 | | /** |
204 | | * Convert US-ASCII hexadecimal digit to its value. |
205 | | * |
206 | | * @param c character to convert |
207 | | * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit |
208 | | */ |
209 | | MHD_static_inline_ MHD_FN_CONST_ int |
210 | | xdigittovalue (char c) |
211 | 52.5k | { |
212 | 52.5k | const unsigned char uc = (unsigned char) c; /* Force unsigned value */ |
213 | 52.5k | #if ! defined(MHD_FAVOR_SMALL_CODE) |
214 | 52.5k | static const signed char map_xdigit_to_value[256] = { |
215 | 52.5k | -1 /* 0x00 (NUL) */, |
216 | 52.5k | -1 /* 0x01 (SOH) */, |
217 | 52.5k | -1 /* 0x02 (STX) */, |
218 | 52.5k | -1 /* 0x03 (ETX) */, |
219 | 52.5k | -1 /* 0x04 (EOT) */, |
220 | 52.5k | -1 /* 0x05 (ENQ) */, |
221 | 52.5k | -1 /* 0x06 (ACK) */, |
222 | 52.5k | -1 /* 0x07 (BEL) */, |
223 | 52.5k | -1 /* 0x08 (BS) */, |
224 | 52.5k | -1 /* 0x09 (HT) */, |
225 | 52.5k | -1 /* 0x0A (LF) */, |
226 | 52.5k | -1 /* 0x0B (VT) */, |
227 | 52.5k | -1 /* 0x0C (FF) */, |
228 | 52.5k | -1 /* 0x0D (CR) */, |
229 | 52.5k | -1 /* 0x0E (SO) */, |
230 | 52.5k | -1 /* 0x0F (SI) */, |
231 | 52.5k | -1 /* 0x10 (DLE) */, |
232 | 52.5k | -1 /* 0x11 (DC1) */, |
233 | 52.5k | -1 /* 0x12 (DC2) */, |
234 | 52.5k | -1 /* 0x13 (DC3) */, |
235 | 52.5k | -1 /* 0x14 (DC4) */, |
236 | 52.5k | -1 /* 0x15 (NAK) */, |
237 | 52.5k | -1 /* 0x16 (SYN) */, |
238 | 52.5k | -1 /* 0x17 (ETB) */, |
239 | 52.5k | -1 /* 0x18 (CAN) */, |
240 | 52.5k | -1 /* 0x19 (EM) */, |
241 | 52.5k | -1 /* 0x1A (SUB) */, |
242 | 52.5k | -1 /* 0x1B (ESC) */, |
243 | 52.5k | -1 /* 0x1C (FS) */, |
244 | 52.5k | -1 /* 0x1D (GS) */, |
245 | 52.5k | -1 /* 0x1E (RS) */, |
246 | 52.5k | -1 /* 0x1F (US) */, |
247 | 52.5k | -1 /* 0x20 (' ') */, |
248 | 52.5k | -1 /* 0x21 ('!') */, |
249 | 52.5k | -1 /* 0x22 ('"') */, |
250 | 52.5k | -1 /* 0x23 ('#') */, |
251 | 52.5k | -1 /* 0x24 ('$') */, |
252 | 52.5k | -1 /* 0x25 ('%') */, |
253 | 52.5k | -1 /* 0x26 ('&') */, |
254 | 52.5k | -1 /* 0x27 ('\'') */, |
255 | 52.5k | -1 /* 0x28 ('(') */, |
256 | 52.5k | -1 /* 0x29 (')') */, |
257 | 52.5k | -1 /* 0x2A ('*') */, |
258 | 52.5k | -1 /* 0x2B ('+') */, |
259 | 52.5k | -1 /* 0x2C (',') */, |
260 | 52.5k | -1 /* 0x2D ('-') */, |
261 | 52.5k | -1 /* 0x2E ('.') */, |
262 | 52.5k | -1 /* 0x2F ('/') */, |
263 | 52.5k | 0 /* 0x30 ('0') */, |
264 | 52.5k | 1 /* 0x31 ('1') */, |
265 | 52.5k | 2 /* 0x32 ('2') */, |
266 | 52.5k | 3 /* 0x33 ('3') */, |
267 | 52.5k | 4 /* 0x34 ('4') */, |
268 | 52.5k | 5 /* 0x35 ('5') */, |
269 | 52.5k | 6 /* 0x36 ('6') */, |
270 | 52.5k | 7 /* 0x37 ('7') */, |
271 | 52.5k | 8 /* 0x38 ('8') */, |
272 | 52.5k | 9 /* 0x39 ('9') */, |
273 | 52.5k | -1 /* 0x3A (':') */, |
274 | 52.5k | -1 /* 0x3B (';') */, |
275 | 52.5k | -1 /* 0x3C ('<') */, |
276 | 52.5k | -1 /* 0x3D ('=') */, |
277 | 52.5k | -1 /* 0x3E ('>') */, |
278 | 52.5k | -1 /* 0x3F ('?') */, |
279 | 52.5k | -1 /* 0x40 ('@') */, |
280 | 52.5k | 10 /* 0x41 ('A') */, |
281 | 52.5k | 11 /* 0x42 ('B') */, |
282 | 52.5k | 12 /* 0x43 ('C') */, |
283 | 52.5k | 13 /* 0x44 ('D') */, |
284 | 52.5k | 14 /* 0x45 ('E') */, |
285 | 52.5k | 15 /* 0x46 ('F') */, |
286 | 52.5k | -1 /* 0x47 ('G') */, |
287 | 52.5k | -1 /* 0x48 ('H') */, |
288 | 52.5k | -1 /* 0x49 ('I') */, |
289 | 52.5k | -1 /* 0x4A ('J') */, |
290 | 52.5k | -1 /* 0x4B ('K') */, |
291 | 52.5k | -1 /* 0x4C ('L') */, |
292 | 52.5k | -1 /* 0x4D ('M') */, |
293 | 52.5k | -1 /* 0x4E ('N') */, |
294 | 52.5k | -1 /* 0x4F ('O') */, |
295 | 52.5k | -1 /* 0x50 ('P') */, |
296 | 52.5k | -1 /* 0x51 ('Q') */, |
297 | 52.5k | -1 /* 0x52 ('R') */, |
298 | 52.5k | -1 /* 0x53 ('S') */, |
299 | 52.5k | -1 /* 0x54 ('T') */, |
300 | 52.5k | -1 /* 0x55 ('U') */, |
301 | 52.5k | -1 /* 0x56 ('V') */, |
302 | 52.5k | -1 /* 0x57 ('W') */, |
303 | 52.5k | -1 /* 0x58 ('X') */, |
304 | 52.5k | -1 /* 0x59 ('Y') */, |
305 | 52.5k | -1 /* 0x5A ('Z') */, |
306 | 52.5k | -1 /* 0x5B ('[') */, |
307 | 52.5k | -1 /* 0x5C ('\') */, |
308 | 52.5k | -1 /* 0x5D (']') */, |
309 | 52.5k | -1 /* 0x5E ('^') */, |
310 | 52.5k | -1 /* 0x5F ('_') */, |
311 | 52.5k | -1 /* 0x60 ('`') */, |
312 | 52.5k | 10 /* 0x61 ('a') */, |
313 | 52.5k | 11 /* 0x62 ('b') */, |
314 | 52.5k | 12 /* 0x63 ('c') */, |
315 | 52.5k | 13 /* 0x64 ('d') */, |
316 | 52.5k | 14 /* 0x65 ('e') */, |
317 | 52.5k | 15 /* 0x66 ('f') */, |
318 | 52.5k | -1 /* 0x67 ('g') */, |
319 | 52.5k | -1 /* 0x68 ('h') */, |
320 | 52.5k | -1 /* 0x69 ('i') */, |
321 | 52.5k | -1 /* 0x6A ('j') */, |
322 | 52.5k | -1 /* 0x6B ('k') */, |
323 | 52.5k | -1 /* 0x6C ('l') */, |
324 | 52.5k | -1 /* 0x6D ('m') */, |
325 | 52.5k | -1 /* 0x6E ('n') */, |
326 | 52.5k | -1 /* 0x6F ('o') */, |
327 | 52.5k | -1 /* 0x70 ('p') */, |
328 | 52.5k | -1 /* 0x71 ('q') */, |
329 | 52.5k | -1 /* 0x72 ('r') */, |
330 | 52.5k | -1 /* 0x73 ('s') */, |
331 | 52.5k | -1 /* 0x74 ('t') */, |
332 | 52.5k | -1 /* 0x75 ('u') */, |
333 | 52.5k | -1 /* 0x76 ('v') */, |
334 | 52.5k | -1 /* 0x77 ('w') */, |
335 | 52.5k | -1 /* 0x78 ('x') */, |
336 | 52.5k | -1 /* 0x79 ('y') */, |
337 | 52.5k | -1 /* 0x7A ('z') */, |
338 | 52.5k | -1 /* 0x7B ('{') */, |
339 | 52.5k | -1 /* 0x7C ('|') */, |
340 | 52.5k | -1 /* 0x7D ('}') */, |
341 | 52.5k | -1 /* 0x7E ('~') */, |
342 | 52.5k | -1 /* 0x7F (DEL) */, |
343 | 52.5k | -1 /* 0x80 (EXT) */, |
344 | 52.5k | -1 /* 0x81 (EXT) */, |
345 | 52.5k | -1 /* 0x82 (EXT) */, |
346 | 52.5k | -1 /* 0x83 (EXT) */, |
347 | 52.5k | -1 /* 0x84 (EXT) */, |
348 | 52.5k | -1 /* 0x85 (EXT) */, |
349 | 52.5k | -1 /* 0x86 (EXT) */, |
350 | 52.5k | -1 /* 0x87 (EXT) */, |
351 | 52.5k | -1 /* 0x88 (EXT) */, |
352 | 52.5k | -1 /* 0x89 (EXT) */, |
353 | 52.5k | -1 /* 0x8A (EXT) */, |
354 | 52.5k | -1 /* 0x8B (EXT) */, |
355 | 52.5k | -1 /* 0x8C (EXT) */, |
356 | 52.5k | -1 /* 0x8D (EXT) */, |
357 | 52.5k | -1 /* 0x8E (EXT) */, |
358 | 52.5k | -1 /* 0x8F (EXT) */, |
359 | 52.5k | -1 /* 0x90 (EXT) */, |
360 | 52.5k | -1 /* 0x91 (EXT) */, |
361 | 52.5k | -1 /* 0x92 (EXT) */, |
362 | 52.5k | -1 /* 0x93 (EXT) */, |
363 | 52.5k | -1 /* 0x94 (EXT) */, |
364 | 52.5k | -1 /* 0x95 (EXT) */, |
365 | 52.5k | -1 /* 0x96 (EXT) */, |
366 | 52.5k | -1 /* 0x97 (EXT) */, |
367 | 52.5k | -1 /* 0x98 (EXT) */, |
368 | 52.5k | -1 /* 0x99 (EXT) */, |
369 | 52.5k | -1 /* 0x9A (EXT) */, |
370 | 52.5k | -1 /* 0x9B (EXT) */, |
371 | 52.5k | -1 /* 0x9C (EXT) */, |
372 | 52.5k | -1 /* 0x9D (EXT) */, |
373 | 52.5k | -1 /* 0x9E (EXT) */, |
374 | 52.5k | -1 /* 0x9F (EXT) */, |
375 | 52.5k | -1 /* 0xA0 (EXT) */, |
376 | 52.5k | -1 /* 0xA1 (EXT) */, |
377 | 52.5k | -1 /* 0xA2 (EXT) */, |
378 | 52.5k | -1 /* 0xA3 (EXT) */, |
379 | 52.5k | -1 /* 0xA4 (EXT) */, |
380 | 52.5k | -1 /* 0xA5 (EXT) */, |
381 | 52.5k | -1 /* 0xA6 (EXT) */, |
382 | 52.5k | -1 /* 0xA7 (EXT) */, |
383 | 52.5k | -1 /* 0xA8 (EXT) */, |
384 | 52.5k | -1 /* 0xA9 (EXT) */, |
385 | 52.5k | -1 /* 0xAA (EXT) */, |
386 | 52.5k | -1 /* 0xAB (EXT) */, |
387 | 52.5k | -1 /* 0xAC (EXT) */, |
388 | 52.5k | -1 /* 0xAD (EXT) */, |
389 | 52.5k | -1 /* 0xAE (EXT) */, |
390 | 52.5k | -1 /* 0xAF (EXT) */, |
391 | 52.5k | -1 /* 0xB0 (EXT) */, |
392 | 52.5k | -1 /* 0xB1 (EXT) */, |
393 | 52.5k | -1 /* 0xB2 (EXT) */, |
394 | 52.5k | -1 /* 0xB3 (EXT) */, |
395 | 52.5k | -1 /* 0xB4 (EXT) */, |
396 | 52.5k | -1 /* 0xB5 (EXT) */, |
397 | 52.5k | -1 /* 0xB6 (EXT) */, |
398 | 52.5k | -1 /* 0xB7 (EXT) */, |
399 | 52.5k | -1 /* 0xB8 (EXT) */, |
400 | 52.5k | -1 /* 0xB9 (EXT) */, |
401 | 52.5k | -1 /* 0xBA (EXT) */, |
402 | 52.5k | -1 /* 0xBB (EXT) */, |
403 | 52.5k | -1 /* 0xBC (EXT) */, |
404 | 52.5k | -1 /* 0xBD (EXT) */, |
405 | 52.5k | -1 /* 0xBE (EXT) */, |
406 | 52.5k | -1 /* 0xBF (EXT) */, |
407 | 52.5k | -1 /* 0xC0 (EXT) */, |
408 | 52.5k | -1 /* 0xC1 (EXT) */, |
409 | 52.5k | -1 /* 0xC2 (EXT) */, |
410 | 52.5k | -1 /* 0xC3 (EXT) */, |
411 | 52.5k | -1 /* 0xC4 (EXT) */, |
412 | 52.5k | -1 /* 0xC5 (EXT) */, |
413 | 52.5k | -1 /* 0xC6 (EXT) */, |
414 | 52.5k | -1 /* 0xC7 (EXT) */, |
415 | 52.5k | -1 /* 0xC8 (EXT) */, |
416 | 52.5k | -1 /* 0xC9 (EXT) */, |
417 | 52.5k | -1 /* 0xCA (EXT) */, |
418 | 52.5k | -1 /* 0xCB (EXT) */, |
419 | 52.5k | -1 /* 0xCC (EXT) */, |
420 | 52.5k | -1 /* 0xCD (EXT) */, |
421 | 52.5k | -1 /* 0xCE (EXT) */, |
422 | 52.5k | -1 /* 0xCF (EXT) */, |
423 | 52.5k | -1 /* 0xD0 (EXT) */, |
424 | 52.5k | -1 /* 0xD1 (EXT) */, |
425 | 52.5k | -1 /* 0xD2 (EXT) */, |
426 | 52.5k | -1 /* 0xD3 (EXT) */, |
427 | 52.5k | -1 /* 0xD4 (EXT) */, |
428 | 52.5k | -1 /* 0xD5 (EXT) */, |
429 | 52.5k | -1 /* 0xD6 (EXT) */, |
430 | 52.5k | -1 /* 0xD7 (EXT) */, |
431 | 52.5k | -1 /* 0xD8 (EXT) */, |
432 | 52.5k | -1 /* 0xD9 (EXT) */, |
433 | 52.5k | -1 /* 0xDA (EXT) */, |
434 | 52.5k | -1 /* 0xDB (EXT) */, |
435 | 52.5k | -1 /* 0xDC (EXT) */, |
436 | 52.5k | -1 /* 0xDD (EXT) */, |
437 | 52.5k | -1 /* 0xDE (EXT) */, |
438 | 52.5k | -1 /* 0xDF (EXT) */, |
439 | 52.5k | -1 /* 0xE0 (EXT) */, |
440 | 52.5k | -1 /* 0xE1 (EXT) */, |
441 | 52.5k | -1 /* 0xE2 (EXT) */, |
442 | 52.5k | -1 /* 0xE3 (EXT) */, |
443 | 52.5k | -1 /* 0xE4 (EXT) */, |
444 | 52.5k | -1 /* 0xE5 (EXT) */, |
445 | 52.5k | -1 /* 0xE6 (EXT) */, |
446 | 52.5k | -1 /* 0xE7 (EXT) */, |
447 | 52.5k | -1 /* 0xE8 (EXT) */, |
448 | 52.5k | -1 /* 0xE9 (EXT) */, |
449 | 52.5k | -1 /* 0xEA (EXT) */, |
450 | 52.5k | -1 /* 0xEB (EXT) */, |
451 | 52.5k | -1 /* 0xEC (EXT) */, |
452 | 52.5k | -1 /* 0xED (EXT) */, |
453 | 52.5k | -1 /* 0xEE (EXT) */, |
454 | 52.5k | -1 /* 0xEF (EXT) */, |
455 | 52.5k | -1 /* 0xF0 (EXT) */, |
456 | 52.5k | -1 /* 0xF1 (EXT) */, |
457 | 52.5k | -1 /* 0xF2 (EXT) */, |
458 | 52.5k | -1 /* 0xF3 (EXT) */, |
459 | 52.5k | -1 /* 0xF4 (EXT) */, |
460 | 52.5k | -1 /* 0xF5 (EXT) */, |
461 | 52.5k | -1 /* 0xF6 (EXT) */, |
462 | 52.5k | -1 /* 0xF7 (EXT) */, |
463 | 52.5k | -1 /* 0xF8 (EXT) */, |
464 | 52.5k | -1 /* 0xF9 (EXT) */, |
465 | 52.5k | -1 /* 0xFA (EXT) */, |
466 | 52.5k | -1 /* 0xFB (EXT) */, |
467 | 52.5k | -1 /* 0xFC (EXT) */, |
468 | 52.5k | -1 /* 0xFD (EXT) */, |
469 | 52.5k | -1 /* 0xFE (EXT) */, |
470 | 52.5k | -1 /* 0xFF (EXT) */ |
471 | 52.5k | }; |
472 | 52.5k | return map_xdigit_to_value[uc]; |
473 | | #else /* MHD_FAVOR_SMALL_CODE */ |
474 | | unsigned int try_val; |
475 | | |
476 | | try_val = uc - (unsigned char) '0'; |
477 | | if (9 >= try_val) |
478 | | return (int) (unsigned int) try_val; |
479 | | try_val = (uc | 0x20u /* fold case */) - (unsigned char) 'a'; |
480 | | if (5 >= try_val) |
481 | | return (int) (unsigned int) (try_val + 10u); |
482 | | |
483 | | return -1; |
484 | | #endif /* MHD_FAVOR_SMALL_CODE */ |
485 | 52.5k | } |
486 | | |
487 | | |
488 | | /** |
489 | | * Convert 4 bit value to US-ASCII hexadecimal digit. |
490 | | * |
491 | | * @param v the value to convert, must be less then 16 |
492 | | * @return hexadecimal digit |
493 | | */ |
494 | | MHD_static_inline_ MHD_FN_CONST_ char |
495 | | valuetoxdigit (unsigned int v) |
496 | 0 | { |
497 | 0 | #if ! defined(MHD_FAVOR_SMALL_CODE) |
498 | 0 | static const char map_value_to_xdigit[16] = |
499 | 0 | { '0', '1', '2', '3', '4', '5', '6', '7', |
500 | 0 | '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; |
501 | |
|
502 | 0 | mhd_assert (16 > v); |
503 | |
|
504 | 0 | return map_value_to_xdigit[v]; |
505 | | #else /* MHD_FAVOR_SMALL_CODE */ |
506 | | |
507 | | mhd_assert (16 > v); |
508 | | |
509 | | if (v <= 9) |
510 | | return '0' + (char) (v); |
511 | | return 'a' + (char) (v - 10); |
512 | | #endif /* MHD_FAVOR_SMALL_CODE */ |
513 | 0 | } |
514 | | |
515 | | |
516 | | #if ! defined(MHD_FAVOR_SMALL_CODE) |
517 | | /** |
518 | | * Convert 8 bit value to two US-ASCII hexadecimal digits. |
519 | | * |
520 | | * @param v the value to convert |
521 | | * @return pointer to char[2] with two hexadecimal digits |
522 | | */ |
523 | | MHD_static_inline_ MHD_FN_CONST_ MHD_FN_RETURNS_NONNULL_ const char* |
524 | | uint8totwoxdigits (uint8_t v) |
525 | 36.8k | { |
526 | 36.8k | static const char map_uint8_to_two_xdigits[][2] = |
527 | 36.8k | { { '0', '0' }, |
528 | 36.8k | { '0', '1' }, |
529 | 36.8k | { '0', '2' }, |
530 | 36.8k | { '0', '3' }, |
531 | 36.8k | { '0', '4' }, |
532 | 36.8k | { '0', '5' }, |
533 | 36.8k | { '0', '6' }, |
534 | 36.8k | { '0', '7' }, |
535 | 36.8k | { '0', '8' }, |
536 | 36.8k | { '0', '9' }, |
537 | 36.8k | { '0', 'a' }, |
538 | 36.8k | { '0', 'b' }, |
539 | 36.8k | { '0', 'c' }, |
540 | 36.8k | { '0', 'd' }, |
541 | 36.8k | { '0', 'e' }, |
542 | 36.8k | { '0', 'f' }, |
543 | 36.8k | { '1', '0' }, |
544 | 36.8k | { '1', '1' }, |
545 | 36.8k | { '1', '2' }, |
546 | 36.8k | { '1', '3' }, |
547 | 36.8k | { '1', '4' }, |
548 | 36.8k | { '1', '5' }, |
549 | 36.8k | { '1', '6' }, |
550 | 36.8k | { '1', '7' }, |
551 | 36.8k | { '1', '8' }, |
552 | 36.8k | { '1', '9' }, |
553 | 36.8k | { '1', 'a' }, |
554 | 36.8k | { '1', 'b' }, |
555 | 36.8k | { '1', 'c' }, |
556 | 36.8k | { '1', 'd' }, |
557 | 36.8k | { '1', 'e' }, |
558 | 36.8k | { '1', 'f' }, |
559 | 36.8k | { '2', '0' }, |
560 | 36.8k | { '2', '1' }, |
561 | 36.8k | { '2', '2' }, |
562 | 36.8k | { '2', '3' }, |
563 | 36.8k | { '2', '4' }, |
564 | 36.8k | { '2', '5' }, |
565 | 36.8k | { '2', '6' }, |
566 | 36.8k | { '2', '7' }, |
567 | 36.8k | { '2', '8' }, |
568 | 36.8k | { '2', '9' }, |
569 | 36.8k | { '2', 'a' }, |
570 | 36.8k | { '2', 'b' }, |
571 | 36.8k | { '2', 'c' }, |
572 | 36.8k | { '2', 'd' }, |
573 | 36.8k | { '2', 'e' }, |
574 | 36.8k | { '2', 'f' }, |
575 | 36.8k | { '3', '0' }, |
576 | 36.8k | { '3', '1' }, |
577 | 36.8k | { '3', '2' }, |
578 | 36.8k | { '3', '3' }, |
579 | 36.8k | { '3', '4' }, |
580 | 36.8k | { '3', '5' }, |
581 | 36.8k | { '3', '6' }, |
582 | 36.8k | { '3', '7' }, |
583 | 36.8k | { '3', '8' }, |
584 | 36.8k | { '3', '9' }, |
585 | 36.8k | { '3', 'a' }, |
586 | 36.8k | { '3', 'b' }, |
587 | 36.8k | { '3', 'c' }, |
588 | 36.8k | { '3', 'd' }, |
589 | 36.8k | { '3', 'e' }, |
590 | 36.8k | { '3', 'f' }, |
591 | 36.8k | { '4', '0' }, |
592 | 36.8k | { '4', '1' }, |
593 | 36.8k | { '4', '2' }, |
594 | 36.8k | { '4', '3' }, |
595 | 36.8k | { '4', '4' }, |
596 | 36.8k | { '4', '5' }, |
597 | 36.8k | { '4', '6' }, |
598 | 36.8k | { '4', '7' }, |
599 | 36.8k | { '4', '8' }, |
600 | 36.8k | { '4', '9' }, |
601 | 36.8k | { '4', 'a' }, |
602 | 36.8k | { '4', 'b' }, |
603 | 36.8k | { '4', 'c' }, |
604 | 36.8k | { '4', 'd' }, |
605 | 36.8k | { '4', 'e' }, |
606 | 36.8k | { '4', 'f' }, |
607 | 36.8k | { '5', '0' }, |
608 | 36.8k | { '5', '1' }, |
609 | 36.8k | { '5', '2' }, |
610 | 36.8k | { '5', '3' }, |
611 | 36.8k | { '5', '4' }, |
612 | 36.8k | { '5', '5' }, |
613 | 36.8k | { '5', '6' }, |
614 | 36.8k | { '5', '7' }, |
615 | 36.8k | { '5', '8' }, |
616 | 36.8k | { '5', '9' }, |
617 | 36.8k | { '5', 'a' }, |
618 | 36.8k | { '5', 'b' }, |
619 | 36.8k | { '5', 'c' }, |
620 | 36.8k | { '5', 'd' }, |
621 | 36.8k | { '5', 'e' }, |
622 | 36.8k | { '5', 'f' }, |
623 | 36.8k | { '6', '0' }, |
624 | 36.8k | { '6', '1' }, |
625 | 36.8k | { '6', '2' }, |
626 | 36.8k | { '6', '3' }, |
627 | 36.8k | { '6', '4' }, |
628 | 36.8k | { '6', '5' }, |
629 | 36.8k | { '6', '6' }, |
630 | 36.8k | { '6', '7' }, |
631 | 36.8k | { '6', '8' }, |
632 | 36.8k | { '6', '9' }, |
633 | 36.8k | { '6', 'a' }, |
634 | 36.8k | { '6', 'b' }, |
635 | 36.8k | { '6', 'c' }, |
636 | 36.8k | { '6', 'd' }, |
637 | 36.8k | { '6', 'e' }, |
638 | 36.8k | { '6', 'f' }, |
639 | 36.8k | { '7', '0' }, |
640 | 36.8k | { '7', '1' }, |
641 | 36.8k | { '7', '2' }, |
642 | 36.8k | { '7', '3' }, |
643 | 36.8k | { '7', '4' }, |
644 | 36.8k | { '7', '5' }, |
645 | 36.8k | { '7', '6' }, |
646 | 36.8k | { '7', '7' }, |
647 | 36.8k | { '7', '8' }, |
648 | 36.8k | { '7', '9' }, |
649 | 36.8k | { '7', 'a' }, |
650 | 36.8k | { '7', 'b' }, |
651 | 36.8k | { '7', 'c' }, |
652 | 36.8k | { '7', 'd' }, |
653 | 36.8k | { '7', 'e' }, |
654 | 36.8k | { '7', 'f' }, |
655 | 36.8k | { '8', '0' }, |
656 | 36.8k | { '8', '1' }, |
657 | 36.8k | { '8', '2' }, |
658 | 36.8k | { '8', '3' }, |
659 | 36.8k | { '8', '4' }, |
660 | 36.8k | { '8', '5' }, |
661 | 36.8k | { '8', '6' }, |
662 | 36.8k | { '8', '7' }, |
663 | 36.8k | { '8', '8' }, |
664 | 36.8k | { '8', '9' }, |
665 | 36.8k | { '8', 'a' }, |
666 | 36.8k | { '8', 'b' }, |
667 | 36.8k | { '8', 'c' }, |
668 | 36.8k | { '8', 'd' }, |
669 | 36.8k | { '8', 'e' }, |
670 | 36.8k | { '8', 'f' }, |
671 | 36.8k | { '9', '0' }, |
672 | 36.8k | { '9', '1' }, |
673 | 36.8k | { '9', '2' }, |
674 | 36.8k | { '9', '3' }, |
675 | 36.8k | { '9', '4' }, |
676 | 36.8k | { '9', '5' }, |
677 | 36.8k | { '9', '6' }, |
678 | 36.8k | { '9', '7' }, |
679 | 36.8k | { '9', '8' }, |
680 | 36.8k | { '9', '9' }, |
681 | 36.8k | { '9', 'a' }, |
682 | 36.8k | { '9', 'b' }, |
683 | 36.8k | { '9', 'c' }, |
684 | 36.8k | { '9', 'd' }, |
685 | 36.8k | { '9', 'e' }, |
686 | 36.8k | { '9', 'f' }, |
687 | 36.8k | { 'a', '0' }, |
688 | 36.8k | { 'a', '1' }, |
689 | 36.8k | { 'a', '2' }, |
690 | 36.8k | { 'a', '3' }, |
691 | 36.8k | { 'a', '4' }, |
692 | 36.8k | { 'a', '5' }, |
693 | 36.8k | { 'a', '6' }, |
694 | 36.8k | { 'a', '7' }, |
695 | 36.8k | { 'a', '8' }, |
696 | 36.8k | { 'a', '9' }, |
697 | 36.8k | { 'a', 'a' }, |
698 | 36.8k | { 'a', 'b' }, |
699 | 36.8k | { 'a', 'c' }, |
700 | 36.8k | { 'a', 'd' }, |
701 | 36.8k | { 'a', 'e' }, |
702 | 36.8k | { 'a', 'f' }, |
703 | 36.8k | { 'b', '0' }, |
704 | 36.8k | { 'b', '1' }, |
705 | 36.8k | { 'b', '2' }, |
706 | 36.8k | { 'b', '3' }, |
707 | 36.8k | { 'b', '4' }, |
708 | 36.8k | { 'b', '5' }, |
709 | 36.8k | { 'b', '6' }, |
710 | 36.8k | { 'b', '7' }, |
711 | 36.8k | { 'b', '8' }, |
712 | 36.8k | { 'b', '9' }, |
713 | 36.8k | { 'b', 'a' }, |
714 | 36.8k | { 'b', 'b' }, |
715 | 36.8k | { 'b', 'c' }, |
716 | 36.8k | { 'b', 'd' }, |
717 | 36.8k | { 'b', 'e' }, |
718 | 36.8k | { 'b', 'f' }, |
719 | 36.8k | { 'c', '0' }, |
720 | 36.8k | { 'c', '1' }, |
721 | 36.8k | { 'c', '2' }, |
722 | 36.8k | { 'c', '3' }, |
723 | 36.8k | { 'c', '4' }, |
724 | 36.8k | { 'c', '5' }, |
725 | 36.8k | { 'c', '6' }, |
726 | 36.8k | { 'c', '7' }, |
727 | 36.8k | { 'c', '8' }, |
728 | 36.8k | { 'c', '9' }, |
729 | 36.8k | { 'c', 'a' }, |
730 | 36.8k | { 'c', 'b' }, |
731 | 36.8k | { 'c', 'c' }, |
732 | 36.8k | { 'c', 'd' }, |
733 | 36.8k | { 'c', 'e' }, |
734 | 36.8k | { 'c', 'f' }, |
735 | 36.8k | { 'd', '0' }, |
736 | 36.8k | { 'd', '1' }, |
737 | 36.8k | { 'd', '2' }, |
738 | 36.8k | { 'd', '3' }, |
739 | 36.8k | { 'd', '4' }, |
740 | 36.8k | { 'd', '5' }, |
741 | 36.8k | { 'd', '6' }, |
742 | 36.8k | { 'd', '7' }, |
743 | 36.8k | { 'd', '8' }, |
744 | 36.8k | { 'd', '9' }, |
745 | 36.8k | { 'd', 'a' }, |
746 | 36.8k | { 'd', 'b' }, |
747 | 36.8k | { 'd', 'c' }, |
748 | 36.8k | { 'd', 'd' }, |
749 | 36.8k | { 'd', 'e' }, |
750 | 36.8k | { 'd', 'f' }, |
751 | 36.8k | { 'e', '0' }, |
752 | 36.8k | { 'e', '1' }, |
753 | 36.8k | { 'e', '2' }, |
754 | 36.8k | { 'e', '3' }, |
755 | 36.8k | { 'e', '4' }, |
756 | 36.8k | { 'e', '5' }, |
757 | 36.8k | { 'e', '6' }, |
758 | 36.8k | { 'e', '7' }, |
759 | 36.8k | { 'e', '8' }, |
760 | 36.8k | { 'e', '9' }, |
761 | 36.8k | { 'e', 'a' }, |
762 | 36.8k | { 'e', 'b' }, |
763 | 36.8k | { 'e', 'c' }, |
764 | 36.8k | { 'e', 'd' }, |
765 | 36.8k | { 'e', 'e' }, |
766 | 36.8k | { 'e', 'f' }, |
767 | 36.8k | { 'f', '0' }, |
768 | 36.8k | { 'f', '1' }, |
769 | 36.8k | { 'f', '2' }, |
770 | 36.8k | { 'f', '3' }, |
771 | 36.8k | { 'f', '4' }, |
772 | 36.8k | { 'f', '5' }, |
773 | 36.8k | { 'f', '6' }, |
774 | 36.8k | { 'f', '7' }, |
775 | 36.8k | { 'f', '8' }, |
776 | 36.8k | { 'f', '9' }, |
777 | 36.8k | { 'f', 'a' }, |
778 | 36.8k | { 'f', 'b' }, |
779 | 36.8k | { 'f', 'c' }, |
780 | 36.8k | { 'f', 'd' }, |
781 | 36.8k | { 'f', 'e' }, |
782 | 36.8k | { 'f', 'f' } |
783 | | #ifndef NDEBUG |
784 | | , |
785 | | { 0, 0 } |
786 | | #endif /* ! NDEBUG */ |
787 | 36.8k | }; |
788 | | |
789 | 36.8k | mhd_assert (257u == \ |
790 | 36.8k | (sizeof(map_uint8_to_two_xdigits) \ |
791 | 36.8k | / sizeof(map_uint8_to_two_xdigits[0]))); |
792 | | |
793 | 36.8k | return map_uint8_to_two_xdigits[v]; |
794 | | /** |
795 | | * Indicates that function uint8totwoxdigits() is available |
796 | | */ |
797 | 36.8k | #define mhd_HAVE_UINT8TOTWOXDIGITS 1 |
798 | 36.8k | } |
799 | | |
800 | | |
801 | | #endif /* ! MHD_FAVOR_SMALL_CODE */ |
802 | | |
803 | | |
804 | | /** |
805 | | * Caseless compare two characters. |
806 | | * |
807 | | * @param c1 the first char to compare |
808 | | * @param c2 the second char to compare |
809 | | * @return boolean 'true' if chars are caseless equal, false otherwise |
810 | | */ |
811 | | MHD_static_inline_ MHD_FN_CONST_ bool |
812 | | charsequalcaseless (char c1, char c2) |
813 | 18.8k | { |
814 | 18.8k | if (c1 == c2) |
815 | 15.0k | return true; |
816 | | /* Fold case on both sides */ |
817 | 3.77k | c1 = ((char) (~0x20u & (unsigned char) c1)); |
818 | 3.77k | c2 = ((char) (~0x20u & (unsigned char) c2)); |
819 | 3.77k | return (c1 == c2) && isasciiupper (c1); |
820 | 18.8k | } |
821 | | |
822 | | |
823 | | #else /* !HAVE_INLINE_FUNCS */ |
824 | | |
825 | | |
826 | | /** |
827 | | * Checks whether character is lower case letter in US-ASCII |
828 | | * |
829 | | * @param c character to check |
830 | | * @return boolean true if character is lower case letter, |
831 | | * boolean false otherwise |
832 | | */ |
833 | | # define isasciilower(c) ((((char) (c)) >= 'a') && (((char) (c)) <= 'z')) |
834 | | |
835 | | |
836 | | /** |
837 | | * Checks whether character is upper case letter in US-ASCII |
838 | | * |
839 | | * @param c character to check |
840 | | * @return boolean true if character is upper case letter, |
841 | | * boolean false otherwise |
842 | | */ |
843 | | # define isasciiupper(c) ((((char) (c)) <= 'Z') && (((char) (c)) >= 'A')) |
844 | | |
845 | | |
846 | | /** |
847 | | * Checks whether character is letter in US-ASCII |
848 | | * |
849 | | * @param c character to check |
850 | | * @return boolean true if character is letter, boolean false |
851 | | * otherwise |
852 | | */ |
853 | | # define isasciialpha(c) (isasciilower (c) || isasciiupper (c)) |
854 | | |
855 | | |
856 | | /** |
857 | | * Check whether character is decimal digit in US-ASCII |
858 | | * |
859 | | * @param c character to check |
860 | | * @return boolean true if character is decimal digit, boolean false |
861 | | * otherwise |
862 | | */ |
863 | | # define isasciidigit(c) ((((char) (c)) <= '9') && (((char) (c)) >= '0')) |
864 | | |
865 | | |
866 | | /** |
867 | | * Check whether character is hexadecimal digit in US-ASCII |
868 | | * |
869 | | * @param c character to check |
870 | | * @return boolean true if character is hexadecimal digit, |
871 | | * boolean false otherwise |
872 | | */ |
873 | | # define isasciixdigit(c) (isasciidigit ((c)) || \ |
874 | | (((char) (c)) <= 'F' && ((char) (c)) >= 'A') || \ |
875 | | (((char) (c)) <= 'f' && ((char) (c)) >= 'a')) |
876 | | |
877 | | |
878 | | /** |
879 | | * Check whether character is decimal digit or letter in US-ASCII |
880 | | * |
881 | | * @param c character to check |
882 | | * @return boolean true if character is decimal digit or letter, |
883 | | * boolean false otherwise |
884 | | */ |
885 | | # define isasciialnum(c) (isasciialpha (c) || isasciidigit (c)) |
886 | | |
887 | | |
888 | | /** |
889 | | * Convert US-ASCII character to lower case. |
890 | | * If character is upper case letter in US-ASCII than it's converted to lower |
891 | | * case analog. If character is NOT upper case letter than it's returned |
892 | | * unmodified. |
893 | | * |
894 | | * @param c character to convert |
895 | | * @return converted to lower case character |
896 | | */ |
897 | | # define toasciilower(c) ((isasciiupper (c)) ? (((char) (c)) - 'A' + 'a') : \ |
898 | | ((char) (c))) |
899 | | |
900 | | |
901 | | /** |
902 | | * Convert US-ASCII character to upper case. |
903 | | * If character is lower case letter in US-ASCII than it's converted to upper |
904 | | * case analog. If character is NOT lower case letter than it's returned |
905 | | * unmodified. |
906 | | * |
907 | | * @param c character to convert |
908 | | * @return converted to upper case character |
909 | | */ |
910 | | # define toasciiupper(c) ((isasciilower (c)) ? (((char) (c)) - 'a' + 'A') : \ |
911 | | ((char) (c))) |
912 | | |
913 | | |
914 | | /** |
915 | | * Convert US-ASCII decimal digit to its value. |
916 | | * |
917 | | * @param c character to convert |
918 | | * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit |
919 | | */ |
920 | | # define todigitvalue(c) (isasciidigit (c) ? (int) (((char) (c)) - '0') : \ |
921 | | (int) (-1)) |
922 | | |
923 | | |
924 | | /** |
925 | | * Convert US-ASCII hexadecimal digit to its value. |
926 | | * @param c character to convert |
927 | | * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit |
928 | | */ |
929 | | # define xdigittovalue(c) (isasciidigit (c) ? (int) (((char) (c)) - '0') : \ |
930 | | ( (((char) (c)) >= 'A' && ((char) (c)) <= 'F') ? \ |
931 | | (int) (((unsigned char) (c)) - 'A' + 10) : \ |
932 | | ( (((char) (c)) >= 'a' && ((char) (c)) <= 'f') ? \ |
933 | | (int) (((unsigned char) (c)) - 'a' + 10) : \ |
934 | | (int) (-1) ))) |
935 | | |
936 | | |
937 | | #if ! defined(MHD_FAVOR_SMALL_CODE) |
938 | | static const char map_value_to_xdigit[16] = |
939 | | { '0', '1', '2', '3', '4', '5', '6', '7', |
940 | | '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; |
941 | | |
942 | | /** |
943 | | * Convert 4 bit value to US-ASCII hexadecimal digit. |
944 | | * |
945 | | * @param v the value to convert, must be less then 16 |
946 | | * @return hexadecimal digit |
947 | | */ |
948 | | # define valuetoxdigit(v) map_value_to_xdigit[v] |
949 | | #else /* MHD_FAVOR_SMALL_CODE */ |
950 | | /** |
951 | | * Convert 4 bit value to US-ASCII hexadecimal digit. |
952 | | * |
953 | | * @param v the value to convert, must be less then 16 |
954 | | * @return hexadecimal digit |
955 | | */ |
956 | | # define valuetoxdigit(v) \ |
957 | | (char) ((v <= 9) ? ('0' + (char) v) : ('a' + (char) v - 10)) |
958 | | #endif /* MHD_FAVOR_SMALL_CODE */ |
959 | | |
960 | | /** |
961 | | * Caseless compare two characters. |
962 | | * |
963 | | * @param c1 the first char to compare |
964 | | * @param c2 the second char to compare |
965 | | * @return boolean 'true' if chars are caseless equal, false otherwise |
966 | | */ |
967 | | #define charsequalcaseless(c1, c2) \ |
968 | | ( ((c1) == (c2)) || \ |
969 | | (((0x20u | (unsigned char) c1) == (0x20u | (unsigned char) c2)) && \ |
970 | | toasciilower (((char) (0x20u | (unsigned char) c2)))) ) |
971 | | |
972 | | #endif /* !HAVE_INLINE_FUNCS */ |
973 | | |
974 | | |
975 | | #ifndef MHD_FAVOR_SMALL_CODE |
976 | | MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ |
977 | | MHD_FN_PAR_CSTR_ (1) MHD_FN_PAR_CSTR_ (2) bool |
978 | | mhd_str_equal_caseless (const char *str1, |
979 | | const char *str2) |
980 | 0 | { |
981 | 0 | while (0 != (*str1)) |
982 | 0 | { |
983 | 0 | const char c1 = *str1; |
984 | 0 | const char c2 = *str2; |
985 | 0 | if (charsequalcaseless (c1, c2)) |
986 | 0 | { |
987 | 0 | str1++; |
988 | 0 | str2++; |
989 | 0 | } |
990 | 0 | else |
991 | 0 | return false; |
992 | 0 | } |
993 | 0 | return 0 == (*str2); |
994 | 0 | } |
995 | | |
996 | | |
997 | | #endif /* ! MHD_FAVOR_SMALL_CODE */ |
998 | | |
999 | | |
1000 | | MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ |
1001 | | MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) bool |
1002 | | mhd_str_equal_caseless_n (const char *const str1, |
1003 | | const char *const str2, |
1004 | | size_t maxlen) |
1005 | 0 | { |
1006 | 0 | size_t i; |
1007 | |
|
1008 | 0 | for (i = 0; i < maxlen; ++i) |
1009 | 0 | { |
1010 | 0 | const char c1 = str1[i]; |
1011 | 0 | const char c2 = str2[i]; |
1012 | 0 | if (0 == c2) |
1013 | 0 | return 0 == c1; |
1014 | 0 | if (charsequalcaseless (c1, c2)) |
1015 | 0 | continue; |
1016 | 0 | else |
1017 | 0 | return false; |
1018 | 0 | } |
1019 | 0 | return true; |
1020 | 0 | } |
1021 | | |
1022 | | |
1023 | | MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ |
1024 | | MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) bool |
1025 | | mhd_str_equal_caseless_bin_n (const char *const str1, |
1026 | | const char *const str2, |
1027 | | size_t len) |
1028 | 1.16k | { |
1029 | 1.16k | size_t i; |
1030 | | |
1031 | 8.02k | for (i = 0; i < len; ++i) |
1032 | 7.02k | { |
1033 | 7.02k | const char c1 = str1[i]; |
1034 | 7.02k | const char c2 = str2[i]; |
1035 | 7.02k | if (charsequalcaseless (c1, c2)) |
1036 | 6.85k | continue; |
1037 | 176 | else |
1038 | 176 | return 0; |
1039 | 7.02k | } |
1040 | 993 | return ! 0; |
1041 | 1.16k | } |
1042 | | |
1043 | | |
1044 | | MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ |
1045 | | MHD_FN_PAR_CSTR_ (1) |
1046 | | MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) bool |
1047 | | mhd_str_has_token_caseless (const char *restrict str, |
1048 | | const char *const restrict token, |
1049 | | size_t token_len) |
1050 | 0 | { |
1051 | 0 | if (0 == token_len) |
1052 | 0 | return false; |
1053 | | |
1054 | 0 | while (0 != *str) |
1055 | 0 | { |
1056 | 0 | size_t i; |
1057 | | /* Skip all whitespaces and empty tokens. */ |
1058 | 0 | while (' ' == *str || '\t' == *str || ',' == *str) |
1059 | 0 | str++; |
1060 | | |
1061 | | /* Check for token match. */ |
1062 | 0 | i = 0; |
1063 | 0 | while (1) |
1064 | 0 | { |
1065 | 0 | const char sc = *(str++); |
1066 | 0 | const char tc = token[i++]; |
1067 | |
|
1068 | 0 | if (0 == sc) |
1069 | 0 | return false; |
1070 | 0 | if (! charsequalcaseless (sc, tc)) |
1071 | 0 | break; |
1072 | 0 | if (i >= token_len) |
1073 | 0 | { |
1074 | | /* Check whether substring match token fully or |
1075 | | * has additional unmatched chars at tail. */ |
1076 | 0 | while (' ' == *str || '\t' == *str) |
1077 | 0 | str++; |
1078 | | /* End of (sub)string? */ |
1079 | 0 | if ((0 == *str) || (',' == *str) ) |
1080 | 0 | return true; |
1081 | | /* Unmatched chars at end of substring. */ |
1082 | 0 | break; |
1083 | 0 | } |
1084 | 0 | } |
1085 | | /* Find next substring. */ |
1086 | 0 | while (0 != *str && ',' != *str) |
1087 | 0 | str++; |
1088 | 0 | } |
1089 | 0 | return false; |
1090 | 0 | } |
1091 | | |
1092 | | |
1093 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1094 | | MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4) |
1095 | | MHD_FN_PAR_OUT_ (5) MHD_FN_PAR_INOUT_ (6) bool |
1096 | | mhd_str_remove_token_caseless (const char *restrict str, |
1097 | | size_t str_len, |
1098 | | const char *const restrict token, |
1099 | | const size_t token_len, |
1100 | | char *restrict buf, |
1101 | | ssize_t *restrict buf_size) |
1102 | 1.25k | { |
1103 | 1.25k | const char *s1; /**< the "input" string / character */ |
1104 | 1.25k | char *s2; /**< the "output" string / character */ |
1105 | 1.25k | size_t t_pos; /**< position of matched character in the token */ |
1106 | 1.25k | bool token_removed; |
1107 | | |
1108 | 1.25k | mhd_assert (NULL == memchr (token, 0, token_len)); |
1109 | 1.25k | mhd_assert (NULL == memchr (token, ' ', token_len)); |
1110 | 1.25k | mhd_assert (NULL == memchr (token, '\t', token_len)); |
1111 | 1.25k | mhd_assert (NULL == memchr (token, ',', token_len)); |
1112 | 1.25k | mhd_assert (0 <= *buf_size); |
1113 | | |
1114 | 1.25k | if (SSIZE_MAX <= ((str_len / 2) * 3 + 3)) |
1115 | 0 | { |
1116 | | /* The return value may overflow, refuse */ |
1117 | 0 | *buf_size = (ssize_t) -1; |
1118 | 0 | return false; |
1119 | 0 | } |
1120 | 1.25k | s1 = str; |
1121 | 1.25k | s2 = buf; |
1122 | 1.25k | token_removed = false; |
1123 | | |
1124 | 4.97k | while ((size_t) (s1 - str) < str_len) |
1125 | 4.39k | { |
1126 | 4.39k | const char *cur_token; /**< the first char of current token */ |
1127 | 4.39k | size_t copy_size; |
1128 | | |
1129 | | /* Skip any initial whitespaces and empty tokens */ |
1130 | 16.2k | while ( ((size_t) (s1 - str) < str_len) && |
1131 | 16.2k | ((' ' == *s1) || ('\t' == *s1) || (',' == *s1)) ) |
1132 | 11.8k | s1++; |
1133 | | |
1134 | | /* 's1' points to the first char of token in the input string or |
1135 | | * points just beyond the end of the input string */ |
1136 | | |
1137 | 4.39k | if ((size_t) (s1 - str) >= str_len) |
1138 | 83 | break; /* Nothing to copy, end of the input string */ |
1139 | | |
1140 | | /* 's1' points to the first char of token in the input string */ |
1141 | | |
1142 | 4.31k | cur_token = s1; /* the first char of input token */ |
1143 | | |
1144 | | /* Check the token with case-insensetive match */ |
1145 | 4.31k | t_pos = 0; |
1146 | 12.1k | while ( ((size_t) (s1 - str) < str_len) && (token_len > t_pos) && |
1147 | 12.1k | (charsequalcaseless (*s1, token[t_pos])) ) |
1148 | 7.87k | { |
1149 | 7.87k | s1++; |
1150 | 7.87k | t_pos++; |
1151 | 7.87k | } |
1152 | | /* s1 may point just beyond the end of the input string */ |
1153 | 4.31k | if ( (token_len == t_pos) && (0 != token_len) ) |
1154 | 1.02k | { |
1155 | | /* 'token' matched, check that current input token does not have |
1156 | | * any suffixes */ |
1157 | 2.45k | while ( ((size_t) (s1 - str) < str_len) && |
1158 | 2.45k | ((' ' == *s1) || ('\t' == *s1)) ) |
1159 | 1.43k | s1++; |
1160 | | /* 's1' points to the first non-whitespace char after the token matched |
1161 | | * requested token or points just beyond the end of the input string after |
1162 | | * the requested token */ |
1163 | 1.02k | if (((size_t) (s1 - str) == str_len) || (',' == *s1)) |
1164 | 794 | {/* full token match, do not copy current token to the output */ |
1165 | 794 | token_removed = true; |
1166 | 794 | continue; |
1167 | 794 | } |
1168 | 1.02k | } |
1169 | | |
1170 | | /* 's1' points to first non-whitespace char, to some char after |
1171 | | * first non-whitespace char in the token in the input string, to |
1172 | | * the ',', or just beyond the end of the input string */ |
1173 | | /* The current token in the input string does not match the token |
1174 | | * to exclude, it must be copied to the output string */ |
1175 | | /* the current token size excluding leading whitespaces and current char */ |
1176 | 3.52k | copy_size = (size_t) (s1 - cur_token); |
1177 | 3.52k | if (buf == s2) |
1178 | 977 | { /* The first token to copy to the output */ |
1179 | 977 | if ((size_t) *buf_size < copy_size) |
1180 | 31 | { /* Not enough space in the output buffer */ |
1181 | 31 | *buf_size = (ssize_t) -1; |
1182 | 31 | return false; |
1183 | 31 | } |
1184 | 977 | } |
1185 | 2.54k | else |
1186 | 2.54k | { /* Some token was already copied to the output buffer */ |
1187 | 2.54k | mhd_assert (s2 > buf); |
1188 | 2.54k | if ((size_t) *buf_size < ((size_t) (s2 - buf)) + copy_size + 2) |
1189 | 22 | { /* Not enough space in the output buffer */ |
1190 | 22 | *buf_size = (ssize_t) -1; |
1191 | 22 | return false; |
1192 | 22 | } |
1193 | 2.52k | *(s2++) = ','; |
1194 | 2.52k | *(s2++) = ' '; |
1195 | 2.52k | } |
1196 | | /* Copy non-matched token to the output */ |
1197 | 3.46k | if (0 != copy_size) |
1198 | 518 | { |
1199 | 518 | memcpy (s2, cur_token, copy_size); |
1200 | 518 | s2 += copy_size; |
1201 | 518 | } |
1202 | | |
1203 | 6.45k | while ( ((size_t) (s1 - str) < str_len) && (',' != *s1)) |
1204 | 3.52k | { |
1205 | | /* 's1' points to first non-whitespace char, to some char after |
1206 | | * first non-whitespace char in the token in the input string */ |
1207 | | /* Copy all non-whitespace chars from the current token in |
1208 | | * the input string */ |
1209 | 18.8k | while ( ((size_t) (s1 - str) < str_len) && |
1210 | 18.8k | (',' != *s1) && (' ' != *s1) && ('\t' != *s1) ) |
1211 | 15.7k | { |
1212 | 15.7k | mhd_assert (s2 >= buf); |
1213 | 15.7k | if ((size_t) *buf_size <= (size_t) (s2 - buf)) /* '<= s2' equals '< s2 + 1' */ |
1214 | 490 | { /* Not enough space in the output buffer */ |
1215 | 490 | *buf_size = (ssize_t) -1; |
1216 | 490 | return false; |
1217 | 490 | } |
1218 | 15.2k | *(s2++) = *(s1++); |
1219 | 15.2k | } |
1220 | | /* 's1' points to some whitespace char in the token in the input |
1221 | | * string, to the ',', or just beyond the end of the input string */ |
1222 | | /* Skip all whitespaces */ |
1223 | 5.77k | while ( ((size_t) (s1 - str) < str_len) && |
1224 | 5.77k | ((' ' == *s1) || ('\t' == *s1)) ) |
1225 | 2.74k | s1++; |
1226 | | |
1227 | | /* 's1' points to the first non-whitespace char in the input string |
1228 | | * after whitespace chars, to the ',', or just beyond the end of |
1229 | | * the input string */ |
1230 | 3.03k | if (((size_t) (s1 - str) < str_len) && (',' != *s1)) |
1231 | 389 | { /* Not the end of the current token */ |
1232 | 389 | mhd_assert (s2 >= buf); |
1233 | 389 | if ((size_t) *buf_size <= (size_t) (s2 - buf)) /* '<= s2' equals '< s2 + 1' */ |
1234 | 50 | { /* Not enough space in the output buffer */ |
1235 | 50 | *buf_size = (ssize_t) -1; |
1236 | 50 | return false; |
1237 | 50 | } |
1238 | 339 | *(s2++) = ' '; |
1239 | 339 | } |
1240 | 3.03k | } |
1241 | 3.46k | } |
1242 | 660 | mhd_assert (((ssize_t) (s2 - buf)) <= *buf_size); |
1243 | 660 | *buf_size = (ssize_t) (s2 - buf); |
1244 | 660 | return token_removed; |
1245 | 1.25k | } |
1246 | | |
1247 | | |
1248 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1249 | | MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_INOUT_ (2) |
1250 | | MHD_FN_PAR_IN_SIZE_ (3,4) bool |
1251 | | mhd_str_remove_tokens_caseless (char *restrict str, |
1252 | | size_t *restrict str_len, |
1253 | | const char *const restrict tkns, |
1254 | | const size_t tkns_len) |
1255 | 0 | { |
1256 | 0 | size_t pt; /**< position in @a tokens */ |
1257 | 0 | bool token_removed; |
1258 | |
|
1259 | 0 | mhd_assert (NULL == memchr (tkns, 0, tkns_len)); |
1260 | |
|
1261 | 0 | token_removed = false; |
1262 | 0 | pt = 0; |
1263 | |
|
1264 | 0 | while (pt < tkns_len && *str_len != 0) |
1265 | 0 | { |
1266 | 0 | const char *tkn; /**< the current token */ |
1267 | 0 | size_t tkn_len; |
1268 | | |
1269 | | /* Skip any initial whitespaces and empty tokens in 'tokens' */ |
1270 | 0 | while ( (pt < tkns_len) && |
1271 | 0 | ((' ' == tkns[pt]) || ('\t' == tkns[pt]) || (',' == tkns[pt])) ) |
1272 | 0 | pt++; |
1273 | |
|
1274 | 0 | if (pt >= tkns_len) |
1275 | 0 | break; /* No more tokens, nothing to remove */ |
1276 | | |
1277 | | /* Found non-whitespace char which is not a comma */ |
1278 | 0 | tkn = tkns + pt; |
1279 | 0 | do |
1280 | 0 | { |
1281 | 0 | do |
1282 | 0 | { |
1283 | 0 | pt++; |
1284 | 0 | } while (pt < tkns_len && |
1285 | 0 | (' ' != tkns[pt] && '\t' != tkns[pt] && ',' != tkns[pt])); |
1286 | | /* Found end of the token string, space, tab, or comma */ |
1287 | 0 | tkn_len = pt - (size_t) (tkn - tkns); |
1288 | | |
1289 | | /* Skip all spaces and tabs */ |
1290 | 0 | while (pt < tkns_len && (' ' == tkns[pt] || '\t' == tkns[pt])) |
1291 | 0 | pt++; |
1292 | | /* Found end of the token string or non-whitespace char */ |
1293 | 0 | } while (pt < tkns_len && ',' != tkns[pt]); |
1294 | | |
1295 | | /* 'tkn' is the input token with 'tkn_len' chars */ |
1296 | 0 | mhd_assert (0 != tkn_len); |
1297 | |
|
1298 | 0 | if (*str_len == tkn_len) |
1299 | 0 | { |
1300 | 0 | if (mhd_str_equal_caseless_bin_n (str, tkn, tkn_len)) |
1301 | 0 | { |
1302 | 0 | *str_len = 0; |
1303 | 0 | token_removed = true; |
1304 | 0 | } |
1305 | 0 | continue; |
1306 | 0 | } |
1307 | | /* 'tkn' cannot match part of 'str' if length of 'tkn' is larger |
1308 | | * than length of 'str'. |
1309 | | * It's know that 'tkn' is not equal to the 'str' (was checked previously). |
1310 | | * As 'str' is normalized when 'tkn' is not equal to the 'str' |
1311 | | * it is required that 'str' to be at least 3 chars larger then 'tkn' |
1312 | | * (the comma, the space and at least one additional character for the next |
1313 | | * token) to remove 'tkn' from the 'str'. */ |
1314 | 0 | if (*str_len > tkn_len + 2) |
1315 | 0 | { /* Remove 'tkn' from the input string */ |
1316 | 0 | size_t pr; /**< the 'read' position in the @a str */ |
1317 | 0 | size_t pw; /**< the 'write' position in the @a str */ |
1318 | |
|
1319 | 0 | pr = 0; |
1320 | 0 | pw = 0; |
1321 | |
|
1322 | 0 | do |
1323 | 0 | { |
1324 | 0 | mhd_assert (pr >= pw); |
1325 | 0 | mhd_assert ((*str_len) >= (pr + tkn_len)); |
1326 | 0 | if ( ( ((*str_len) == (pr + tkn_len)) || (',' == str[pr + tkn_len]) ) && |
1327 | 0 | mhd_str_equal_caseless_bin_n (str + pr, tkn, tkn_len) ) |
1328 | 0 | { |
1329 | | /* current token in the input string matches the 'tkn', skip it */ |
1330 | 0 | mhd_assert ((*str_len == pr + tkn_len) || \ |
1331 | 0 | (' ' == str[pr + tkn_len + 1])); /* 'str' must be normalized */ |
1332 | 0 | token_removed = true; |
1333 | | /* Advance to the next token in the input string or beyond |
1334 | | * the end of the input string. */ |
1335 | 0 | pr += tkn_len + 2; |
1336 | 0 | } |
1337 | 0 | else |
1338 | 0 | { |
1339 | | /* current token in the input string does not match the 'tkn', |
1340 | | * copy to the output */ |
1341 | 0 | if (0 != pw) |
1342 | 0 | { /* not the first output token, add ", " to separate */ |
1343 | 0 | if (pr != pw + 2) |
1344 | 0 | { |
1345 | 0 | str[pw++] = ','; |
1346 | 0 | str[pw++] = ' '; |
1347 | 0 | } |
1348 | 0 | else |
1349 | 0 | pw += 2; /* 'str' is not yet modified in this round */ |
1350 | 0 | } |
1351 | 0 | do |
1352 | 0 | { |
1353 | 0 | if (pr != pw) |
1354 | 0 | str[pw] = str[pr]; |
1355 | 0 | pr++; |
1356 | 0 | pw++; |
1357 | 0 | } while (pr < *str_len && ',' != str[pr]); |
1358 | | /* Advance to the next token in the input string or beyond |
1359 | | * the end of the input string. */ |
1360 | 0 | pr += 2; |
1361 | 0 | } |
1362 | | /* 'pr' should point to the next token in the input string or beyond |
1363 | | * the end of the input string */ |
1364 | 0 | if ((*str_len) < (pr + tkn_len)) |
1365 | 0 | { /* The rest of the 'str + pr' is too small to match 'tkn' */ |
1366 | 0 | if ((*str_len) > pr) |
1367 | 0 | { /* Copy the rest of the string */ |
1368 | 0 | size_t copy_size; |
1369 | 0 | copy_size = *str_len - pr; |
1370 | 0 | if (0 != pw) |
1371 | 0 | { /* not the first output token, add ", " to separate */ |
1372 | 0 | if (pr != pw + 2) |
1373 | 0 | { |
1374 | 0 | str[pw++] = ','; |
1375 | 0 | str[pw++] = ' '; |
1376 | 0 | } |
1377 | 0 | else |
1378 | 0 | pw += 2; /* 'str' is not yet modified in this round */ |
1379 | 0 | } |
1380 | 0 | if (pr != pw) |
1381 | 0 | memmove (str + pw, str + pr, copy_size); |
1382 | 0 | pw += copy_size; |
1383 | 0 | } |
1384 | 0 | *str_len = pw; |
1385 | 0 | break; |
1386 | 0 | } |
1387 | 0 | mhd_assert ((' ' != str[0]) && ('\t' != str[0])); |
1388 | 0 | mhd_assert ((0 == pr) || (3 <= pr)); |
1389 | 0 | mhd_assert ((0 == pr) || (' ' == str[pr - 1])); |
1390 | 0 | mhd_assert ((0 == pr) || (',' == str[pr - 2])); |
1391 | 0 | } while (1); |
1392 | 0 | } |
1393 | 0 | } |
1394 | |
|
1395 | 0 | return token_removed; |
1396 | 0 | } |
1397 | | |
1398 | | |
1399 | | #ifndef MHD_FAVOR_SMALL_CODE |
1400 | | /* Use individual function for each case */ |
1401 | | |
1402 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1403 | | MHD_FN_PAR_CSTR_ (1) MHD_FN_PAR_IN_ (1) |
1404 | | MHD_FN_PAR_OUT_ (2) size_t |
1405 | | mhd_str_to_uint64 (const char *restrict str, |
1406 | | uint_fast64_t *restrict out_val) |
1407 | 1.17k | { |
1408 | 1.17k | const char *const start = str; |
1409 | 1.17k | uint_fast64_t res; |
1410 | | |
1411 | 1.17k | if (! isasciidigit (str[0])) |
1412 | 708 | return 0; |
1413 | | |
1414 | 463 | res = 0; |
1415 | 463 | do |
1416 | 10.1k | { |
1417 | 10.1k | const int digit = (unsigned char) (*str) - '0'; |
1418 | 10.1k | uint_fast64_t prev_res = res; |
1419 | | |
1420 | 10.1k | res *= 10; |
1421 | 10.1k | if (res / 10 != prev_res) |
1422 | 26 | return 0; |
1423 | 10.1k | res += (unsigned int) digit; |
1424 | 10.1k | if (res < (unsigned int) digit) |
1425 | 32 | return 0; |
1426 | | |
1427 | 10.1k | str++; |
1428 | 10.1k | } while (isasciidigit (*str)); |
1429 | | |
1430 | 405 | *out_val = res; |
1431 | 405 | return (size_t) (str - start); |
1432 | 463 | } |
1433 | | |
1434 | | |
1435 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1436 | | MHD_FN_PAR_IN_SIZE_ (1,2) |
1437 | | MHD_FN_PAR_OUT_ (3) size_t |
1438 | | mhd_str_to_uint64_n (const char *restrict str, |
1439 | | size_t maxlen, |
1440 | | uint_fast64_t *restrict out_val) |
1441 | 1.17k | { |
1442 | 1.17k | uint_fast64_t res; |
1443 | 1.17k | size_t i; |
1444 | | |
1445 | 1.17k | if (! maxlen || ! isasciidigit (str[0])) |
1446 | 901 | return 0; |
1447 | | |
1448 | 270 | res = 0; |
1449 | 270 | i = 0; |
1450 | 270 | do |
1451 | 5.93k | { |
1452 | 5.93k | const int digit = (unsigned char) str[i] - '0'; |
1453 | 5.93k | uint_fast64_t prev_res = res; |
1454 | | |
1455 | 5.93k | res *= 10; |
1456 | 5.93k | if (res / 10 != prev_res) |
1457 | 15 | return 0; |
1458 | 5.92k | res += (unsigned int) digit; |
1459 | 5.92k | if (res < (unsigned int) digit) |
1460 | 19 | return 0; |
1461 | 5.90k | i++; |
1462 | 5.90k | } while ( (i < maxlen) && |
1463 | 5.90k | isasciidigit (str[i]) ); |
1464 | | |
1465 | 236 | *out_val = res; |
1466 | 236 | return i; |
1467 | 270 | } |
1468 | | |
1469 | | |
1470 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1471 | | MHD_FN_PAR_CSTR_ (1) |
1472 | | MHD_FN_PAR_IN_ (1) MHD_FN_PAR_OUT_ (2) size_t |
1473 | | mhd_strx_to_uint32 (const char *restrict str, |
1474 | | uint_fast32_t *restrict out_val) |
1475 | 1.17k | { |
1476 | 1.17k | const char *const start = str; |
1477 | 1.17k | uint_fast32_t res; |
1478 | 1.17k | int digit; |
1479 | | |
1480 | 1.17k | res = 0; |
1481 | 1.17k | digit = xdigittovalue (*str); |
1482 | 14.2k | while (digit >= 0) |
1483 | 13.2k | { |
1484 | 13.2k | uint_fast32_t prev_res = res; |
1485 | | |
1486 | 13.2k | res *= 16; |
1487 | 13.2k | if (res / 16 != prev_res) |
1488 | 173 | return 0; |
1489 | 13.0k | res += (unsigned int) digit; |
1490 | 13.0k | if (res < (unsigned int) digit) |
1491 | 0 | return 0; |
1492 | | |
1493 | 13.0k | str++; |
1494 | 13.0k | digit = xdigittovalue (*str); |
1495 | 13.0k | } |
1496 | | |
1497 | 998 | if (str - start > 0) |
1498 | 544 | *out_val = res; |
1499 | 998 | return (size_t) (str - start); |
1500 | 1.17k | } |
1501 | | |
1502 | | |
1503 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1504 | | MHD_FN_PAR_IN_SIZE_ (1,2) |
1505 | | MHD_FN_PAR_OUT_ (3) size_t |
1506 | | mhd_strx_to_uint32_n (const char *restrict str, |
1507 | | size_t maxlen, |
1508 | | uint_fast32_t *restrict out_val) |
1509 | 1.17k | { |
1510 | 1.17k | size_t i; |
1511 | 1.17k | uint_fast32_t res; |
1512 | 1.17k | int digit; |
1513 | | |
1514 | 1.17k | res = 0; |
1515 | 1.17k | i = 0; |
1516 | 6.94k | while (i < maxlen && (digit = xdigittovalue (str[i])) >= 0) |
1517 | 6.01k | { |
1518 | 6.01k | uint_fast32_t prev_res = res; |
1519 | | |
1520 | 6.01k | res *= 16; |
1521 | 6.01k | if (res / 16 != prev_res) |
1522 | 243 | return 0; |
1523 | 5.77k | res += (unsigned int) digit; |
1524 | 5.77k | if (res < (unsigned int) digit) |
1525 | 0 | return 0; |
1526 | | |
1527 | 5.77k | res *= 16; |
1528 | 5.77k | res += (unsigned int) digit; |
1529 | 5.77k | i++; |
1530 | 5.77k | } |
1531 | | |
1532 | 928 | if (i) |
1533 | 159 | *out_val = res; |
1534 | 928 | return i; |
1535 | 1.17k | } |
1536 | | |
1537 | | |
1538 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1539 | | MHD_FN_PAR_CSTR_ (1) |
1540 | | MHD_FN_PAR_IN_ (1) MHD_FN_PAR_OUT_ (2) size_t |
1541 | | mhd_strx_to_uint64 (const char *restrict str, |
1542 | | uint_fast64_t *restrict out_val) |
1543 | 1.17k | { |
1544 | 1.17k | const char *const start = str; |
1545 | 1.17k | uint_fast64_t res; |
1546 | 1.17k | int digit; |
1547 | | |
1548 | 1.17k | res = 0; |
1549 | 1.17k | digit = xdigittovalue (*str); |
1550 | 14.2k | while (digit >= 0) |
1551 | 13.2k | { |
1552 | 13.2k | uint_fast64_t prev_res = res; |
1553 | | |
1554 | 13.2k | res *= 16; |
1555 | 13.2k | if (res / 16 != prev_res) |
1556 | 173 | return 0; |
1557 | 13.0k | res += (unsigned int) digit; |
1558 | 13.0k | if (res < (unsigned int) digit) |
1559 | 0 | return 0; |
1560 | | |
1561 | 13.0k | str++; |
1562 | 13.0k | digit = xdigittovalue (*str); |
1563 | 13.0k | } |
1564 | | |
1565 | 998 | if (str - start > 0) |
1566 | 544 | *out_val = res; |
1567 | 998 | return (size_t) (str - start); |
1568 | 1.17k | } |
1569 | | |
1570 | | |
1571 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1572 | | MHD_FN_PAR_IN_SIZE_ (1,2) |
1573 | | MHD_FN_PAR_OUT_ (3) size_t |
1574 | | mhd_strx_to_uint64_n (const char *restrict str, |
1575 | | size_t maxlen, |
1576 | | uint_fast64_t *restrict out_val) |
1577 | 1.17k | { |
1578 | 1.17k | size_t i; |
1579 | 1.17k | uint_fast64_t res; |
1580 | 1.17k | int digit; |
1581 | | |
1582 | 1.17k | res = 0; |
1583 | 1.17k | i = 0; |
1584 | 8.54k | while (i < maxlen && (digit = xdigittovalue (str[i])) >= 0) |
1585 | 7.48k | { |
1586 | 7.48k | uint_fast64_t prev_res = res; |
1587 | | |
1588 | 7.48k | res *= 16; |
1589 | 7.48k | if (res / 16 != prev_res) |
1590 | 102 | return 0; |
1591 | 7.37k | res += (unsigned int) digit; |
1592 | 7.37k | if (res < (unsigned int) digit) |
1593 | 0 | return 0; |
1594 | 7.37k | i++; |
1595 | 7.37k | } |
1596 | | |
1597 | 1.06k | if (i) |
1598 | 300 | *out_val = res; |
1599 | 1.06k | return i; |
1600 | 1.17k | } |
1601 | | |
1602 | | |
1603 | | #else /* MHD_FAVOR_SMALL_CODE */ |
1604 | | |
1605 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1606 | | MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t |
1607 | | mhd_str_to_uvalue_n (const char *restrict str, |
1608 | | size_t maxlen, |
1609 | | void *restrict out_val, |
1610 | | size_t val_size, |
1611 | | uint_fast64_t max_val, |
1612 | | unsigned int base) |
1613 | | { |
1614 | | size_t i; |
1615 | | uint_fast64_t res; |
1616 | | const uint_fast64_t max_v_div_b = max_val / base; |
1617 | | const uint_fast64_t max_v_mod_b = max_val % base; |
1618 | | |
1619 | | if ((base != 16) && (base != 10)) |
1620 | | return 0; |
1621 | | |
1622 | | res = 0; |
1623 | | i = 0; |
1624 | | while (maxlen > i) |
1625 | | { |
1626 | | const int digit = (base == 16) ? |
1627 | | xdigittovalue (str[i]) : todigitvalue (str[i]); |
1628 | | |
1629 | | if (0 > digit) |
1630 | | break; |
1631 | | if ( ((max_v_div_b) < res) || |
1632 | | (( (max_v_div_b) == res) && |
1633 | | ( (max_v_mod_b) < (uint_fast64_t) digit) ) ) |
1634 | | return 0; |
1635 | | |
1636 | | res *= base; |
1637 | | res += (unsigned int) digit; |
1638 | | i++; |
1639 | | } |
1640 | | |
1641 | | if (i) |
1642 | | { |
1643 | | if (8 == val_size) |
1644 | | *(uint_fast64_t *) out_val = res; |
1645 | | else if (4 == val_size) |
1646 | | *(uint_fast32_t *) out_val = (uint_fast32_t) res; |
1647 | | else |
1648 | | return 0; |
1649 | | } |
1650 | | return i; |
1651 | | } |
1652 | | |
1653 | | |
1654 | | #endif /* MHD_FAVOR_SMALL_CODE */ |
1655 | | |
1656 | | |
1657 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1658 | | MHD_FN_PAR_OUT_SIZE_ (2,3) size_t |
1659 | | mhd_uint32_to_strx (uint_fast32_t val, |
1660 | | char *buf, |
1661 | | size_t buf_size) |
1662 | 0 | { |
1663 | 0 | size_t o_pos = 0; /**< position of the output character */ |
1664 | 0 | int digit_pos = 8; /** zero-based, digit position in @a 'val' */ |
1665 | 0 | uint_least32_t val32 = ((uint_least32_t) val) & 0xFFFFFFFFu; |
1666 | 0 | unsigned int xdigit; |
1667 | | |
1668 | | /* Skip leading zeros */ |
1669 | 0 | do |
1670 | 0 | { |
1671 | 0 | digit_pos--; |
1672 | 0 | xdigit = (unsigned int) (val32 >> 28); |
1673 | 0 | val32 <<= 4; |
1674 | 0 | val32 &= 0xFFFFFFFFu; |
1675 | 0 | } while ((0 == xdigit) && (0 != digit_pos)); |
1676 | |
|
1677 | 0 | while (o_pos < buf_size) |
1678 | 0 | { |
1679 | 0 | buf[o_pos++] = valuetoxdigit (xdigit); |
1680 | 0 | if (0 == digit_pos) |
1681 | 0 | return o_pos; |
1682 | 0 | digit_pos--; |
1683 | 0 | xdigit = (unsigned int) (val32 >> 28); |
1684 | 0 | val32 <<= 4; |
1685 | 0 | val32 &= 0xFFFFFFFFu; |
1686 | 0 | } |
1687 | 0 | return 0; /* The buffer is too small */ |
1688 | 0 | } |
1689 | | |
1690 | | |
1691 | | #ifndef MHD_FAVOR_SMALL_CODE |
1692 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1693 | | MHD_FN_PAR_OUT_SIZE_ (2,3) size_t |
1694 | | mhd_uint16_to_str (uint_least16_t val, |
1695 | | char *buf, |
1696 | | size_t buf_size) |
1697 | 2.34k | { |
1698 | 2.34k | char *chr; /**< pointer to the current printed digit */ |
1699 | | /* The biggest printable number is 65535 */ |
1700 | 2.34k | uint_least16_t divisor = UINT16_C (10000); |
1701 | 2.34k | int digit; |
1702 | | |
1703 | 2.34k | val &= 0xFFFFu; |
1704 | 2.34k | chr = buf; |
1705 | 2.34k | digit = (int) (val / divisor); |
1706 | 2.34k | mhd_assert (digit < 10); |
1707 | | |
1708 | | /* Do not print leading zeros */ |
1709 | 9.19k | while ((0 == digit) && (1 < divisor)) |
1710 | 6.85k | { |
1711 | 6.85k | divisor /= 10; |
1712 | 6.85k | digit = (int) (val / divisor); |
1713 | 6.85k | mhd_assert (digit < 10); |
1714 | 6.85k | } |
1715 | | |
1716 | 4.85k | while (0 != buf_size) |
1717 | 4.58k | { |
1718 | 4.58k | *chr = (char) ((char) digit + '0'); |
1719 | 4.58k | chr++; |
1720 | 4.58k | buf_size--; |
1721 | 4.58k | if (1 == divisor) |
1722 | 2.06k | return (size_t) (chr - buf); |
1723 | 2.51k | val = (uint_least16_t) (val % divisor); |
1724 | 2.51k | divisor /= 10; |
1725 | 2.51k | digit = (int) (val / divisor); |
1726 | 2.51k | mhd_assert (digit < 10); |
1727 | 2.51k | } |
1728 | 274 | return 0; /* The buffer is too small */ |
1729 | 2.34k | } |
1730 | | |
1731 | | |
1732 | | #endif /* !MHD_FAVOR_SMALL_CODE */ |
1733 | | |
1734 | | |
1735 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1736 | | MHD_FN_PAR_OUT_SIZE_ (2,3) size_t |
1737 | | mhd_uint64_to_str (uint_fast64_t val, |
1738 | | char *buf, |
1739 | | size_t buf_size) |
1740 | 2.34k | { |
1741 | 2.34k | char *chr; /**< pointer to the current printed digit */ |
1742 | | /* The biggest printable number is 18446744073709551615 */ |
1743 | 2.34k | uint_fast64_t divisor = (uint_fast64_t) 10000000000000000000U; |
1744 | 2.34k | int digit; |
1745 | | |
1746 | 2.34k | val &= 0xFFFFFFFFFFFFFFFFu; |
1747 | 2.34k | chr = buf; |
1748 | 2.34k | digit = (int) (val / divisor); |
1749 | 2.34k | mhd_assert (digit < 10); |
1750 | | |
1751 | | /* Do not print leading zeros */ |
1752 | 31.6k | while ((0 == digit) && (1 < divisor)) |
1753 | 29.2k | { |
1754 | 29.2k | divisor /= 10; |
1755 | 29.2k | digit = (int) (val / divisor); |
1756 | 29.2k | mhd_assert (digit < 10); |
1757 | 29.2k | } |
1758 | | |
1759 | 11.0k | while (0 != buf_size) |
1760 | 10.5k | { |
1761 | 10.5k | *chr = (char) ((char) digit + '0'); |
1762 | 10.5k | chr++; |
1763 | 10.5k | buf_size--; |
1764 | 10.5k | if (1 == divisor) |
1765 | 1.83k | return (size_t) (chr - buf); |
1766 | 8.70k | val %= divisor; |
1767 | 8.70k | divisor /= 10; |
1768 | 8.70k | digit = (int) (val / divisor); |
1769 | 8.70k | mhd_assert (digit < 10); |
1770 | 8.70k | } |
1771 | 508 | return 0; /* The buffer is too small */ |
1772 | 2.34k | } |
1773 | | |
1774 | | |
1775 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1776 | | MHD_FN_PAR_OUT_SIZE_ (3,4) size_t |
1777 | | mhd_uint8_to_str_pad (uint8_t val, |
1778 | | uint8_t min_digits, |
1779 | | char *buf, |
1780 | | size_t buf_size) |
1781 | 0 | { |
1782 | 0 | size_t pos; /**< the position of the current printed digit */ |
1783 | 0 | int digit; |
1784 | 0 | mhd_assert (3 >= min_digits); |
1785 | |
|
1786 | 0 | pos = 0; |
1787 | 0 | digit = val / 100; |
1788 | 0 | if (0 == digit) |
1789 | 0 | { |
1790 | 0 | if (3 <= min_digits) |
1791 | 0 | buf[pos++] = '0'; |
1792 | 0 | } |
1793 | 0 | else |
1794 | 0 | { |
1795 | 0 | buf[pos++] = (char) ('0' + (char) digit); |
1796 | 0 | val %= 100; |
1797 | 0 | min_digits = 2; |
1798 | 0 | } |
1799 | |
|
1800 | 0 | if (buf_size <= pos) |
1801 | 0 | return 0; |
1802 | 0 | digit = val / 10; |
1803 | 0 | if (0 == digit) |
1804 | 0 | { |
1805 | 0 | if (2 <= min_digits) |
1806 | 0 | buf[pos++] = '0'; |
1807 | 0 | } |
1808 | 0 | else |
1809 | 0 | { |
1810 | 0 | buf[pos++] = (char) ('0' + (char) digit); |
1811 | 0 | val %= 10; |
1812 | 0 | } |
1813 | |
|
1814 | 0 | if (buf_size <= pos) |
1815 | 0 | return 0; |
1816 | 0 | buf[pos++] = (char) ('0' + (char) val); |
1817 | 0 | return pos; |
1818 | 0 | } |
1819 | | |
1820 | | |
1821 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1822 | | MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3) size_t |
1823 | | mhd_bin_to_hex (const void *restrict bin, |
1824 | | size_t size, |
1825 | | char *restrict hex) |
1826 | 218 | { |
1827 | 218 | size_t i; |
1828 | | |
1829 | 37.0k | for (i = 0; i < size; ++i) |
1830 | 36.8k | { |
1831 | 36.8k | const uint8_t b = ((const uint8_t *) bin)[i]; |
1832 | 36.8k | #ifdef mhd_HAVE_UINT8TOTWOXDIGITS |
1833 | 36.8k | const char *two_xdigits = uint8totwoxdigits (b); |
1834 | 36.8k | hex[i * 2] = two_xdigits[0]; |
1835 | 36.8k | hex[i * 2 + 1] = two_xdigits[1]; |
1836 | | #else /* ! mhd_HAVE_UINT8TOTWOXDIGITS */ |
1837 | | hex[i * 2] = valuetoxdigit (b >> 4); |
1838 | | hex[i * 2 + 1] = valuetoxdigit (b & 0x0Fu); |
1839 | | #endif /* ! mhd_HAVE_UINT8TOTWOXDIGITS */ |
1840 | 36.8k | } |
1841 | 218 | return i * 2; |
1842 | 218 | } |
1843 | | |
1844 | | |
1845 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1846 | | MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3) size_t |
1847 | | mhd_bin_to_hex_z (const void *restrict bin, |
1848 | | size_t size, |
1849 | | char *restrict hex) |
1850 | 0 | { |
1851 | 0 | size_t res; |
1852 | |
|
1853 | 0 | res = mhd_bin_to_hex (bin, size, hex); |
1854 | 0 | hex[res] = 0; |
1855 | |
|
1856 | 0 | return res; |
1857 | 0 | } |
1858 | | |
1859 | | |
1860 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1861 | | MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3) size_t |
1862 | | mhd_hex_to_bin (const char *restrict hex, |
1863 | | size_t len, |
1864 | | void *restrict bin) |
1865 | 123 | { |
1866 | 123 | size_t r; |
1867 | 123 | size_t w; |
1868 | | |
1869 | 123 | r = 0; |
1870 | 123 | w = 0; |
1871 | 123 | if (0 != len % 2) |
1872 | 55 | { |
1873 | | /* Assume the first byte is encoded with single digit */ |
1874 | 55 | const char c2 = hex[r++]; |
1875 | 55 | const int l = xdigittovalue (c2); |
1876 | 55 | if (0 > l) |
1877 | 37 | return 0; |
1878 | 18 | ((uint8_t *) bin)[w++] = (uint8_t) ((unsigned int) l); |
1879 | 18 | } |
1880 | 1.85k | while (r < len) |
1881 | 1.81k | { |
1882 | 1.81k | const char c1 = hex[r++]; |
1883 | 1.81k | const char c2 = hex[r++]; |
1884 | 1.81k | const int h = xdigittovalue (c1); |
1885 | 1.81k | const int l = xdigittovalue (c2); |
1886 | 1.81k | if ((0 > h) || (0 > l)) |
1887 | 45 | return 0; |
1888 | 1.77k | ((uint8_t *) bin)[w++] = |
1889 | 1.77k | (uint8_t) ( ((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) |
1890 | 1.77k | | ((uint8_t) ((unsigned int) l)) ); |
1891 | 1.77k | } |
1892 | 41 | mhd_assert (len == r); |
1893 | 41 | mhd_assert ((len + 1) / 2 == w); |
1894 | 41 | return w; |
1895 | 86 | } |
1896 | | |
1897 | | |
1898 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
1899 | | MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t |
1900 | | mhd_str_pct_decode_strict_n (const char *pct_encoded, |
1901 | | size_t pct_encoded_len, |
1902 | | char *decoded, |
1903 | | size_t buf_size) |
1904 | 232 | { |
1905 | | #ifdef MHD_FAVOR_SMALL_CODE |
1906 | | bool broken; |
1907 | | size_t res; |
1908 | | |
1909 | | res = mhd_str_pct_decode_lenient_n (pct_encoded, pct_encoded_len, decoded, |
1910 | | buf_size, &broken); |
1911 | | if (broken) |
1912 | | return 0; |
1913 | | return res; |
1914 | | #else /* ! MHD_FAVOR_SMALL_CODE */ |
1915 | 232 | size_t r; |
1916 | 232 | size_t w; |
1917 | 232 | r = 0; |
1918 | 232 | w = 0; |
1919 | | |
1920 | 232 | if (buf_size >= pct_encoded_len) |
1921 | 232 | { |
1922 | 11.1k | while (r < pct_encoded_len) |
1923 | 11.0k | { |
1924 | 11.0k | const char chr = pct_encoded[r]; |
1925 | 11.0k | if ('%' == chr) |
1926 | 349 | { |
1927 | 349 | if (2 > pct_encoded_len - r) |
1928 | 16 | return 0; |
1929 | 333 | else |
1930 | 333 | { |
1931 | 333 | const char c1 = pct_encoded[++r]; |
1932 | 333 | const char c2 = pct_encoded[++r]; |
1933 | 333 | const int h = xdigittovalue (c1); |
1934 | 333 | const int l = xdigittovalue (c2); |
1935 | 333 | unsigned char out; |
1936 | 333 | if ((0 > h) || (0 > l)) |
1937 | 108 | return 0; |
1938 | 225 | out = |
1939 | 225 | (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) |
1940 | 225 | | ((uint8_t) ((unsigned int) l))); |
1941 | 225 | decoded[w] = (char) out; |
1942 | 225 | } |
1943 | 349 | } |
1944 | 10.7k | else |
1945 | 10.7k | decoded[w] = chr; |
1946 | 10.9k | ++r; |
1947 | 10.9k | ++w; |
1948 | 10.9k | } |
1949 | 108 | return w; |
1950 | 232 | } |
1951 | | |
1952 | 0 | while (r < pct_encoded_len) |
1953 | 0 | { |
1954 | 0 | const char chr = pct_encoded[r]; |
1955 | 0 | if (w >= buf_size) |
1956 | 0 | return 0; |
1957 | 0 | if ('%' == chr) |
1958 | 0 | { |
1959 | 0 | if (2 > pct_encoded_len - r) |
1960 | 0 | return 0; |
1961 | 0 | else |
1962 | 0 | { |
1963 | 0 | const char c1 = pct_encoded[++r]; |
1964 | 0 | const char c2 = pct_encoded[++r]; |
1965 | 0 | const int h = xdigittovalue (c1); |
1966 | 0 | const int l = xdigittovalue (c2); |
1967 | 0 | unsigned char out; |
1968 | 0 | if ((0 > h) || (0 > l)) |
1969 | 0 | return 0; |
1970 | 0 | out = |
1971 | 0 | (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) |
1972 | 0 | | ((uint8_t) ((unsigned int) l))); |
1973 | 0 | decoded[w] = (char) out; |
1974 | 0 | } |
1975 | 0 | } |
1976 | 0 | else |
1977 | 0 | decoded[w] = chr; |
1978 | 0 | ++r; |
1979 | 0 | ++w; |
1980 | 0 | } |
1981 | 0 | return w; |
1982 | 0 | #endif /* ! MHD_FAVOR_SMALL_CODE */ |
1983 | 0 | } |
1984 | | |
1985 | | |
1986 | | MHD_INTERNAL |
1987 | | MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3) |
1988 | | MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t |
1989 | | mhd_str_pct_decode_lenient_n (const char *pct_encoded, |
1990 | | size_t pct_encoded_len, |
1991 | | char *decoded, |
1992 | | size_t buf_size, |
1993 | | bool *restrict broken_encoding) |
1994 | 232 | { |
1995 | 232 | size_t r; |
1996 | 232 | size_t w; |
1997 | 232 | r = 0; |
1998 | 232 | w = 0; |
1999 | 232 | if (NULL != broken_encoding) |
2000 | 232 | *broken_encoding = false; |
2001 | 232 | #ifndef MHD_FAVOR_SMALL_CODE |
2002 | 232 | if (buf_size >= pct_encoded_len) |
2003 | 232 | { |
2004 | 15.4k | while (r < pct_encoded_len) |
2005 | 15.2k | { |
2006 | 15.2k | const char chr = pct_encoded[r]; |
2007 | 15.2k | if ('%' == chr) |
2008 | 1.82k | { |
2009 | 1.82k | if (2 > pct_encoded_len - r) |
2010 | 30 | { |
2011 | 30 | if (NULL != broken_encoding) |
2012 | 30 | *broken_encoding = true; |
2013 | 30 | decoded[w] = chr; /* Copy "as is" */ |
2014 | 30 | } |
2015 | 1.79k | else |
2016 | 1.79k | { |
2017 | 1.79k | const char c1 = pct_encoded[++r]; |
2018 | 1.79k | const char c2 = pct_encoded[++r]; |
2019 | 1.79k | const int h = xdigittovalue (c1); |
2020 | 1.79k | const int l = xdigittovalue (c2); |
2021 | 1.79k | unsigned char out; |
2022 | 1.79k | if ((0 > h) || (0 > l)) |
2023 | 1.25k | { |
2024 | 1.25k | r -= 2; |
2025 | 1.25k | if (NULL != broken_encoding) |
2026 | 1.25k | *broken_encoding = true; |
2027 | 1.25k | decoded[w] = chr; /* Copy "as is" */ |
2028 | 1.25k | } |
2029 | 543 | else |
2030 | 543 | { |
2031 | 543 | out = |
2032 | 543 | (unsigned char) |
2033 | 543 | (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) |
2034 | 543 | | ((uint8_t) ((unsigned int) l))); |
2035 | 543 | decoded[w] = (char) out; |
2036 | 543 | } |
2037 | 1.79k | } |
2038 | 1.82k | } |
2039 | 13.4k | else |
2040 | 13.4k | decoded[w] = chr; |
2041 | 15.2k | ++r; |
2042 | 15.2k | ++w; |
2043 | 15.2k | } |
2044 | 232 | return w; |
2045 | 232 | } |
2046 | 0 | #endif /* ! MHD_FAVOR_SMALL_CODE */ |
2047 | 0 | while (r < pct_encoded_len) |
2048 | 0 | { |
2049 | 0 | const char chr = pct_encoded[r]; |
2050 | 0 | if (w >= buf_size) |
2051 | 0 | return 0; |
2052 | 0 | if ('%' == chr) |
2053 | 0 | { |
2054 | 0 | if (2 > pct_encoded_len - r) |
2055 | 0 | { |
2056 | 0 | if (NULL != broken_encoding) |
2057 | 0 | *broken_encoding = true; |
2058 | 0 | decoded[w] = chr; /* Copy "as is" */ |
2059 | 0 | } |
2060 | 0 | else |
2061 | 0 | { |
2062 | 0 | const char c1 = pct_encoded[++r]; |
2063 | 0 | const char c2 = pct_encoded[++r]; |
2064 | 0 | const int h = xdigittovalue (c1); |
2065 | 0 | const int l = xdigittovalue (c2); |
2066 | 0 | if ((0 > h) || (0 > l)) |
2067 | 0 | { |
2068 | 0 | r -= 2; |
2069 | 0 | if (NULL != broken_encoding) |
2070 | 0 | *broken_encoding = true; |
2071 | 0 | decoded[w] = chr; /* Copy "as is" */ |
2072 | 0 | } |
2073 | 0 | else |
2074 | 0 | { |
2075 | 0 | unsigned char out; |
2076 | 0 | out = |
2077 | 0 | (unsigned char) |
2078 | 0 | (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) |
2079 | 0 | | ((uint8_t) ((unsigned int) l))); |
2080 | 0 | decoded[w] = (char) out; |
2081 | 0 | } |
2082 | 0 | } |
2083 | 0 | } |
2084 | 0 | else |
2085 | 0 | decoded[w] = chr; |
2086 | 0 | ++r; |
2087 | 0 | ++w; |
2088 | 0 | } |
2089 | 0 | return w; |
2090 | 0 | } |
2091 | | |
2092 | | |
2093 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
2094 | | MHD_FN_PAR_CSTR_ (1) size_t |
2095 | | mhd_str_pct_decode_in_place_strict (char *str) |
2096 | 232 | { |
2097 | | #ifdef MHD_FAVOR_SMALL_CODE |
2098 | | size_t res; |
2099 | | bool broken; |
2100 | | |
2101 | | res = mhd_str_pct_decode_in_place_lenient (str, &broken); |
2102 | | if (broken) |
2103 | | { |
2104 | | res = 0; |
2105 | | str[0] = 0; |
2106 | | } |
2107 | | return res; |
2108 | | #else /* ! MHD_FAVOR_SMALL_CODE */ |
2109 | 232 | size_t r; |
2110 | 232 | size_t w; |
2111 | 232 | r = 0; |
2112 | 232 | w = 0; |
2113 | | |
2114 | 5.08k | while (0 != str[r]) |
2115 | 4.97k | { |
2116 | 4.97k | const char chr = str[r++]; |
2117 | 4.97k | if ('%' == chr) |
2118 | 340 | { |
2119 | 340 | const char d1 = str[r++]; |
2120 | 340 | if (0 == d1) |
2121 | 12 | return 0; |
2122 | 328 | else |
2123 | 328 | { |
2124 | 328 | const char d2 = str[r++]; |
2125 | 328 | if (0 == d2) |
2126 | 35 | return 0; |
2127 | 293 | else |
2128 | 293 | { |
2129 | 293 | const int h = xdigittovalue (d1); |
2130 | 293 | const int l = xdigittovalue (d2); |
2131 | 293 | unsigned char out; |
2132 | 293 | if ((0 > h) || (0 > l)) |
2133 | 72 | return 0; |
2134 | 221 | out = |
2135 | 221 | (unsigned char) |
2136 | 221 | (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) |
2137 | 221 | | ((uint8_t) ((unsigned int) l))); |
2138 | 221 | str[w++] = (char) out; |
2139 | 221 | } |
2140 | 328 | } |
2141 | 340 | } |
2142 | 4.63k | else |
2143 | 4.63k | str[w++] = chr; |
2144 | 4.97k | } |
2145 | 113 | str[w] = 0; |
2146 | 113 | return w; |
2147 | 232 | #endif /* ! MHD_FAVOR_SMALL_CODE */ |
2148 | 232 | } |
2149 | | |
2150 | | |
2151 | | MHD_INTERNAL |
2152 | | MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (1) size_t |
2153 | | mhd_str_pct_decode_in_place_lenient (char *restrict str, |
2154 | | bool *restrict broken_encoding) |
2155 | 232 | { |
2156 | | #ifdef MHD_FAVOR_SMALL_CODE |
2157 | | size_t len; |
2158 | | size_t res; |
2159 | | |
2160 | | len = strlen (str); |
2161 | | res = mhd_str_pct_decode_lenient_n (str, len, str, len, broken_encoding); |
2162 | | str[res] = 0; |
2163 | | |
2164 | | return res; |
2165 | | #else /* ! MHD_FAVOR_SMALL_CODE */ |
2166 | 232 | size_t r; |
2167 | 232 | size_t w; |
2168 | 232 | if (NULL != broken_encoding) |
2169 | 232 | *broken_encoding = false; |
2170 | 232 | r = 0; |
2171 | 232 | w = 0; |
2172 | 6.82k | while (0 != str[r]) |
2173 | 6.64k | { |
2174 | 6.64k | const char chr = str[r++]; |
2175 | 6.64k | if ('%' == chr) |
2176 | 914 | { |
2177 | 914 | const char d1 = str[r++]; |
2178 | 914 | if (0 == d1) |
2179 | 14 | { |
2180 | 14 | if (NULL != broken_encoding) |
2181 | 14 | *broken_encoding = true; |
2182 | 14 | str[w++] = chr; /* Copy "as is" */ |
2183 | 14 | str[w] = 0; |
2184 | 14 | return w; |
2185 | 14 | } |
2186 | 900 | else |
2187 | 900 | { |
2188 | 900 | const char d2 = str[r++]; |
2189 | 900 | if (0 == d2) |
2190 | 38 | { |
2191 | 38 | if (NULL != broken_encoding) |
2192 | 38 | *broken_encoding = true; |
2193 | 38 | str[w++] = chr; /* Copy "as is" */ |
2194 | 38 | str[w++] = d1; /* Copy "as is" */ |
2195 | 38 | str[w] = 0; |
2196 | 38 | return w; |
2197 | 38 | } |
2198 | 862 | else |
2199 | 862 | { |
2200 | 862 | const int h = xdigittovalue (d1); |
2201 | 862 | const int l = xdigittovalue (d2); |
2202 | 862 | unsigned char out; |
2203 | 862 | if ((0 > h) || (0 > l)) |
2204 | 620 | { |
2205 | 620 | if (NULL != broken_encoding) |
2206 | 620 | *broken_encoding = true; |
2207 | 620 | str[w++] = chr; /* Copy "as is" */ |
2208 | 620 | str[w++] = d1; |
2209 | 620 | str[w++] = d2; |
2210 | 620 | continue; |
2211 | 620 | } |
2212 | 242 | out = |
2213 | 242 | (unsigned char) |
2214 | 242 | (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4)) |
2215 | 242 | | ((uint8_t) ((unsigned int) l))); |
2216 | 242 | str[w++] = (char) out; |
2217 | 242 | continue; |
2218 | 862 | } |
2219 | 900 | } |
2220 | 914 | } |
2221 | 5.72k | str[w++] = chr; |
2222 | 5.72k | } |
2223 | 180 | str[w] = 0; |
2224 | 180 | return w; |
2225 | 232 | #endif /* ! MHD_FAVOR_SMALL_CODE */ |
2226 | 232 | } |
2227 | | |
2228 | | |
2229 | | #ifdef MHD_SUPPORT_AUTH_DIGEST |
2230 | | |
2231 | | MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ |
2232 | | MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4) bool |
2233 | | mhd_str_equal_quoted_bin_n (const char *quoted, |
2234 | | size_t quoted_len, |
2235 | | const char *unquoted, |
2236 | | size_t unquoted_len) |
2237 | 0 | { |
2238 | 0 | size_t i; |
2239 | 0 | size_t j; |
2240 | 0 | if (unquoted_len < quoted_len / 2) |
2241 | 0 | return false; |
2242 | | |
2243 | 0 | j = 0; |
2244 | 0 | for (i = 0; quoted_len > i && unquoted_len > j; ++i, ++j) |
2245 | 0 | { |
2246 | 0 | if ('\\' == quoted[i]) |
2247 | 0 | { |
2248 | 0 | i++; /* Advance to the next character */ |
2249 | 0 | if (quoted_len == i) |
2250 | 0 | return false; /* No character after escaping backslash */ |
2251 | 0 | } |
2252 | 0 | if (quoted[i] != unquoted[j]) |
2253 | 0 | return false; /* Different characters */ |
2254 | 0 | } |
2255 | 0 | if ((quoted_len != i) || (unquoted_len != j)) |
2256 | 0 | return false; /* The strings have different length */ |
2257 | | |
2258 | 0 | return true; |
2259 | 0 | } |
2260 | | |
2261 | | |
2262 | | MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ |
2263 | | MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4) bool |
2264 | | mhd_str_equal_caseless_quoted_bin_n (const char *quoted, |
2265 | | size_t quoted_len, |
2266 | | const char *unquoted, |
2267 | | size_t unquoted_len) |
2268 | 0 | { |
2269 | 0 | size_t i; |
2270 | 0 | size_t j; |
2271 | 0 | if (unquoted_len < quoted_len / 2) |
2272 | 0 | return false; |
2273 | | |
2274 | 0 | j = 0; |
2275 | 0 | for (i = 0; quoted_len > i && unquoted_len > j; ++i, ++j) |
2276 | 0 | { |
2277 | 0 | if ('\\' == quoted[i]) |
2278 | 0 | { |
2279 | 0 | i++; /* Advance to the next character */ |
2280 | 0 | if (quoted_len == i) |
2281 | 0 | return false; /* No character after escaping backslash */ |
2282 | 0 | } |
2283 | 0 | if (! charsequalcaseless (quoted[i], unquoted[j])) |
2284 | 0 | return false; /* Different characters */ |
2285 | 0 | } |
2286 | 0 | if ((quoted_len != i) || (unquoted_len != j)) |
2287 | 0 | return false; /* The strings have different length */ |
2288 | | |
2289 | 0 | return true; |
2290 | 0 | } |
2291 | | |
2292 | | |
2293 | | #endif /* MHD_SUPPORT_AUTH_DIGEST */ |
2294 | | |
2295 | | #if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_POST_PARSER) |
2296 | | |
2297 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
2298 | | MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,2) size_t |
2299 | | mhd_str_unquote (const char *quoted, |
2300 | | size_t quoted_len, |
2301 | | char *result) |
2302 | 366 | { |
2303 | 366 | size_t r; |
2304 | 366 | size_t w; |
2305 | | |
2306 | 366 | r = 0; |
2307 | 366 | w = 0; |
2308 | | |
2309 | 33.8k | while (quoted_len > r) |
2310 | 33.5k | { |
2311 | 33.5k | if ('\\' == quoted[r]) |
2312 | 446 | { |
2313 | 446 | ++r; |
2314 | 446 | if (quoted_len == r) |
2315 | 23 | return 0; /* Last backslash is not followed by char to unescape */ |
2316 | 446 | } |
2317 | 33.4k | result[w++] = quoted[r++]; |
2318 | 33.4k | } |
2319 | 343 | return w; |
2320 | 366 | } |
2321 | | |
2322 | | |
2323 | | #endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_POST_PARSER */ |
2324 | | |
2325 | | #if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_AUTH_BASIC) |
2326 | | |
2327 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
2328 | | MHD_FN_PAR_IN_SIZE_ (1,2) |
2329 | | MHD_FN_PAR_OUT_SIZE_ (3,4) size_t |
2330 | | mhd_str_quote (const char *unquoted, |
2331 | | size_t unquoted_len, |
2332 | | char *result, |
2333 | | size_t buf_size) |
2334 | 1.06k | { |
2335 | 1.06k | size_t r; |
2336 | 1.06k | size_t w; |
2337 | | |
2338 | 1.06k | r = 0; |
2339 | 1.06k | w = 0; |
2340 | | |
2341 | 1.06k | #ifndef MHD_FAVOR_SMALL_CODE |
2342 | 1.06k | if (unquoted_len * 2 <= buf_size) |
2343 | 1.06k | { |
2344 | | /* Fast loop: the output will fit the buffer with any input string content */ |
2345 | 39.6k | while (unquoted_len > r) |
2346 | 38.5k | { |
2347 | 38.5k | const char chr = unquoted[r++]; |
2348 | 38.5k | if (('\\' == chr) || ('\"' == chr)) |
2349 | 1.05k | result[w++] = '\\'; /* Escape current char */ |
2350 | 38.5k | result[w++] = chr; |
2351 | 38.5k | } |
2352 | 1.06k | } |
2353 | 0 | else |
2354 | 0 | { |
2355 | 0 | if (unquoted_len > buf_size) |
2356 | 0 | return 0; /* Quick fail: the output buffer is too small */ |
2357 | | #else /* MHD_FAVOR_SMALL_CODE */ |
2358 | | if (1) |
2359 | | { |
2360 | | #endif /* MHD_FAVOR_SMALL_CODE */ |
2361 | | |
2362 | 0 | while (unquoted_len > r) |
2363 | 0 | { |
2364 | 0 | if (buf_size <= w) |
2365 | 0 | return 0; /* The output buffer is too small */ |
2366 | 0 | else |
2367 | 0 | { |
2368 | 0 | const char chr = unquoted[r++]; |
2369 | 0 | if (('\\' == chr) || ('\"' == chr)) |
2370 | 0 | { |
2371 | 0 | result[w++] = '\\'; /* Escape current char */ |
2372 | 0 | if (buf_size <= w) |
2373 | 0 | return 0; /* The output buffer is too small */ |
2374 | 0 | } |
2375 | 0 | result[w++] = chr; |
2376 | 0 | } |
2377 | 0 | } |
2378 | 0 | } |
2379 | | |
2380 | 1.06k | mhd_assert (w >= r); |
2381 | 1.06k | mhd_assert (w <= r * 2); |
2382 | 1.06k | return w; |
2383 | 1.06k | } |
2384 | | |
2385 | | |
2386 | | #endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_AUTH_BASIC */ |
2387 | | |
2388 | | #ifdef MHD_SUPPORT_AUTH_BASIC |
2389 | | |
2390 | | /* |
2391 | | * MHD_BASE64_FUNC_VERSION |
2392 | | * 1 = smallest, |
2393 | | * 2 = medium, |
2394 | | * 3 = fastest |
2395 | | */ |
2396 | | #ifndef MHD_BASE64_FUNC_VERSION |
2397 | | #ifdef MHD_FAVOR_SMALL_CODE |
2398 | | #define MHD_BASE64_FUNC_VERSION 1 |
2399 | | #else /* ! MHD_FAVOR_SMALL_CODE */ |
2400 | | #define MHD_BASE64_FUNC_VERSION 3 |
2401 | | #endif /* ! MHD_FAVOR_SMALL_CODE */ |
2402 | | #endif /* ! MHD_BASE64_FUNC_VERSION */ |
2403 | | |
2404 | | #if MHD_BASE64_FUNC_VERSION < 1 || MHD_BASE64_FUNC_VERSION > 3 |
2405 | | #error Wrong MHD_BASE64_FUNC_VERSION value |
2406 | | #endif /* MHD_BASE64_FUNC_VERSION < 1 || MHD_BASE64_FUNC_VERSION > 3 */ |
2407 | | |
2408 | | #if MHD_BASE64_FUNC_VERSION == 3 |
2409 | | #define mhd_base64_map_type int |
2410 | | #else /* MHD_BASE64_FUNC_VERSION < 3 */ |
2411 | | #define mhd_base64_map_type int8_t |
2412 | | #endif /* MHD_BASE64_FUNC_VERSION < 3 */ |
2413 | | |
2414 | | #if MHD_BASE64_FUNC_VERSION == 1 |
2415 | | static mhd_base64_map_type |
2416 | | base64_char_to_value_ (uint8_t c) |
2417 | | { |
2418 | | if ('Z' >= c) |
2419 | | { |
2420 | | if ('A' <= c) |
2421 | | return (mhd_base64_map_type) ((c - 'A') + 0); |
2422 | | else if ('0' <= c) |
2423 | | { |
2424 | | if ('9' >= c) |
2425 | | return (mhd_base64_map_type) ((c - '0') + 52); |
2426 | | else if ('=' == c) |
2427 | | return -2; |
2428 | | else |
2429 | | return -1; |
2430 | | } |
2431 | | else if ('+' == c) |
2432 | | return 62; |
2433 | | else if ('/' == c) |
2434 | | return 63; |
2435 | | else |
2436 | | return -1; |
2437 | | } |
2438 | | else if (('z' >= c) && ('a' <= c)) |
2439 | | return (mhd_base64_map_type) ((c - 'a') + 26); |
2440 | | return -1; |
2441 | | } |
2442 | | |
2443 | | |
2444 | | #endif /* MHD_BASE64_FUNC_VERSION == 1 */ |
2445 | | |
2446 | | |
2447 | | mhd_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE |
2448 | | |
2449 | | |
2450 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
2451 | | MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t |
2452 | | mhd_base64_to_bin_n (const char *base64, |
2453 | | size_t base64_len, |
2454 | | void *bin, |
2455 | | size_t bin_size) |
2456 | 143 | { |
2457 | 143 | #if MHD_BASE64_FUNC_VERSION >= 2 |
2458 | 143 | static const mhd_base64_map_type map[] = { |
2459 | | /* -1 = invalid char, -2 = padding |
2460 | | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
2461 | | NUL, SOH, STX, ETX, EOT, ENQ, ACK, BEL, */ |
2462 | 143 | -1, -1, -1, -1, -1, -1, -1, -1, |
2463 | | /* |
2464 | | 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, |
2465 | | BS, HT, LF, VT, FF, CR, SO, SI, */ |
2466 | 143 | -1, -1, -1, -1, -1, -1, -1, -1, |
2467 | | /* |
2468 | | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
2469 | | DLE, DC1, DC2, DC3, DC4, NAK, SYN, ETB, */ |
2470 | 143 | -1, -1, -1, -1, -1, -1, -1, -1, |
2471 | | /* |
2472 | | 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, |
2473 | | CAN, EM, SUB, ESC, FS, GS, RS, US, */ |
2474 | 143 | -1, -1, -1, -1, -1, -1, -1, -1, |
2475 | | /* |
2476 | | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, |
2477 | | ' ', '!', '"', '#', '$', '%', '&', '\'', */ |
2478 | 143 | -1, -1, -1, -1, -1, -1, -1, -1, |
2479 | | /* |
2480 | | 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, |
2481 | | '(', ')', '*', '+', ',', '-', '.', '/', */ |
2482 | 143 | -1, -1, -1, 62, -1, -1, -1, 63, |
2483 | | /* |
2484 | | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, |
2485 | | '0', '1', '2', '3', '4', '5', '6', '7', */ |
2486 | 143 | 52, 53, 54, 55, 56, 57, 58, 59, |
2487 | | /* |
2488 | | 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, |
2489 | | '8', '9', ':', ';', '<', '=', '>', '?', */ |
2490 | 143 | 60, 61, -1, -1, -1, -2, -1, -1, |
2491 | | /* |
2492 | | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, |
2493 | | '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', */ |
2494 | 143 | -1, 0, 1, 2, 3, 4, 5, 6, |
2495 | | /* |
2496 | | 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, |
2497 | | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', */ |
2498 | 143 | 7, 8, 9, 10, 11, 12, 13, 14, |
2499 | | /* |
2500 | | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, |
2501 | | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', */ |
2502 | 143 | 15, 16, 17, 18, 19, 20, 21, 22, |
2503 | | /* |
2504 | | 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, |
2505 | | 'X', 'Y', 'Z', '[', '\', ']', '^', '_', */ |
2506 | 143 | 23, 24, 25, -1, -1, -1, -1, -1, |
2507 | | /* |
2508 | | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, |
2509 | | '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', */ |
2510 | 143 | -1, 26, 27, 28, 29, 30, 31, 32, |
2511 | | /* |
2512 | | 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, |
2513 | | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', */ |
2514 | 143 | 33, 34, 35, 36, 37, 38, 39, 40, |
2515 | | /* |
2516 | | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, |
2517 | | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', */ |
2518 | 143 | 41, 42, 43, 44, 45, 46, 47, 48, |
2519 | | /* |
2520 | | 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, |
2521 | | 'x', 'y', 'z', '{', '|', '}', '~', DEL, */ |
2522 | 143 | 49, 50, 51, -1, -1, -1, -1, -1 |
2523 | | |
2524 | 143 | #if MHD_BASE64_FUNC_VERSION == 3 |
2525 | 143 | , |
2526 | 143 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80..8F */ |
2527 | 143 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90..9F */ |
2528 | 143 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A0..AF */ |
2529 | 143 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* B0..BF */ |
2530 | 143 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* C0..CF */ |
2531 | 143 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* D0..DF */ |
2532 | 143 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* E0..EF */ |
2533 | 143 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* F0..FF */ |
2534 | 143 | #endif /* ! MHD_BASE64_FUNC_VERSION == 3 */ |
2535 | 143 | }; |
2536 | 14.3k | #define base64_char_to_value_(c) map[(c)] |
2537 | 143 | #endif /* MHD_BASE64_FUNC_VERSION >= 2 */ |
2538 | 143 | const uint8_t *const in = (const uint8_t *) base64; |
2539 | 143 | uint8_t *const out = (uint8_t *) bin; |
2540 | 143 | size_t i; |
2541 | 143 | size_t j; |
2542 | 143 | if (0 == base64_len) |
2543 | 24 | return 0; /* Nothing to decode */ |
2544 | 119 | if (0 != base64_len % 4) |
2545 | 61 | return 0; /* Wrong input length */ |
2546 | 58 | if (base64_len / 4 * 3 - 2 > bin_size) |
2547 | 0 | return 0; |
2548 | | |
2549 | 58 | j = 0; |
2550 | 3.58k | for (i = 0; i < (base64_len - 4); i += 4) |
2551 | 3.52k | { |
2552 | | #if MHD_BASE64_FUNC_VERSION == 2 |
2553 | | if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3]))) |
2554 | | return 0; |
2555 | | #endif /* MHD_BASE64_FUNC_VERSION == 2 */ |
2556 | 3.52k | if (1) |
2557 | 3.52k | { |
2558 | 3.52k | const mhd_base64_map_type v1 = base64_char_to_value_ (in[i + 0]); |
2559 | 3.52k | const mhd_base64_map_type v2 = base64_char_to_value_ (in[i + 1]); |
2560 | 3.52k | const mhd_base64_map_type v3 = base64_char_to_value_ (in[i + 2]); |
2561 | 3.52k | const mhd_base64_map_type v4 = base64_char_to_value_ (in[i + 3]); |
2562 | 3.52k | if ((0 > v1) || (0 > v2) || (0 > v3) || (0 > v4)) |
2563 | 0 | return 0; |
2564 | 3.52k | out[j + 0] = (uint8_t) (((uint8_t) (((uint8_t) v1) << 2)) |
2565 | 3.52k | | ((uint8_t) (((uint8_t) v2) >> 4))); |
2566 | 3.52k | out[j + 1] = (uint8_t) (((uint8_t) (((uint8_t) v2) << 4)) |
2567 | 3.52k | | ((uint8_t) (((uint8_t) v3) >> 2))); |
2568 | 3.52k | out[j + 2] = (uint8_t) (((uint8_t) (((uint8_t) v3) << 6)) |
2569 | 3.52k | | ((uint8_t) v4)); |
2570 | 3.52k | } |
2571 | 3.52k | j += 3; |
2572 | 3.52k | } |
2573 | | #if MHD_BASE64_FUNC_VERSION == 2 |
2574 | | if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3]))) |
2575 | | return 0; |
2576 | | #endif /* MHD_BASE64_FUNC_VERSION == 2 */ |
2577 | 58 | if (1) |
2578 | 58 | { /* The last four chars block */ |
2579 | 58 | const mhd_base64_map_type v1 = base64_char_to_value_ (in[i + 0]); |
2580 | 58 | const mhd_base64_map_type v2 = base64_char_to_value_ (in[i + 1]); |
2581 | 58 | const mhd_base64_map_type v3 = base64_char_to_value_ (in[i + 2]); |
2582 | 58 | const mhd_base64_map_type v4 = base64_char_to_value_ (in[i + 3]); |
2583 | 58 | if ((0 > v1) || (0 > v2)) |
2584 | 0 | return 0; /* Invalid char or padding at first two positions */ |
2585 | 58 | mhd_assert (j < bin_size); |
2586 | 58 | out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v1) << 2)) |
2587 | 58 | | ((uint8_t) (((uint8_t) v2) >> 4))); |
2588 | 58 | if (0 > v3) |
2589 | 0 | { /* Third char is either padding or invalid */ |
2590 | 0 | if ((-2 != v3) || (-2 != v4)) |
2591 | 0 | return 0; /* Both two last chars must be padding */ |
2592 | 0 | if (0 != (uint8_t) (((uint8_t) v2) << 4)) |
2593 | 0 | return 0; /* Wrong last char */ |
2594 | 0 | return j; |
2595 | 0 | } |
2596 | 58 | if (j >= bin_size) |
2597 | 0 | return 0; /* Not enough space */ |
2598 | 58 | out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v2) << 4)) |
2599 | 58 | | ((uint8_t) (((uint8_t) v3) >> 2))); |
2600 | 58 | if (0 > v4) |
2601 | 0 | { /* Fourth char is either padding or invalid */ |
2602 | 0 | if (-2 != v4) |
2603 | 0 | return 0; /* The char must be padding */ |
2604 | 0 | if (0 != (uint8_t) (((uint8_t) v3) << 6)) |
2605 | 0 | return 0; /* Wrong last char */ |
2606 | 0 | return j; |
2607 | 0 | } |
2608 | 58 | if (j >= bin_size) |
2609 | 0 | return 0; /* Not enough space */ |
2610 | 58 | out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v3) << 6)) |
2611 | 58 | | ((uint8_t) v4)); |
2612 | 58 | } |
2613 | 58 | return j; |
2614 | 58 | #if MHD_BASE64_FUNC_VERSION >= 2 |
2615 | 58 | #undef base64_char_to_value_ |
2616 | 58 | #endif /* MHD_BASE64_FUNC_VERSION >= 2 */ |
2617 | 58 | } |
2618 | | |
2619 | | |
2620 | | mhd_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE |
2621 | | |
2622 | | |
2623 | | #undef mhd_base64_map_type |
2624 | | |
2625 | | #endif /* MHD_SUPPORT_AUTH_BASIC */ |
2626 | | |
2627 | | |
2628 | | MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ bool |
2629 | | mhd_str_starts_with_token_opt_param (const struct MHD_String *restrict str, |
2630 | | const struct MHD_String *restrict token) |
2631 | 0 | { |
2632 | 0 | size_t i; |
2633 | |
|
2634 | 0 | mhd_assert (0 != token->len); |
2635 | 0 | mhd_assert (NULL == memchr (token->cstr, '=', token->len)); |
2636 | 0 | mhd_assert (NULL == memchr (token->cstr, ' ', token->len)); |
2637 | 0 | mhd_assert (NULL == memchr (token->cstr, '\t', token->len)); |
2638 | |
|
2639 | 0 | if (str->len < token->len) |
2640 | 0 | return false; /* The string is too short to match */ |
2641 | | |
2642 | 0 | if (! mhd_str_equal_caseless_bin_n (str->cstr, |
2643 | 0 | token->cstr, |
2644 | 0 | token->len)) |
2645 | 0 | return false; /* The string does not start with the token */ |
2646 | | |
2647 | 0 | for (i = token->len; i < str->len; ++i) |
2648 | 0 | { |
2649 | 0 | const char c = str->cstr[i]; |
2650 | 0 | if ((' ' == c) || ('\t' == c)) |
2651 | 0 | continue; |
2652 | 0 | if (';' == c) |
2653 | 0 | return true; /* Found the start of the token parameters */ |
2654 | 0 | return false; /* The initial part of the string does not fully match the token */ |
2655 | 0 | } |
2656 | 0 | mhd_assert (0 && "The string should not have whitespace at the end"); |
2657 | 0 | return true; |
2658 | 0 | } |
2659 | | |
2660 | | |
2661 | | MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ |
2662 | | MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) MHD_FN_PAR_IN_ (3) |
2663 | | MHD_FN_PAR_OUT_ (4) MHD_FN_PAR_OUT_ (5) enum mhd_StingStartsWithTokenResult |
2664 | | mhd_str_starts_with_token_req_param ( |
2665 | | const struct MHD_String *restrict str, |
2666 | | const struct MHD_String *restrict token, |
2667 | | const struct MHD_String *restrict par, |
2668 | | struct mhd_BufferConst *restrict par_value, |
2669 | | bool *restrict par_value_needs_unquote) |
2670 | 1.25k | { |
2671 | 1.25k | size_t i; |
2672 | 1.25k | const char *const restrict cstr = str->cstr; |
2673 | 1.25k | bool token_found; |
2674 | 1.25k | bool param_found; |
2675 | | |
2676 | 1.25k | mhd_assert (0 != token->len); |
2677 | 1.25k | mhd_assert (NULL == memchr (token->cstr, '=', token->len)); |
2678 | 1.25k | mhd_assert (NULL == memchr (token->cstr, ' ', token->len)); |
2679 | 1.25k | mhd_assert (NULL == memchr (token->cstr, '\t', token->len)); |
2680 | 1.25k | mhd_assert (NULL == memchr (par->cstr, '=', par->len)); |
2681 | 1.25k | mhd_assert (NULL == memchr (par->cstr, ' ', par->len)); |
2682 | 1.25k | mhd_assert (NULL == memchr (par->cstr, '\t', par->len)); |
2683 | | |
2684 | 1.25k | par_value->data = NULL; |
2685 | 1.25k | par_value->size = 0; |
2686 | | |
2687 | 1.25k | if (str->len < token->len) |
2688 | 84 | return mhd_STR_STARTS_W_TOKEN_NO_TOKEN; /* The string is too short to match */ |
2689 | | |
2690 | 1.16k | if (! mhd_str_equal_caseless_bin_n (cstr, |
2691 | 1.16k | token->cstr, |
2692 | 1.16k | token->len)) |
2693 | 176 | return mhd_STR_STARTS_W_TOKEN_NO_TOKEN; /* The string does not start with the token */ |
2694 | 993 | token_found = false; |
2695 | 993 | param_found = false; |
2696 | | |
2697 | 993 | i = token->len; |
2698 | 993 | do |
2699 | 3.43k | { |
2700 | | /* Find start of the next parameter */ |
2701 | 9.21k | for ((void) 0; i < str->len; ++i) |
2702 | 8.99k | { |
2703 | 8.99k | const char c = cstr[i]; |
2704 | 8.99k | if ((' ' == c) || ('\t' == c)) |
2705 | 5.77k | continue; |
2706 | 3.22k | if (';' == c) |
2707 | 2.91k | { |
2708 | | /* Found the start of the next token parameter */ |
2709 | 2.91k | if (param_found) |
2710 | 20 | return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; |
2711 | 2.89k | ++i; /* Move to the next char */ |
2712 | 2.89k | break; |
2713 | 2.91k | } |
2714 | 310 | if (',' == c) |
2715 | 42 | return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* Found the start of the next token */ |
2716 | | |
2717 | 268 | if (! token_found) |
2718 | 248 | { |
2719 | 248 | if (i == token->len) |
2720 | 200 | { |
2721 | | /* The initial part of the string does not fully match the token or |
2722 | | formatting is not correct */ |
2723 | 200 | return mhd_STR_STARTS_W_TOKEN_NO_TOKEN; |
2724 | 200 | } |
2725 | | /* The string has garbage after the token and whitespace */ |
2726 | 48 | return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT; |
2727 | 248 | } |
2728 | | /* The garbage after the parameter */ |
2729 | 20 | return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT; |
2730 | 268 | } |
2731 | 3.10k | token_found = true; |
2732 | | |
2733 | 3.10k | if (i == str->len) |
2734 | 241 | return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; |
2735 | | |
2736 | | /* 'i' is at the start of the parameter */ |
2737 | | |
2738 | 3.48k | while ((' ' == cstr[i]) || ('\t' == cstr[i])) |
2739 | 636 | { |
2740 | 636 | if (++i == str->len) |
2741 | 23 | return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; |
2742 | 636 | } |
2743 | | |
2744 | | /* 'i' is at the start of the parameter name */ |
2745 | | |
2746 | 2.84k | if (par->len > str->len - i - 1) |
2747 | 30 | return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* the token is found, but the parameter is not */ |
2748 | 2.81k | else |
2749 | 2.81k | { /* Check the parameter */ |
2750 | 2.81k | bool val_needs_unquote; |
2751 | 2.81k | size_t j; |
2752 | 2.81k | const char *const prm_str = cstr + i; |
2753 | | |
2754 | 4.28k | for (j = 0; j < par->len; ++j) |
2755 | 2.71k | if (! charsequalcaseless (prm_str[j], |
2756 | 2.71k | par->cstr[j])) |
2757 | 1.24k | break; |
2758 | 2.81k | i += j; |
2759 | 2.81k | mhd_assert (str->len > i); |
2760 | 2.81k | if ((j == par->len) && |
2761 | 2.81k | ('=' == cstr[i])) |
2762 | 186 | { |
2763 | | /* The parameter name matches required parameter */ |
2764 | 186 | param_found = true; |
2765 | 186 | par_value->data = cstr + i + 1; |
2766 | 186 | } |
2767 | 2.62k | else |
2768 | 2.62k | { |
2769 | | /* i points to the char in the parameter name */ |
2770 | 7.20k | while ('=' != cstr[i]) |
2771 | 4.74k | { |
2772 | 4.74k | if ((';' == cstr[i]) /* end of the parameter */ |
2773 | 4.74k | || (',' == cstr[i]) /* end of the token */ |
2774 | 4.74k | || (str->len == ++i)) /* end of the field string */ |
2775 | 168 | { |
2776 | | /* parameter without the value */ |
2777 | 168 | return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT; |
2778 | 168 | } |
2779 | 4.74k | } |
2780 | 2.62k | } |
2781 | 2.64k | mhd_assert (str->len > i); |
2782 | 2.64k | mhd_assert ('=' == cstr[i]); |
2783 | | |
2784 | | /* 'i' points to '=' between parameter name and parameter value */ |
2785 | | |
2786 | 2.64k | ++i; /* Advance to the first char in the parameter value */ |
2787 | 2.64k | if (str->len == i) |
2788 | 30 | return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* Zero-length parameter value */ |
2789 | | |
2790 | 2.61k | val_needs_unquote = false; |
2791 | | |
2792 | | /* 'i' points to the char after '=' */ |
2793 | | |
2794 | 2.61k | if ('"' == cstr[i]) |
2795 | 430 | { |
2796 | | /* The value is quoted */ |
2797 | 430 | if (param_found) |
2798 | 81 | ++(par_value->data); /* Point to the first quoted char */ |
2799 | 430 | do |
2800 | 8.28k | { |
2801 | 8.28k | ++i; /* Advance to the next char */ |
2802 | 8.28k | if (str->len == i) |
2803 | 73 | return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT; /* No closing quote */ |
2804 | 8.21k | if ('\\' == cstr[i]) |
2805 | 272 | { |
2806 | 272 | val_needs_unquote = true; |
2807 | 272 | ++i; /* Skip quoted char */ |
2808 | 272 | if (str->len == i) |
2809 | 11 | return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT; /* No closing quote */ |
2810 | 272 | } |
2811 | 8.21k | } while ('"' != cstr[i]); |
2812 | 346 | if (param_found) |
2813 | 15 | { |
2814 | 15 | par_value->size = (size_t) ((cstr + i) - par_value->data); |
2815 | 15 | *par_value_needs_unquote = val_needs_unquote; |
2816 | 15 | } |
2817 | | /* Complete value found */ |
2818 | | /* Check for the garbage data at the end */ |
2819 | 346 | ++i; /* Advance to the next char */ |
2820 | 346 | } |
2821 | 2.18k | else |
2822 | 2.18k | { |
2823 | | /* The value is not quoted */ |
2824 | 4.65k | while ((' ' != cstr[i]) && |
2825 | 4.65k | ('\t' != cstr[i])) |
2826 | 4.01k | { |
2827 | 4.01k | if ((';' == cstr[i]) /* end of the parameter */ |
2828 | 4.01k | || (',' == cstr[i]) /* end of the token */ |
2829 | 4.01k | || (str->len == ++i)) /* end of the field string */ |
2830 | 1.55k | break; |
2831 | 4.01k | } |
2832 | | /* The end parameter value */ |
2833 | 2.18k | if (param_found) |
2834 | 89 | { |
2835 | 89 | par_value->size = (size_t) ((cstr + i) - par_value->data); |
2836 | 89 | *par_value_needs_unquote = false; |
2837 | 89 | } |
2838 | | /* Check for the garbage data at the end */ |
2839 | 2.18k | } |
2840 | | |
2841 | | /* 'i' points to the next char after end of the parameter value */ |
2842 | 2.61k | } |
2843 | 2.84k | } while (i < str->len); |
2844 | | |
2845 | 87 | mhd_assert (token_found); |
2846 | 87 | return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; |
2847 | 993 | } |