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