GNU libmicrohttpd 0.9.77
Loading...
Searching...
No Matches
mhd_str.c
Go to the documentation of this file.
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
26#include "mhd_str.h"
27
28#ifdef HAVE_STDBOOL_H
29#include <stdbool.h>
30#endif /* HAVE_STDBOOL_H */
31#include <string.h>
32
33#include "mhd_assert.h"
34#include "mhd_limits.h"
35#include "mhd_assert.h"
36
37#ifdef MHD_FAVOR_SMALL_CODE
38#ifdef _MHD_static_inline
39#undef _MHD_static_inline
40#endif /* _MHD_static_inline */
41/* Do not force inlining and do not use macro functions, use normal static
42 functions instead.
43 This may give more flexibility for size optimizations. */
44#define _MHD_static_inline static
45#ifndef INLINE_FUNC
46#define INLINE_FUNC 1
47#endif /* !INLINE_FUNC */
48#endif /* MHD_FAVOR_SMALL_CODE */
49
50/*
51 * Block of functions/macros that use US-ASCII charset as required by HTTP
52 * standards. Not affected by current locale settings.
53 */
54
55#ifdef INLINE_FUNC
56
57#if 0 /* Disable unused functions. */
64_MHD_static_inline bool
65isasciilower (char c)
66{
67 return (c >= 'a') && (c <= 'z');
68}
69
70
71#endif /* Disable unused functions. */
72
73
80_MHD_static_inline bool
81isasciiupper (char c)
82{
83 return (c >= 'A') && (c <= 'Z');
84}
85
86
87#if 0 /* Disable unused functions. */
94_MHD_static_inline bool
95isasciialpha (char c)
96{
97 return isasciilower (c) || isasciiupper (c);
98}
99
100
101#endif /* Disable unused functions. */
102
103
110_MHD_static_inline bool
111isasciidigit (char c)
112{
113 return (c >= '0') && (c <= '9');
114}
115
116
117#if 0 /* Disable unused functions. */
124_MHD_static_inline bool
125isasciixdigit (char c)
126{
127 return isasciidigit (c) ||
128 ( (c >= 'A') && (c <= 'F') ) ||
129 ( (c >= 'a') && (c <= 'f') );
130}
131
132
139_MHD_static_inline bool
140isasciialnum (char c)
141{
142 return isasciialpha (c) || isasciidigit (c);
143}
144
145
146#endif /* Disable unused functions. */
147
148
149#if 0 /* Disable unused functions. */
159_MHD_static_inline char
160toasciilower (char c)
161{
162 return isasciiupper (c) ? (c - 'A' + 'a') : c;
163}
164
165
175_MHD_static_inline char
176toasciiupper (char c)
177{
178 return isasciilower (c) ? (c - 'a' + 'A') : c;
179}
180
181
182#endif /* Disable unused functions. */
183
184
185#if defined(MHD_FAVOR_SMALL_CODE) /* Used only in MHD_str_to_uvalue_n_() */
192_MHD_static_inline int
193todigitvalue (char c)
194{
195 if (isasciidigit (c))
196 return (unsigned char) (c - '0');
197
198 return -1;
199}
200
201
202#endif /* MHD_FAVOR_SMALL_CODE */
203
204
211_MHD_static_inline int
212toxdigitvalue (char c)
213{
214 if (isasciidigit (c))
215 return (unsigned char) (c - '0');
216 if ( (c >= 'A') && (c <= 'F') )
217 return (unsigned char) (c - 'A' + 10);
218 if ( (c >= 'a') && (c <= 'f') )
219 return (unsigned char) (c - 'a' + 10);
220
221 return -1;
222}
223
224
232_MHD_static_inline bool
233charsequalcaseless (const char c1, const char c2)
234{
235 return ( (c1 == c2) ||
236 (isasciiupper (c1) ?
237 ((c1 - 'A' + 'a') == c2) :
238 ((c1 == (c2 - 'A' + 'a')) && isasciiupper (c2))) );
239}
240
241
242#else /* !INLINE_FUNC */
243
244
252#define isasciilower(c) (((char) (c)) >= 'a' && ((char) (c)) <= 'z')
253
254
262#define isasciiupper(c) (((char) (c)) >= 'A' && ((char) (c)) <= 'Z')
263
264
272#define isasciialpha(c) (isasciilower (c) || isasciiupper (c))
273
274
282#define isasciidigit(c) (((char) (c)) >= '0' && ((char) (c)) <= '9')
283
284
292#define isasciixdigit(c) (isasciidigit ((c)) || \
293 (((char) (c)) >= 'A' && ((char) (c)) <= 'F') || \
294 (((char) (c)) >= 'a' && ((char) (c)) <= 'f') )
295
296
304#define isasciialnum(c) (isasciialpha (c) || isasciidigit (c))
305
306
316#define toasciilower(c) ((isasciiupper (c)) ? (((char) (c)) - 'A' + 'a') : \
317 ((char) (c)))
318
319
329#define toasciiupper(c) ((isasciilower (c)) ? (((char) (c)) - 'a' + 'A') : \
330 ((char) (c)))
331
332
339#define todigitvalue(c) (isasciidigit (c) ? (int) (((char) (c)) - '0') : \
340 (int) (-1))
341
342
348#define toxdigitvalue(c) (isasciidigit (c) ? (int) (((char) (c)) - '0') : \
349 ( (((char) (c)) >= 'A' && ((char) (c)) <= 'F') ? \
350 (int) (((unsigned char) (c)) - 'A' + 10) : \
351 ( (((char) (c)) >= 'a' && ((char) (c)) <= 'f') ? \
352 (int) (((unsigned char) (c)) - 'a' + 10) : \
353 (int) (-1) )))
354
362#define charsequalcaseless(c1, c2) \
363 ( ((c1) == (c2)) || \
364 (isasciiupper (c1) ? \
365 (((c1) - 'A' + 'a') == (c2)) : \
366 (((c1) == ((c2) - 'A' + 'a')) && isasciiupper (c2))) )
367
368#endif /* !INLINE_FUNC */
369
370
371#ifndef MHD_FAVOR_SMALL_CODE
379int
380MHD_str_equal_caseless_ (const char *str1,
381 const char *str2)
382{
383 while (0 != (*str1))
384 {
385 const char c1 = *str1;
386 const char c2 = *str2;
387 if (charsequalcaseless (c1, c2))
388 {
389 str1++;
390 str2++;
391 }
392 else
393 return 0;
394 }
395 return 0 == (*str2);
396}
397
398
399#endif /* ! MHD_FAVOR_SMALL_CODE */
400
401
413int
414MHD_str_equal_caseless_n_ (const char *const str1,
415 const char *const str2,
416 size_t maxlen)
417{
418 size_t i;
419
420 for (i = 0; i < maxlen; ++i)
421 {
422 const char c1 = str1[i];
423 const char c2 = str2[i];
424 if (0 == c2)
425 return 0 == c1;
426 if (charsequalcaseless (c1, c2))
427 continue;
428 else
429 return 0;
430 }
431 return ! 0;
432}
433
434
444bool
445MHD_str_equal_caseless_bin_n_ (const char *const str1,
446 const char *const str2,
447 size_t len)
448{
449 size_t i;
450
451 for (i = 0; i < len; ++i)
452 {
453 const char c1 = str1[i];
454 const char c2 = str2[i];
455 if (charsequalcaseless (c1, c2))
456 continue;
457 else
458 return 0;
459 }
460 return ! 0;
461}
462
463
477bool
479 const char *const token,
480 size_t token_len)
481{
482 if (0 == token_len)
483 return false;
484
485 while (0 != *str)
486 {
487 size_t i;
488 /* Skip all whitespaces and empty tokens. */
489 while (' ' == *str || '\t' == *str || ',' == *str)
490 str++;
491
492 /* Check for token match. */
493 i = 0;
494 while (1)
495 {
496 const char sc = *(str++);
497 const char tc = token[i++];
498
499 if (0 == sc)
500 return false;
501 if (! charsequalcaseless (sc, tc))
502 break;
503 if (i >= token_len)
504 {
505 /* Check whether substring match token fully or
506 * has additional unmatched chars at tail. */
507 while (' ' == *str || '\t' == *str)
508 str++;
509 /* End of (sub)string? */
510 if ((0 == *str) || (',' == *str) )
511 return true;
512 /* Unmatched chars at end of substring. */
513 break;
514 }
515 }
516 /* Find next substring. */
517 while (0 != *str && ',' != *str)
518 str++;
519 }
520 return false;
521}
522
523
552bool
554 size_t str_len,
555 const char *const token,
556 const size_t token_len,
557 char *buf,
558 ssize_t *buf_size)
559{
560 const char *s1;
561 char *s2;
562 size_t t_pos;
563 bool token_removed;
564
565 mhd_assert (NULL == memchr (token, 0, token_len));
566 mhd_assert (NULL == memchr (token, ' ', token_len));
567 mhd_assert (NULL == memchr (token, '\t', token_len));
568 mhd_assert (NULL == memchr (token, ',', token_len));
569 mhd_assert (0 <= *buf_size);
570
571 s1 = str;
572 s2 = buf;
573 token_removed = false;
574
575 while ((size_t) (s1 - str) < str_len)
576 {
577 const char *cur_token;
578 size_t copy_size;
579
580 /* Skip any initial whitespaces and empty tokens */
581 while ( ((size_t) (s1 - str) < str_len) &&
582 ((' ' == *s1) || ('\t' == *s1) || (',' == *s1)) )
583 s1++;
584
585 /* 's1' points to the first char of token in the input string or
586 * points just beyond the end of the input string */
587
588 if ((size_t) (s1 - str) >= str_len)
589 break; /* Nothing to copy, end of the input string */
590
591 /* 's1' points to the first char of token in the input string */
592
593 cur_token = s1; /* the first char of input token */
594
595 /* Check the token with case-insensetive match */
596 t_pos = 0;
597 while ( ((size_t) (s1 - str) < str_len) && (token_len > t_pos) &&
598 (charsequalcaseless (*s1, token[t_pos])) )
599 {
600 s1++;
601 t_pos++;
602 }
603 /* s1 may point just beyond the end of the input string */
604 if ( (token_len == t_pos) && (0 != token_len) )
605 {
606 /* 'token' matched, check that current input token does not have
607 * any suffixes */
608 while ( ((size_t) (s1 - str) < str_len) &&
609 ((' ' == *s1) || ('\t' == *s1)) )
610 s1++;
611 /* 's1' points to the first non-whitespace char after the token matched
612 * requested token or points just beyond the end of the input string after
613 * the requested token */
614 if (((size_t) (s1 - str) == str_len) || (',' == *s1))
615 {/* full token match, do not copy current token to the output */
616 token_removed = true;
617 continue;
618 }
619 }
620
621 /* 's1' points to first non-whitespace char, to some char after
622 * first non-whitespace char in the token in the input string, to
623 * the ',', or just beyond the end of the input string */
624 /* The current token in the input string does not match the token
625 * to exclude, it must be copied to the output string */
626 /* the current token size excluding leading whitespaces and current char */
627 copy_size = (size_t) (s1 - cur_token);
628 if (buf == s2)
629 { /* The first token to copy to the output */
630 if (buf + *buf_size < s2 + copy_size)
631 { /* Not enough space in the output buffer */
632 *buf_size = (ssize_t) -1;
633 return false;
634 }
635 }
636 else
637 { /* Some token was already copied to the output buffer */
638 if (buf + *buf_size < s2 + copy_size + 2)
639 { /* Not enough space in the output buffer */
640 *buf_size = (ssize_t) -1;
641 return false;
642 }
643 *(s2++) = ',';
644 *(s2++) = ' ';
645 }
646 /* Copy non-matched token to the output */
647 if (0 != copy_size)
648 {
649 memcpy (s2, cur_token, copy_size);
650 s2 += copy_size;
651 }
652
653 while ( ((size_t) (s1 - str) < str_len) && (',' != *s1))
654 {
655 /* 's1' points to first non-whitespace char, to some char after
656 * first non-whitespace char in the token in the input string */
657 /* Copy all non-whitespace chars from the current token in
658 * the input string */
659 while ( ((size_t) (s1 - str) < str_len) &&
660 (',' != *s1) && (' ' != *s1) && ('\t' != *s1) )
661 {
662 if (buf + *buf_size <= s2) /* '<= s2' equals '< s2 + 1' */
663 { /* Not enough space in the output buffer */
664 *buf_size = (ssize_t) -1;
665 return false;
666 }
667 *(s2++) = *(s1++);
668 }
669 /* 's1' points to some whitespace char in the token in the input
670 * string, to the ',', or just beyond the end of the input string */
671 /* Skip all whitespaces */
672 while ( ((size_t) (s1 - str) < str_len) &&
673 ((' ' == *s1) || ('\t' == *s1)) )
674 s1++;
675
676 /* 's1' points to the first non-whitespace char in the input string
677 * after whitespace chars, to the ',', or just beyond the end of
678 * the input string */
679 if (((size_t) (s1 - str) < str_len) && (',' != *s1))
680 { /* Not the end of the current token */
681 if (buf + *buf_size <= s2) /* '<= s2' equals '< s2 + 1' */
682 { /* Not enough space in the output buffer */
683 *buf_size = (ssize_t) -1;
684 return false;
685 }
686 *(s2++) = ' ';
687 }
688 }
689 }
690 mhd_assert (((ssize_t) (s2 - buf)) <= *buf_size);
691 *buf_size = (ssize_t) (s2 - buf);
692 return token_removed;
693}
694
695
719bool
721 size_t *str_len,
722 const char *const tokens,
723 const size_t tokens_len)
724{
725 const char *const t = tokens;
726 size_t pt;
727 bool token_removed;
728
729 mhd_assert (NULL == memchr (tokens, 0, tokens_len));
730
731 token_removed = false;
732 pt = 0;
733
734 while (pt < tokens_len && *str_len != 0)
735 {
736 const char *tkn;
737 size_t tkn_len;
738
739 /* Skip any initial whitespaces and empty tokens in 'tokens' */
740 while ( (pt < tokens_len) &&
741 ((' ' == t[pt]) || ('\t' == t[pt]) || (',' == t[pt])) )
742 pt++;
743
744 if (pt >= tokens_len)
745 break; /* No more tokens, nothing to remove */
746
747 /* Found non-whitespace char which is not a comma */
748 tkn = t + pt;
749 do
750 {
751 do
752 {
753 pt++;
754 } while (pt < tokens_len &&
755 (' ' != t[pt] && '\t' != t[pt] && ',' != t[pt]));
756 /* Found end of the token string, space, tab, or comma */
757 tkn_len = pt - (size_t) (tkn - t);
758
759 /* Skip all spaces and tabs */
760 while (pt < tokens_len && (' ' == t[pt] || '\t' == t[pt]))
761 pt++;
762 /* Found end of the token string or non-whitespace char */
763 } while(pt < tokens_len && ',' != t[pt]);
764
765 /* 'tkn' is the input token with 'tkn_len' chars */
766 mhd_assert (0 != tkn_len);
767
768 if (*str_len == tkn_len)
769 {
770 if (MHD_str_equal_caseless_bin_n_ (str, tkn, tkn_len))
771 {
772 *str_len = 0;
773 token_removed = true;
774 }
775 continue;
776 }
777 /* 'tkn' cannot match part of 'str' if length of 'tkn' is larger
778 * than length of 'str'.
779 * It's know that 'tkn' is not equal to the 'str' (was checked previously).
780 * As 'str' is normalized when 'tkn' is not equal to the 'str'
781 * it is required that 'str' to be at least 3 chars larger then 'tkn'
782 * (the comma, the space and at least one additional character for the next
783 * token) to remove 'tkn' from the 'str'. */
784 if (*str_len > tkn_len + 2)
785 { /* Remove 'tkn' from the input string */
786 size_t pr;
787 size_t pw;
789 pr = 0;
790 pw = 0;
791
792 do
793 {
794 mhd_assert (pr >= pw);
795 mhd_assert ((*str_len) >= (pr + tkn_len));
796 if ( ( ((*str_len) == (pr + tkn_len)) || (',' == str[pr + tkn_len]) ) &&
797 MHD_str_equal_caseless_bin_n_ (str + pr, tkn, tkn_len) )
798 {
799 /* current token in the input string matches the 'tkn', skip it */
800 mhd_assert ((*str_len == pr + tkn_len) || \
801 (' ' == str[pr + tkn_len + 1])); /* 'str' must be normalized */
802 token_removed = true;
803 /* Advance to the next token in the input string or beyond
804 * the end of the input string. */
805 pr += tkn_len + 2;
806 }
807 else
808 {
809 /* current token in the input string does not match the 'tkn',
810 * copy to the output */
811 if (0 != pw)
812 { /* not the first output token, add ", " to separate */
813 if (pr != pw + 2)
814 {
815 str[pw++] = ',';
816 str[pw++] = ' ';
817 }
818 else
819 pw += 2; /* 'str' is not yet modified in this round */
820 }
821 do
822 {
823 if (pr != pw)
824 str[pw] = str[pr];
825 pr++;
826 pw++;
827 } while (pr < *str_len && ',' != str[pr]);
828 /* Advance to the next token in the input string or beyond
829 * the end of the input string. */
830 pr += 2;
831 }
832 /* 'pr' should point to the next token in the input string or beyond
833 * the end of the input string */
834 if ((*str_len) < (pr + tkn_len))
835 { /* The rest of the 'str + pr' is too small to match 'tkn' */
836 if ((*str_len) > pr)
837 { /* Copy the rest of the string */
838 size_t copy_size;
839 copy_size = *str_len - pr;
840 if (0 != pw)
841 { /* not the first output token, add ", " to separate */
842 if (pr != pw + 2)
843 {
844 str[pw++] = ',';
845 str[pw++] = ' ';
846 }
847 else
848 pw += 2; /* 'str' is not yet modified in this round */
849 }
850 if (pr != pw)
851 memmove (str + pw, str + pr, copy_size);
852 pw += copy_size;
853 }
854 *str_len = pw;
855 break;
856 }
857 mhd_assert ((' ' != str[0]) && ('\t' != str[0]));
858 mhd_assert ((0 == pr) || (3 <= pr));
859 mhd_assert ((0 == pr) || (' ' == str[pr - 1]));
860 mhd_assert ((0 == pr) || (',' == str[pr - 2]));
861 } while (1);
862 }
863 }
864
865 return token_removed;
866}
867
868
869#ifndef MHD_FAVOR_SMALL_CODE
870/* Use individual function for each case */
871
882size_t
883MHD_str_to_uint64_ (const char *str,
884 uint64_t *out_val)
885{
886 const char *const start = str;
887 uint64_t res;
888
889 if (! str || ! out_val || ! isasciidigit (str[0]))
890 return 0;
891
892 res = 0;
893 do
894 {
895 const int digit = (unsigned char) (*str) - '0';
896 if ( (res > (UINT64_MAX / 10)) ||
897 ( (res == (UINT64_MAX / 10)) &&
898 ((uint64_t) digit > (UINT64_MAX % 10)) ) )
899 return 0;
900
901 res *= 10;
902 res += digit;
903 str++;
904 } while (isasciidigit (*str));
905
906 *out_val = res;
907 return str - start;
908}
909
910
924size_t
925MHD_str_to_uint64_n_ (const char *str,
926 size_t maxlen,
927 uint64_t *out_val)
928{
929 uint64_t res;
930 size_t i;
931
932 if (! str || ! maxlen || ! out_val || ! isasciidigit (str[0]))
933 return 0;
934
935 res = 0;
936 i = 0;
937 do
938 {
939 const int digit = (unsigned char) str[i] - '0';
940
941 if ( (res > (UINT64_MAX / 10)) ||
942 ( (res == (UINT64_MAX / 10)) &&
943 ((uint64_t) digit > (UINT64_MAX % 10)) ) )
944 return 0;
945
946 res *= 10;
947 res += digit;
948 i++;
949 } while ( (i < maxlen) &&
950 isasciidigit (str[i]) );
951
952 *out_val = res;
953 return i;
954}
955
956
967size_t
968MHD_strx_to_uint32_ (const char *str,
969 uint32_t *out_val)
970{
971 const char *const start = str;
972 uint32_t res;
973 int digit;
974
975 if (! str || ! out_val)
976 return 0;
977
978 res = 0;
979 digit = toxdigitvalue (*str);
980 while (digit >= 0)
981 {
982 if ( (res < (UINT32_MAX / 16)) ||
983 ((res == (UINT32_MAX / 16)) && ( (uint32_t) digit <= (UINT32_MAX
984 % 16)) ) )
985 {
986 res *= 16;
987 res += digit;
988 }
989 else
990 return 0;
991 str++;
992 digit = toxdigitvalue (*str);
993 }
994
995 if (str - start > 0)
996 *out_val = res;
997 return str - start;
998}
999
1000
1014size_t
1015MHD_strx_to_uint32_n_ (const char *str,
1016 size_t maxlen,
1017 uint32_t *out_val)
1018{
1019 size_t i;
1020 uint32_t res;
1021 int digit;
1022 if (! str || ! out_val)
1023 return 0;
1024
1025 res = 0;
1026 i = 0;
1027 while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0)
1028 {
1029 if ( (res > (UINT32_MAX / 16)) ||
1030 ((res == (UINT32_MAX / 16)) && ( (uint32_t) digit > (UINT32_MAX
1031 % 16)) ) )
1032 return 0;
1033
1034 res *= 16;
1035 res += digit;
1036 i++;
1037 }
1038
1039 if (i)
1040 *out_val = res;
1041 return i;
1042}
1043
1044
1055size_t
1056MHD_strx_to_uint64_ (const char *str,
1057 uint64_t *out_val)
1058{
1059 const char *const start = str;
1060 uint64_t res;
1061 int digit;
1062 if (! str || ! out_val)
1063 return 0;
1064
1065 res = 0;
1066 digit = toxdigitvalue (*str);
1067 while (digit >= 0)
1068 {
1069 if ( (res < (UINT64_MAX / 16)) ||
1070 ((res == (UINT64_MAX / 16)) && ( (uint64_t) digit <= (UINT64_MAX
1071 % 16)) ) )
1072 {
1073 res *= 16;
1074 res += digit;
1075 }
1076 else
1077 return 0;
1078 str++;
1079 digit = toxdigitvalue (*str);
1080 }
1081
1082 if (str - start > 0)
1083 *out_val = res;
1084 return str - start;
1085}
1086
1087
1101size_t
1102MHD_strx_to_uint64_n_ (const char *str,
1103 size_t maxlen,
1104 uint64_t *out_val)
1105{
1106 size_t i;
1107 uint64_t res;
1108 int digit;
1109 if (! str || ! out_val)
1110 return 0;
1111
1112 res = 0;
1113 i = 0;
1114 while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0)
1115 {
1116 if ( (res > (UINT64_MAX / 16)) ||
1117 ((res == (UINT64_MAX / 16)) && ( (uint64_t) digit > (UINT64_MAX
1118 % 16)) ) )
1119 return 0;
1120
1121 res *= 16;
1122 res += digit;
1123 i++;
1124 }
1125
1126 if (i)
1127 *out_val = res;
1128 return i;
1129}
1130
1131
1132#else /* MHD_FAVOR_SMALL_CODE */
1133
1151size_t
1152MHD_str_to_uvalue_n_ (const char *str,
1153 size_t maxlen,
1154 void *out_val,
1155 size_t val_size,
1156 uint64_t max_val,
1157 unsigned int base)
1158{
1159 size_t i;
1160 uint64_t res;
1161 int digit;
1162 const uint64_t max_v_div_b = max_val / base;
1163 const uint64_t max_v_mod_b = max_val % base;
1164 /* 'digit->value' must be function, not macro */
1165 int (*const dfunc)(char) = (base == 16) ?
1167
1168 if (! str || ! out_val ||
1169 ((base != 16) && (base != 10)) )
1170 return 0;
1171
1172 res = 0;
1173 i = 0;
1174 while (maxlen > i && 0 <= (digit = dfunc (str[i])))
1175 {
1176 if ( ((max_v_div_b) < res) ||
1177 (( (max_v_div_b) == res) && ( (max_v_mod_b) < (uint64_t) digit) ) )
1178 return 0;
1179
1180 res *= base;
1181 res += digit;
1182 i++;
1183 }
1184
1185 if (i)
1186 {
1187 if (8 == val_size)
1188 *(uint64_t *) out_val = res;
1189 else if (4 == val_size)
1190 *(uint32_t *) out_val = (uint32_t) res;
1191 else
1192 return 0;
1193 }
1194 return i;
1195}
1196
1197
1198#endif /* MHD_FAVOR_SMALL_CODE */
1199
1200
1201size_t
1203 char *buf,
1204 size_t buf_size)
1205{
1206 size_t o_pos = 0;
1207 int digit_pos = 8;
1208 int digit;
1209
1210 /* Skip leading zeros */
1211 do
1212 {
1213 digit_pos--;
1214 digit = (int) (val >> 28);
1215 val <<= 4;
1216 } while ((0 == digit) && (0 != digit_pos));
1217
1218 while (o_pos < buf_size)
1219 {
1220 buf[o_pos++] = (digit <= 9) ? ('0' + (char) digit) :
1221 ('A' + (char) digit - 10);
1222 if (0 == digit_pos)
1223 return o_pos;
1224 digit_pos--;
1225 digit = (int) (val >> 28);
1226 val <<= 4;
1227 }
1228 return 0; /* The buffer is too small */
1229}
1230
1231
1232#ifndef MHD_FAVOR_SMALL_CODE
1233size_t
1234MHD_uint16_to_str (uint16_t val,
1235 char *buf,
1236 size_t buf_size)
1237{
1238 char *chr;
1239 /* The biggest printable number is 65535 */
1240 uint16_t divisor = UINT16_C (10000);
1241 int digit;
1242
1243 chr = buf;
1244 digit = (int) (val / divisor);
1245 mhd_assert (digit < 10);
1246
1247 /* Do not print leading zeros */
1248 while ((0 == digit) && (1 < divisor))
1249 {
1250 divisor /= 10;
1251 digit = (int) (val / divisor);
1252 mhd_assert (digit < 10);
1253 }
1254
1255 while (0 != buf_size)
1256 {
1257 *chr = (char) digit + '0';
1258 chr++;
1259 buf_size--;
1260 if (1 == divisor)
1261 return (size_t) (chr - buf);
1262 val %= divisor;
1263 divisor /= 10;
1264 digit = (int) (val / divisor);
1265 mhd_assert (digit < 10);
1266 }
1267 return 0; /* The buffer is too small */
1268}
1269
1270
1271#endif /* !MHD_FAVOR_SMALL_CODE */
1272
1273
1274size_t
1275MHD_uint64_to_str (uint64_t val,
1276 char *buf,
1277 size_t buf_size)
1278{
1279 char *chr;
1280 /* The biggest printable number is 18446744073709551615 */
1281 uint64_t divisor = UINT64_C (10000000000000000000);
1282 int digit;
1283
1284 chr = buf;
1285 digit = (int) (val / divisor);
1286 mhd_assert (digit < 10);
1287
1288 /* Do not print leading zeros */
1289 while ((0 == digit) && (1 < divisor))
1290 {
1291 divisor /= 10;
1292 digit = (int) (val / divisor);
1293 mhd_assert (digit < 10);
1294 }
1295
1296 while (0 != buf_size)
1297 {
1298 *chr = (char) digit + '0';
1299 chr++;
1300 buf_size--;
1301 if (1 == divisor)
1302 return (size_t) (chr - buf);
1303 val %= divisor;
1304 divisor /= 10;
1305 digit = (int) (val / divisor);
1306 mhd_assert (digit < 10);
1307 }
1308 return 0; /* The buffer is too small */
1309}
1310
1311
1312size_t
1314 uint8_t min_digits,
1315 char *buf,
1316 size_t buf_size)
1317{
1318 size_t pos;
1319 int digit;
1320 mhd_assert (3 >= min_digits);
1321 if (0 == buf_size)
1322 return 0;
1323
1324 pos = 0;
1325 digit = val / 100;
1326 if (0 == digit)
1327 {
1328 if (3 <= min_digits)
1329 buf[pos++] = '0';
1330 }
1331 else
1332 {
1333 buf[pos++] = '0' + digit;
1334 val %= 100;
1335 min_digits = 2;
1336 }
1337
1338 if (buf_size <= pos)
1339 return 0;
1340 digit = val / 10;
1341 if (0 == digit)
1342 {
1343 if (2 <= min_digits)
1344 buf[pos++] = '0';
1345 }
1346 else
1347 {
1348 buf[pos++] = '0' + digit;
1349 val %= 10;
1350 }
1351
1352 if (buf_size <= pos)
1353 return 0;
1354 buf[pos++] = '0' + val;
1355 return pos;
1356}
1357
1358
1359#ifdef BAUTH_SUPPORT
1360
1361size_t
1362MHD_base64_to_bin_n (const char *base64,
1363 size_t base64_len,
1364 void *bin,
1365 size_t bin_size)
1366{
1367#ifndef MHD_FAVOR_SMALL_CODE
1368#define map_type int
1369#else /* MHD_FAVOR_SMALL_CODE */
1370#define map_type int8_t
1371#endif /* MHD_FAVOR_SMALL_CODE */
1372 static const map_type map[] = {
1373 /* -1 = invalid char, -2 = padding
1374 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F */
1375 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00..0F */
1376 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10..1F */
1377 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 20..2F */
1378 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, /* 30..3F */
1379 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 40..4F */
1380 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 50..5F */
1381 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 60..6F */
1382 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 70..7F */
1383#ifndef MHD_FAVOR_SMALL_CODE
1384 ,
1385 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80..8F */
1386 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90..9F */
1387 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A0..AF */
1388 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* B0..BF */
1389 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* C0..CF */
1390 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* D0..DF */
1391 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* E0..EF */
1392 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* F0..FF */
1393#endif /* ! MHD_FAVOR_SMALL_CODE */
1394 };
1395 const uint8_t *const in = (const uint8_t *) base64;
1396 uint8_t *const out = (uint8_t *) bin;
1397 size_t i;
1398 size_t j;
1399 if (0 == base64_len)
1400 return 0; /* Nothing to decode */
1401 if (0 != base64_len % 4)
1402 return 0; /* Wrong input length */
1403 if (base64_len / 4 * 3 - 2 > bin_size)
1404 return 0;
1405
1406 j = 0;
1407 for (i = 0; i < (base64_len - 4); i += 4)
1408 {
1409#ifdef MHD_FAVOR_SMALL_CODE
1410 if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3])))
1411 return 0;
1412#endif /* MHD_FAVOR_SMALL_CODE */
1413 if (1)
1414 {
1415 const map_type v1 = map[in[i + 0]];
1416 const map_type v2 = map[in[i + 1]];
1417 const map_type v3 = map[in[i + 2]];
1418 const map_type v4 = map[in[i + 3]];
1419 if ((0 > v1) || (0 > v2) || (0 > v3) || (0 > v4))
1420 return 0;
1421 out[j + 0] = (uint8_t) ((((uint8_t) v1) << 2) | (((uint8_t) v2) >> 4));
1422 out[j + 1] = (uint8_t) ((((uint8_t) v2) << 4) | (((uint8_t) v3) >> 2));
1423 out[j + 2] = (uint8_t) ((((uint8_t) v3) << 6) | (((uint8_t) v4)));
1424 }
1425 j += 3;
1426 }
1427#ifdef MHD_FAVOR_SMALL_CODE
1428 if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3])))
1429 return 0;
1430#endif /* MHD_FAVOR_SMALL_CODE */
1431 if (1)
1432 { /* The last four chars block */
1433 const map_type v1 = map[in[i + 0]];
1434 const map_type v2 = map[in[i + 1]];
1435 const map_type v3 = map[in[i + 2]];
1436 const map_type v4 = map[in[i + 3]];
1437 if ((0 > v1) || (0 > v2))
1438 return 0; /* Invalid char or padding at first two positions */
1439 mhd_assert (j < bin_size);
1440 out[j++] = (uint8_t) ((((uint8_t) v1) << 2) | (((uint8_t) v2) >> 4));
1441 if (0 > v3)
1442 { /* Third char is either padding or invalid */
1443 if ((-2 != v3) || (-2 != v4))
1444 return 0; /* Both two last chars must be padding */
1445 if (0 != (uint8_t) (((uint8_t) v2) << 4))
1446 return 0; /* Wrong last char */
1447 return j;
1448 }
1449 if (j >= bin_size)
1450 return 0; /* Not enough space */
1451 out[j++] = (uint8_t) ((((uint8_t) v2) << 4) | (((uint8_t) v3) >> 2));
1452 if (0 > v4)
1453 { /* Fourth char is either padding or invalid */
1454 if (-2 != v4)
1455 return 0; /* The char must be padding */
1456 if (0 != (uint8_t) (((uint8_t) v3) << 6))
1457 return 0; /* Wrong last char */
1458 return j;
1459 }
1460 if (j >= bin_size)
1461 return 0; /* Not enough space */
1462 out[j++] = (uint8_t) ((((uint8_t) v3) << 6) | (((uint8_t) v4)));
1463 }
1464 return j;
1465#undef map_type
1466}
1467
1468
1469#endif /* BAUTH_SUPPORT */
#define mhd_assert(CHK)
Definition mhd_assert.h:39
#define UINT64_MAX
Definition mhd_limits.h:81
#define UINT32_MAX
Definition mhd_limits.h:73
int MHD_str_equal_caseless_(const char *str1, const char *str2)
Definition mhd_str.c:346
size_t MHD_strx_to_uint32_(const char *str, uint32_t *out_val)
Definition mhd_str.c:558
#define toasciilower(c)
Definition mhd_str.c:296
size_t MHD_str_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition mhd_str.c:515
size_t MHD_strx_to_uint64_n_(const char *str, size_t maxlen, uint64_t *out_val)
Definition mhd_str.c:692
int MHD_str_equal_caseless_n_(const char *const str1, const char *const str2, size_t maxlen)
Definition mhd_str.c:378
size_t MHD_str_to_uint64_(const char *str, uint64_t *out_val)
Definition mhd_str.c:473
#define isasciialnum(c)
Definition mhd_str.c:284
bool MHD_str_has_token_caseless_(const char *str, const char *const token, size_t token_len)
Definition mhd_str.c:412
#define toxdigitvalue(c)
Definition mhd_str.c:328
#define toasciiupper(c)
Definition mhd_str.c:309
#define isasciilower(c)
Definition mhd_str.c:232
#define isasciidigit(c)
Definition mhd_str.c:262
size_t MHD_strx_to_uint64_(const char *str, uint64_t *out_val)
Definition mhd_str.c:646
#define isasciiupper(c)
Definition mhd_str.c:242
#define isasciialpha(c)
Definition mhd_str.c:252
size_t MHD_strx_to_uint32_n_(const char *str, size_t maxlen, uint32_t *out_val)
Definition mhd_str.c:605
#define isasciixdigit(c)
Definition mhd_str.c:272
#define todigitvalue(c)
Definition mhd_str.c:319
#define NULL
macros for mhd_assert()
limits values definitions
size_t MHD_uint8_to_str_pad(uint8_t val, uint8_t min_digits, char *buf, size_t buf_size)
Definition mhd_str.c:1313
bool MHD_str_remove_tokens_caseless_(char *str, size_t *str_len, const char *const tokens, const size_t tokens_len)
Definition mhd_str.c:720
size_t MHD_uint16_to_str(uint16_t val, char *buf, size_t buf_size)
Definition mhd_str.c:1234
size_t MHD_uint64_to_str(uint64_t val, char *buf, size_t buf_size)
Definition mhd_str.c:1275
#define charsequalcaseless(c1, c2)
Definition mhd_str.c:362
bool MHD_str_remove_token_caseless_(const char *str, size_t str_len, const char *const token, const size_t token_len, char *buf, ssize_t *buf_size)
Definition mhd_str.c:553
bool MHD_str_equal_caseless_bin_n_(const char *const str1, const char *const str2, size_t len)
Definition mhd_str.c:445
size_t MHD_uint32_to_strx(uint32_t val, char *buf, size_t buf_size)
Definition mhd_str.c:1202
Header for string manipulating helpers.