diff options
Diffstat (limited to 'src/lib/mhd_str.c')
-rw-r--r-- | src/lib/mhd_str.c | 758 |
1 files changed, 758 insertions, 0 deletions
diff --git a/src/lib/mhd_str.c b/src/lib/mhd_str.c new file mode 100644 index 00000000..d0b03ead --- /dev/null +++ b/src/lib/mhd_str.c | |||
@@ -0,0 +1,758 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2015, 2016 Karlson2k (Evgeny Grin) | ||
4 | |||
5 | This library 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 | This library 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_str.h" | ||
27 | |||
28 | #ifdef HAVE_STDBOOL_H | ||
29 | #include <stdbool.h> | ||
30 | #endif | ||
31 | |||
32 | #include "mhd_limits.h" | ||
33 | |||
34 | #ifdef MHD_FAVOR_SMALL_CODE | ||
35 | #ifdef _MHD_static_inline | ||
36 | #undef _MHD_static_inline | ||
37 | #endif /* _MHD_static_inline */ | ||
38 | /* Do not force inlining and do not use macro functions, use normal static | ||
39 | functions instead. | ||
40 | This may give more flexibility for size optimizations. */ | ||
41 | #define _MHD_static_inline static | ||
42 | #ifndef INLINE_FUNC | ||
43 | #define INLINE_FUNC 1 | ||
44 | #endif /* !INLINE_FUNC */ | ||
45 | #endif /* MHD_FAVOR_SMALL_CODE */ | ||
46 | |||
47 | /* | ||
48 | * Block of functions/macros that use US-ASCII charset as required by HTTP | ||
49 | * standards. Not affected by current locale settings. | ||
50 | */ | ||
51 | |||
52 | #ifdef INLINE_FUNC | ||
53 | |||
54 | #if 0 /* Disable unused functions. */ | ||
55 | /** | ||
56 | * Check whether character is lower case letter in US-ASCII | ||
57 | * | ||
58 | * @param c character to check | ||
59 | * @return non-zero if character is lower case letter, zero otherwise | ||
60 | */ | ||
61 | _MHD_static_inline bool | ||
62 | isasciilower (char c) | ||
63 | { | ||
64 | return (c >= 'a') && (c <= 'z'); | ||
65 | } | ||
66 | #endif /* Disable unused functions. */ | ||
67 | |||
68 | |||
69 | /** | ||
70 | * Check whether character is upper case letter in US-ASCII | ||
71 | * | ||
72 | * @param c character to check | ||
73 | * @return non-zero if character is upper case letter, zero otherwise | ||
74 | */ | ||
75 | _MHD_static_inline bool | ||
76 | isasciiupper (char c) | ||
77 | { | ||
78 | return (c >= 'A') && (c <= 'Z'); | ||
79 | } | ||
80 | |||
81 | |||
82 | #if 0 /* Disable unused functions. */ | ||
83 | /** | ||
84 | * Check whether character is letter in US-ASCII | ||
85 | * | ||
86 | * @param c character to check | ||
87 | * @return non-zero if character is letter in US-ASCII, zero otherwise | ||
88 | */ | ||
89 | _MHD_static_inline bool | ||
90 | isasciialpha (char c) | ||
91 | { | ||
92 | return isasciilower (c) || isasciiupper (c); | ||
93 | } | ||
94 | #endif /* Disable unused functions. */ | ||
95 | |||
96 | |||
97 | /** | ||
98 | * Check whether character is decimal digit in US-ASCII | ||
99 | * | ||
100 | * @param c character to check | ||
101 | * @return non-zero if character is decimal digit, zero otherwise | ||
102 | */ | ||
103 | _MHD_static_inline bool | ||
104 | isasciidigit (char c) | ||
105 | { | ||
106 | return (c >= '0') && (c <= '9'); | ||
107 | } | ||
108 | |||
109 | #if 0 /* Disable unused functions. */ | ||
110 | /** | ||
111 | * Check whether character is hexadecimal digit in US-ASCII | ||
112 | * | ||
113 | * @param c character to check | ||
114 | * @return non-zero if character is decimal digit, zero otherwise | ||
115 | */ | ||
116 | _MHD_static_inline bool | ||
117 | isasciixdigit (char c) | ||
118 | { | ||
119 | return isasciidigit (c) || | ||
120 | ( (c >= 'A') && (c <= 'F') ) || | ||
121 | ( (c >= 'a') && (c <= 'f') ); | ||
122 | } | ||
123 | |||
124 | |||
125 | /** | ||
126 | * Check whether character is decimal digit or letter in US-ASCII | ||
127 | * | ||
128 | * @param c character to check | ||
129 | * @return non-zero if character is decimal digit or letter, zero otherwise | ||
130 | */ | ||
131 | _MHD_static_inline bool | ||
132 | isasciialnum (char c) | ||
133 | { | ||
134 | return isasciialpha (c) || isasciidigit (c); | ||
135 | } | ||
136 | #endif /* Disable unused functions. */ | ||
137 | |||
138 | |||
139 | /** | ||
140 | * Convert US-ASCII character to lower case. | ||
141 | * If character is upper case letter in US-ASCII than it's converted to lower | ||
142 | * case analog. If character is NOT upper case letter than it's returned | ||
143 | * unmodified. | ||
144 | * | ||
145 | * @param c character to convert | ||
146 | * @return converted to lower case character | ||
147 | */ | ||
148 | _MHD_static_inline char | ||
149 | toasciilower (char c) | ||
150 | { | ||
151 | return isasciiupper (c) ? (c - 'A' + 'a') : c; | ||
152 | } | ||
153 | |||
154 | |||
155 | #if 0 /* Disable unused functions. */ | ||
156 | /** | ||
157 | * Convert US-ASCII character to upper case. | ||
158 | * If character is lower case letter in US-ASCII than it's converted to upper | ||
159 | * case analog. If character is NOT lower case letter than it's returned | ||
160 | * unmodified. | ||
161 | * | ||
162 | * @param c character to convert | ||
163 | * @return converted to upper case character | ||
164 | */ | ||
165 | _MHD_static_inline char | ||
166 | toasciiupper (char c) | ||
167 | { | ||
168 | return isasciilower (c) ? (c - 'a' + 'A') : c; | ||
169 | } | ||
170 | #endif /* Disable unused functions. */ | ||
171 | |||
172 | |||
173 | #if defined(MHD_FAVOR_SMALL_CODE) /* Used only in MHD_str_to_uvalue_n_() */ | ||
174 | /** | ||
175 | * Convert US-ASCII decimal digit to its value. | ||
176 | * | ||
177 | * @param c character to convert | ||
178 | * @return value of decimal digit or -1 if @ c is not decimal digit | ||
179 | */ | ||
180 | _MHD_static_inline int | ||
181 | todigitvalue (char c) | ||
182 | { | ||
183 | if (isasciidigit (c)) | ||
184 | return (unsigned char)(c - '0'); | ||
185 | |||
186 | return -1; | ||
187 | } | ||
188 | #endif /* MHD_FAVOR_SMALL_CODE */ | ||
189 | |||
190 | |||
191 | /** | ||
192 | * Convert US-ASCII hexadecimal digit to its value. | ||
193 | * | ||
194 | * @param c character to convert | ||
195 | * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit | ||
196 | */ | ||
197 | _MHD_static_inline int | ||
198 | toxdigitvalue (char c) | ||
199 | { | ||
200 | if (isasciidigit (c)) | ||
201 | return (unsigned char)(c - '0'); | ||
202 | if ( (c >= 'A') && (c <= 'F') ) | ||
203 | return (unsigned char)(c - 'A' + 10); | ||
204 | if ( (c >= 'a') && (c <= 'f') ) | ||
205 | return (unsigned char)(c - 'a' + 10); | ||
206 | |||
207 | return -1; | ||
208 | } | ||
209 | #else /* !INLINE_FUNC */ | ||
210 | |||
211 | |||
212 | /** | ||
213 | * Checks whether character is lower case letter in US-ASCII | ||
214 | * | ||
215 | * @param c character to check | ||
216 | * @return boolean true if character is lower case letter, | ||
217 | * boolean false otherwise | ||
218 | */ | ||
219 | #define isasciilower(c) (((char)(c)) >= 'a' && ((char)(c)) <= 'z') | ||
220 | |||
221 | |||
222 | /** | ||
223 | * Checks whether character is upper case letter in US-ASCII | ||
224 | * | ||
225 | * @param c character to check | ||
226 | * @return boolean true if character is upper case letter, | ||
227 | * boolean false otherwise | ||
228 | */ | ||
229 | #define isasciiupper(c) (((char)(c)) >= 'A' && ((char)(c)) <= 'Z') | ||
230 | |||
231 | |||
232 | /** | ||
233 | * Checks whether character is letter in US-ASCII | ||
234 | * | ||
235 | * @param c character to check | ||
236 | * @return boolean true if character is letter, boolean false | ||
237 | * otherwise | ||
238 | */ | ||
239 | #define isasciialpha(c) (isasciilower(c) || isasciiupper(c)) | ||
240 | |||
241 | |||
242 | /** | ||
243 | * Check whether character is decimal digit in US-ASCII | ||
244 | * | ||
245 | * @param c character to check | ||
246 | * @return boolean true if character is decimal digit, boolean false | ||
247 | * otherwise | ||
248 | */ | ||
249 | #define isasciidigit(c) (((char)(c)) >= '0' && ((char)(c)) <= '9') | ||
250 | |||
251 | |||
252 | /** | ||
253 | * Check whether character is hexadecimal digit in US-ASCII | ||
254 | * | ||
255 | * @param c character to check | ||
256 | * @return boolean true if character is hexadecimal digit, | ||
257 | * boolean false otherwise | ||
258 | */ | ||
259 | #define isasciixdigit(c) (isasciidigit((c)) || \ | ||
260 | (((char)(c)) >= 'A' && ((char)(c)) <= 'F') || \ | ||
261 | (((char)(c)) >= 'a' && ((char)(c)) <= 'f') ) | ||
262 | |||
263 | |||
264 | /** | ||
265 | * Check whether character is decimal digit or letter in US-ASCII | ||
266 | * | ||
267 | * @param c character to check | ||
268 | * @return boolean true if character is decimal digit or letter, | ||
269 | * boolean false otherwise | ||
270 | */ | ||
271 | #define isasciialnum(c) (isasciialpha(c) || isasciidigit(c)) | ||
272 | |||
273 | |||
274 | /** | ||
275 | * Convert US-ASCII character to lower case. | ||
276 | * If character is upper case letter in US-ASCII than it's converted to lower | ||
277 | * case analog. If character is NOT upper case letter than it's returned | ||
278 | * unmodified. | ||
279 | * | ||
280 | * @param c character to convert | ||
281 | * @return converted to lower case character | ||
282 | */ | ||
283 | #define toasciilower(c) ((isasciiupper(c)) ? (((char)(c)) - 'A' + 'a') : ((char)(c))) | ||
284 | |||
285 | |||
286 | /** | ||
287 | * Convert US-ASCII character to upper case. | ||
288 | * If character is lower case letter in US-ASCII than it's converted to upper | ||
289 | * case analog. If character is NOT lower case letter than it's returned | ||
290 | * unmodified. | ||
291 | * | ||
292 | * @param c character to convert | ||
293 | * @return converted to upper case character | ||
294 | */ | ||
295 | #define toasciiupper(c) ((isasciilower(c)) ? (((char)(c)) - 'a' + 'A') : ((char)(c))) | ||
296 | |||
297 | |||
298 | /** | ||
299 | * Convert US-ASCII decimal digit to its value. | ||
300 | * | ||
301 | * @param c character to convert | ||
302 | * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit | ||
303 | */ | ||
304 | #define todigitvalue(c) (isasciidigit(c) ? (int)(((char)(c)) - '0') : (int)(-1)) | ||
305 | |||
306 | |||
307 | /** | ||
308 | * Convert US-ASCII hexadecimal digit to its value. | ||
309 | * @param c character to convert | ||
310 | * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit | ||
311 | */ | ||
312 | #define toxdigitvalue(c) ( isasciidigit(c) ? (int)(((char)(c)) - '0') : \ | ||
313 | ( (((char)(c)) >= 'A' && ((char)(c)) <= 'F') ? \ | ||
314 | (int)(((unsigned char)(c)) - 'A' + 10) : \ | ||
315 | ( (((char)(c)) >= 'a' && ((char)(c)) <= 'f') ? \ | ||
316 | (int)(((unsigned char)(c)) - 'a' + 10) : (int)(-1) ))) | ||
317 | #endif /* !INLINE_FUNC */ | ||
318 | |||
319 | |||
320 | #ifndef MHD_FAVOR_SMALL_CODE | ||
321 | /** | ||
322 | * Check two string for equality, ignoring case of US-ASCII letters. | ||
323 | * | ||
324 | * @param str1 first string to compare | ||
325 | * @param str2 second string to compare | ||
326 | * @return non-zero if two strings are equal, zero otherwise. | ||
327 | */ | ||
328 | int | ||
329 | MHD_str_equal_caseless_ (const char * str1, | ||
330 | const char * str2) | ||
331 | { | ||
332 | while (0 != (*str1)) | ||
333 | { | ||
334 | const char c1 = *str1; | ||
335 | const char c2 = *str2; | ||
336 | if ( (c1 != c2) && | ||
337 | (toasciilower (c1) != toasciilower (c2)) ) | ||
338 | return 0; | ||
339 | str1++; | ||
340 | str2++; | ||
341 | } | ||
342 | return 0 == (*str2); | ||
343 | } | ||
344 | #endif /* ! MHD_FAVOR_SMALL_CODE */ | ||
345 | |||
346 | |||
347 | /** | ||
348 | * Check two string for equality, ignoring case of US-ASCII letters and | ||
349 | * checking not more than @a maxlen characters. | ||
350 | * Compares up to first terminating null character, but not more than | ||
351 | * first @a maxlen characters. | ||
352 | * | ||
353 | * @param str1 first string to compare | ||
354 | * @param str2 second string to compare | ||
355 | * @param maxlen maximum number of characters to compare | ||
356 | * @return non-zero if two strings are equal, zero otherwise. | ||
357 | */ | ||
358 | int | ||
359 | MHD_str_equal_caseless_n_ (const char * const str1, | ||
360 | const char * const str2, | ||
361 | size_t maxlen) | ||
362 | { | ||
363 | size_t i; | ||
364 | |||
365 | for (i = 0; i < maxlen; ++i) | ||
366 | { | ||
367 | const char c1 = str1[i]; | ||
368 | const char c2 = str2[i]; | ||
369 | if (0 == c2) | ||
370 | return 0 == c1; | ||
371 | if ( (c1 != c2) && | ||
372 | (toasciilower (c1) != toasciilower (c2)) ) | ||
373 | return 0; | ||
374 | } | ||
375 | return !0; | ||
376 | } | ||
377 | |||
378 | |||
379 | /** | ||
380 | * Check whether @a str has case-insensitive @a token. | ||
381 | * Token could be surrounded by spaces and tabs and delimited by comma. | ||
382 | * Match succeed if substring between start, end (of string) or comma | ||
383 | * contains only case-insensitive token and optional spaces and tabs. | ||
384 | * @warning token must not contain null-charters except optional | ||
385 | * terminating null-character. | ||
386 | * @param str the string to check | ||
387 | * @param token the token to find | ||
388 | * @param token_len length of token, not including optional terminating | ||
389 | * null-character. | ||
390 | * @return non-zero if two strings are equal, zero otherwise. | ||
391 | */ | ||
392 | bool | ||
393 | MHD_str_has_token_caseless_ (const char * str, | ||
394 | const char * const token, | ||
395 | size_t token_len) | ||
396 | { | ||
397 | if (0 == token_len) | ||
398 | return false; | ||
399 | |||
400 | while (0 != *str) | ||
401 | { | ||
402 | size_t i; | ||
403 | /* Skip all whitespaces and empty tokens. */ | ||
404 | while (' ' == *str || '\t' == *str || ',' == *str) str++; | ||
405 | |||
406 | /* Check for token match. */ | ||
407 | i = 0; | ||
408 | while (1) | ||
409 | { | ||
410 | const char sc = *(str++); | ||
411 | const char tc = token[i++]; | ||
412 | |||
413 | if (0 == sc) | ||
414 | return false; | ||
415 | if ( (sc != tc) && | ||
416 | (toasciilower (sc) != toasciilower (tc)) ) | ||
417 | break; | ||
418 | if (i >= token_len) | ||
419 | { | ||
420 | /* Check whether substring match token fully or | ||
421 | * has additional unmatched chars at tail. */ | ||
422 | while (' ' == *str || '\t' == *str) str++; | ||
423 | /* End of (sub)string? */ | ||
424 | if (0 == *str || ',' == *str) | ||
425 | return true; | ||
426 | /* Unmatched chars at end of substring. */ | ||
427 | break; | ||
428 | } | ||
429 | } | ||
430 | /* Find next substring. */ | ||
431 | while (0 != *str && ',' != *str) str++; | ||
432 | } | ||
433 | return false; | ||
434 | } | ||
435 | |||
436 | #ifndef MHD_FAVOR_SMALL_CODE | ||
437 | /* Use individual function for each case */ | ||
438 | |||
439 | /** | ||
440 | * Convert decimal US-ASCII digits in string to number in uint64_t. | ||
441 | * Conversion stopped at first non-digit character. | ||
442 | * | ||
443 | * @param str string to convert | ||
444 | * @param[out] out_val pointer to uint64_t to store result of conversion | ||
445 | * @return non-zero number of characters processed on succeed, | ||
446 | * zero if no digit is found, resulting value is larger | ||
447 | * then possible to store in uint64_t or @a out_val is NULL | ||
448 | */ | ||
449 | size_t | ||
450 | MHD_str_to_uint64_ (const char *str, | ||
451 | uint64_t *out_val) | ||
452 | { | ||
453 | const char * const start = str; | ||
454 | uint64_t res; | ||
455 | |||
456 | if (!str || !out_val || !isasciidigit(str[0])) | ||
457 | return 0; | ||
458 | |||
459 | res = 0; | ||
460 | do | ||
461 | { | ||
462 | const int digit = (unsigned char)(*str) - '0'; | ||
463 | if ( (res > (UINT64_MAX / 10)) || | ||
464 | ( (res == (UINT64_MAX / 10)) && | ||
465 | ((uint64_t)digit > (UINT64_MAX % 10)) ) ) | ||
466 | return 0; | ||
467 | |||
468 | res *= 10; | ||
469 | res += digit; | ||
470 | str++; | ||
471 | } while (isasciidigit (*str)); | ||
472 | |||
473 | *out_val = res; | ||
474 | return str - start; | ||
475 | } | ||
476 | |||
477 | |||
478 | /** | ||
479 | * Convert not more then @a maxlen decimal US-ASCII digits in string to | ||
480 | * number in uint64_t. | ||
481 | * Conversion stopped at first non-digit character or after @a maxlen | ||
482 | * digits. | ||
483 | * | ||
484 | * @param str string to convert | ||
485 | * @param maxlen maximum number of characters to process | ||
486 | * @param[out] out_val pointer to uint64_t to store result of conversion | ||
487 | * @return non-zero number of characters processed on succeed, | ||
488 | * zero if no digit is found, resulting value is larger | ||
489 | * then possible to store in uint64_t or @a out_val is NULL | ||
490 | */ | ||
491 | size_t | ||
492 | MHD_str_to_uint64_n_ (const char * str, | ||
493 | size_t maxlen, | ||
494 | uint64_t *out_val) | ||
495 | { | ||
496 | uint64_t res; | ||
497 | size_t i; | ||
498 | |||
499 | if (!str || !maxlen || !out_val || !isasciidigit (str[0])) | ||
500 | return 0; | ||
501 | |||
502 | res = 0; | ||
503 | i = 0; | ||
504 | do | ||
505 | { | ||
506 | const int digit = (unsigned char)str[i] - '0'; | ||
507 | |||
508 | if ( (res > (UINT64_MAX / 10)) || | ||
509 | ( (res == (UINT64_MAX / 10)) && | ||
510 | ((uint64_t)digit > (UINT64_MAX % 10)) ) ) | ||
511 | return 0; | ||
512 | |||
513 | res *= 10; | ||
514 | res += digit; | ||
515 | i++; | ||
516 | } while ( (i < maxlen) && | ||
517 | isasciidigit (str[i]) ); | ||
518 | |||
519 | *out_val= res; | ||
520 | return i; | ||
521 | } | ||
522 | |||
523 | |||
524 | /** | ||
525 | * Convert hexadecimal US-ASCII digits in string to number in uint32_t. | ||
526 | * Conversion stopped at first non-digit character. | ||
527 | * | ||
528 | * @param str string to convert | ||
529 | * @param[out] out_val pointer to uint32_t to store result of conversion | ||
530 | * @return non-zero number of characters processed on succeed, | ||
531 | * zero if no digit is found, resulting value is larger | ||
532 | * then possible to store in uint32_t or @a out_val is NULL | ||
533 | */ | ||
534 | size_t | ||
535 | MHD_strx_to_uint32_ (const char * str, | ||
536 | uint32_t *out_val) | ||
537 | { | ||
538 | const char * const start = str; | ||
539 | uint32_t res; | ||
540 | int digit; | ||
541 | |||
542 | if (!str || !out_val) | ||
543 | return 0; | ||
544 | |||
545 | res = 0; | ||
546 | digit = toxdigitvalue (*str); | ||
547 | while (digit >= 0) | ||
548 | { | ||
549 | if ( (res < (UINT32_MAX / 16)) || | ||
550 | (res == (UINT32_MAX / 16) && (uint32_t)digit <= (UINT32_MAX % 16)) ) | ||
551 | { | ||
552 | res *= 16; | ||
553 | res += digit; | ||
554 | } | ||
555 | else | ||
556 | return 0; | ||
557 | str++; | ||
558 | digit = toxdigitvalue (*str); | ||
559 | } | ||
560 | |||
561 | if (str - start > 0) | ||
562 | *out_val = res; | ||
563 | return str - start; | ||
564 | } | ||
565 | |||
566 | |||
567 | /** | ||
568 | * Convert not more then @a maxlen hexadecimal US-ASCII digits in string | ||
569 | * to number in uint32_t. | ||
570 | * Conversion stopped at first non-digit character or after @a maxlen | ||
571 | * digits. | ||
572 | * | ||
573 | * @param str string to convert | ||
574 | * @param maxlen maximum number of characters to process | ||
575 | * @param[out] out_val pointer to uint32_t to store result of conversion | ||
576 | * @return non-zero number of characters processed on succeed, | ||
577 | * zero if no digit is found, resulting value is larger | ||
578 | * then possible to store in uint32_t or @a out_val is NULL | ||
579 | */ | ||
580 | size_t | ||
581 | MHD_strx_to_uint32_n_ (const char *str, | ||
582 | size_t maxlen, | ||
583 | uint32_t *out_val) | ||
584 | { | ||
585 | size_t i; | ||
586 | uint32_t res; | ||
587 | int digit; | ||
588 | if (!str || !out_val) | ||
589 | return 0; | ||
590 | |||
591 | res = 0; | ||
592 | i = 0; | ||
593 | while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0) | ||
594 | { | ||
595 | if ( (res > (UINT32_MAX / 16)) || | ||
596 | (res == (UINT32_MAX / 16) && (uint32_t)digit > (UINT32_MAX % 16)) ) | ||
597 | return 0; | ||
598 | |||
599 | res *= 16; | ||
600 | res += digit; | ||
601 | i++; | ||
602 | } | ||
603 | |||
604 | if (i) | ||
605 | *out_val = res; | ||
606 | return i; | ||
607 | } | ||
608 | |||
609 | |||
610 | /** | ||
611 | * Convert hexadecimal US-ASCII digits in string to number in uint64_t. | ||
612 | * Conversion stopped at first non-digit character. | ||
613 | * | ||
614 | * @param str string to convert | ||
615 | * @param[out] out_val pointer to uint64_t to store result of conversion | ||
616 | * @return non-zero number of characters processed on succeed, | ||
617 | * zero if no digit is found, resulting value is larger | ||
618 | * then possible to store in uint64_t or @a out_val is NULL | ||
619 | */ | ||
620 | size_t | ||
621 | MHD_strx_to_uint64_ (const char *str, | ||
622 | uint64_t *out_val) | ||
623 | { | ||
624 | const char * const start = str; | ||
625 | uint64_t res; | ||
626 | int digit; | ||
627 | if (!str || !out_val) | ||
628 | return 0; | ||
629 | |||
630 | res = 0; | ||
631 | digit = toxdigitvalue (*str); | ||
632 | while (digit >= 0) | ||
633 | { | ||
634 | if ( (res < (UINT64_MAX / 16)) || | ||
635 | (res == (UINT64_MAX / 16) && (uint64_t)digit <= (UINT64_MAX % 16)) ) | ||
636 | { | ||
637 | res *= 16; | ||
638 | res += digit; | ||
639 | } | ||
640 | else | ||
641 | return 0; | ||
642 | str++; | ||
643 | digit = toxdigitvalue (*str); | ||
644 | } | ||
645 | |||
646 | if (str - start > 0) | ||
647 | *out_val = res; | ||
648 | return str - start; | ||
649 | } | ||
650 | |||
651 | |||
652 | /** | ||
653 | * Convert not more then @a maxlen hexadecimal US-ASCII digits in string | ||
654 | * to number in uint64_t. | ||
655 | * Conversion stopped at first non-digit character or after @a maxlen | ||
656 | * digits. | ||
657 | * | ||
658 | * @param str string to convert | ||
659 | * @param maxlen maximum number of characters to process | ||
660 | * @param[out] out_val pointer to uint64_t to store result of conversion | ||
661 | * @return non-zero number of characters processed on succeed, | ||
662 | * zero if no digit is found, resulting value is larger | ||
663 | * then possible to store in uint64_t or @a out_val is NULL | ||
664 | */ | ||
665 | size_t | ||
666 | MHD_strx_to_uint64_n_ (const char * str, | ||
667 | size_t maxlen, | ||
668 | uint64_t *out_val) | ||
669 | { | ||
670 | size_t i; | ||
671 | uint64_t res; | ||
672 | int digit; | ||
673 | if (!str || !out_val) | ||
674 | return 0; | ||
675 | |||
676 | res = 0; | ||
677 | i = 0; | ||
678 | while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0) | ||
679 | { | ||
680 | if ( (res > (UINT64_MAX / 16)) || | ||
681 | (res == (UINT64_MAX / 16) && (uint64_t)digit > (UINT64_MAX % 16)) ) | ||
682 | return 0; | ||
683 | |||
684 | res *= 16; | ||
685 | res += digit; | ||
686 | i++; | ||
687 | } | ||
688 | |||
689 | if (i) | ||
690 | *out_val = res; | ||
691 | return i; | ||
692 | } | ||
693 | |||
694 | #else /* MHD_FAVOR_SMALL_CODE */ | ||
695 | |||
696 | /** | ||
697 | * Generic function for converting not more then @a maxlen | ||
698 | * hexadecimal or decimal US-ASCII digits in string to number. | ||
699 | * Conversion stopped at first non-digit character or after @a maxlen | ||
700 | * digits. | ||
701 | * To be used only within macro. | ||
702 | * | ||
703 | * @param str the string to convert | ||
704 | * @param maxlen the maximum number of characters to process | ||
705 | * @param out_val the pointer to variable to store result of conversion | ||
706 | * @param val_size the size of variable pointed by @a out_val, in bytes, 4 or 8 | ||
707 | * @param max_val the maximum decoded number | ||
708 | * @param base the numeric base, 10 or 16 | ||
709 | * @return non-zero number of characters processed on succeed, | ||
710 | * zero if no digit is found, resulting value is larger | ||
711 | * then @max_val, @val_size is not 16/32 or @a out_val is NULL | ||
712 | */ | ||
713 | size_t | ||
714 | MHD_str_to_uvalue_n_ (const char *str, | ||
715 | size_t maxlen, | ||
716 | void * out_val, | ||
717 | size_t val_size, | ||
718 | uint64_t max_val, | ||
719 | int base) | ||
720 | { | ||
721 | size_t i; | ||
722 | uint64_t res; | ||
723 | int digit; | ||
724 | const uint64_t max_v_div_b = max_val / base; | ||
725 | const uint64_t max_v_mod_b = max_val % base; | ||
726 | /* 'digit->value' must be function, not macro */ | ||
727 | int (*const dfunc)(char) = (base == 16) ? | ||
728 | toxdigitvalue : todigitvalue; | ||
729 | |||
730 | if ( !str || !out_val || | ||
731 | (base != 16 && base != 10) ) | ||
732 | return 0; | ||
733 | |||
734 | res = 0; | ||
735 | i = 0; | ||
736 | while (maxlen > i && 0 <= (digit = dfunc (str[i]))) | ||
737 | { | ||
738 | if ( ((max_v_div_b) < res) || | ||
739 | ((max_v_div_b) == res && (max_v_mod_b) < (uint64_t)digit) ) | ||
740 | return 0; | ||
741 | |||
742 | res *= base; | ||
743 | res += digit; | ||
744 | i++; | ||
745 | } | ||
746 | |||
747 | if (i) | ||
748 | { | ||
749 | if (8 == val_size) | ||
750 | *(uint64_t*)out_val = res; | ||
751 | else if (4 == val_size) | ||
752 | *(uint32_t*)out_val = (uint32_t)res; | ||
753 | else | ||
754 | return 0; | ||
755 | } | ||
756 | return i; | ||
757 | } | ||
758 | #endif /* MHD_FAVOR_SMALL_CODE */ | ||