libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

mhd_str.c (84551B)


      1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
      2 /*
      3   This file is part of GNU libmicrohttpd.
      4   Copyright (C) 2015-2024 Evgeny Grin (Karlson2k)
      5 
      6   GNU libmicrohttpd is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU Lesser General Public
      8   License as published by the Free Software Foundation; either
      9   version 2.1 of the License, or (at your option) any later version.
     10 
     11   GNU libmicrohttpd is distributed in the hope that it will be useful,
     12   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   Lesser General Public License for more details.
     15 
     16   Alternatively, you can redistribute GNU libmicrohttpd and/or
     17   modify it under the terms of the GNU General Public License as
     18   published by the Free Software Foundation; either version 2 of
     19   the License, or (at your option) any later version, together
     20   with the eCos exception, as follows:
     21 
     22     As a special exception, if other files instantiate templates or
     23     use macros or inline functions from this file, or you compile this
     24     file and link it with other works to produce a work based on this
     25     file, this file does not by itself cause the resulting work to be
     26     covered by the GNU General Public License. However the source code
     27     for this file must still be made available in accordance with
     28     section (3) of the GNU General Public License v2.
     29 
     30     This exception does not invalidate any other reasons why a work
     31     based on this file might be covered by the GNU General Public
     32     License.
     33 
     34   You should have received copies of the GNU Lesser General Public
     35   License and the GNU General Public License along with this library;
     36   if not, see <https://www.gnu.org/licenses/>.
     37 */
     38 
     39 /**
     40  * @file microhttpd/mhd_str.c
     41  * @brief  Functions implementations for string manipulating
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 
     45 #include "mhd_sys_options.h"
     46 
     47 #include "mhd_assert.h"
     48 #include "mhd_limits.h"
     49 
     50 #include "mhd_constexpr.h"
     51 #include "mhd_assume.h"
     52 
     53 #include <string.h>
     54 
     55 #include "mhd_str.h"
     56 
     57 #ifdef MHD_FAVOR_SMALL_CODE
     58 #  ifdef mhd_static_inline
     59 #    undef mhd_static_inline
     60 #  endif /* mhd_static_inline */
     61 /* Do not force inlining and do not use macro functions, use normal static
     62    functions instead.
     63    This may give more flexibility for size optimizations. */
     64 #  define mhd_static_inline static
     65 #  ifndef HAVE_INLINE_FUNCS
     66 #    define HAVE_INLINE_FUNCS 1
     67 #  endif /* !HAVE_INLINE_FUNCS */
     68 #endif /* MHD_FAVOR_SMALL_CODE */
     69 
     70 /*
     71  * Block of functions/macros that use US-ASCII charset as required by HTTP
     72  * standards. Not affected by current locale settings.
     73  */
     74 
     75 #ifdef HAVE_INLINE_FUNCS
     76 
     77 #ifdef mhd_HAVE_STR_TO_UPPER
     78 /**
     79  * Check whether character is lower case letter in US-ASCII
     80  *
     81  * @param c character to check
     82  * @return non-zero if character is lower case letter, zero otherwise
     83  */
     84 mhd_static_inline MHD_FN_CONST_ bool
     85 isasciilower (char c)
     86 {
     87   const unsigned int uc = (unsigned int) (unsigned char) c;
     88   const unsigned int t = uc - (unsigned int) (unsigned char) 'a';
     89   return (((unsigned int) ('z' - 'a')) >= t);
     90 }
     91 
     92 
     93 #endif /* mhd_HAVE_STR_TO_UPPER */
     94 
     95 
     96 /**
     97  * Check whether character is upper case letter in US-ASCII
     98  *
     99  * @param c character to check
    100  * @return non-zero if character is upper case letter, zero otherwise
    101  */
    102 mhd_static_inline MHD_FN_CONST_ bool
    103 isasciiupper (char c)
    104 {
    105   const unsigned int uc = (unsigned int) (unsigned char) c;
    106   const unsigned int t = uc - (unsigned int) (unsigned char) 'A';
    107   return (((unsigned int) ('Z' - 'A')) >= t);
    108 }
    109 
    110 
    111 #if 0 /* Disable unused functions. */
    112 /**
    113  * Check whether character is letter in US-ASCII
    114  *
    115  * @param c character to check
    116  * @return non-zero if character is letter in US-ASCII, zero otherwise
    117  */
    118 mhd_static_inline MHD_FN_CONST_ bool
    119 isasciialpha (char c)
    120 {
    121   return isasciilower (c) || isasciiupper (c);
    122 }
    123 
    124 
    125 #endif /* Disable unused functions. */
    126 
    127 
    128 /**
    129  * Check whether character is decimal digit in US-ASCII
    130  *
    131  * @param c character to check
    132  * @return non-zero if character is decimal digit, zero otherwise
    133  */
    134 mhd_static_inline MHD_FN_CONST_ bool
    135 isasciidigit (char c)
    136 {
    137   return (c <= '9') && (c >= '0');
    138 }
    139 
    140 
    141 #if 0 /* Disable unused functions. */
    142 /**
    143  * Check whether character is hexadecimal digit in US-ASCII
    144  *
    145  * @param c character to check
    146  * @return non-zero if character is decimal digit, zero otherwise
    147  */
    148 mhd_static_inline MHD_FN_CONST_ bool
    149 isasciixdigit (char c)
    150 {
    151   return isasciidigit (c) ||
    152          ( (c <= 'F') && (c >= 'A') ) ||
    153          ( (c <= 'f') && (c >= 'a') );
    154 }
    155 
    156 
    157 /**
    158  * Check whether character is decimal digit or letter in US-ASCII
    159  *
    160  * @param c character to check
    161  * @return non-zero if character is decimal digit or letter, zero otherwise
    162  */
    163 mhd_static_inline MHD_FN_CONST_ bool
    164 isasciialnum (char c)
    165 {
    166   return isasciialpha (c) || isasciidigit (c);
    167 }
    168 
    169 
    170 #endif /* Disable unused functions. */
    171 
    172 /**
    173  * Convert US-ASCII character to lower case.
    174  * If character is upper case letter in US-ASCII than it's converted to lower
    175  * case analog. If character is NOT upper case letter than it's returned
    176  * unmodified.
    177  *
    178  * @param c character to convert
    179  * @return converted to lower case character
    180  */
    181 mhd_static_inline MHD_FN_CONST_ char
    182 toasciilower (char c)
    183 {
    184   return (char) (((unsigned char) c) | ((isasciiupper (c) ? 1u : 0u) << 5u));
    185 }
    186 
    187 
    188 #ifdef mhd_HAVE_STR_TO_UPPER
    189 
    190 /**
    191  * Convert US-ASCII character to upper case.
    192  * If character is lower case letter in US-ASCII than it's converted to upper
    193  * case counterpart. If character is NOT lower case letter than it's returned
    194  * unmodified.
    195  *
    196  * @param c character to convert
    197  * @return converted to upper case character
    198  */
    199 mhd_static_inline MHD_FN_CONST_ char
    200 toasciiupper (char c)
    201 {
    202   return (char) (unsigned char)
    203          (((unsigned char) c) & ~((isasciilower (c) ? 1u : 0u) << 5u));
    204 }
    205 
    206 
    207 #endif /* mhd_HAVE_STR_TO_UPPER */
    208 
    209 
    210 #if defined(MHD_FAVOR_SMALL_CODE) /* Used only in mhd_str_to_uvalue_n() */
    211 /**
    212  * Convert US-ASCII decimal digit to its value.
    213  *
    214  * @param c character to convert
    215  * @return value of decimal digit or -1 if @ c is not decimal digit
    216  */
    217 mhd_static_inline MHD_FN_CONST_ int
    218 todigitvalue (char c)
    219 {
    220   if (isasciidigit (c))
    221     return (unsigned char) (c - '0');
    222 
    223   return -1;
    224 }
    225 
    226 
    227 #endif /* MHD_FAVOR_SMALL_CODE */
    228 
    229 
    230 /**
    231  * Convert US-ASCII hexadecimal digit to its value.
    232  *
    233  * @param c character to convert
    234  * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
    235  */
    236 mhd_static_inline MHD_FN_CONST_ int
    237 xdigittovalue (char c)
    238 {
    239   const unsigned char uc = (unsigned char) c; /* Force unsigned value */
    240 #if ! defined(MHD_FAVOR_SMALL_CODE)
    241   static const signed char map_xdigit_to_value[256] = {
    242     -1 /* 0x00 (NUL) */,
    243     -1 /* 0x01 (SOH) */,
    244     -1 /* 0x02 (STX) */,
    245     -1 /* 0x03 (ETX) */,
    246     -1 /* 0x04 (EOT) */,
    247     -1 /* 0x05 (ENQ) */,
    248     -1 /* 0x06 (ACK) */,
    249     -1 /* 0x07 (BEL) */,
    250     -1 /* 0x08 (BS)  */,
    251     -1 /* 0x09 (HT)  */,
    252     -1 /* 0x0A (LF)  */,
    253     -1 /* 0x0B (VT)  */,
    254     -1 /* 0x0C (FF)  */,
    255     -1 /* 0x0D (CR)  */,
    256     -1 /* 0x0E (SO)  */,
    257     -1 /* 0x0F (SI)  */,
    258     -1 /* 0x10 (DLE) */,
    259     -1 /* 0x11 (DC1) */,
    260     -1 /* 0x12 (DC2) */,
    261     -1 /* 0x13 (DC3) */,
    262     -1 /* 0x14 (DC4) */,
    263     -1 /* 0x15 (NAK) */,
    264     -1 /* 0x16 (SYN) */,
    265     -1 /* 0x17 (ETB) */,
    266     -1 /* 0x18 (CAN) */,
    267     -1 /* 0x19 (EM)  */,
    268     -1 /* 0x1A (SUB) */,
    269     -1 /* 0x1B (ESC) */,
    270     -1 /* 0x1C (FS)  */,
    271     -1 /* 0x1D (GS)  */,
    272     -1 /* 0x1E (RS)  */,
    273     -1 /* 0x1F (US)  */,
    274     -1 /* 0x20 (' ') */,
    275     -1 /* 0x21 ('!') */,
    276     -1 /* 0x22 ('"') */,
    277     -1 /* 0x23 ('#') */,
    278     -1 /* 0x24 ('$') */,
    279     -1 /* 0x25 ('%') */,
    280     -1 /* 0x26 ('&') */,
    281     -1 /* 0x27 ('\'') */,
    282     -1 /* 0x28 ('(') */,
    283     -1 /* 0x29 (')') */,
    284     -1 /* 0x2A ('*') */,
    285     -1 /* 0x2B ('+') */,
    286     -1 /* 0x2C (',') */,
    287     -1 /* 0x2D ('-') */,
    288     -1 /* 0x2E ('.') */,
    289     -1 /* 0x2F ('/') */,
    290     0 /*  0x30 ('0') */,
    291     1 /*  0x31 ('1') */,
    292     2 /*  0x32 ('2') */,
    293     3 /*  0x33 ('3') */,
    294     4 /*  0x34 ('4') */,
    295     5 /*  0x35 ('5') */,
    296     6 /*  0x36 ('6') */,
    297     7 /*  0x37 ('7') */,
    298     8 /*  0x38 ('8') */,
    299     9 /*  0x39 ('9') */,
    300     -1 /* 0x3A (':') */,
    301     -1 /* 0x3B (';') */,
    302     -1 /* 0x3C ('<') */,
    303     -1 /* 0x3D ('=') */,
    304     -1 /* 0x3E ('>') */,
    305     -1 /* 0x3F ('?') */,
    306     -1 /* 0x40 ('@') */,
    307     10 /* 0x41 ('A') */,
    308     11 /* 0x42 ('B') */,
    309     12 /* 0x43 ('C') */,
    310     13 /* 0x44 ('D') */,
    311     14 /* 0x45 ('E') */,
    312     15 /* 0x46 ('F') */,
    313     -1 /* 0x47 ('G') */,
    314     -1 /* 0x48 ('H') */,
    315     -1 /* 0x49 ('I') */,
    316     -1 /* 0x4A ('J') */,
    317     -1 /* 0x4B ('K') */,
    318     -1 /* 0x4C ('L') */,
    319     -1 /* 0x4D ('M') */,
    320     -1 /* 0x4E ('N') */,
    321     -1 /* 0x4F ('O') */,
    322     -1 /* 0x50 ('P') */,
    323     -1 /* 0x51 ('Q') */,
    324     -1 /* 0x52 ('R') */,
    325     -1 /* 0x53 ('S') */,
    326     -1 /* 0x54 ('T') */,
    327     -1 /* 0x55 ('U') */,
    328     -1 /* 0x56 ('V') */,
    329     -1 /* 0x57 ('W') */,
    330     -1 /* 0x58 ('X') */,
    331     -1 /* 0x59 ('Y') */,
    332     -1 /* 0x5A ('Z') */,
    333     -1 /* 0x5B ('[') */,
    334     -1 /* 0x5C ('\') */,
    335     -1 /* 0x5D (']') */,
    336     -1 /* 0x5E ('^') */,
    337     -1 /* 0x5F ('_') */,
    338     -1 /* 0x60 ('`') */,
    339     10 /* 0x61 ('a') */,
    340     11 /* 0x62 ('b') */,
    341     12 /* 0x63 ('c') */,
    342     13 /* 0x64 ('d') */,
    343     14 /* 0x65 ('e') */,
    344     15 /* 0x66 ('f') */,
    345     -1 /* 0x67 ('g') */,
    346     -1 /* 0x68 ('h') */,
    347     -1 /* 0x69 ('i') */,
    348     -1 /* 0x6A ('j') */,
    349     -1 /* 0x6B ('k') */,
    350     -1 /* 0x6C ('l') */,
    351     -1 /* 0x6D ('m') */,
    352     -1 /* 0x6E ('n') */,
    353     -1 /* 0x6F ('o') */,
    354     -1 /* 0x70 ('p') */,
    355     -1 /* 0x71 ('q') */,
    356     -1 /* 0x72 ('r') */,
    357     -1 /* 0x73 ('s') */,
    358     -1 /* 0x74 ('t') */,
    359     -1 /* 0x75 ('u') */,
    360     -1 /* 0x76 ('v') */,
    361     -1 /* 0x77 ('w') */,
    362     -1 /* 0x78 ('x') */,
    363     -1 /* 0x79 ('y') */,
    364     -1 /* 0x7A ('z') */,
    365     -1 /* 0x7B ('{') */,
    366     -1 /* 0x7C ('|') */,
    367     -1 /* 0x7D ('}') */,
    368     -1 /* 0x7E ('~') */,
    369     -1 /* 0x7F (DEL) */,
    370     -1 /* 0x80 (EXT) */,
    371     -1 /* 0x81 (EXT) */,
    372     -1 /* 0x82 (EXT) */,
    373     -1 /* 0x83 (EXT) */,
    374     -1 /* 0x84 (EXT) */,
    375     -1 /* 0x85 (EXT) */,
    376     -1 /* 0x86 (EXT) */,
    377     -1 /* 0x87 (EXT) */,
    378     -1 /* 0x88 (EXT) */,
    379     -1 /* 0x89 (EXT) */,
    380     -1 /* 0x8A (EXT) */,
    381     -1 /* 0x8B (EXT) */,
    382     -1 /* 0x8C (EXT) */,
    383     -1 /* 0x8D (EXT) */,
    384     -1 /* 0x8E (EXT) */,
    385     -1 /* 0x8F (EXT) */,
    386     -1 /* 0x90 (EXT) */,
    387     -1 /* 0x91 (EXT) */,
    388     -1 /* 0x92 (EXT) */,
    389     -1 /* 0x93 (EXT) */,
    390     -1 /* 0x94 (EXT) */,
    391     -1 /* 0x95 (EXT) */,
    392     -1 /* 0x96 (EXT) */,
    393     -1 /* 0x97 (EXT) */,
    394     -1 /* 0x98 (EXT) */,
    395     -1 /* 0x99 (EXT) */,
    396     -1 /* 0x9A (EXT) */,
    397     -1 /* 0x9B (EXT) */,
    398     -1 /* 0x9C (EXT) */,
    399     -1 /* 0x9D (EXT) */,
    400     -1 /* 0x9E (EXT) */,
    401     -1 /* 0x9F (EXT) */,
    402     -1 /* 0xA0 (EXT) */,
    403     -1 /* 0xA1 (EXT) */,
    404     -1 /* 0xA2 (EXT) */,
    405     -1 /* 0xA3 (EXT) */,
    406     -1 /* 0xA4 (EXT) */,
    407     -1 /* 0xA5 (EXT) */,
    408     -1 /* 0xA6 (EXT) */,
    409     -1 /* 0xA7 (EXT) */,
    410     -1 /* 0xA8 (EXT) */,
    411     -1 /* 0xA9 (EXT) */,
    412     -1 /* 0xAA (EXT) */,
    413     -1 /* 0xAB (EXT) */,
    414     -1 /* 0xAC (EXT) */,
    415     -1 /* 0xAD (EXT) */,
    416     -1 /* 0xAE (EXT) */,
    417     -1 /* 0xAF (EXT) */,
    418     -1 /* 0xB0 (EXT) */,
    419     -1 /* 0xB1 (EXT) */,
    420     -1 /* 0xB2 (EXT) */,
    421     -1 /* 0xB3 (EXT) */,
    422     -1 /* 0xB4 (EXT) */,
    423     -1 /* 0xB5 (EXT) */,
    424     -1 /* 0xB6 (EXT) */,
    425     -1 /* 0xB7 (EXT) */,
    426     -1 /* 0xB8 (EXT) */,
    427     -1 /* 0xB9 (EXT) */,
    428     -1 /* 0xBA (EXT) */,
    429     -1 /* 0xBB (EXT) */,
    430     -1 /* 0xBC (EXT) */,
    431     -1 /* 0xBD (EXT) */,
    432     -1 /* 0xBE (EXT) */,
    433     -1 /* 0xBF (EXT) */,
    434     -1 /* 0xC0 (EXT) */,
    435     -1 /* 0xC1 (EXT) */,
    436     -1 /* 0xC2 (EXT) */,
    437     -1 /* 0xC3 (EXT) */,
    438     -1 /* 0xC4 (EXT) */,
    439     -1 /* 0xC5 (EXT) */,
    440     -1 /* 0xC6 (EXT) */,
    441     -1 /* 0xC7 (EXT) */,
    442     -1 /* 0xC8 (EXT) */,
    443     -1 /* 0xC9 (EXT) */,
    444     -1 /* 0xCA (EXT) */,
    445     -1 /* 0xCB (EXT) */,
    446     -1 /* 0xCC (EXT) */,
    447     -1 /* 0xCD (EXT) */,
    448     -1 /* 0xCE (EXT) */,
    449     -1 /* 0xCF (EXT) */,
    450     -1 /* 0xD0 (EXT) */,
    451     -1 /* 0xD1 (EXT) */,
    452     -1 /* 0xD2 (EXT) */,
    453     -1 /* 0xD3 (EXT) */,
    454     -1 /* 0xD4 (EXT) */,
    455     -1 /* 0xD5 (EXT) */,
    456     -1 /* 0xD6 (EXT) */,
    457     -1 /* 0xD7 (EXT) */,
    458     -1 /* 0xD8 (EXT) */,
    459     -1 /* 0xD9 (EXT) */,
    460     -1 /* 0xDA (EXT) */,
    461     -1 /* 0xDB (EXT) */,
    462     -1 /* 0xDC (EXT) */,
    463     -1 /* 0xDD (EXT) */,
    464     -1 /* 0xDE (EXT) */,
    465     -1 /* 0xDF (EXT) */,
    466     -1 /* 0xE0 (EXT) */,
    467     -1 /* 0xE1 (EXT) */,
    468     -1 /* 0xE2 (EXT) */,
    469     -1 /* 0xE3 (EXT) */,
    470     -1 /* 0xE4 (EXT) */,
    471     -1 /* 0xE5 (EXT) */,
    472     -1 /* 0xE6 (EXT) */,
    473     -1 /* 0xE7 (EXT) */,
    474     -1 /* 0xE8 (EXT) */,
    475     -1 /* 0xE9 (EXT) */,
    476     -1 /* 0xEA (EXT) */,
    477     -1 /* 0xEB (EXT) */,
    478     -1 /* 0xEC (EXT) */,
    479     -1 /* 0xED (EXT) */,
    480     -1 /* 0xEE (EXT) */,
    481     -1 /* 0xEF (EXT) */,
    482     -1 /* 0xF0 (EXT) */,
    483     -1 /* 0xF1 (EXT) */,
    484     -1 /* 0xF2 (EXT) */,
    485     -1 /* 0xF3 (EXT) */,
    486     -1 /* 0xF4 (EXT) */,
    487     -1 /* 0xF5 (EXT) */,
    488     -1 /* 0xF6 (EXT) */,
    489     -1 /* 0xF7 (EXT) */,
    490     -1 /* 0xF8 (EXT) */,
    491     -1 /* 0xF9 (EXT) */,
    492     -1 /* 0xFA (EXT) */,
    493     -1 /* 0xFB (EXT) */,
    494     -1 /* 0xFC (EXT) */,
    495     -1 /* 0xFD (EXT) */,
    496     -1 /* 0xFE (EXT) */,
    497     -1   /* 0xFF (EXT) */
    498   };
    499   return map_xdigit_to_value[uc];
    500 #else  /* MHD_FAVOR_SMALL_CODE */
    501   unsigned int try_val;
    502 
    503   try_val = uc - (unsigned char) '0';
    504   if (9 >= try_val)
    505     return (int) (unsigned int) try_val;
    506   try_val = (uc | 0x20u /* fold case */) - (unsigned char) 'a';
    507   if (5 >= try_val)
    508     return (int) (unsigned int) (try_val + 10u);
    509 
    510   return -1;
    511 #endif /* MHD_FAVOR_SMALL_CODE */
    512 }
    513 
    514 
    515 /**
    516  * Convert 4 bit value to US-ASCII hexadecimal digit.
    517  *
    518  * @param v the value to convert, must be less then 16
    519  * @return hexadecimal digit
    520  */
    521 mhd_static_inline MHD_FN_CONST_ char
    522 valuetoxdigit (unsigned int v)
    523 {
    524 #if ! defined(MHD_FAVOR_SMALL_CODE)
    525   static const char map_value_to_xdigit[16] =
    526   { '0', '1', '2', '3', '4', '5', '6', '7',
    527     '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
    528 
    529   mhd_assert (16 > v);
    530 
    531   return map_value_to_xdigit[v];
    532 #else  /* MHD_FAVOR_SMALL_CODE */
    533 
    534   mhd_assert (16 > v);
    535 
    536   if (v <= 9)
    537     return '0' + (char) (v);
    538   return 'a' + (char) (v - 10);
    539 #endif /* MHD_FAVOR_SMALL_CODE */
    540 }
    541 
    542 
    543 #if ! defined(MHD_FAVOR_SMALL_CODE)
    544 /**
    545  * Convert 8 bit value to two US-ASCII hexadecimal digits.
    546  *
    547  * @param v the value to convert
    548  * @return pointer to char[2] with two hexadecimal digits
    549  */
    550 mhd_static_inline MHD_FN_CONST_ MHD_FN_RETURNS_NONNULL_ const char*
    551 uint8totwoxdigits (uint8_t v)
    552 {
    553   static const char map_uint8_to_two_xdigits[][2] =
    554   { { '0', '0' },
    555     { '0', '1' },
    556     { '0', '2' },
    557     { '0', '3' },
    558     { '0', '4' },
    559     { '0', '5' },
    560     { '0', '6' },
    561     { '0', '7' },
    562     { '0', '8' },
    563     { '0', '9' },
    564     { '0', 'a' },
    565     { '0', 'b' },
    566     { '0', 'c' },
    567     { '0', 'd' },
    568     { '0', 'e' },
    569     { '0', 'f' },
    570     { '1', '0' },
    571     { '1', '1' },
    572     { '1', '2' },
    573     { '1', '3' },
    574     { '1', '4' },
    575     { '1', '5' },
    576     { '1', '6' },
    577     { '1', '7' },
    578     { '1', '8' },
    579     { '1', '9' },
    580     { '1', 'a' },
    581     { '1', 'b' },
    582     { '1', 'c' },
    583     { '1', 'd' },
    584     { '1', 'e' },
    585     { '1', 'f' },
    586     { '2', '0' },
    587     { '2', '1' },
    588     { '2', '2' },
    589     { '2', '3' },
    590     { '2', '4' },
    591     { '2', '5' },
    592     { '2', '6' },
    593     { '2', '7' },
    594     { '2', '8' },
    595     { '2', '9' },
    596     { '2', 'a' },
    597     { '2', 'b' },
    598     { '2', 'c' },
    599     { '2', 'd' },
    600     { '2', 'e' },
    601     { '2', 'f' },
    602     { '3', '0' },
    603     { '3', '1' },
    604     { '3', '2' },
    605     { '3', '3' },
    606     { '3', '4' },
    607     { '3', '5' },
    608     { '3', '6' },
    609     { '3', '7' },
    610     { '3', '8' },
    611     { '3', '9' },
    612     { '3', 'a' },
    613     { '3', 'b' },
    614     { '3', 'c' },
    615     { '3', 'd' },
    616     { '3', 'e' },
    617     { '3', 'f' },
    618     { '4', '0' },
    619     { '4', '1' },
    620     { '4', '2' },
    621     { '4', '3' },
    622     { '4', '4' },
    623     { '4', '5' },
    624     { '4', '6' },
    625     { '4', '7' },
    626     { '4', '8' },
    627     { '4', '9' },
    628     { '4', 'a' },
    629     { '4', 'b' },
    630     { '4', 'c' },
    631     { '4', 'd' },
    632     { '4', 'e' },
    633     { '4', 'f' },
    634     { '5', '0' },
    635     { '5', '1' },
    636     { '5', '2' },
    637     { '5', '3' },
    638     { '5', '4' },
    639     { '5', '5' },
    640     { '5', '6' },
    641     { '5', '7' },
    642     { '5', '8' },
    643     { '5', '9' },
    644     { '5', 'a' },
    645     { '5', 'b' },
    646     { '5', 'c' },
    647     { '5', 'd' },
    648     { '5', 'e' },
    649     { '5', 'f' },
    650     { '6', '0' },
    651     { '6', '1' },
    652     { '6', '2' },
    653     { '6', '3' },
    654     { '6', '4' },
    655     { '6', '5' },
    656     { '6', '6' },
    657     { '6', '7' },
    658     { '6', '8' },
    659     { '6', '9' },
    660     { '6', 'a' },
    661     { '6', 'b' },
    662     { '6', 'c' },
    663     { '6', 'd' },
    664     { '6', 'e' },
    665     { '6', 'f' },
    666     { '7', '0' },
    667     { '7', '1' },
    668     { '7', '2' },
    669     { '7', '3' },
    670     { '7', '4' },
    671     { '7', '5' },
    672     { '7', '6' },
    673     { '7', '7' },
    674     { '7', '8' },
    675     { '7', '9' },
    676     { '7', 'a' },
    677     { '7', 'b' },
    678     { '7', 'c' },
    679     { '7', 'd' },
    680     { '7', 'e' },
    681     { '7', 'f' },
    682     { '8', '0' },
    683     { '8', '1' },
    684     { '8', '2' },
    685     { '8', '3' },
    686     { '8', '4' },
    687     { '8', '5' },
    688     { '8', '6' },
    689     { '8', '7' },
    690     { '8', '8' },
    691     { '8', '9' },
    692     { '8', 'a' },
    693     { '8', 'b' },
    694     { '8', 'c' },
    695     { '8', 'd' },
    696     { '8', 'e' },
    697     { '8', 'f' },
    698     { '9', '0' },
    699     { '9', '1' },
    700     { '9', '2' },
    701     { '9', '3' },
    702     { '9', '4' },
    703     { '9', '5' },
    704     { '9', '6' },
    705     { '9', '7' },
    706     { '9', '8' },
    707     { '9', '9' },
    708     { '9', 'a' },
    709     { '9', 'b' },
    710     { '9', 'c' },
    711     { '9', 'd' },
    712     { '9', 'e' },
    713     { '9', 'f' },
    714     { 'a', '0' },
    715     { 'a', '1' },
    716     { 'a', '2' },
    717     { 'a', '3' },
    718     { 'a', '4' },
    719     { 'a', '5' },
    720     { 'a', '6' },
    721     { 'a', '7' },
    722     { 'a', '8' },
    723     { 'a', '9' },
    724     { 'a', 'a' },
    725     { 'a', 'b' },
    726     { 'a', 'c' },
    727     { 'a', 'd' },
    728     { 'a', 'e' },
    729     { 'a', 'f' },
    730     { 'b', '0' },
    731     { 'b', '1' },
    732     { 'b', '2' },
    733     { 'b', '3' },
    734     { 'b', '4' },
    735     { 'b', '5' },
    736     { 'b', '6' },
    737     { 'b', '7' },
    738     { 'b', '8' },
    739     { 'b', '9' },
    740     { 'b', 'a' },
    741     { 'b', 'b' },
    742     { 'b', 'c' },
    743     { 'b', 'd' },
    744     { 'b', 'e' },
    745     { 'b', 'f' },
    746     { 'c', '0' },
    747     { 'c', '1' },
    748     { 'c', '2' },
    749     { 'c', '3' },
    750     { 'c', '4' },
    751     { 'c', '5' },
    752     { 'c', '6' },
    753     { 'c', '7' },
    754     { 'c', '8' },
    755     { 'c', '9' },
    756     { 'c', 'a' },
    757     { 'c', 'b' },
    758     { 'c', 'c' },
    759     { 'c', 'd' },
    760     { 'c', 'e' },
    761     { 'c', 'f' },
    762     { 'd', '0' },
    763     { 'd', '1' },
    764     { 'd', '2' },
    765     { 'd', '3' },
    766     { 'd', '4' },
    767     { 'd', '5' },
    768     { 'd', '6' },
    769     { 'd', '7' },
    770     { 'd', '8' },
    771     { 'd', '9' },
    772     { 'd', 'a' },
    773     { 'd', 'b' },
    774     { 'd', 'c' },
    775     { 'd', 'd' },
    776     { 'd', 'e' },
    777     { 'd', 'f' },
    778     { 'e', '0' },
    779     { 'e', '1' },
    780     { 'e', '2' },
    781     { 'e', '3' },
    782     { 'e', '4' },
    783     { 'e', '5' },
    784     { 'e', '6' },
    785     { 'e', '7' },
    786     { 'e', '8' },
    787     { 'e', '9' },
    788     { 'e', 'a' },
    789     { 'e', 'b' },
    790     { 'e', 'c' },
    791     { 'e', 'd' },
    792     { 'e', 'e' },
    793     { 'e', 'f' },
    794     { 'f', '0' },
    795     { 'f', '1' },
    796     { 'f', '2' },
    797     { 'f', '3' },
    798     { 'f', '4' },
    799     { 'f', '5' },
    800     { 'f', '6' },
    801     { 'f', '7' },
    802     { 'f', '8' },
    803     { 'f', '9' },
    804     { 'f', 'a' },
    805     { 'f', 'b' },
    806     { 'f', 'c' },
    807     { 'f', 'd' },
    808     { 'f', 'e' },
    809     { 'f', 'f' }
    810 #ifndef NDEBUG
    811     ,
    812     { 0, 0 }
    813 #endif /* ! NDEBUG */
    814   };
    815 
    816   mhd_assert (257u == \
    817               (sizeof(map_uint8_to_two_xdigits) \
    818                / sizeof(map_uint8_to_two_xdigits[0])));
    819 
    820   return map_uint8_to_two_xdigits[v];
    821   /**
    822    * Indicates that function uint8totwoxdigits() is available
    823    */
    824 #define mhd_HAVE_UINT8TOTWOXDIGITS 1
    825 }
    826 
    827 
    828 #endif /* ! MHD_FAVOR_SMALL_CODE */
    829 
    830 
    831 /**
    832  * Caseless compare two characters.
    833  *
    834  * @param c1 the first char to compare
    835  * @param c2 the second char to compare
    836  * @return boolean 'true' if chars are caseless equal, false otherwise
    837  */
    838 mhd_static_inline MHD_FN_CONST_ bool
    839 charsequalcaseless (char c1, char c2)
    840 {
    841   if (c1 == c2)
    842     return true;
    843   /* Fold case on both sides */
    844   c1 = ((char) (~0x20u & (unsigned char) c1));
    845   c2 = ((char) (~0x20u & (unsigned char) c2));
    846   return (c1 == c2) && isasciiupper (c1);
    847 }
    848 
    849 
    850 /**
    851  * Compare mixed case and lower case characters.
    852  *
    853  * @param mc the mixed case char to compare
    854  * @param lc the lower case char to compare
    855  * @return boolean 'true' if chars are caseless equal, false otherwise
    856  */
    857 mhd_static_inline MHD_FN_CONST_ bool
    858 charsequallowercase (char mc, char lc)
    859 {
    860   char uc;
    861   if (mc == lc)
    862     return true;
    863   uc = ((char) (~0x20u & (unsigned char) lc));
    864   return (mc == uc) && isasciiupper (mc);
    865 }
    866 
    867 
    868 #else  /* !HAVE_INLINE_FUNCS */
    869 
    870 
    871 /**
    872  * Checks whether character is lower case letter in US-ASCII
    873  *
    874  * @param c character to check
    875  * @return boolean true if character is lower case letter,
    876  *         boolean false otherwise
    877  */
    878 #  define isasciilower(c) ((((char) (c)) >= 'a') && (((char) (c)) <= 'z'))
    879 
    880 
    881 /**
    882  * Checks whether character is upper case letter in US-ASCII
    883  *
    884  * @param c character to check
    885  * @return boolean true if character is upper case letter,
    886  *         boolean false otherwise
    887  */
    888 #  define isasciiupper(c) ((((char) (c)) <= 'Z') && (((char) (c)) >= 'A'))
    889 
    890 
    891 /**
    892  * Checks whether character is letter in US-ASCII
    893  *
    894  * @param c character to check
    895  * @return boolean true if character is letter, boolean false
    896  *         otherwise
    897  */
    898 #  define isasciialpha(c) (isasciilower (c) || isasciiupper (c))
    899 
    900 
    901 /**
    902  * Check whether character is decimal digit in US-ASCII
    903  *
    904  * @param c character to check
    905  * @return boolean true if character is decimal digit, boolean false
    906  *         otherwise
    907  */
    908 #  define isasciidigit(c) ((((char) (c)) <= '9') && (((char) (c)) >= '0'))
    909 
    910 
    911 /**
    912  * Check whether character is hexadecimal digit in US-ASCII
    913  *
    914  * @param c character to check
    915  * @return boolean true if character is hexadecimal digit,
    916  *         boolean false otherwise
    917  */
    918 #  define isasciixdigit(c) (isasciidigit ((c)) || \
    919                             (((char) (c)) <= 'F' && ((char) (c)) >= 'A') || \
    920                             (((char) (c)) <= 'f' && ((char) (c)) >= 'a'))
    921 
    922 
    923 /**
    924  * Check whether character is decimal digit or letter in US-ASCII
    925  *
    926  * @param c character to check
    927  * @return boolean true if character is decimal digit or letter,
    928  *         boolean false otherwise
    929  */
    930 #  define isasciialnum(c) (isasciialpha (c) || isasciidigit (c))
    931 
    932 
    933 /**
    934  * Convert US-ASCII character to lower case.
    935  * If character is upper case letter in US-ASCII than it's converted to lower
    936  * case analog. If character is NOT upper case letter than it's returned
    937  * unmodified.
    938  *
    939  * @param c character to convert
    940  * @return converted to lower case character
    941  */
    942 #  define toasciilower(c) \
    943         ((isasciiupper (c)) ? (((char) (c)) - 'A' + 'a') : ((char) (c)))
    944 
    945 
    946 /**
    947  * Convert US-ASCII character to upper case.
    948  * If character is lower case letter in US-ASCII than it's converted to upper
    949  * case analog. If character is NOT lower case letter than it's returned
    950  * unmodified.
    951  *
    952  * @param c character to convert
    953  * @return converted to upper case character
    954  */
    955 #  define toasciiupper(c) ((isasciilower (c)) ? (((char) (c)) - 'a' + 'A') : \
    956                            ((char) (c)))
    957 
    958 
    959 /**
    960  * Convert US-ASCII decimal digit to its value.
    961  *
    962  * @param c character to convert
    963  * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
    964  */
    965 #  define todigitvalue(c) (isasciidigit (c) ? (int) (((char) (c)) - '0') : \
    966                            (int) (-1))
    967 
    968 
    969 /**
    970  * Convert US-ASCII hexadecimal digit to its value.
    971  * @param c character to convert
    972  * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
    973  */
    974 #  define xdigittovalue(c) (isasciidigit (c) ? (int) (((char) (c)) - '0') : \
    975                             ( (((char) (c)) >= 'A' && ((char) (c)) <= 'F') ? \
    976                               (int) (((unsigned char) (c)) - 'A' + 10) : \
    977                               ( (((char) (c)) >= 'a' && ((char) (c)) <= 'f') ? \
    978                                 (int) (((unsigned char) (c)) - 'a' + 10) : \
    979                                 (int) (-1) )))
    980 
    981 
    982 #if ! defined(MHD_FAVOR_SMALL_CODE)
    983 static const char map_value_to_xdigit[16] =
    984 { '0', '1', '2', '3', '4', '5', '6', '7',
    985   '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
    986 
    987 /**
    988  * Convert 4 bit value to US-ASCII hexadecimal digit.
    989  *
    990  * @param v the value to convert, must be less then 16
    991  * @return hexadecimal digit
    992  */
    993 #    define valuetoxdigit(v) map_value_to_xdigit[v]
    994 #else  /* MHD_FAVOR_SMALL_CODE */
    995 /**
    996  * Convert 4 bit value to US-ASCII hexadecimal digit.
    997  *
    998  * @param v the value to convert, must be less then 16
    999  * @return hexadecimal digit
   1000  */
   1001  #    define valuetoxdigit(v) \
   1002          (char) ((v <= 9) ? ('0' + (char) v) : ('a' + (char) v - 10))
   1003 #endif /* MHD_FAVOR_SMALL_CODE */
   1004 
   1005 /**
   1006  * Caseless compare two characters.
   1007  *
   1008  * @param c1 the first char to compare
   1009  * @param c2 the second char to compare
   1010  * @return boolean 'true' if chars are caseless equal, false otherwise
   1011  */
   1012 #define charsequalcaseless(c1, c2) \
   1013         (((c1) == (c2)) || \
   1014          (((0x20u | (unsigned char) (c1)) == (0x20u | (unsigned char) (c2))) \
   1015           && isasciilower (((char) (0x20u | (unsigned char) (c2))))) )
   1016 
   1017 /**
   1018   * Compare mixed case and lower case characters.
   1019   *
   1020   * @param mc the mixed case char to compare
   1021   * @param lc the lower case char to compare
   1022   * @return boolean 'true' if chars are caseless equal, false otherwise
   1023   */
   1024 #define charsequallowercase(mc,lc) \
   1025         ( ((mc) == (lc)) || \
   1026           (((0x20u | (unsigned char) (mc)) == ((unsigned char) (lc))) && \
   1027            isasciilower (lc)) )
   1028 #endif /* !HAVE_INLINE_FUNCS */
   1029 
   1030 
   1031 #ifndef MHD_FAVOR_SMALL_CODE
   1032 MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
   1033 MHD_FN_PAR_CSTR_ (1) MHD_FN_PAR_CSTR_ (2) bool
   1034 mhd_str_equal_caseless (const char *str1,
   1035                         const char *str2)
   1036 {
   1037   while (0 != (*str1))
   1038   {
   1039     const char c1 = *str1;
   1040     const char c2 = *str2;
   1041     if (charsequalcaseless (c1, c2))
   1042     {
   1043       str1++;
   1044       str2++;
   1045     }
   1046     else
   1047       return false;
   1048   }
   1049   return 0 == (*str2);
   1050 }
   1051 
   1052 
   1053 #endif /* ! MHD_FAVOR_SMALL_CODE */
   1054 
   1055 
   1056 MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
   1057 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) bool
   1058 mhd_str_equal_caseless_n (const char *const str1,
   1059                           const char *const str2,
   1060                           size_t maxlen)
   1061 {
   1062   size_t i;
   1063 
   1064   for (i = 0; i < maxlen; ++i)
   1065   {
   1066     const char c1 = str1[i];
   1067     const char c2 = str2[i];
   1068     if (0 == c2)
   1069       return 0 == c1;
   1070     if (charsequalcaseless (c1, c2))
   1071       continue;
   1072     else
   1073       return false;
   1074   }
   1075   return true;
   1076 }
   1077 
   1078 
   1079 MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
   1080 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) bool
   1081 mhd_str_equal_caseless_bin_n (const char *const str1,
   1082                               const char *const str2,
   1083                               size_t len)
   1084 {
   1085   size_t i;
   1086 
   1087   for (i = 0; i < len; ++i)
   1088   {
   1089     const char c1 = str1[i];
   1090     const char c2 = str2[i];
   1091     if (charsequalcaseless (c1, c2))
   1092       continue;
   1093     else
   1094       return 0;
   1095   }
   1096   return ! 0;
   1097 }
   1098 
   1099 
   1100 MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
   1101 MHD_FN_PAR_IN_ (1)
   1102 MHD_FN_PAR_IN_ (2) bool
   1103 mhd_str_equal_lowercase_bin_n (const char *const mixstr,
   1104                                const char *const lowstr,
   1105                                size_t len)
   1106 {
   1107   size_t i;
   1108 
   1109   for (i = 0; i < len; ++i)
   1110   {
   1111     const char mc = mixstr[i];
   1112     const char lc = lowstr[i];
   1113     mhd_assert (! isasciiupper (lc));
   1114     if (! charsequallowercase (mc, lc))
   1115       return false;
   1116   }
   1117   return true;
   1118 }
   1119 
   1120 
   1121 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1122 MHD_FN_PAR_IN_SIZE_ (2,1)
   1123 MHD_FN_PAR_OUT_SIZE_ (3,1) void
   1124 mhd_str_to_lowercase_bin_n (size_t size,
   1125                             const char *restrict inbuff,
   1126                             char *restrict outbuff)
   1127 {
   1128   size_t i;
   1129 
   1130   for (i = 0; i < size; ++i)
   1131     outbuff[i] = toasciilower (inbuff[i]);
   1132 }
   1133 
   1134 
   1135 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1136 MHD_FN_PAR_IN_SIZE_ (2,1) bool
   1137 mhd_str_is_lowercase_bin_n (size_t len,
   1138                             const char *restrict str)
   1139 {
   1140   size_t i;
   1141 
   1142   for (i = 0; i < len; ++i)
   1143     if (isasciiupper (str[i]))
   1144       return false;
   1145 
   1146   return true;
   1147 }
   1148 
   1149 
   1150 #ifdef mhd_HAVE_STR_TO_UPPER
   1151 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1152 MHD_FN_PAR_IN_SIZE_ (2,1)
   1153 MHD_FN_PAR_OUT_SIZE_ (3,1) void
   1154 mhd_str_to_uppercase_bin_n (size_t size,
   1155                             const char *restrict inbuff,
   1156                             char *restrict outbuff)
   1157 {
   1158   size_t i;
   1159 
   1160   for (i = 0; i < size; ++i)
   1161     outbuff[i] = toasciiupper (inbuff[i]);
   1162 }
   1163 
   1164 
   1165 #endif /* mhd_HAVE_STR_TO_UPPER */
   1166 
   1167 
   1168 MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
   1169 MHD_FN_PAR_CSTR_ (1)
   1170 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) bool
   1171 mhd_str_has_token_caseless (const char *restrict str,
   1172                             const char *const restrict token,
   1173                             size_t token_len)
   1174 {
   1175   if (0 == token_len)
   1176     return false;
   1177 
   1178   while (0 != *str)
   1179   {
   1180     size_t i;
   1181     /* Skip all whitespaces and empty tokens. */
   1182     while (' ' == *str || '\t' == *str || ',' == *str)
   1183       str++;
   1184 
   1185     /* Check for token match. */
   1186     i = 0;
   1187     while (1)
   1188     {
   1189       const char sc = *(str++);
   1190       const char tc = token[i++];
   1191 
   1192       if (0 == sc)
   1193         return false;
   1194       if (! charsequalcaseless (sc, tc))
   1195         break;
   1196       if (i >= token_len)
   1197       {
   1198         /* Check whether substring match token fully or
   1199          * has additional unmatched chars at tail. */
   1200         while (' ' == *str || '\t' == *str)
   1201           str++;
   1202         /* End of (sub)string? */
   1203         if ((0 == *str) || (',' == *str) )
   1204           return true;
   1205         /* Unmatched chars at end of substring. */
   1206         break;
   1207       }
   1208     }
   1209     /* Find next substring. */
   1210     while (0 != *str && ',' != *str)
   1211       str++;
   1212   }
   1213   return false;
   1214 }
   1215 
   1216 
   1217 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1218 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4)
   1219 MHD_FN_PAR_OUT_ (5) MHD_FN_PAR_INOUT_ (6) bool
   1220 mhd_str_remove_token_caseless (const char *restrict str,
   1221                                size_t str_len,
   1222                                const char *const restrict token,
   1223                                const size_t token_len,
   1224                                char *restrict buf,
   1225                                ssize_t *restrict buf_size)
   1226 {
   1227   const char *s1; /**< the "input" string / character */
   1228   char *s2;       /**< the "output" string / character */
   1229   size_t t_pos;   /**< position of matched character in the token */
   1230   bool token_removed;
   1231 
   1232   mhd_assert (NULL == memchr (token, 0, token_len));
   1233   mhd_assert (NULL == memchr (token, ' ', token_len));
   1234   mhd_assert (NULL == memchr (token, '\t', token_len));
   1235   mhd_assert (NULL == memchr (token, ',', token_len));
   1236   mhd_assert (0 <= *buf_size);
   1237 
   1238   if (SSIZE_MAX <= ((str_len / 2) * 3 + 3))
   1239   {
   1240     /* The return value may overflow, refuse */
   1241     *buf_size = (ssize_t) -1;
   1242     return false;
   1243   }
   1244   s1 = str;
   1245   s2 = buf;
   1246   token_removed = false;
   1247 
   1248   while ((size_t) (s1 - str) < str_len)
   1249   {
   1250     const char *cur_token; /**< the first char of current token */
   1251     size_t copy_size;
   1252 
   1253     /* Skip any initial whitespaces and empty tokens */
   1254     while ( ((size_t) (s1 - str) < str_len) &&
   1255             ((' ' == *s1) || ('\t' == *s1) || (',' == *s1)) )
   1256       s1++;
   1257 
   1258     /* 's1' points to the first char of token in the input string or
   1259      * points just beyond the end of the input string */
   1260 
   1261     if ((size_t) (s1 - str) >= str_len)
   1262       break; /* Nothing to copy, end of the input string */
   1263 
   1264     /* 's1' points to the first char of token in the input string */
   1265 
   1266     cur_token = s1; /* the first char of input token */
   1267 
   1268     /* Check the token with case-insensetive match */
   1269     t_pos = 0;
   1270     while ( ((size_t) (s1 - str) < str_len) && (token_len > t_pos) &&
   1271             (charsequalcaseless (*s1, token[t_pos])) )
   1272     {
   1273       s1++;
   1274       t_pos++;
   1275     }
   1276     /* s1 may point just beyond the end of the input string */
   1277     if ( (token_len == t_pos) && (0 != token_len) )
   1278     {
   1279       /* 'token' matched, check that current input token does not have
   1280        * any suffixes */
   1281       while ( ((size_t) (s1 - str) < str_len) &&
   1282               ((' ' == *s1) || ('\t' == *s1)) )
   1283         s1++;
   1284       /* 's1' points to the first non-whitespace char after the token matched
   1285        * requested token or points just beyond the end of the input string after
   1286        * the requested token */
   1287       if (((size_t) (s1 - str) == str_len) || (',' == *s1))
   1288       {/* full token match, do not copy current token to the output */
   1289         token_removed = true;
   1290         continue;
   1291       }
   1292     }
   1293 
   1294     /* 's1' points to first non-whitespace char, to some char after
   1295      * first non-whitespace char in the token in the input string, to
   1296      * the ',', or just beyond the end of the input string */
   1297     /* The current token in the input string does not match the token
   1298      * to exclude, it must be copied to the output string */
   1299     /* the current token size excluding leading whitespaces and current char */
   1300     copy_size = (size_t) (s1 - cur_token);
   1301     if (buf == s2)
   1302     { /* The first token to copy to the output */
   1303       if ((size_t) *buf_size < copy_size)
   1304       { /* Not enough space in the output buffer */
   1305         *buf_size = (ssize_t) -1;
   1306         return false;
   1307       }
   1308     }
   1309     else
   1310     { /* Some token was already copied to the output buffer */
   1311       mhd_assert (s2 > buf);
   1312       if ((size_t) *buf_size < ((size_t) (s2 - buf)) + copy_size + 2)
   1313       { /* Not enough space in the output buffer */
   1314         *buf_size = (ssize_t) -1;
   1315         return false;
   1316       }
   1317       *(s2++) = ',';
   1318       *(s2++) = ' ';
   1319     }
   1320     /* Copy non-matched token to the output */
   1321     if (0 != copy_size)
   1322     {
   1323       memcpy (s2, cur_token, copy_size);
   1324       s2 += copy_size;
   1325     }
   1326 
   1327     while ( ((size_t) (s1 - str) < str_len) && (',' != *s1))
   1328     {
   1329       /* 's1' points to first non-whitespace char, to some char after
   1330        * first non-whitespace char in the token in the input string */
   1331       /* Copy all non-whitespace chars from the current token in
   1332        * the input string */
   1333       while ( ((size_t) (s1 - str) < str_len) &&
   1334               (',' != *s1) && (' ' != *s1) && ('\t' != *s1) )
   1335       {
   1336         mhd_assert (s2 >= buf);
   1337         if ((size_t) *buf_size <= (size_t) (s2 - buf)) /* '<= s2' equals '< s2 + 1' */
   1338         { /* Not enough space in the output buffer */
   1339           *buf_size = (ssize_t) -1;
   1340           return false;
   1341         }
   1342         *(s2++) = *(s1++);
   1343       }
   1344       /* 's1' points to some whitespace char in the token in the input
   1345        * string, to the ',', or just beyond the end of the input string */
   1346       /* Skip all whitespaces */
   1347       while ( ((size_t) (s1 - str) < str_len) &&
   1348               ((' ' == *s1) || ('\t' == *s1)) )
   1349         s1++;
   1350 
   1351       /* 's1' points to the first non-whitespace char in the input string
   1352        * after whitespace chars, to the ',', or just beyond the end of
   1353        * the input string */
   1354       if (((size_t) (s1 - str) < str_len) && (',' != *s1))
   1355       { /* Not the end of the current token */
   1356         mhd_assert (s2 >= buf);
   1357         if ((size_t) *buf_size <= (size_t) (s2 - buf)) /* '<= s2' equals '< s2 + 1' */
   1358         { /* Not enough space in the output buffer */
   1359           *buf_size = (ssize_t) -1;
   1360           return false;
   1361         }
   1362         *(s2++) = ' ';
   1363       }
   1364     }
   1365   }
   1366   mhd_assert (((ssize_t) (s2 - buf)) <= *buf_size);
   1367   *buf_size = (ssize_t) (s2 - buf);
   1368   return token_removed;
   1369 }
   1370 
   1371 
   1372 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1373 MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_INOUT_ (2)
   1374 MHD_FN_PAR_IN_SIZE_ (3,4) bool
   1375 mhd_str_remove_tokens_caseless (char *restrict str,
   1376                                 size_t *restrict str_len,
   1377                                 const char *const restrict tkns,
   1378                                 const size_t tkns_len)
   1379 {
   1380   size_t pt;                      /**< position in @a tokens */
   1381   bool token_removed;
   1382 
   1383   mhd_assert (NULL == memchr (tkns, 0, tkns_len));
   1384 
   1385   token_removed = false;
   1386   pt = 0;
   1387 
   1388   while (pt < tkns_len && *str_len != 0)
   1389   {
   1390     const char *tkn; /**< the current token */
   1391     size_t tkn_len;
   1392 
   1393     /* Skip any initial whitespaces and empty tokens in 'tokens' */
   1394     while ( (pt < tkns_len) &&
   1395             ((' ' == tkns[pt]) || ('\t' == tkns[pt]) || (',' == tkns[pt])) )
   1396       pt++;
   1397 
   1398     if (pt >= tkns_len)
   1399       break; /* No more tokens, nothing to remove */
   1400 
   1401     /* Found non-whitespace char which is not a comma */
   1402     tkn = tkns + pt;
   1403     do
   1404     {
   1405       do
   1406       {
   1407         pt++;
   1408       } while (pt < tkns_len &&
   1409                (' ' != tkns[pt] && '\t' != tkns[pt] && ',' != tkns[pt]));
   1410       /* Found end of the token string, space, tab, or comma */
   1411       tkn_len = pt - (size_t) (tkn - tkns);
   1412 
   1413       /* Skip all spaces and tabs */
   1414       while (pt < tkns_len && (' ' == tkns[pt] || '\t' == tkns[pt]))
   1415         pt++;
   1416       /* Found end of the token string or non-whitespace char */
   1417     } while (pt < tkns_len && ',' != tkns[pt]);
   1418 
   1419     /* 'tkn' is the input token with 'tkn_len' chars */
   1420     mhd_assert (0 != tkn_len);
   1421 
   1422     if (*str_len == tkn_len)
   1423     {
   1424       if (mhd_str_equal_caseless_bin_n (str, tkn, tkn_len))
   1425       {
   1426         *str_len = 0;
   1427         token_removed = true;
   1428       }
   1429       continue;
   1430     }
   1431     /* 'tkn' cannot match part of 'str' if length of 'tkn' is larger
   1432      * than length of 'str'.
   1433      * It's know that 'tkn' is not equal to the 'str' (was checked previously).
   1434      * As 'str' is normalized when 'tkn' is not equal to the 'str'
   1435      * it is required that 'str' to be at least 3 chars larger then 'tkn'
   1436      * (the comma, the space and at least one additional character for the next
   1437      * token) to remove 'tkn' from the 'str'. */
   1438     if (*str_len > tkn_len + 2)
   1439     { /* Remove 'tkn' from the input string */
   1440       size_t pr;    /**< the 'read' position in the @a str */
   1441       size_t pw;    /**< the 'write' position in the @a str */
   1442 
   1443       pr = 0;
   1444       pw = 0;
   1445 
   1446       do
   1447       {
   1448         mhd_assert (pr >= pw);
   1449         mhd_assert ((*str_len) >= (pr + tkn_len));
   1450         if ( ( ((*str_len) == (pr + tkn_len)) || (',' == str[pr + tkn_len]) ) &&
   1451              mhd_str_equal_caseless_bin_n (str + pr, tkn, tkn_len) )
   1452         {
   1453           /* current token in the input string matches the 'tkn', skip it */
   1454           mhd_assert ((*str_len == pr + tkn_len) || \
   1455                       (' ' == str[pr + tkn_len + 1])); /* 'str' must be normalized */
   1456           token_removed = true;
   1457           /* Advance to the next token in the input string or beyond
   1458            * the end of the input string. */
   1459           pr += tkn_len + 2;
   1460         }
   1461         else
   1462         {
   1463           /* current token in the input string does not match the 'tkn',
   1464            * copy to the output */
   1465           if (0 != pw)
   1466           { /* not the first output token, add ", " to separate */
   1467             if (pr != pw + 2)
   1468             {
   1469               str[pw++] = ',';
   1470               str[pw++] = ' ';
   1471             }
   1472             else
   1473               pw += 2; /* 'str' is not yet modified in this round */
   1474           }
   1475           do
   1476           {
   1477             if (pr != pw)
   1478               str[pw] = str[pr];
   1479             pr++;
   1480             pw++;
   1481           } while (pr < *str_len && ',' != str[pr]);
   1482           /* Advance to the next token in the input string or beyond
   1483            * the end of the input string. */
   1484           pr += 2;
   1485         }
   1486         /* 'pr' should point to the next token in the input string or beyond
   1487          * the end of the input string */
   1488         if ((*str_len) < (pr + tkn_len))
   1489         { /* The rest of the 'str + pr' is too small to match 'tkn' */
   1490           if ((*str_len) > pr)
   1491           { /* Copy the rest of the string */
   1492             size_t copy_size;
   1493             copy_size = *str_len - pr;
   1494             if (0 != pw)
   1495             { /* not the first output token, add ", " to separate */
   1496               if (pr != pw + 2)
   1497               {
   1498                 str[pw++] = ',';
   1499                 str[pw++] = ' ';
   1500               }
   1501               else
   1502                 pw += 2; /* 'str' is not yet modified in this round */
   1503             }
   1504             if (pr != pw)
   1505               memmove (str + pw, str + pr, copy_size);
   1506             pw += copy_size;
   1507           }
   1508           *str_len = pw;
   1509           break;
   1510         }
   1511         mhd_assert ((' ' != str[0]) && ('\t' != str[0]));
   1512         mhd_assert ((0 == pr) || (3 <= pr));
   1513         mhd_assert ((0 == pr) || (' ' == str[pr - 1]));
   1514         mhd_assert ((0 == pr) || (',' == str[pr - 2]));
   1515       } while (1);
   1516     }
   1517   }
   1518 
   1519   return token_removed;
   1520 }
   1521 
   1522 
   1523 #ifndef MHD_FAVOR_SMALL_CODE
   1524 /* Use individual function for each case */
   1525 
   1526 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1527 MHD_FN_PAR_CSTR_ (1) MHD_FN_PAR_IN_ (1)
   1528 MHD_FN_PAR_OUT_ (2) size_t
   1529 mhd_str_to_uint64 (const char *restrict str,
   1530                    uint_fast64_t *restrict out_val)
   1531 {
   1532   const char *const start = str;
   1533   uint_fast64_t res;
   1534 
   1535   if (! isasciidigit (str[0]))
   1536     return 0;
   1537 
   1538   res = 0;
   1539   do
   1540   {
   1541     const int digit = (unsigned char) (*str) - '0';
   1542     uint_fast64_t prev_res = res;
   1543 
   1544     res *= 10;
   1545     if (res / 10 != prev_res)
   1546       return 0;
   1547     res += (unsigned int) digit;
   1548     if (res < (unsigned int) digit)
   1549       return 0;
   1550 
   1551     str++;
   1552   } while (isasciidigit (*str));
   1553 
   1554   *out_val = res;
   1555   return (size_t) (str - start);
   1556 }
   1557 
   1558 
   1559 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1560 MHD_FN_PAR_IN_SIZE_ (1,2)
   1561 MHD_FN_PAR_OUT_ (3) size_t
   1562 mhd_str_to_uint64_n (const char *restrict str,
   1563                      size_t maxlen,
   1564                      uint_fast64_t *restrict out_val)
   1565 {
   1566   uint_fast64_t res;
   1567   size_t i;
   1568 
   1569   if (! maxlen || ! isasciidigit (str[0]))
   1570     return 0;
   1571 
   1572   res = 0;
   1573   i = 0;
   1574   do
   1575   {
   1576     const int digit = (unsigned char) str[i] - '0';
   1577     uint_fast64_t prev_res = res;
   1578 
   1579     res *= 10;
   1580     if (res / 10 != prev_res)
   1581       return 0;
   1582     res += (unsigned int) digit;
   1583     if (res < (unsigned int) digit)
   1584       return 0;
   1585     i++;
   1586   } while ( (i < maxlen) &&
   1587             isasciidigit (str[i]) );
   1588 
   1589   *out_val = res;
   1590   return i;
   1591 }
   1592 
   1593 
   1594 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1595 MHD_FN_PAR_CSTR_ (1)
   1596 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_OUT_ (2) size_t
   1597 mhd_strx_to_uint32 (const char *restrict str,
   1598                     uint_fast32_t *restrict out_val)
   1599 {
   1600   const char *const start = str;
   1601   uint_fast32_t res;
   1602   int digit;
   1603 
   1604   res = 0;
   1605   digit = xdigittovalue (*str);
   1606   while (digit >= 0)
   1607   {
   1608     uint_fast32_t prev_res = res;
   1609 
   1610     res *= 16;
   1611     if (res / 16 != prev_res)
   1612       return 0;
   1613     res += (unsigned int) digit;
   1614     if (res < (unsigned int) digit)
   1615       return 0;
   1616 
   1617     str++;
   1618     digit = xdigittovalue (*str);
   1619   }
   1620 
   1621   if (str - start > 0)
   1622     *out_val = res;
   1623   return (size_t) (str - start);
   1624 }
   1625 
   1626 
   1627 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1628 MHD_FN_PAR_IN_SIZE_ (1,2)
   1629 MHD_FN_PAR_OUT_ (3) size_t
   1630 mhd_strx_to_uint32_n (const char *restrict str,
   1631                       size_t maxlen,
   1632                       uint_fast32_t *restrict out_val)
   1633 {
   1634   size_t i;
   1635   uint_fast32_t res;
   1636 
   1637   res = 0;
   1638   i = 0;
   1639   while (i < maxlen)
   1640   {
   1641     const int digit = xdigittovalue (str[i]);
   1642     uint_fast32_t prev_res = res;
   1643 
   1644     if (0 > digit)
   1645       break;
   1646 
   1647     res *= 16;
   1648     if (res / 16 != prev_res)
   1649       return 0;
   1650     res += (uint_fast32_t) digit;
   1651     if (res < (uint_fast32_t) digit)
   1652       return 0;
   1653 
   1654     i++;
   1655   }
   1656 
   1657   if (0 != i)
   1658     *out_val = res;
   1659   return i;
   1660 }
   1661 
   1662 
   1663 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1664 MHD_FN_PAR_CSTR_ (1)
   1665 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_OUT_ (2) size_t
   1666 mhd_strx_to_uint64 (const char *restrict str,
   1667                     uint_fast64_t *restrict out_val)
   1668 {
   1669   const char *const start = str;
   1670   uint_fast64_t res;
   1671   int digit;
   1672 
   1673   res = 0;
   1674   digit = xdigittovalue (*str);
   1675   while (digit >= 0)
   1676   {
   1677     uint_fast64_t prev_res = res;
   1678 
   1679     res *= 16;
   1680     if (res / 16 != prev_res)
   1681       return 0;
   1682     res += (unsigned int) digit;
   1683     if (res < (unsigned int) digit)
   1684       return 0;
   1685 
   1686     str++;
   1687     digit = xdigittovalue (*str);
   1688   }
   1689 
   1690   if (str - start > 0)
   1691     *out_val = res;
   1692   return (size_t) (str - start);
   1693 }
   1694 
   1695 
   1696 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1697 MHD_FN_PAR_IN_SIZE_ (1,2)
   1698 MHD_FN_PAR_OUT_ (3) size_t
   1699 mhd_strx_to_uint64_n (const char *restrict str,
   1700                       size_t maxlen,
   1701                       uint_fast64_t *restrict out_val)
   1702 {
   1703   size_t i;
   1704   uint_fast64_t res;
   1705 
   1706   res = 0;
   1707   i = 0;
   1708   while (i < maxlen)
   1709   {
   1710     const int digit = xdigittovalue (str[i]);
   1711     uint_fast64_t prev_res = res;
   1712 
   1713     if (0 > digit)
   1714       break;
   1715 
   1716     res *= 16;
   1717     if (res / 16 != prev_res)
   1718       return 0;
   1719     res += (unsigned int) digit;
   1720     if (res < (unsigned int) digit)
   1721       return 0;
   1722     i++;
   1723   }
   1724 
   1725   if (0 != i)
   1726     *out_val = res;
   1727   return i;
   1728 }
   1729 
   1730 
   1731 #else  /* MHD_FAVOR_SMALL_CODE */
   1732 
   1733 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1734 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
   1735 mhd_str_to_uvalue_n (const char *restrict str,
   1736                      size_t maxlen,
   1737                      void *restrict out_val,
   1738                      size_t val_size,
   1739                      uint_fast64_t max_val,
   1740                      unsigned int base)
   1741 {
   1742   size_t i;
   1743   uint_fast64_t res;
   1744   const uint_fast64_t max_v_div_b = max_val / base;
   1745   const uint_fast64_t max_v_mod_b = max_val % base;
   1746 
   1747   if ((base != 16) && (base != 10))
   1748     return 0;
   1749 
   1750   res = 0;
   1751   i = 0;
   1752   while (maxlen > i)
   1753   {
   1754     const int digit = (base == 16) ?
   1755                       xdigittovalue (str[i]) : todigitvalue (str[i]);
   1756 
   1757     if (0 > digit)
   1758       break;
   1759     if ( ((max_v_div_b) < res) ||
   1760          (( (max_v_div_b) == res) &&
   1761           ( (max_v_mod_b) < (uint_fast64_t) digit) ) )
   1762       return 0;
   1763 
   1764     res *= base;
   1765     res += (unsigned int) digit;
   1766     i++;
   1767   }
   1768 
   1769   if (i)
   1770   {
   1771     if (8 == val_size)
   1772       *(uint_fast64_t *) out_val = res;
   1773     else if (4 == val_size)
   1774       *(uint_fast32_t *) out_val = (uint_fast32_t) res;
   1775     else
   1776       return 0;
   1777   }
   1778   return i;
   1779 }
   1780 
   1781 
   1782 #endif /* MHD_FAVOR_SMALL_CODE */
   1783 
   1784 
   1785 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1786 MHD_FN_PAR_OUT_SIZE_ (2,3) size_t
   1787 mhd_uint32_to_strx (uint_fast32_t val,
   1788                     char *buf,
   1789                     size_t buf_size)
   1790 {
   1791   size_t o_pos = 0; /**< position of the output character */
   1792   int digit_pos = 8; /** zero-based, digit position in @a 'val' */
   1793   uint_least32_t val32 = ((uint_least32_t) val) & 0xFFFFFFFFu;
   1794   unsigned int xdigit;
   1795 
   1796   /* Skip leading zeros */
   1797   do
   1798   {
   1799     digit_pos--;
   1800     xdigit = (unsigned int) (val32 >> 28);
   1801     val32 <<= 4;
   1802     val32 &= 0xFFFFFFFFu;
   1803   } while ((0 == xdigit) && (0 != digit_pos));
   1804 
   1805   while (o_pos < buf_size)
   1806   {
   1807     buf[o_pos++] = valuetoxdigit (xdigit);
   1808     if (0 == digit_pos)
   1809       return o_pos;
   1810     digit_pos--;
   1811     xdigit = (unsigned int) (val32 >> 28);
   1812     val32 <<= 4;
   1813     val32 &= 0xFFFFFFFFu;
   1814   }
   1815   return 0; /* The buffer is too small */
   1816 }
   1817 
   1818 
   1819 #ifndef MHD_FAVOR_SMALL_CODE
   1820 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1821 MHD_FN_PAR_OUT_SIZE_ (2,3) size_t
   1822 mhd_uint16_to_str (uint_least16_t val,
   1823                    char *buf,
   1824                    size_t buf_size)
   1825 {
   1826   char *chr;  /**< pointer to the current printed digit */
   1827   /* The biggest printable number is 65535 */
   1828   uint_least16_t divisor = UINT16_C (10000);
   1829   int digit;
   1830 
   1831   val &= 0xFFFFu;
   1832   chr = buf;
   1833   digit = (int) (val / divisor);
   1834   mhd_assert (digit < 10);
   1835 
   1836   /* Do not print leading zeros */
   1837   while ((0 == digit) && (1 < divisor))
   1838   {
   1839     divisor /= 10;
   1840     digit = (int) (val / divisor);
   1841     mhd_assert (digit < 10);
   1842   }
   1843 
   1844   while (0 != buf_size)
   1845   {
   1846     *chr = (char) ((char) digit + '0');
   1847     chr++;
   1848     buf_size--;
   1849     if (1 == divisor)
   1850       return (size_t) (chr - buf);
   1851     val = (uint_least16_t) (val % divisor);
   1852     divisor /= 10;
   1853     digit = (int) (val / divisor);
   1854     mhd_assert (digit < 10);
   1855   }
   1856   return 0; /* The buffer is too small */
   1857 }
   1858 
   1859 
   1860 #endif /* !MHD_FAVOR_SMALL_CODE */
   1861 
   1862 
   1863 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1864 MHD_FN_PAR_OUT_SIZE_ (2,3) size_t
   1865 mhd_uint64_to_str (uint_fast64_t val,
   1866                    char *buf,
   1867                    size_t buf_size)
   1868 {
   1869   char *chr;  /**< pointer to the current printed digit */
   1870   /* The biggest printable number is 18446744073709551615 */
   1871   uint_fast64_t divisor = (uint_fast64_t) 10000000000000000000U;
   1872   int digit;
   1873 
   1874   val &= 0xFFFFFFFFFFFFFFFFu;
   1875   chr = buf;
   1876   digit = (int) (val / divisor);
   1877   mhd_assert (digit < 10);
   1878 
   1879   /* Do not print leading zeros */
   1880   while ((0 == digit) && (1 < divisor))
   1881   {
   1882     divisor /= 10;
   1883     digit = (int) (val / divisor);
   1884     mhd_assert (digit < 10);
   1885   }
   1886 
   1887   while (0 != buf_size)
   1888   {
   1889     *chr = (char) ((char) digit + '0');
   1890     chr++;
   1891     buf_size--;
   1892     if (1 == divisor)
   1893       return (size_t) (chr - buf);
   1894     val %= divisor;
   1895     divisor /= 10;
   1896     digit = (int) (val / divisor);
   1897     mhd_assert (digit < 10);
   1898   }
   1899   return 0; /* The buffer is too small */
   1900 }
   1901 
   1902 
   1903 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1904 MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
   1905 mhd_uint8_to_str_pad (uint8_t val,
   1906                       uint8_t min_digits,
   1907                       char *buf,
   1908                       size_t buf_size)
   1909 {
   1910   size_t pos; /**< the position of the current printed digit */
   1911   int digit;
   1912   mhd_assert (3 >= min_digits);
   1913 
   1914   if (0u == buf_size)
   1915     return 0u;
   1916 
   1917   pos = 0;
   1918   digit = val / 100;
   1919   if (0 == digit)
   1920   {
   1921     if (3 <= min_digits)
   1922       buf[pos++] = '0';
   1923   }
   1924   else
   1925   {
   1926     buf[pos++] = (char) ('0' + (char) digit);
   1927     val %= 100;
   1928     min_digits = 2;
   1929   }
   1930 
   1931   if (buf_size <= pos)
   1932     return 0;
   1933   digit = val / 10;
   1934   if (0 == digit)
   1935   {
   1936     if (2 <= min_digits)
   1937       buf[pos++] = '0';
   1938   }
   1939   else
   1940   {
   1941     buf[pos++] = (char) ('0' + (char) digit);
   1942     val %= 10;
   1943   }
   1944 
   1945   if (buf_size <= pos)
   1946     return 0;
   1947   buf[pos++] = (char) ('0' + (char) val);
   1948   return pos;
   1949 }
   1950 
   1951 
   1952 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1953 MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3) size_t
   1954 mhd_bin_to_hex (const void *restrict bin,
   1955                 size_t size,
   1956                 char *restrict hex)
   1957 {
   1958   size_t i;
   1959 
   1960   for (i = 0; i < size; ++i)
   1961   {
   1962     const uint8_t b = ((const uint8_t *) bin)[i];
   1963 #ifdef mhd_HAVE_UINT8TOTWOXDIGITS
   1964     const char *two_xdigits = uint8totwoxdigits (b);
   1965     hex[i * 2] = two_xdigits[0];
   1966     hex[i * 2 + 1] = two_xdigits[1];
   1967 #else  /* ! mhd_HAVE_UINT8TOTWOXDIGITS */
   1968     hex[i * 2] = valuetoxdigit (b >> 4);
   1969     hex[i * 2 + 1] = valuetoxdigit (b & 0x0Fu);
   1970 #endif /* ! mhd_HAVE_UINT8TOTWOXDIGITS */
   1971   }
   1972   return i * 2;
   1973 }
   1974 
   1975 
   1976 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1977 MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3) size_t
   1978 mhd_bin_to_hex_z (const void *restrict bin,
   1979                   size_t size,
   1980                   char *restrict hex)
   1981 {
   1982   size_t res;
   1983 
   1984   res = mhd_bin_to_hex (bin, size, hex);
   1985   hex[res] = 0;
   1986 
   1987   return res;
   1988 }
   1989 
   1990 
   1991 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1992 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3) size_t
   1993 mhd_hex_to_bin (const char *restrict hex,
   1994                 size_t len,
   1995                 void *restrict bin)
   1996 {
   1997   size_t r;
   1998   size_t w;
   1999 
   2000   r = 0;
   2001   w = 0;
   2002   if (0 != len % 2)
   2003   {
   2004     /* Assume the first byte is encoded with single digit */
   2005     const char c2 = hex[r++];
   2006     const int l = xdigittovalue (c2);
   2007     if (0 > l)
   2008       return 0;
   2009     ((uint8_t *) bin)[w++] = (uint8_t) ((unsigned int) l);
   2010   }
   2011   while (r < len)
   2012   {
   2013     const char c1 = hex[r++];
   2014     const char c2 = hex[r++];
   2015     const int h = xdigittovalue (c1);
   2016     const int l = xdigittovalue (c2);
   2017     if ((0 > h) || (0 > l))
   2018       return 0;
   2019     ((uint8_t *) bin)[w++] =
   2020       (uint8_t) ( ((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2021                   | ((uint8_t) ((unsigned int) l)) );
   2022   }
   2023   mhd_assert (len == r);
   2024   mhd_assert ((len + 1) / 2 == w);
   2025   return w;
   2026 }
   2027 
   2028 
   2029 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   2030 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
   2031 mhd_str_pct_decode_strict_n (const char *pct_encoded,
   2032                              size_t pct_encoded_len,
   2033                              char *decoded,
   2034                              size_t buf_size)
   2035 {
   2036 #ifdef MHD_FAVOR_SMALL_CODE
   2037   bool broken;
   2038   size_t res;
   2039 
   2040   res = mhd_str_pct_decode_lenient_n (pct_encoded, pct_encoded_len, decoded,
   2041                                       buf_size, &broken);
   2042   if (broken)
   2043     return 0;
   2044   return res;
   2045 #else  /* ! MHD_FAVOR_SMALL_CODE */
   2046   size_t r;
   2047   size_t w;
   2048   r = 0;
   2049   w = 0;
   2050 
   2051   if (buf_size >= pct_encoded_len)
   2052   {
   2053     while (r < pct_encoded_len)
   2054     {
   2055       const char chr = pct_encoded[r];
   2056       if ('%' == chr)
   2057       {
   2058         if (2 >= pct_encoded_len - r)
   2059           return 0;
   2060         else
   2061         {
   2062           const char c1 = pct_encoded[++r];
   2063           const char c2 = pct_encoded[++r];
   2064           const int h = xdigittovalue (c1);
   2065           const int l = xdigittovalue (c2);
   2066           unsigned char out;
   2067           if ((0 > h) || (0 > l))
   2068             return 0;
   2069           out =
   2070             (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2071                              | ((uint8_t) ((unsigned int) l)));
   2072           decoded[w] = (char) out;
   2073         }
   2074       }
   2075       else
   2076         decoded[w] = chr;
   2077       ++r;
   2078       ++w;
   2079     }
   2080     return w;
   2081   }
   2082 
   2083   while (r < pct_encoded_len)
   2084   {
   2085     const char chr = pct_encoded[r];
   2086     if (w >= buf_size)
   2087       return 0;
   2088     if ('%' == chr)
   2089     {
   2090       if (2 >= pct_encoded_len - r)
   2091         return 0;
   2092       else
   2093       {
   2094         const char c1 = pct_encoded[++r];
   2095         const char c2 = pct_encoded[++r];
   2096         const int h = xdigittovalue (c1);
   2097         const int l = xdigittovalue (c2);
   2098         unsigned char out;
   2099         if ((0 > h) || (0 > l))
   2100           return 0;
   2101         out =
   2102           (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2103                            | ((uint8_t) ((unsigned int) l)));
   2104         decoded[w] = (char) out;
   2105       }
   2106     }
   2107     else
   2108       decoded[w] = chr;
   2109     ++r;
   2110     ++w;
   2111   }
   2112   return w;
   2113 #endif /* ! MHD_FAVOR_SMALL_CODE */
   2114 }
   2115 
   2116 
   2117 MHD_INTERNAL
   2118 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3)
   2119 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
   2120 mhd_str_pct_decode_lenient_n (const char *pct_encoded,
   2121                               size_t pct_encoded_len,
   2122                               char *decoded,
   2123                               size_t buf_size,
   2124                               bool *restrict broken_encoding)
   2125 {
   2126   size_t r;
   2127   size_t w;
   2128   r = 0;
   2129   w = 0;
   2130   if (NULL != broken_encoding)
   2131     *broken_encoding = false;
   2132 #ifndef MHD_FAVOR_SMALL_CODE
   2133   if (buf_size >= pct_encoded_len)
   2134   {
   2135     while (r < pct_encoded_len)
   2136     {
   2137       const char chr = pct_encoded[r];
   2138       if ('%' == chr)
   2139       {
   2140         if (2 >= pct_encoded_len - r)
   2141         {
   2142           if (NULL != broken_encoding)
   2143             *broken_encoding = true;
   2144           decoded[w] = chr; /* Copy "as is" */
   2145         }
   2146         else
   2147         {
   2148           const char c1 = pct_encoded[++r];
   2149           const char c2 = pct_encoded[++r];
   2150           const int h = xdigittovalue (c1);
   2151           const int l = xdigittovalue (c2);
   2152           unsigned char out;
   2153           if ((0 > h) || (0 > l))
   2154           {
   2155             r -= 2;
   2156             if (NULL != broken_encoding)
   2157               *broken_encoding = true;
   2158             decoded[w] = chr; /* Copy "as is" */
   2159           }
   2160           else
   2161           {
   2162             out =
   2163               (unsigned char)
   2164               (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2165                | ((uint8_t) ((unsigned int) l)));
   2166             decoded[w] = (char) out;
   2167           }
   2168         }
   2169       }
   2170       else
   2171         decoded[w] = chr;
   2172       ++r;
   2173       ++w;
   2174     }
   2175     return w;
   2176   }
   2177 #endif /* ! MHD_FAVOR_SMALL_CODE */
   2178   while (r < pct_encoded_len)
   2179   {
   2180     const char chr = pct_encoded[r];
   2181     if (w >= buf_size)
   2182       return 0;
   2183     if ('%' == chr)
   2184     {
   2185       if (2 >= pct_encoded_len - r)
   2186       {
   2187         if (NULL != broken_encoding)
   2188           *broken_encoding = true;
   2189         decoded[w] = chr; /* Copy "as is" */
   2190       }
   2191       else
   2192       {
   2193         const char c1 = pct_encoded[++r];
   2194         const char c2 = pct_encoded[++r];
   2195         const int h = xdigittovalue (c1);
   2196         const int l = xdigittovalue (c2);
   2197         if ((0 > h) || (0 > l))
   2198         {
   2199           r -= 2;
   2200           if (NULL != broken_encoding)
   2201             *broken_encoding = true;
   2202           decoded[w] = chr; /* Copy "as is" */
   2203         }
   2204         else
   2205         {
   2206           unsigned char out;
   2207           out =
   2208             (unsigned char)
   2209             (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2210              | ((uint8_t) ((unsigned int) l)));
   2211           decoded[w] = (char) out;
   2212         }
   2213       }
   2214     }
   2215     else
   2216       decoded[w] = chr;
   2217     ++r;
   2218     ++w;
   2219   }
   2220   return w;
   2221 }
   2222 
   2223 
   2224 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   2225 MHD_FN_PAR_CSTR_ (1) size_t
   2226 mhd_str_pct_decode_in_place_strict (char *str)
   2227 {
   2228 #ifdef MHD_FAVOR_SMALL_CODE
   2229   size_t res;
   2230   bool broken;
   2231 
   2232   res = mhd_str_pct_decode_in_place_lenient (str, &broken);
   2233   if (broken)
   2234   {
   2235     res = 0;
   2236     str[0] = 0;
   2237   }
   2238   return res;
   2239 #else  /* ! MHD_FAVOR_SMALL_CODE */
   2240   size_t r;
   2241   size_t w;
   2242   r = 0;
   2243   w = 0;
   2244 
   2245   while (0 != str[r])
   2246   {
   2247     const char chr = str[r++];
   2248     if ('%' == chr)
   2249     {
   2250       const char d1 = str[r++];
   2251       if (0 == d1)
   2252         return 0;
   2253       else
   2254       {
   2255         const char d2 = str[r++];
   2256         if (0 == d2)
   2257           return 0;
   2258         else
   2259         {
   2260           const int h = xdigittovalue (d1);
   2261           const int l = xdigittovalue (d2);
   2262           unsigned char out;
   2263           if ((0 > h) || (0 > l))
   2264             return 0;
   2265           out =
   2266             (unsigned char)
   2267             (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2268              | ((uint8_t) ((unsigned int) l)));
   2269           str[w++] = (char) out;
   2270         }
   2271       }
   2272     }
   2273     else
   2274       str[w++] = chr;
   2275   }
   2276   str[w] = 0;
   2277   return w;
   2278 #endif /* ! MHD_FAVOR_SMALL_CODE */
   2279 }
   2280 
   2281 
   2282 MHD_INTERNAL
   2283 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (1) size_t
   2284 mhd_str_pct_decode_in_place_lenient (char *restrict str,
   2285                                      bool *restrict broken_encoding)
   2286 {
   2287 #ifdef MHD_FAVOR_SMALL_CODE
   2288   size_t len;
   2289   size_t res;
   2290 
   2291   len = strlen (str);
   2292   res = mhd_str_pct_decode_lenient_n (str, len, str, len, broken_encoding);
   2293   str[res] = 0;
   2294 
   2295   return res;
   2296 #else  /* ! MHD_FAVOR_SMALL_CODE */
   2297   size_t r;
   2298   size_t w;
   2299   if (NULL != broken_encoding)
   2300     *broken_encoding = false;
   2301   r = 0;
   2302   w = 0;
   2303   while (0 != str[r])
   2304   {
   2305     const char chr = str[r++];
   2306     if ('%' == chr)
   2307     {
   2308       const char d1 = str[r++];
   2309       if (0 == d1)
   2310       {
   2311         if (NULL != broken_encoding)
   2312           *broken_encoding = true;
   2313         str[w++] = chr; /* Copy "as is" */
   2314         str[w] = 0;
   2315         return w;
   2316       }
   2317       else
   2318       {
   2319         const char d2 = str[r++];
   2320         if (0 == d2)
   2321         {
   2322           if (NULL != broken_encoding)
   2323             *broken_encoding = true;
   2324           str[w++] = chr; /* Copy "as is" */
   2325           str[w++] = d1; /* Copy "as is" */
   2326           str[w] = 0;
   2327           return w;
   2328         }
   2329         else
   2330         {
   2331           const int h = xdigittovalue (d1);
   2332           const int l = xdigittovalue (d2);
   2333           unsigned char out;
   2334           if ((0 > h) || (0 > l))
   2335           {
   2336             if (NULL != broken_encoding)
   2337               *broken_encoding = true;
   2338             str[w++] = chr; /* Copy "as is" */
   2339             str[w++] = d1;
   2340             str[w++] = d2;
   2341             continue;
   2342           }
   2343           out =
   2344             (unsigned char)
   2345             (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2346              | ((uint8_t) ((unsigned int) l)));
   2347           str[w++] = (char) out;
   2348           continue;
   2349         }
   2350       }
   2351     }
   2352     str[w++] = chr;
   2353   }
   2354   str[w] = 0;
   2355   return w;
   2356 #endif /* ! MHD_FAVOR_SMALL_CODE */
   2357 }
   2358 
   2359 
   2360 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_
   2361 MHD_FN_PAR_IN_SIZE_ (2, 1) bool
   2362 pct_decode_no_slash (const size_t str_len,
   2363                      const char *restrict str,
   2364                      const size_t chr_pos,
   2365                      char *restrict chr)
   2366 {
   2367   mhd_assert ('%' == *chr);
   2368   mhd_assert (*chr == str[chr_pos]);
   2369   mhd_ASSUME (str_len > chr_pos);
   2370 
   2371   if ((str_len - chr_pos) <= 2u) /* Overflow-safe check */
   2372     return false; /* The string tail has less than two chars */
   2373   else
   2374   {
   2375     const char d1 = str[chr_pos + 1u];
   2376     const char d2 = str[chr_pos + 2u];
   2377     const int h = xdigittovalue (d1);
   2378     const int l = xdigittovalue (d2);
   2379 
   2380     if ((0 <= h) && (0 <= l))
   2381     {
   2382       char dec;
   2383       mhd_ASSUME (15 >= h);
   2384       mhd_ASSUME (15 >= l);
   2385       dec = (char) ((((unsigned char) h) << 4u) | ((unsigned char) l));
   2386       if ('/' != dec)
   2387       {
   2388         *chr = dec;
   2389         return true;
   2390       }
   2391     }
   2392   }
   2393   /* No valid hex-number or a slash character (must not be encoded!) */
   2394   return false;
   2395 }
   2396 
   2397 
   2398 MHD_INTERNAL
   2399 MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_INOUT_SIZE_ (2,1) size_t
   2400 mhd_str_dec_norm_uri_path (size_t str_len,
   2401                            char *restrict str)
   2402 {
   2403   size_t r; /**< "read" position */
   2404   size_t w; /**< "write" position */
   2405 
   2406   w = 0u;
   2407   r = 0u;
   2408   while (str_len > r)
   2409   {
   2410     /* Process all segments not started with "/" (if any) */
   2411     char c;
   2412     mhd_ASSUME (w <= r);
   2413     c = str[r];
   2414     if ('/' == c)
   2415       break; /* Processed after this loop */
   2416     if (('%' == c) &&
   2417         pct_decode_no_slash (str_len,
   2418                              str,
   2419                              r,
   2420                              &c))
   2421       r += 2u;
   2422     if ('.' == c)
   2423     {
   2424       char c2;
   2425       if (str_len == r + 1u) /* overflow-safe as 'str_len > r' */
   2426       {
   2427         /* The complete string is "." */
   2428         ++r;    /* Skip "." */
   2429         break;  /* At the edge, stop */
   2430       }
   2431       mhd_ASSUME (w <= r);
   2432       c2 = str[r + 1u];
   2433       if ('/' == c2)
   2434       {
   2435         /* Found "./" at the start of the string */
   2436         r += 2u;  /* Skip "./" */
   2437         continue;
   2438       }
   2439       if (('%' == c2) &&
   2440           pct_decode_no_slash (str_len,
   2441                                str,
   2442                                r + 1u,
   2443                                &c2))
   2444         r += 2u;
   2445       if ('.' == c2)
   2446       {
   2447         char c3;
   2448         if (str_len == r + 2u) /* overflow-safe as 'str_len > r + 1 ' */
   2449         {
   2450           /* The complete string is ".." */
   2451           r += 2u;  /* Skip ".." */
   2452           break;    /* At the edge, stop */
   2453         }
   2454         mhd_ASSUME (w <= r);
   2455         c3 = str[r + 2u];
   2456         if ('/' == c3)
   2457         {
   2458           /* Found "../" at the start of the string */
   2459           r += 3u;  /* Skip "../" */
   2460           continue;
   2461         }
   2462         /* Do not write 'c3' as it has not been percent-decoded */
   2463       }
   2464       str[w++] = c;
   2465       str[w++] = c2;
   2466       r += 2u;
   2467     }
   2468     else
   2469     {
   2470       str[w++] = c;
   2471       r += 1u;
   2472     }
   2473     break;
   2474   }
   2475 
   2476   mhd_ASSUME (w <= r);
   2477   /* Found first segment which is not "../" and is not "./" OR the end of the string */
   2478   for ((void) r; str_len > r && '/' != str[r]; ++r)
   2479   {
   2480     char c;
   2481     mhd_ASSUME (w <= r);
   2482     c = str[r];
   2483     if (('%' == c) &&
   2484         pct_decode_no_slash (str_len,
   2485                              str,
   2486                              r,
   2487                              &c))
   2488       r += 2u;
   2489     mhd_ASSUME (w <= r);
   2490     str[w++] = c;
   2491   }
   2492 
   2493   /* Found first '/' which is not skipped OR the end of the string */
   2494   while (str_len > r)
   2495   {
   2496     /* Start of a "/segment" */
   2497     char slash_chr = str[r];
   2498     const size_t seg_start = w;
   2499     mhd_ASSUME ('/' == slash_chr);
   2500     str[w++] = slash_chr;
   2501     ++r;
   2502     if (str_len > r)
   2503     {
   2504       char c;
   2505       mhd_ASSUME (w <= r);
   2506       c = str[r];
   2507       if ('/' == c)
   2508         continue;
   2509       if (('%' == c) &&
   2510           pct_decode_no_slash (str_len,
   2511                                str,
   2512                                r,
   2513                                &c))
   2514         r += 2u;
   2515       if ('.' == c)
   2516       {
   2517         char c2;
   2518         if (str_len == r + 1u) /* overflow-safe as 'str_len > r' */
   2519         {
   2520           /* Found "/." at the end of the string */
   2521           ++r;   /* Skip ".", leave bare '/' */
   2522           break; /* At the edge, stop */
   2523         }
   2524         mhd_ASSUME (w <= r);
   2525         c2 = str[r + 1u];
   2526         if ('/' == c2)
   2527         {
   2528           /* Found "/./" */
   2529           w = seg_start; /* Rewind output to the '/' at the start of the segment */
   2530           ++r;      /* Skip "." */
   2531           continue; /* Go to the next "/", which will be written again */
   2532         }
   2533         if (('%' == c2) &&
   2534             pct_decode_no_slash (str_len,
   2535                                  str,
   2536                                  r + 1u,
   2537                                  &c2))
   2538           r += 2u;
   2539         if ('.' == c2)
   2540         {
   2541           char c3;
   2542           if (str_len == r + 2u) /* overflow-safe as 'str_len > r + 1 ' */
   2543           {
   2544             /* Found "/.." at the end of the string */
   2545             w = seg_start;
   2546             if (0 < w)
   2547               do
   2548               { /* Rewind output to the start of prev segment */
   2549                 --w;
   2550               } while (0 < w && '/' != str[w]);
   2551             mhd_ASSUME (w < r);
   2552             str[w++] = '/'; /* Replace prev segment with '/' */
   2553             r += 2u; /* Skip ".." */
   2554             break;   /* At the edge, stop */
   2555           }
   2556           mhd_ASSUME (w <= r);
   2557           c3 = str[r + 2u];
   2558           if ('/' == c3)
   2559           {
   2560             /* Found "/../" */
   2561             w = seg_start;
   2562             if (0 < w)
   2563               do
   2564               { /* Rewind output to the start of prev segment */
   2565                 --w;
   2566               } while (0 < w && '/' != str[w]);
   2567             r += 2u;  /* Skip ".."; put next '/' to the start of prev segment */
   2568             continue;
   2569           }
   2570           /* Do not write 'c3' as it has not been percent-decoded */
   2571         }
   2572         str[w++] = c;
   2573         str[w++] = c2;
   2574         r += 2u;
   2575       }
   2576       else
   2577       {
   2578         str[w++] = c;
   2579         r += 1u;
   2580       }
   2581       mhd_assert (seg_start < w);
   2582     }
   2583     for ((void) r; str_len > r && '/' != str[r]; ++r)
   2584     {
   2585       /* Process the end of the segment */
   2586       char c;
   2587       mhd_ASSUME (w <= r);
   2588       c = str[r];
   2589       if (('%' == c) &&
   2590           pct_decode_no_slash (str_len,
   2591                                str,
   2592                                r,
   2593                                &c))
   2594         r += 2u;
   2595       mhd_ASSUME (w <= r);
   2596       str[w++] = c;
   2597     }
   2598     mhd_assert (0u != w);
   2599   }
   2600   mhd_assert (r == str_len);
   2601 
   2602   if (str_len > w)
   2603     str[w] = '\0';
   2604 
   2605   return w;
   2606 }
   2607 
   2608 
   2609 #ifdef MHD_SUPPORT_AUTH_DIGEST
   2610 
   2611 MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
   2612 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4) bool
   2613 mhd_str_equal_quoted_bin_n (const char *quoted,
   2614                             size_t quoted_len,
   2615                             const char *unquoted,
   2616                             size_t unquoted_len)
   2617 {
   2618   size_t i;
   2619   size_t j;
   2620   if (unquoted_len < quoted_len / 2)
   2621     return false;
   2622 
   2623   j = 0;
   2624   for (i = 0; quoted_len > i && unquoted_len > j; ++i, ++j)
   2625   {
   2626     if ('\\' == quoted[i])
   2627     {
   2628       i++; /* Advance to the next character */
   2629       if (quoted_len == i)
   2630         return false; /* No character after escaping backslash */
   2631     }
   2632     if (quoted[i] != unquoted[j])
   2633       return false; /* Different characters */
   2634   }
   2635   if ((quoted_len != i) || (unquoted_len != j))
   2636     return false; /* The strings have different length */
   2637 
   2638   return true;
   2639 }
   2640 
   2641 
   2642 MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
   2643 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4) bool
   2644 mhd_str_equal_caseless_quoted_bin_n (const char *quoted,
   2645                                      size_t quoted_len,
   2646                                      const char *unquoted,
   2647                                      size_t unquoted_len)
   2648 {
   2649   size_t i;
   2650   size_t j;
   2651   if (unquoted_len < quoted_len / 2)
   2652     return false;
   2653 
   2654   j = 0;
   2655   for (i = 0; quoted_len > i && unquoted_len > j; ++i, ++j)
   2656   {
   2657     if ('\\' == quoted[i])
   2658     {
   2659       i++; /* Advance to the next character */
   2660       if (quoted_len == i)
   2661         return false; /* No character after escaping backslash */
   2662     }
   2663     if (! charsequalcaseless (quoted[i], unquoted[j]))
   2664       return false; /* Different characters */
   2665   }
   2666   if ((quoted_len != i) || (unquoted_len != j))
   2667     return false; /* The strings have different length */
   2668 
   2669   return true;
   2670 }
   2671 
   2672 
   2673 #endif /* MHD_SUPPORT_AUTH_DIGEST */
   2674 
   2675 #if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_POST_PARSER)
   2676 
   2677 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   2678 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,2) size_t
   2679 mhd_str_unquote (const char *quoted,
   2680                  size_t quoted_len,
   2681                  char *result)
   2682 {
   2683   size_t r;
   2684   size_t w;
   2685 
   2686   r = 0;
   2687   w = 0;
   2688 
   2689   while (quoted_len > r)
   2690   {
   2691     if ('\\' == quoted[r])
   2692     {
   2693       ++r;
   2694       if (quoted_len == r)
   2695         return 0; /* Last backslash is not followed by char to unescape */
   2696     }
   2697     result[w++] = quoted[r++];
   2698   }
   2699   return w;
   2700 }
   2701 
   2702 
   2703 #endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_POST_PARSER */
   2704 
   2705 #if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_AUTH_BASIC)
   2706 
   2707 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   2708 MHD_FN_PAR_IN_SIZE_ (1,2)
   2709 MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
   2710 mhd_str_quote (const char *unquoted,
   2711                size_t unquoted_len,
   2712                char *result,
   2713                size_t buf_size)
   2714 {
   2715   size_t r;
   2716   size_t w;
   2717 
   2718   r = 0;
   2719   w = 0;
   2720 
   2721 #ifndef MHD_FAVOR_SMALL_CODE
   2722   if (unquoted_len * 2 <= buf_size)
   2723   {
   2724     /* Fast loop: the output will fit the buffer with any input string content */
   2725     while (unquoted_len > r)
   2726     {
   2727       const char chr = unquoted[r++];
   2728       if (('\\' == chr) || ('\"' == chr))
   2729         result[w++] = '\\'; /* Escape current char */
   2730       result[w++] = chr;
   2731     }
   2732   }
   2733   else
   2734   {
   2735     if (unquoted_len > buf_size)
   2736       return 0; /* Quick fail: the output buffer is too small */
   2737 #else  /* MHD_FAVOR_SMALL_CODE */
   2738   if (1)
   2739   {
   2740 #endif /* MHD_FAVOR_SMALL_CODE */
   2741 
   2742     while (unquoted_len > r)
   2743     {
   2744       if (buf_size <= w)
   2745         return 0; /* The output buffer is too small */
   2746       else
   2747       {
   2748         const char chr = unquoted[r++];
   2749         if (('\\' == chr) || ('\"' == chr))
   2750         {
   2751           result[w++] = '\\'; /* Escape current char */
   2752           if (buf_size <= w)
   2753             return 0; /* The output buffer is too small */
   2754         }
   2755         result[w++] = chr;
   2756       }
   2757     }
   2758   }
   2759 
   2760   mhd_assert (w >= r);
   2761   mhd_assert (w <= r * 2);
   2762   return w;
   2763 }
   2764 
   2765 
   2766 #endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_AUTH_BASIC */
   2767 
   2768 #ifdef MHD_SUPPORT_AUTH_BASIC
   2769 
   2770 /*
   2771  * MHD_BASE64_FUNC_VERSION
   2772  * 1 = smallest,
   2773  * 2 = medium,
   2774  * 3 = fastest
   2775  */
   2776 #ifndef MHD_BASE64_FUNC_VERSION
   2777 #ifdef MHD_FAVOR_SMALL_CODE
   2778 #define MHD_BASE64_FUNC_VERSION 1
   2779 #else  /* ! MHD_FAVOR_SMALL_CODE */
   2780 #define MHD_BASE64_FUNC_VERSION 3
   2781 #endif /* ! MHD_FAVOR_SMALL_CODE */
   2782 #endif /* ! MHD_BASE64_FUNC_VERSION */
   2783 
   2784 #if MHD_BASE64_FUNC_VERSION < 1 || MHD_BASE64_FUNC_VERSION > 3
   2785 #error Wrong MHD_BASE64_FUNC_VERSION value
   2786 #endif /* MHD_BASE64_FUNC_VERSION < 1 || MHD_BASE64_FUNC_VERSION > 3 */
   2787 
   2788 #if MHD_BASE64_FUNC_VERSION == 3
   2789 #define mhd_base64_map_type int
   2790 #else  /* MHD_BASE64_FUNC_VERSION < 3 */
   2791 #define mhd_base64_map_type int8_t
   2792 #endif /* MHD_BASE64_FUNC_VERSION < 3 */
   2793 
   2794 #if MHD_BASE64_FUNC_VERSION == 1
   2795 static mhd_base64_map_type
   2796 base64_char_to_value_ (uint8_t c)
   2797 {
   2798   if ('Z' >= c)
   2799   {
   2800     if ('A' <= c)
   2801       return (mhd_base64_map_type) ((c - 'A') + 0);
   2802     else if ('0' <= c)
   2803     {
   2804       if ('9' >= c)
   2805         return (mhd_base64_map_type) ((c - '0') + 52);
   2806       else if ('=' == c)
   2807         return -2;
   2808       else
   2809         return -1;
   2810     }
   2811     else if ('+' == c)
   2812       return 62;
   2813     else if ('/' == c)
   2814       return 63;
   2815     else
   2816       return -1;
   2817   }
   2818   else if (('z' >= c) && ('a' <= c))
   2819     return (mhd_base64_map_type) ((c - 'a') + 26);
   2820   return -1;
   2821 }
   2822 
   2823 
   2824 #endif /* MHD_BASE64_FUNC_VERSION == 1 */
   2825 
   2826 
   2827 mhd_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE
   2828 
   2829 
   2830 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   2831 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
   2832 mhd_base64_to_bin_n (const char *base64,
   2833                      size_t base64_len,
   2834                      void *bin,
   2835                      size_t bin_size)
   2836 {
   2837 #if MHD_BASE64_FUNC_VERSION >= 2
   2838   static const mhd_base64_map_type map[] = {
   2839     /* -1 = invalid char, -2 = padding
   2840     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
   2841     NUL,  SOH,  STX,  ETX,  EOT,  ENQ,  ACK,  BEL,  */
   2842     -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   2843     /*
   2844     0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
   2845     BS,   HT,   LF,   VT,   FF,   CR,   SO,   SI,   */
   2846     -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   2847     /*
   2848     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
   2849     DLE,  DC1,  DC2,  DC3,  DC4,  NAK,  SYN,  ETB,  */
   2850     -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   2851     /*
   2852     0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
   2853     CAN,  EM,   SUB,  ESC,  FS,   GS,   RS,   US,   */
   2854     -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   2855     /*
   2856     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
   2857     ' ',  '!',  '"',  '#',  '$',  '%',  '&',  '\'', */
   2858     -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   2859     /*
   2860     0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
   2861     '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',  */
   2862     -1,   -1,   -1,   62,   -1,   -1,   -1,   63,
   2863     /*
   2864     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
   2865     '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  */
   2866     52,   53,   54,   55,   56,   57,   58,   59,
   2867     /*
   2868     0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
   2869     '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',  */
   2870     60,   61,   -1,   -1,   -1,   -2,   -1,   -1,
   2871     /*
   2872     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
   2873     '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  */
   2874     -1,    0,    1,    2,    3,    4,    5,    6,
   2875     /*
   2876     0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
   2877     'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',  */
   2878     7,     8,    9,   10,   11,   12,   13,   14,
   2879     /*
   2880     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
   2881     'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  */
   2882     15,   16,   17,   18,   19,   20,   21,   22,
   2883     /*
   2884      0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
   2885     'X',  'Y',  'Z',  '[',  '\',  ']',  '^',  '_',  */
   2886     23,   24,   25,   -1,   -1,   -1,   -1,   -1,
   2887     /*
   2888     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
   2889     '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',  */
   2890     -1,   26,   27,   28,   29,   30,   31,   32,
   2891     /*
   2892     0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
   2893     'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',  */
   2894     33,   34,   35,   36,   37,   38,   39,   40,
   2895     /*
   2896     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
   2897     'p',  'q',  'r',  's',  't',  'u',  'v',  'w',  */
   2898     41,   42,   43,   44,   45,   46,   47,   48,
   2899     /*
   2900     0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
   2901     'x',  'y',  'z',  '{',  '|',  '}',  '~',  DEL,  */
   2902     49,   50,   51,   -1,   -1,   -1,   -1,   -1
   2903 
   2904 #if MHD_BASE64_FUNC_VERSION == 3
   2905     ,
   2906     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 80..8F */
   2907     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 90..9F */
   2908     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* A0..AF */
   2909     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* B0..BF */
   2910     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* C0..CF */
   2911     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* D0..DF */
   2912     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* E0..EF */
   2913     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* F0..FF */
   2914 #endif /* ! MHD_BASE64_FUNC_VERSION == 3 */
   2915   };
   2916 #define base64_char_to_value_(c) map[(c)]
   2917 #endif /* MHD_BASE64_FUNC_VERSION >= 2 */
   2918   const uint8_t *const in = (const uint8_t *) base64;
   2919   uint8_t *const out = (uint8_t *) bin;
   2920   size_t i;
   2921   size_t j;
   2922   if (0 == base64_len)
   2923     return 0;  /* Nothing to decode */
   2924   if (0 != base64_len % 4)
   2925     return 0;  /* Wrong input length */
   2926   if (base64_len / 4 * 3 - 2 > bin_size)
   2927     return 0;
   2928 
   2929   j = 0;
   2930   for (i = 0; i < (base64_len - 4); i += 4)
   2931   {
   2932 #if MHD_BASE64_FUNC_VERSION == 2
   2933     if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3])))
   2934       return 0;
   2935 #endif /* MHD_BASE64_FUNC_VERSION == 2 */
   2936     if (1)
   2937     {
   2938       const mhd_base64_map_type v1 = base64_char_to_value_ (in[i + 0]);
   2939       const mhd_base64_map_type v2 = base64_char_to_value_ (in[i + 1]);
   2940       const mhd_base64_map_type v3 = base64_char_to_value_ (in[i + 2]);
   2941       const mhd_base64_map_type v4 = base64_char_to_value_ (in[i + 3]);
   2942       if ((0 > v1) || (0 > v2) || (0 > v3) || (0 > v4))
   2943         return 0;
   2944       out[j + 0] = (uint8_t) (((uint8_t) (((uint8_t) v1) << 2))
   2945                               | ((uint8_t) (((uint8_t) v2) >> 4)));
   2946       out[j + 1] = (uint8_t) (((uint8_t) (((uint8_t) v2) << 4))
   2947                               | ((uint8_t) (((uint8_t) v3) >> 2)));
   2948       out[j + 2] = (uint8_t) (((uint8_t) (((uint8_t) v3) << 6))
   2949                               | ((uint8_t) v4));
   2950     }
   2951     j += 3;
   2952   }
   2953 #if MHD_BASE64_FUNC_VERSION == 2
   2954   if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3])))
   2955     return 0;
   2956 #endif /* MHD_BASE64_FUNC_VERSION == 2 */
   2957   if (1)
   2958   { /* The last four chars block */
   2959     const mhd_base64_map_type v1 = base64_char_to_value_ (in[i + 0]);
   2960     const mhd_base64_map_type v2 = base64_char_to_value_ (in[i + 1]);
   2961     const mhd_base64_map_type v3 = base64_char_to_value_ (in[i + 2]);
   2962     const mhd_base64_map_type v4 = base64_char_to_value_ (in[i + 3]);
   2963     if ((0 > v1) || (0 > v2))
   2964       return 0; /* Invalid char or padding at first two positions */
   2965     mhd_assert (j < bin_size);
   2966     out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v1) << 2))
   2967                           | ((uint8_t) (((uint8_t) v2) >> 4)));
   2968     if (0 > v3)
   2969     { /* Third char is either padding or invalid */
   2970       if ((-2 != v3) || (-2 != v4))
   2971         return 0;  /* Both two last chars must be padding */
   2972       if (0 != (uint8_t) (((uint8_t) v2) << 4))
   2973         return 0;  /* Wrong last char */
   2974       return j;
   2975     }
   2976     if (j >= bin_size)
   2977       return 0; /* Not enough space */
   2978     out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v2) << 4))
   2979                           | ((uint8_t) (((uint8_t) v3) >> 2)));
   2980     if (0 > v4)
   2981     { /* Fourth char is either padding or invalid */
   2982       if (-2 != v4)
   2983         return 0;  /* The char must be padding */
   2984       if (0 != (uint8_t) (((uint8_t) v3) << 6))
   2985         return 0;  /* Wrong last char */
   2986       return j;
   2987     }
   2988     if (j >= bin_size)
   2989       return 0; /* Not enough space */
   2990     out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v3) << 6))
   2991                           | ((uint8_t) v4));
   2992   }
   2993   return j;
   2994 #if MHD_BASE64_FUNC_VERSION >= 2
   2995 #undef base64_char_to_value_
   2996 #endif /* MHD_BASE64_FUNC_VERSION >= 2 */
   2997 }
   2998 
   2999 
   3000 mhd_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE
   3001 
   3002 
   3003 #undef mhd_base64_map_type
   3004 
   3005 #endif /* MHD_SUPPORT_AUTH_BASIC */
   3006 
   3007 
   3008 MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ bool
   3009 mhd_str_starts_with_token_opt_param (const struct MHD_String *restrict str,
   3010                                      const struct MHD_String *restrict token)
   3011 {
   3012   size_t i;
   3013 
   3014   mhd_assert (0 != token->len);
   3015   mhd_assert (NULL == memchr (token->cstr, '=', token->len));
   3016   mhd_assert (NULL == memchr (token->cstr, ' ', token->len));
   3017   mhd_assert (NULL == memchr (token->cstr, '\t', token->len));
   3018 
   3019   if (str->len < token->len)
   3020     return false; /* The string is too short to match */
   3021 
   3022   if (! mhd_str_equal_caseless_bin_n (str->cstr,
   3023                                       token->cstr,
   3024                                       token->len))
   3025     return false; /* The string does not start with the token */
   3026 
   3027   for (i = token->len; i < str->len; ++i)
   3028   {
   3029     const char c = str->cstr[i];
   3030     if ((' ' == c) || ('\t' == c))
   3031       continue;
   3032     if (';' == c)
   3033       return true; /* Found the start of the token parameters */
   3034     return false; /* The initial part of the string does not fully match the token */
   3035   }
   3036   mhd_assert (0 && "The string should not have whitespace at the end");
   3037   return true;
   3038 }
   3039 
   3040 
   3041 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   3042 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) MHD_FN_PAR_IN_ (3)
   3043 MHD_FN_PAR_OUT_ (4) MHD_FN_PAR_OUT_ (5) enum mhd_StingStartsWithTokenResult
   3044 mhd_str_starts_with_token_req_param (
   3045   const struct MHD_String *restrict str,
   3046   const struct MHD_String *restrict token,
   3047   const struct MHD_String *restrict par,
   3048   struct mhd_BufferConst *restrict par_value,
   3049   bool *restrict par_value_needs_unquote)
   3050 {
   3051   size_t i;
   3052   const char *const restrict cstr = str->cstr;
   3053   bool token_found;
   3054   bool param_found;
   3055 
   3056   mhd_assert (0 != token->len);
   3057   mhd_assert (NULL == memchr (token->cstr, '=', token->len));
   3058   mhd_assert (NULL == memchr (token->cstr, ' ', token->len));
   3059   mhd_assert (NULL == memchr (token->cstr, '\t', token->len));
   3060   mhd_assert (NULL == memchr (par->cstr, '=', par->len));
   3061   mhd_assert (NULL == memchr (par->cstr, ' ', par->len));
   3062   mhd_assert (NULL == memchr (par->cstr, '\t', par->len));
   3063 
   3064   par_value->data = NULL;
   3065   par_value->size = 0;
   3066 
   3067   if (str->len < token->len)
   3068     return mhd_STR_STARTS_W_TOKEN_NO_TOKEN; /* The string is too short to match */
   3069 
   3070   if (! mhd_str_equal_caseless_bin_n (cstr,
   3071                                       token->cstr,
   3072                                       token->len))
   3073     return mhd_STR_STARTS_W_TOKEN_NO_TOKEN; /* The string does not start with the token */
   3074   token_found = false;
   3075   param_found = false;
   3076 
   3077   i = token->len;
   3078   do
   3079   {
   3080     /* Find start of the next parameter */
   3081     for ((void) 0; i < str->len; ++i)
   3082     {
   3083       const char c = cstr[i];
   3084       if ((' ' == c) || ('\t' == c))
   3085         continue;
   3086       if (';' == c)
   3087       {
   3088         /* Found the start of the next token parameter */
   3089         if (param_found)
   3090           return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
   3091         ++i; /* Move to the next char */
   3092         break;
   3093       }
   3094       if (',' == c)
   3095         return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* Found the start of the next token */
   3096 
   3097       if (! token_found)
   3098       {
   3099         if (i == token->len)
   3100         {
   3101           /* The initial part of the string does not fully match the token or
   3102              formatting is not correct */
   3103           return mhd_STR_STARTS_W_TOKEN_NO_TOKEN;
   3104         }
   3105         /* The string has garbage after the token and whitespace */
   3106         return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT;
   3107       }
   3108       /* The garbage after the parameter */
   3109       return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT;
   3110     }
   3111     token_found = true;
   3112 
   3113     if (i == str->len)
   3114       return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
   3115 
   3116     /* 'i' is at the start of the parameter */
   3117 
   3118     while ((' ' == cstr[i]) || ('\t' == cstr[i]))
   3119     {
   3120       if (++i == str->len)
   3121         return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
   3122     }
   3123 
   3124     /* 'i' is at the start of the parameter name */
   3125 
   3126     if (par->len > str->len - i - 1)
   3127       return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* the token is found, but the parameter is not */
   3128     else
   3129     { /* Check the parameter */
   3130       bool val_needs_unquote;
   3131       size_t j;
   3132       const char *const prm_str = cstr + i;
   3133 
   3134       for (j = 0; j < par->len; ++j)
   3135         if (! charsequalcaseless (prm_str[j],
   3136                                   par->cstr[j]))
   3137           break;
   3138       i += j;
   3139       mhd_assert (str->len > i);
   3140       if ((j == par->len) &&
   3141           ('=' == cstr[i]))
   3142       {
   3143         /* The parameter name matches required parameter */
   3144         param_found = true;
   3145         par_value->data = cstr + i + 1;
   3146       }
   3147       else
   3148       {
   3149         /* i points to the char in the parameter name */
   3150         while ('=' != cstr[i])
   3151         {
   3152           if ((';' == cstr[i])      /* end of the parameter */
   3153               || (',' == cstr[i])   /* end of the token */
   3154               || (str->len == ++i)) /* end of the field string */
   3155           {
   3156             /* parameter without the value */
   3157             return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT;
   3158           }
   3159         }
   3160       }
   3161       mhd_assert (str->len > i);
   3162       mhd_assert ('=' == cstr[i]);
   3163 
   3164       /* 'i' points to '=' between parameter name and parameter value */
   3165 
   3166       ++i; /* Advance to the first char in the parameter value */
   3167       if (str->len == i)
   3168         return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* Zero-length parameter value */
   3169 
   3170       val_needs_unquote = false;
   3171 
   3172       /* 'i' points to the char after '=' */
   3173 
   3174       if ('"' == cstr[i])
   3175       {
   3176         /* The value is quoted */
   3177         if (param_found)
   3178           ++(par_value->data); /* Point to the first quoted char */
   3179         do
   3180         {
   3181           ++i; /* Advance to the next char */
   3182           if (str->len == i)
   3183             return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT; /* No closing quote */
   3184           if ('\\' == cstr[i])
   3185           {
   3186             val_needs_unquote = true;
   3187             ++i; /* Skip quoted char */
   3188             if (str->len == i)
   3189               return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT; /* No closing quote */
   3190           }
   3191         } while ('"' != cstr[i]);
   3192         if (param_found)
   3193         {
   3194           par_value->size = (size_t) ((cstr + i) - par_value->data);
   3195           *par_value_needs_unquote = val_needs_unquote;
   3196         }
   3197         /* Complete value found */
   3198         /* Check for the garbage data at the end */
   3199         ++i; /* Advance to the next char */
   3200       }
   3201       else
   3202       {
   3203         /* The value is not quoted */
   3204         while ((' ' != cstr[i]) &&
   3205                ('\t' != cstr[i]))
   3206         {
   3207           if ((';' == cstr[i])      /* end of the parameter */
   3208               || (',' == cstr[i])   /* end of the token */
   3209               || (str->len == ++i)) /* end of the field string */
   3210             break;
   3211         }
   3212         /* The end parameter value */
   3213         if (param_found)
   3214         {
   3215           par_value->size = (size_t) ((cstr + i) - par_value->data);
   3216           *par_value_needs_unquote = false;
   3217         }
   3218         /* Check for the garbage data at the end */
   3219       }
   3220 
   3221       /* 'i' points to the next char after end of the parameter value */
   3222     }
   3223   } while (i < str->len);
   3224 
   3225   mhd_assert (token_found);
   3226   return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
   3227 }