aboutsummaryrefslogtreecommitdiff
path: root/src/lib/mhd_str.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/mhd_str.c')
-rw-r--r--src/lib/mhd_str.c758
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
62isasciilower (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
76isasciiupper (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
90isasciialpha (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
104isasciidigit (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
117isasciixdigit (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
132isasciialnum (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
149toasciilower (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
166toasciiupper (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
181todigitvalue (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
198toxdigitvalue (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 */
328int
329MHD_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 */
358int
359MHD_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 */
392bool
393MHD_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 */
449size_t
450MHD_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 */
491size_t
492MHD_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 */
534size_t
535MHD_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 */
580size_t
581MHD_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 */
620size_t
621MHD_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 */
665size_t
666MHD_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 */
713size_t
714MHD_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 */