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_inline
36 #undef _MHD_inline
37 #endif /* _MHD_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_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  * Check whether character is lower case letter in US-ASCII
55  *
56  * @param c character to check
57  * @return non-zero if character is lower case letter, zero otherwise
58  */
59 _MHD_inline bool
isasciilower(char c)60 isasciilower (char c)
61 {
62   return (c >= 'a') && (c <= 'z');
63 }
64 
65 
66 /**
67  * Check whether character is upper case letter in US-ASCII
68  *
69  * @param c character to check
70  * @return non-zero if character is upper case letter, zero otherwise
71  */
72 _MHD_inline bool
isasciiupper(char c)73 isasciiupper (char c)
74 {
75   return (c >= 'A') && (c <= 'Z');
76 }
77 
78 
79 /**
80  * Check whether character is letter in US-ASCII
81  *
82  * @param c character to check
83  * @return non-zero if character is letter in US-ASCII, zero otherwise
84  */
85 _MHD_inline bool
isasciialpha(char c)86 isasciialpha (char c)
87 {
88   return isasciilower (c) || isasciiupper (c);
89 }
90 
91 
92 /**
93  * Check whether character is decimal digit in US-ASCII
94  *
95  * @param c character to check
96  * @return non-zero if character is decimal digit, zero otherwise
97  */
98 _MHD_inline bool
isasciidigit(char c)99 isasciidigit (char c)
100 {
101   return (c >= '0') && (c <= '9');
102 }
103 
104 
105 /**
106  * Check whether character is hexadecimal digit in US-ASCII
107  *
108  * @param c character to check
109  * @return non-zero if character is decimal digit, zero otherwise
110  */
111 _MHD_inline bool
isasciixdigit(char c)112 isasciixdigit (char c)
113 {
114   return isasciidigit (c) ||
115     ( (c >= 'A') && (c <= 'F') ) ||
116     ( (c >= 'a') && (c <= 'f') );
117 }
118 
119 
120 /**
121  * Check whether character is decimal digit or letter in US-ASCII
122  *
123  * @param c character to check
124  * @return non-zero if character is decimal digit or letter, zero otherwise
125  */
126 _MHD_inline bool
isasciialnum(char c)127 isasciialnum (char c)
128 {
129   return isasciialpha (c) || isasciidigit (c);
130 }
131 
132 
133 /**
134  * Convert US-ASCII character to lower case.
135  * If character is upper case letter in US-ASCII than it's converted to lower
136  * case analog. If character is NOT upper case letter than it's returned
137  * unmodified.
138  *
139  * @param c character to convert
140  * @return converted to lower case character
141  */
142 _MHD_inline char
toasciilower(char c)143 toasciilower (char c)
144 {
145   return isasciiupper (c) ? (c - 'A' + 'a') : c;
146 }
147 
148 
149 /**
150  * Convert US-ASCII character to upper case.
151  * If character is lower case letter in US-ASCII than it's converted to upper
152  * case analog. If character is NOT lower case letter than it's returned
153  * unmodified.
154  *
155  * @param c character to convert
156  * @return converted to upper case character
157  */
158 _MHD_inline char
toasciiupper(char c)159 toasciiupper (char c)
160 {
161   return isasciilower (c) ? (c - 'a' + 'A') : c;
162 }
163 
164 
165 /**
166  * Convert US-ASCII decimal digit to its value.
167  *
168  * @param c character to convert
169  * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
170  */
171 _MHD_inline int
todigitvalue(char c)172 todigitvalue (char c)
173 {
174   if (isasciidigit (c))
175     return (unsigned char)(c - '0');
176 
177   return -1;
178 }
179 
180 
181 /**
182  * Convert US-ASCII hexadecimal digit to its value.
183  *
184  * @param c character to convert
185  * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
186  */
187 _MHD_inline int
toxdigitvalue(char c)188 toxdigitvalue (char c)
189 {
190   if (isasciidigit (c))
191     return (unsigned char)(c - '0');
192   if ( (c >= 'A') && (c <= 'F') )
193     return (unsigned char)(c - 'A' + 10);
194   if ( (c >= 'a') && (c <= 'f') )
195     return (unsigned char)(c - 'a' + 10);
196 
197   return -1;
198 }
199 #else  /* !INLINE_FUNC */
200 
201 
202 /**
203  * Checks whether character is lower case letter in US-ASCII
204  *
205  * @param c character to check
206  * @return boolean true if character is lower case letter,
207  *         boolean false otherwise
208  */
209 #define isasciilower(c) (((char)(c)) >= 'a' && ((char)(c)) <= 'z')
210 
211 
212 /**
213  * Checks whether character is upper case letter in US-ASCII
214  *
215  * @param c character to check
216  * @return boolean true if character is upper case letter,
217  *         boolean false otherwise
218  */
219 #define isasciiupper(c) (((char)(c)) >= 'A' && ((char)(c)) <= 'Z')
220 
221 
222 /**
223  * Checks whether character is letter in US-ASCII
224  *
225  * @param c character to check
226  * @return boolean true if character is letter, boolean false
227  *         otherwise
228  */
229 #define isasciialpha(c) (isasciilower(c) || isasciiupper(c))
230 
231 
232 /**
233  * Check whether character is decimal digit in US-ASCII
234  *
235  * @param c character to check
236  * @return boolean true if character is decimal digit, boolean false
237  *         otherwise
238  */
239 #define isasciidigit(c) (((char)(c)) >= '0' && ((char)(c)) <= '9')
240 
241 
242 /**
243  * Check whether character is hexadecimal digit in US-ASCII
244  *
245  * @param c character to check
246  * @return boolean true if character is hexadecimal digit,
247  *         boolean false otherwise
248  */
249 #define isasciixdigit(c) (isasciidigit((c)) || \
250                           (((char)(c)) >= 'A' && ((char)(c)) <= 'F') || \
251                           (((char)(c)) >= 'a' && ((char)(c)) <= 'f') )
252 
253 
254 /**
255  * Check whether character is decimal digit or letter in US-ASCII
256  *
257  * @param c character to check
258  * @return boolean true if character is decimal digit or letter,
259  *         boolean false otherwise
260  */
261 #define isasciialnum(c) (isasciialpha(c) || isasciidigit(c))
262 
263 
264 /**
265  * Convert US-ASCII character to lower case.
266  * If character is upper case letter in US-ASCII than it's converted to lower
267  * case analog. If character is NOT upper case letter than it's returned
268  * unmodified.
269  *
270  * @param c character to convert
271  * @return converted to lower case character
272  */
273 #define toasciilower(c) ((isasciiupper(c)) ? (((char)(c)) - 'A' + 'a') : ((char)(c)))
274 
275 
276 /**
277  * Convert US-ASCII character to upper case.
278  * If character is lower case letter in US-ASCII than it's converted to upper
279  * case analog. If character is NOT lower case letter than it's returned
280  * unmodified.
281  *
282  * @param c character to convert
283  * @return converted to upper case character
284  */
285 #define toasciiupper(c) ((isasciilower(c)) ? (((char)(c)) - 'a' + 'A') : ((char)(c)))
286 
287 
288 /**
289  * Convert US-ASCII decimal digit to its value.
290  *
291  * @param c character to convert
292  * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
293  */
294 #define todigitvalue(c) (isasciidigit(c) ? (int)(((char)(c)) - '0') : (int)(-1))
295 
296 
297 /**
298  * Convert US-ASCII hexadecimal digit to its value.
299  * @param c character to convert
300  * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
301  */
302 #define toxdigitvalue(c) ( isasciidigit(c) ? (int)(((char)(c)) - '0') : \
303                            ( (((char)(c)) >= 'A' && ((char)(c)) <= 'F') ? \
304                              (int)(((unsigned char)(c)) - 'A' + 10) : \
305                              ( (((char)(c)) >= 'a' && ((char)(c)) <= 'f') ? \
306                                (int)(((unsigned char)(c)) - 'a' + 10) : (int)(-1) )))
307 #endif /* !INLINE_FUNC */
308 
309 
310 #ifndef MHD_FAVOR_SMALL_CODE
311 /**
312  * Check two string for equality, ignoring case of US-ASCII letters.
313  *
314  * @param str1 first string to compare
315  * @param str2 second string to compare
316  * @return non-zero if two strings are equal, zero otherwise.
317  */
318 int
MHD_str_equal_caseless_(const char * str1,const char * str2)319 MHD_str_equal_caseless_ (const char * str1,
320                          const char * str2)
321 {
322   while (0 != (*str1))
323     {
324       const char c1 = *str1;
325       const char c2 = *str2;
326       if ( (c1 != c2) &&
327            (toasciilower (c1) != toasciilower (c2)) )
328         return 0;
329       str1++;
330       str2++;
331     }
332   return 0 == (*str2);
333 }
334 #endif /* ! MHD_FAVOR_SMALL_CODE */
335 
336 
337 /**
338  * Check two string for equality, ignoring case of US-ASCII letters and
339  * checking not more than @a maxlen characters.
340  * Compares up to first terminating null character, but not more than
341  * first @a maxlen characters.
342  *
343  * @param str1 first string to compare
344  * @param str2 second string to compare
345  * @param maxlen maximum number of characters to compare
346  * @return non-zero if two strings are equal, zero otherwise.
347  */
348 int
MHD_str_equal_caseless_n_(const char * const str1,const char * const str2,size_t maxlen)349 MHD_str_equal_caseless_n_ (const char * const str1,
350                            const char * const str2,
351                            size_t maxlen)
352 {
353   size_t i;
354 
355   for (i = 0; i < maxlen; ++i)
356     {
357       const char c1 = str1[i];
358       const char c2 = str2[i];
359       if (0 == c2)
360         return 0 == c1;
361       if ( (c1 != c2) &&
362            (toasciilower (c1) != toasciilower (c2)) )
363         return 0;
364     }
365   return !0;
366 }
367 
368 #ifndef MHD_FAVOR_SMALL_CODE
369 /* Use individual function for each case */
370 
371 /**
372  * Convert decimal US-ASCII digits in string to number in uint64_t.
373  * Conversion stopped at first non-digit character.
374  *
375  * @param str string to convert
376  * @param[out] out_val pointer to uint64_t to store result of conversion
377  * @return non-zero number of characters processed on succeed,
378  *         zero if no digit is found, resulting value is larger
379  *         then possible to store in uint64_t or @a out_val is NULL
380  */
381 size_t
MHD_str_to_uint64_(const char * str,uint64_t * out_val)382 MHD_str_to_uint64_ (const char *str,
383                     uint64_t *out_val)
384 {
385   const char * const start = str;
386   uint64_t res;
387 
388   if (!str || !out_val || !isasciidigit(str[0]))
389     return 0;
390 
391   res = 0;
392   do
393     {
394       const int digit = (unsigned char)(*str) - '0';
395       if ( (res > (UINT64_MAX / 10)) ||
396            ( (res == (UINT64_MAX / 10)) &&
397              ((uint64_t)digit > (UINT64_MAX % 10)) ) )
398         return 0;
399 
400       res *= 10;
401       res += digit;
402       str++;
403     } while (isasciidigit (*str));
404 
405   *out_val = res;
406   return str - start;
407 }
408 
409 
410 /**
411  * Convert not more then @a maxlen decimal US-ASCII digits in string to
412  * number in uint64_t.
413  * Conversion stopped at first non-digit character or after @a maxlen
414  * digits.
415  *
416  * @param str string to convert
417  * @param maxlen maximum number of characters to process
418  * @param[out] out_val pointer to uint64_t to store result of conversion
419  * @return non-zero number of characters processed on succeed,
420  *         zero if no digit is found, resulting value is larger
421  *         then possible to store in uint64_t or @a out_val is NULL
422  */
423 size_t
MHD_str_to_uint64_n_(const char * str,size_t maxlen,uint64_t * out_val)424 MHD_str_to_uint64_n_ (const char * str,
425                       size_t maxlen,
426                       uint64_t *out_val)
427 {
428   uint64_t res;
429   size_t i;
430 
431   if (!str || !maxlen || !out_val || !isasciidigit (str[0]))
432     return 0;
433 
434   res = 0;
435   i = 0;
436   do
437     {
438       const int digit = (unsigned char)str[i] - '0';
439 
440       if ( (res > (UINT64_MAX / 10)) ||
441            ( (res == (UINT64_MAX / 10)) &&
442              ((uint64_t)digit > (UINT64_MAX % 10)) ) )
443         return 0;
444 
445       res *= 10;
446       res += digit;
447       i++;
448     } while ( (i < maxlen) &&
449               isasciidigit (str[i]) );
450 
451   *out_val= res;
452   return i;
453 }
454 
455 
456 /**
457  * Convert hexadecimal US-ASCII digits in string to number in uint32_t.
458  * Conversion stopped at first non-digit character.
459  *
460  * @param str string to convert
461  * @param[out] out_val pointer to uint32_t to store result of conversion
462  * @return non-zero number of characters processed on succeed,
463  *         zero if no digit is found, resulting value is larger
464  *         then possible to store in uint32_t or @a out_val is NULL
465  */
466 size_t
MHD_strx_to_uint32_(const char * str,uint32_t * out_val)467 MHD_strx_to_uint32_ (const char * str,
468                      uint32_t *out_val)
469 {
470   const char * const start = str;
471   uint32_t res;
472   int digit;
473 
474   if (!str || !out_val)
475     return 0;
476 
477   res = 0;
478   digit = toxdigitvalue (*str);
479   while (digit >= 0)
480     {
481       if ( (res < (UINT32_MAX / 16)) ||
482            (res == (UINT32_MAX / 16) && (uint32_t)digit <= (UINT32_MAX % 16)) )
483         {
484           res *= 16;
485           res += digit;
486         }
487       else
488         return 0;
489       str++;
490       digit = toxdigitvalue (*str);
491     }
492 
493   if (str - start > 0)
494     *out_val = res;
495   return str - start;
496 }
497 
498 
499 /**
500  * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
501  * to number in uint32_t.
502  * Conversion stopped at first non-digit character or after @a maxlen
503  * digits.
504  *
505  * @param str string to convert
506  * @param maxlen maximum number of characters to process
507  * @param[out] out_val pointer to uint32_t to store result of conversion
508  * @return non-zero number of characters processed on succeed,
509  *         zero if no digit is found, resulting value is larger
510  *         then possible to store in uint32_t or @a out_val is NULL
511  */
512 size_t
MHD_strx_to_uint32_n_(const char * str,size_t maxlen,uint32_t * out_val)513 MHD_strx_to_uint32_n_ (const char *str,
514                        size_t maxlen,
515                        uint32_t *out_val)
516 {
517   size_t i;
518   uint32_t res;
519   int digit;
520   if (!str || !out_val)
521     return 0;
522 
523   res = 0;
524   i = 0;
525   while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0)
526     {
527       if ( (res > (UINT32_MAX / 16)) ||
528            (res == (UINT32_MAX / 16) && (uint32_t)digit > (UINT32_MAX % 16)) )
529         return 0;
530 
531       res *= 16;
532       res += digit;
533       i++;
534     }
535 
536   if (i)
537     *out_val = res;
538   return i;
539 }
540 
541 
542 /**
543  * Convert hexadecimal US-ASCII digits in string to number in uint64_t.
544  * Conversion stopped at first non-digit character.
545  *
546  * @param str string to convert
547  * @param[out] out_val pointer to uint64_t to store result of conversion
548  * @return non-zero number of characters processed on succeed,
549  *         zero if no digit is found, resulting value is larger
550  *         then possible to store in uint64_t or @a out_val is NULL
551  */
552 size_t
MHD_strx_to_uint64_(const char * str,uint64_t * out_val)553 MHD_strx_to_uint64_ (const char *str,
554                      uint64_t *out_val)
555 {
556   const char * const start = str;
557   uint64_t res;
558   int digit;
559   if (!str || !out_val)
560     return 0;
561 
562   res = 0;
563   digit = toxdigitvalue (*str);
564   while (digit >= 0)
565     {
566       if ( (res < (UINT64_MAX / 16)) ||
567            (res == (UINT64_MAX / 16) && (uint64_t)digit <= (UINT64_MAX % 16)) )
568         {
569           res *= 16;
570           res += digit;
571         }
572       else
573         return 0;
574       str++;
575       digit = toxdigitvalue (*str);
576     }
577 
578   if (str - start > 0)
579     *out_val = res;
580   return str - start;
581 }
582 
583 
584 /**
585  * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
586  * to number in uint64_t.
587  * Conversion stopped at first non-digit character or after @a maxlen
588  * digits.
589  *
590  * @param str string to convert
591  * @param maxlen maximum number of characters to process
592  * @param[out] out_val pointer to uint64_t to store result of conversion
593  * @return non-zero number of characters processed on succeed,
594  *         zero if no digit is found, resulting value is larger
595  *         then possible to store in uint64_t or @a out_val is NULL
596  */
597 size_t
MHD_strx_to_uint64_n_(const char * str,size_t maxlen,uint64_t * out_val)598 MHD_strx_to_uint64_n_ (const char * str,
599                        size_t maxlen,
600                        uint64_t *out_val)
601 {
602   size_t i;
603   uint64_t res;
604   int digit;
605   if (!str || !out_val)
606     return 0;
607 
608   res = 0;
609   i = 0;
610   while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0)
611     {
612       if ( (res > (UINT64_MAX / 16)) ||
613            (res == (UINT64_MAX / 16) && (uint64_t)digit > (UINT64_MAX % 16)) )
614         return 0;
615 
616       res *= 16;
617       res += digit;
618       i++;
619     }
620 
621   if (i)
622     *out_val = res;
623   return i;
624 }
625 
626 #else  /* MHD_FAVOR_SMALL_CODE */
627 
628 /**
629  * Generic function for converting not more then @a maxlen
630  * hexadecimal or decimal US-ASCII digits in string to number.
631  * Conversion stopped at first non-digit character or after @a maxlen
632  * digits.
633  * To be used only within macro.
634  *
635  * @param str the string to convert
636  * @param maxlen the maximum number of characters to process
637  * @param out_val the pointer to variable to store result of conversion
638  * @param val_size the size of variable pointed by @a out_val, in bytes, 4 or 8
639  * @param max_val the maximum decoded number
640  * @param base the numeric base, 10 or 16
641  * @return non-zero number of characters processed on succeed,
642  *         zero if no digit is found, resulting value is larger
643  *         then @max_val, @val_size is not 16/32 or @a out_val is NULL
644  */
645 size_t
MHD_str_to_uvalue_n_(const char * str,size_t maxlen,void * out_val,size_t val_size,uint64_t max_val,int base)646 MHD_str_to_uvalue_n_ (const char *str,
647                       size_t maxlen,
648                       void * out_val,
649                       size_t val_size,
650                       uint64_t max_val,
651                       int base)
652 {
653   size_t i;
654   uint64_t res;
655   int digit;
656   const uint64_t max_v_div_b = max_val / base;
657   const uint64_t max_v_mod_b = max_val % base;
658   /* 'digit->value' must be function, not macro */
659   int (*const dfunc)(char) = (base == 16) ?
660                               toxdigitvalue : todigitvalue;
661 
662   if ( !str || !out_val ||
663        (base != 16 && base != 10) )
664     return 0;
665 
666   res = 0;
667   i = 0;
668   while (maxlen > i && 0 <= (digit = dfunc (str[i])))
669     {
670       if ( ((max_v_div_b) < res) ||
671           ((max_v_div_b) == res && (max_v_mod_b) < (uint64_t)digit) )
672         return 0;
673 
674       res *= base;
675       res += digit;
676       i++;
677     }
678 
679   if (i)
680     {
681       if (8 == val_size)
682         *(uint64_t*)out_val = res;
683       else if (4 == val_size)
684         *(uint32_t*)out_val = (uint32_t)res;
685       else
686         return 0;
687     }
688   return i;
689 }
690 #endif /* MHD_FAVOR_SMALL_CODE */
691