libmicrohttpd2

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

mhd_str.c (84509B)


      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   pos = 0;
   1915   digit = val / 100;
   1916   if (0 == digit)
   1917   {
   1918     if (3 <= min_digits)
   1919       buf[pos++] = '0';
   1920   }
   1921   else
   1922   {
   1923     buf[pos++] = (char) ('0' + (char) digit);
   1924     val %= 100;
   1925     min_digits = 2;
   1926   }
   1927 
   1928   if (buf_size <= pos)
   1929     return 0;
   1930   digit = val / 10;
   1931   if (0 == digit)
   1932   {
   1933     if (2 <= min_digits)
   1934       buf[pos++] = '0';
   1935   }
   1936   else
   1937   {
   1938     buf[pos++] = (char) ('0' + (char) digit);
   1939     val %= 10;
   1940   }
   1941 
   1942   if (buf_size <= pos)
   1943     return 0;
   1944   buf[pos++] = (char) ('0' + (char) val);
   1945   return pos;
   1946 }
   1947 
   1948 
   1949 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1950 MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3) size_t
   1951 mhd_bin_to_hex (const void *restrict bin,
   1952                 size_t size,
   1953                 char *restrict hex)
   1954 {
   1955   size_t i;
   1956 
   1957   for (i = 0; i < size; ++i)
   1958   {
   1959     const uint8_t b = ((const uint8_t *) bin)[i];
   1960 #ifdef mhd_HAVE_UINT8TOTWOXDIGITS
   1961     const char *two_xdigits = uint8totwoxdigits (b);
   1962     hex[i * 2] = two_xdigits[0];
   1963     hex[i * 2 + 1] = two_xdigits[1];
   1964 #else  /* ! mhd_HAVE_UINT8TOTWOXDIGITS */
   1965     hex[i * 2] = valuetoxdigit (b >> 4);
   1966     hex[i * 2 + 1] = valuetoxdigit (b & 0x0Fu);
   1967 #endif /* ! mhd_HAVE_UINT8TOTWOXDIGITS */
   1968   }
   1969   return i * 2;
   1970 }
   1971 
   1972 
   1973 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1974 MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3) size_t
   1975 mhd_bin_to_hex_z (const void *restrict bin,
   1976                   size_t size,
   1977                   char *restrict hex)
   1978 {
   1979   size_t res;
   1980 
   1981   res = mhd_bin_to_hex (bin, size, hex);
   1982   hex[res] = 0;
   1983 
   1984   return res;
   1985 }
   1986 
   1987 
   1988 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   1989 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3) size_t
   1990 mhd_hex_to_bin (const char *restrict hex,
   1991                 size_t len,
   1992                 void *restrict bin)
   1993 {
   1994   size_t r;
   1995   size_t w;
   1996 
   1997   r = 0;
   1998   w = 0;
   1999   if (0 != len % 2)
   2000   {
   2001     /* Assume the first byte is encoded with single digit */
   2002     const char c2 = hex[r++];
   2003     const int l = xdigittovalue (c2);
   2004     if (0 > l)
   2005       return 0;
   2006     ((uint8_t *) bin)[w++] = (uint8_t) ((unsigned int) l);
   2007   }
   2008   while (r < len)
   2009   {
   2010     const char c1 = hex[r++];
   2011     const char c2 = hex[r++];
   2012     const int h = xdigittovalue (c1);
   2013     const int l = xdigittovalue (c2);
   2014     if ((0 > h) || (0 > l))
   2015       return 0;
   2016     ((uint8_t *) bin)[w++] =
   2017       (uint8_t) ( ((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2018                   | ((uint8_t) ((unsigned int) l)) );
   2019   }
   2020   mhd_assert (len == r);
   2021   mhd_assert ((len + 1) / 2 == w);
   2022   return w;
   2023 }
   2024 
   2025 
   2026 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   2027 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
   2028 mhd_str_pct_decode_strict_n (const char *pct_encoded,
   2029                              size_t pct_encoded_len,
   2030                              char *decoded,
   2031                              size_t buf_size)
   2032 {
   2033 #ifdef MHD_FAVOR_SMALL_CODE
   2034   bool broken;
   2035   size_t res;
   2036 
   2037   res = mhd_str_pct_decode_lenient_n (pct_encoded, pct_encoded_len, decoded,
   2038                                       buf_size, &broken);
   2039   if (broken)
   2040     return 0;
   2041   return res;
   2042 #else  /* ! MHD_FAVOR_SMALL_CODE */
   2043   size_t r;
   2044   size_t w;
   2045   r = 0;
   2046   w = 0;
   2047 
   2048   if (buf_size >= pct_encoded_len)
   2049   {
   2050     while (r < pct_encoded_len)
   2051     {
   2052       const char chr = pct_encoded[r];
   2053       if ('%' == chr)
   2054       {
   2055         if (2 > pct_encoded_len - r)
   2056           return 0;
   2057         else
   2058         {
   2059           const char c1 = pct_encoded[++r];
   2060           const char c2 = pct_encoded[++r];
   2061           const int h = xdigittovalue (c1);
   2062           const int l = xdigittovalue (c2);
   2063           unsigned char out;
   2064           if ((0 > h) || (0 > l))
   2065             return 0;
   2066           out =
   2067             (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2068                              | ((uint8_t) ((unsigned int) l)));
   2069           decoded[w] = (char) out;
   2070         }
   2071       }
   2072       else
   2073         decoded[w] = chr;
   2074       ++r;
   2075       ++w;
   2076     }
   2077     return w;
   2078   }
   2079 
   2080   while (r < pct_encoded_len)
   2081   {
   2082     const char chr = pct_encoded[r];
   2083     if (w >= buf_size)
   2084       return 0;
   2085     if ('%' == chr)
   2086     {
   2087       if (2 > pct_encoded_len - r)
   2088         return 0;
   2089       else
   2090       {
   2091         const char c1 = pct_encoded[++r];
   2092         const char c2 = pct_encoded[++r];
   2093         const int h = xdigittovalue (c1);
   2094         const int l = xdigittovalue (c2);
   2095         unsigned char out;
   2096         if ((0 > h) || (0 > l))
   2097           return 0;
   2098         out =
   2099           (unsigned char) (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2100                            | ((uint8_t) ((unsigned int) l)));
   2101         decoded[w] = (char) out;
   2102       }
   2103     }
   2104     else
   2105       decoded[w] = chr;
   2106     ++r;
   2107     ++w;
   2108   }
   2109   return w;
   2110 #endif /* ! MHD_FAVOR_SMALL_CODE */
   2111 }
   2112 
   2113 
   2114 MHD_INTERNAL
   2115 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3)
   2116 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
   2117 mhd_str_pct_decode_lenient_n (const char *pct_encoded,
   2118                               size_t pct_encoded_len,
   2119                               char *decoded,
   2120                               size_t buf_size,
   2121                               bool *restrict broken_encoding)
   2122 {
   2123   size_t r;
   2124   size_t w;
   2125   r = 0;
   2126   w = 0;
   2127   if (NULL != broken_encoding)
   2128     *broken_encoding = false;
   2129 #ifndef MHD_FAVOR_SMALL_CODE
   2130   if (buf_size >= pct_encoded_len)
   2131   {
   2132     while (r < pct_encoded_len)
   2133     {
   2134       const char chr = pct_encoded[r];
   2135       if ('%' == chr)
   2136       {
   2137         if (2 > pct_encoded_len - r)
   2138         {
   2139           if (NULL != broken_encoding)
   2140             *broken_encoding = true;
   2141           decoded[w] = chr; /* Copy "as is" */
   2142         }
   2143         else
   2144         {
   2145           const char c1 = pct_encoded[++r];
   2146           const char c2 = pct_encoded[++r];
   2147           const int h = xdigittovalue (c1);
   2148           const int l = xdigittovalue (c2);
   2149           unsigned char out;
   2150           if ((0 > h) || (0 > l))
   2151           {
   2152             r -= 2;
   2153             if (NULL != broken_encoding)
   2154               *broken_encoding = true;
   2155             decoded[w] = chr; /* Copy "as is" */
   2156           }
   2157           else
   2158           {
   2159             out =
   2160               (unsigned char)
   2161               (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2162                | ((uint8_t) ((unsigned int) l)));
   2163             decoded[w] = (char) out;
   2164           }
   2165         }
   2166       }
   2167       else
   2168         decoded[w] = chr;
   2169       ++r;
   2170       ++w;
   2171     }
   2172     return w;
   2173   }
   2174 #endif /* ! MHD_FAVOR_SMALL_CODE */
   2175   while (r < pct_encoded_len)
   2176   {
   2177     const char chr = pct_encoded[r];
   2178     if (w >= buf_size)
   2179       return 0;
   2180     if ('%' == chr)
   2181     {
   2182       if (2 > pct_encoded_len - r)
   2183       {
   2184         if (NULL != broken_encoding)
   2185           *broken_encoding = true;
   2186         decoded[w] = chr; /* Copy "as is" */
   2187       }
   2188       else
   2189       {
   2190         const char c1 = pct_encoded[++r];
   2191         const char c2 = pct_encoded[++r];
   2192         const int h = xdigittovalue (c1);
   2193         const int l = xdigittovalue (c2);
   2194         if ((0 > h) || (0 > l))
   2195         {
   2196           r -= 2;
   2197           if (NULL != broken_encoding)
   2198             *broken_encoding = true;
   2199           decoded[w] = chr; /* Copy "as is" */
   2200         }
   2201         else
   2202         {
   2203           unsigned char out;
   2204           out =
   2205             (unsigned char)
   2206             (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2207              | ((uint8_t) ((unsigned int) l)));
   2208           decoded[w] = (char) out;
   2209         }
   2210       }
   2211     }
   2212     else
   2213       decoded[w] = chr;
   2214     ++r;
   2215     ++w;
   2216   }
   2217   return w;
   2218 }
   2219 
   2220 
   2221 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   2222 MHD_FN_PAR_CSTR_ (1) size_t
   2223 mhd_str_pct_decode_in_place_strict (char *str)
   2224 {
   2225 #ifdef MHD_FAVOR_SMALL_CODE
   2226   size_t res;
   2227   bool broken;
   2228 
   2229   res = mhd_str_pct_decode_in_place_lenient (str, &broken);
   2230   if (broken)
   2231   {
   2232     res = 0;
   2233     str[0] = 0;
   2234   }
   2235   return res;
   2236 #else  /* ! MHD_FAVOR_SMALL_CODE */
   2237   size_t r;
   2238   size_t w;
   2239   r = 0;
   2240   w = 0;
   2241 
   2242   while (0 != str[r])
   2243   {
   2244     const char chr = str[r++];
   2245     if ('%' == chr)
   2246     {
   2247       const char d1 = str[r++];
   2248       if (0 == d1)
   2249         return 0;
   2250       else
   2251       {
   2252         const char d2 = str[r++];
   2253         if (0 == d2)
   2254           return 0;
   2255         else
   2256         {
   2257           const int h = xdigittovalue (d1);
   2258           const int l = xdigittovalue (d2);
   2259           unsigned char out;
   2260           if ((0 > h) || (0 > l))
   2261             return 0;
   2262           out =
   2263             (unsigned char)
   2264             (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2265              | ((uint8_t) ((unsigned int) l)));
   2266           str[w++] = (char) out;
   2267         }
   2268       }
   2269     }
   2270     else
   2271       str[w++] = chr;
   2272   }
   2273   str[w] = 0;
   2274   return w;
   2275 #endif /* ! MHD_FAVOR_SMALL_CODE */
   2276 }
   2277 
   2278 
   2279 MHD_INTERNAL
   2280 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (1) size_t
   2281 mhd_str_pct_decode_in_place_lenient (char *restrict str,
   2282                                      bool *restrict broken_encoding)
   2283 {
   2284 #ifdef MHD_FAVOR_SMALL_CODE
   2285   size_t len;
   2286   size_t res;
   2287 
   2288   len = strlen (str);
   2289   res = mhd_str_pct_decode_lenient_n (str, len, str, len, broken_encoding);
   2290   str[res] = 0;
   2291 
   2292   return res;
   2293 #else  /* ! MHD_FAVOR_SMALL_CODE */
   2294   size_t r;
   2295   size_t w;
   2296   if (NULL != broken_encoding)
   2297     *broken_encoding = false;
   2298   r = 0;
   2299   w = 0;
   2300   while (0 != str[r])
   2301   {
   2302     const char chr = str[r++];
   2303     if ('%' == chr)
   2304     {
   2305       const char d1 = str[r++];
   2306       if (0 == d1)
   2307       {
   2308         if (NULL != broken_encoding)
   2309           *broken_encoding = true;
   2310         str[w++] = chr; /* Copy "as is" */
   2311         str[w] = 0;
   2312         return w;
   2313       }
   2314       else
   2315       {
   2316         const char d2 = str[r++];
   2317         if (0 == d2)
   2318         {
   2319           if (NULL != broken_encoding)
   2320             *broken_encoding = true;
   2321           str[w++] = chr; /* Copy "as is" */
   2322           str[w++] = d1; /* Copy "as is" */
   2323           str[w] = 0;
   2324           return w;
   2325         }
   2326         else
   2327         {
   2328           const int h = xdigittovalue (d1);
   2329           const int l = xdigittovalue (d2);
   2330           unsigned char out;
   2331           if ((0 > h) || (0 > l))
   2332           {
   2333             if (NULL != broken_encoding)
   2334               *broken_encoding = true;
   2335             str[w++] = chr; /* Copy "as is" */
   2336             str[w++] = d1;
   2337             str[w++] = d2;
   2338             continue;
   2339           }
   2340           out =
   2341             (unsigned char)
   2342             (((uint8_t) (((uint8_t) ((unsigned int) h)) << 4))
   2343              | ((uint8_t) ((unsigned int) l)));
   2344           str[w++] = (char) out;
   2345           continue;
   2346         }
   2347       }
   2348     }
   2349     str[w++] = chr;
   2350   }
   2351   str[w] = 0;
   2352   return w;
   2353 #endif /* ! MHD_FAVOR_SMALL_CODE */
   2354 }
   2355 
   2356 
   2357 mhd_static_inline MHD_FN_PAR_NONNULL_ALL_
   2358 MHD_FN_PAR_IN_SIZE_ (2, 1) bool
   2359 pct_decode_no_slash (const size_t str_len,
   2360                      const char *restrict str,
   2361                      const size_t chr_pos,
   2362                      char *restrict chr)
   2363 {
   2364   mhd_assert ('%' == *chr);
   2365   mhd_assert (*chr == str[chr_pos]);
   2366   mhd_ASSUME (str_len > chr_pos);
   2367 
   2368   if ((str_len - chr_pos) <= 2u) /* Overflow-safe check */
   2369     return false; /* The string tail has less than two chars */
   2370   else
   2371   {
   2372     const char d1 = str[chr_pos + 1u];
   2373     const char d2 = str[chr_pos + 2u];
   2374     const int h = xdigittovalue (d1);
   2375     const int l = xdigittovalue (d2);
   2376 
   2377     if ((0 <= h) && (0 <= l))
   2378     {
   2379       char dec;
   2380       mhd_ASSUME (15 >= h);
   2381       mhd_ASSUME (15 >= l);
   2382       dec = (char) ((((unsigned char) h) << 4u) | ((unsigned char) l));
   2383       if ('/' != dec)
   2384       {
   2385         *chr = dec;
   2386         return true;
   2387       }
   2388     }
   2389   }
   2390   /* No valid hex-number or a slash character (must not be encoded!) */
   2391   return false;
   2392 }
   2393 
   2394 
   2395 MHD_INTERNAL
   2396 MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_INOUT_SIZE_ (2,1) size_t
   2397 mhd_str_dec_norm_uri_path (size_t str_len,
   2398                            char *restrict str)
   2399 {
   2400   size_t r; /**< "read" position */
   2401   size_t w; /**< "write" position */
   2402 
   2403   w = 0u;
   2404   r = 0u;
   2405   while (str_len > r)
   2406   {
   2407     /* Process all segments not started with "/" (if any) */
   2408     char c;
   2409     mhd_ASSUME (w <= r);
   2410     c = str[r];
   2411     if ('/' == c)
   2412       break; /* Processed after this loop */
   2413     if (('%' == c) &&
   2414         pct_decode_no_slash (str_len,
   2415                              str,
   2416                              r,
   2417                              &c))
   2418       r += 2u;
   2419     if ('.' == c)
   2420     {
   2421       char c2;
   2422       if (str_len == r + 1u) /* overflow-safe as 'str_len > r' */
   2423       {
   2424         /* The complete string is "." */
   2425         ++r;    /* Skip "." */
   2426         break;  /* At the edge, stop */
   2427       }
   2428       mhd_ASSUME (w <= r);
   2429       c2 = str[r + 1u];
   2430       if ('/' == c2)
   2431       {
   2432         /* Found "./" at the start of the string */
   2433         r += 2u;  /* Skip "./" */
   2434         continue;
   2435       }
   2436       if (('%' == c2) &&
   2437           pct_decode_no_slash (str_len,
   2438                                str,
   2439                                r + 1u,
   2440                                &c2))
   2441         r += 2u;
   2442       if ('.' == c2)
   2443       {
   2444         char c3;
   2445         if (str_len == r + 2u) /* overflow-safe as 'str_len > r + 1 ' */
   2446         {
   2447           /* The complete string is ".." */
   2448           r += 2u;  /* Skip ".." */
   2449           break;    /* At the edge, stop */
   2450         }
   2451         mhd_ASSUME (w <= r);
   2452         c3 = str[r + 2u];
   2453         if ('/' == c3)
   2454         {
   2455           /* Found "../" at the start of the string */
   2456           r += 3u;  /* Skip "../" */
   2457           continue;
   2458         }
   2459         /* Do not write 'c3' as it has not been percent-decoded */
   2460       }
   2461       str[w++] = c;
   2462       str[w++] = c2;
   2463       r += 2u;
   2464     }
   2465     else
   2466     {
   2467       str[w++] = c;
   2468       r += 1u;
   2469     }
   2470     break;
   2471   }
   2472 
   2473   mhd_ASSUME (w <= r);
   2474   /* Found first segment which is not "../" and is not "./" OR the end of the string */
   2475   for ((void) r; str_len > r && '/' != str[r]; ++r)
   2476   {
   2477     char c;
   2478     mhd_ASSUME (w <= r);
   2479     c = str[r];
   2480     if (('%' == c) &&
   2481         pct_decode_no_slash (str_len,
   2482                              str,
   2483                              r,
   2484                              &c))
   2485       r += 2u;
   2486     mhd_ASSUME (w <= r);
   2487     str[w++] = c;
   2488   }
   2489 
   2490   /* Found first '/' which is not skipped OR the end of the string */
   2491   while (str_len > r)
   2492   {
   2493     /* Start of a "/segment" */
   2494     char slash_chr = str[r];
   2495     const size_t seg_start = w;
   2496     mhd_ASSUME ('/' == slash_chr);
   2497     str[w++] = slash_chr;
   2498     ++r;
   2499     if (str_len > r)
   2500     {
   2501       char c;
   2502       mhd_ASSUME (w <= r);
   2503       c = str[r];
   2504       if ('/' == c)
   2505         continue;
   2506       if (('%' == c) &&
   2507           pct_decode_no_slash (str_len,
   2508                                str,
   2509                                r,
   2510                                &c))
   2511         r += 2u;
   2512       if ('.' == c)
   2513       {
   2514         char c2;
   2515         if (str_len == r + 1u) /* overflow-safe as 'str_len > r' */
   2516         {
   2517           /* Found "/." at the end of the string */
   2518           ++r;   /* Skip ".", leave bare '/' */
   2519           break; /* At the edge, stop */
   2520         }
   2521         mhd_ASSUME (w <= r);
   2522         c2 = str[r + 1u];
   2523         if ('/' == c2)
   2524         {
   2525           /* Found "/./" */
   2526           w = seg_start; /* Rewind output to the '/' at the start of the segment */
   2527           ++r;      /* Skip "." */
   2528           continue; /* Go to the next "/", which will be written again */
   2529         }
   2530         if (('%' == c2) &&
   2531             pct_decode_no_slash (str_len,
   2532                                  str,
   2533                                  r + 1u,
   2534                                  &c2))
   2535           r += 2u;
   2536         if ('.' == c2)
   2537         {
   2538           char c3;
   2539           if (str_len == r + 2u) /* overflow-safe as 'str_len > r + 1 ' */
   2540           {
   2541             /* Found "/.." at the end of the string */
   2542             w = seg_start;
   2543             if (0 < w)
   2544               do
   2545               { /* Rewind output to the start of prev segment */
   2546                 --w;
   2547               } while (0 < w && '/' != str[w]);
   2548             mhd_ASSUME (w < r);
   2549             str[w++] = '/'; /* Replace prev segment with '/' */
   2550             r += 2u; /* Skip ".." */
   2551             break;   /* At the edge, stop */
   2552           }
   2553           mhd_ASSUME (w <= r);
   2554           c3 = str[r + 2u];
   2555           if ('/' == c3)
   2556           {
   2557             /* Found "/../" */
   2558             w = seg_start;
   2559             if (0 < w)
   2560               do
   2561               { /* Rewind output to the start of prev segment */
   2562                 --w;
   2563               } while (0 < w && '/' != str[w]);
   2564             r += 2u;  /* Skip ".."; put next '/' to the start of prev segment */
   2565             continue;
   2566           }
   2567           /* Do not write 'c3' as it has not been percent-decoded */
   2568         }
   2569         str[w++] = c;
   2570         str[w++] = c2;
   2571         r += 2u;
   2572       }
   2573       else
   2574       {
   2575         str[w++] = c;
   2576         r += 1u;
   2577       }
   2578       mhd_assert (seg_start < w);
   2579     }
   2580     for ((void) r; str_len > r && '/' != str[r]; ++r)
   2581     {
   2582       /* Process the end of the segment */
   2583       char c;
   2584       mhd_ASSUME (w <= r);
   2585       c = str[r];
   2586       if (('%' == c) &&
   2587           pct_decode_no_slash (str_len,
   2588                                str,
   2589                                r,
   2590                                &c))
   2591         r += 2u;
   2592       mhd_ASSUME (w <= r);
   2593       str[w++] = c;
   2594     }
   2595     mhd_assert (0u != w);
   2596   }
   2597   mhd_assert (r == str_len);
   2598 
   2599   if (str_len > w)
   2600     str[w] = '\0';
   2601 
   2602   return w;
   2603 }
   2604 
   2605 
   2606 #ifdef MHD_SUPPORT_AUTH_DIGEST
   2607 
   2608 MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
   2609 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4) bool
   2610 mhd_str_equal_quoted_bin_n (const char *quoted,
   2611                             size_t quoted_len,
   2612                             const char *unquoted,
   2613                             size_t unquoted_len)
   2614 {
   2615   size_t i;
   2616   size_t j;
   2617   if (unquoted_len < quoted_len / 2)
   2618     return false;
   2619 
   2620   j = 0;
   2621   for (i = 0; quoted_len > i && unquoted_len > j; ++i, ++j)
   2622   {
   2623     if ('\\' == quoted[i])
   2624     {
   2625       i++; /* Advance to the next character */
   2626       if (quoted_len == i)
   2627         return false; /* No character after escaping backslash */
   2628     }
   2629     if (quoted[i] != unquoted[j])
   2630       return false; /* Different characters */
   2631   }
   2632   if ((quoted_len != i) || (unquoted_len != j))
   2633     return false; /* The strings have different length */
   2634 
   2635   return true;
   2636 }
   2637 
   2638 
   2639 MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
   2640 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4) bool
   2641 mhd_str_equal_caseless_quoted_bin_n (const char *quoted,
   2642                                      size_t quoted_len,
   2643                                      const char *unquoted,
   2644                                      size_t unquoted_len)
   2645 {
   2646   size_t i;
   2647   size_t j;
   2648   if (unquoted_len < quoted_len / 2)
   2649     return false;
   2650 
   2651   j = 0;
   2652   for (i = 0; quoted_len > i && unquoted_len > j; ++i, ++j)
   2653   {
   2654     if ('\\' == quoted[i])
   2655     {
   2656       i++; /* Advance to the next character */
   2657       if (quoted_len == i)
   2658         return false; /* No character after escaping backslash */
   2659     }
   2660     if (! charsequalcaseless (quoted[i], unquoted[j]))
   2661       return false; /* Different characters */
   2662   }
   2663   if ((quoted_len != i) || (unquoted_len != j))
   2664     return false; /* The strings have different length */
   2665 
   2666   return true;
   2667 }
   2668 
   2669 
   2670 #endif /* MHD_SUPPORT_AUTH_DIGEST */
   2671 
   2672 #if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_POST_PARSER)
   2673 
   2674 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   2675 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,2) size_t
   2676 mhd_str_unquote (const char *quoted,
   2677                  size_t quoted_len,
   2678                  char *result)
   2679 {
   2680   size_t r;
   2681   size_t w;
   2682 
   2683   r = 0;
   2684   w = 0;
   2685 
   2686   while (quoted_len > r)
   2687   {
   2688     if ('\\' == quoted[r])
   2689     {
   2690       ++r;
   2691       if (quoted_len == r)
   2692         return 0; /* Last backslash is not followed by char to unescape */
   2693     }
   2694     result[w++] = quoted[r++];
   2695   }
   2696   return w;
   2697 }
   2698 
   2699 
   2700 #endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_POST_PARSER */
   2701 
   2702 #if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_AUTH_BASIC)
   2703 
   2704 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   2705 MHD_FN_PAR_IN_SIZE_ (1,2)
   2706 MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
   2707 mhd_str_quote (const char *unquoted,
   2708                size_t unquoted_len,
   2709                char *result,
   2710                size_t buf_size)
   2711 {
   2712   size_t r;
   2713   size_t w;
   2714 
   2715   r = 0;
   2716   w = 0;
   2717 
   2718 #ifndef MHD_FAVOR_SMALL_CODE
   2719   if (unquoted_len * 2 <= buf_size)
   2720   {
   2721     /* Fast loop: the output will fit the buffer with any input string content */
   2722     while (unquoted_len > r)
   2723     {
   2724       const char chr = unquoted[r++];
   2725       if (('\\' == chr) || ('\"' == chr))
   2726         result[w++] = '\\'; /* Escape current char */
   2727       result[w++] = chr;
   2728     }
   2729   }
   2730   else
   2731   {
   2732     if (unquoted_len > buf_size)
   2733       return 0; /* Quick fail: the output buffer is too small */
   2734 #else  /* MHD_FAVOR_SMALL_CODE */
   2735   if (1)
   2736   {
   2737 #endif /* MHD_FAVOR_SMALL_CODE */
   2738 
   2739     while (unquoted_len > r)
   2740     {
   2741       if (buf_size <= w)
   2742         return 0; /* The output buffer is too small */
   2743       else
   2744       {
   2745         const char chr = unquoted[r++];
   2746         if (('\\' == chr) || ('\"' == chr))
   2747         {
   2748           result[w++] = '\\'; /* Escape current char */
   2749           if (buf_size <= w)
   2750             return 0; /* The output buffer is too small */
   2751         }
   2752         result[w++] = chr;
   2753       }
   2754     }
   2755   }
   2756 
   2757   mhd_assert (w >= r);
   2758   mhd_assert (w <= r * 2);
   2759   return w;
   2760 }
   2761 
   2762 
   2763 #endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_AUTH_BASIC */
   2764 
   2765 #ifdef MHD_SUPPORT_AUTH_BASIC
   2766 
   2767 /*
   2768  * MHD_BASE64_FUNC_VERSION
   2769  * 1 = smallest,
   2770  * 2 = medium,
   2771  * 3 = fastest
   2772  */
   2773 #ifndef MHD_BASE64_FUNC_VERSION
   2774 #ifdef MHD_FAVOR_SMALL_CODE
   2775 #define MHD_BASE64_FUNC_VERSION 1
   2776 #else  /* ! MHD_FAVOR_SMALL_CODE */
   2777 #define MHD_BASE64_FUNC_VERSION 3
   2778 #endif /* ! MHD_FAVOR_SMALL_CODE */
   2779 #endif /* ! MHD_BASE64_FUNC_VERSION */
   2780 
   2781 #if MHD_BASE64_FUNC_VERSION < 1 || MHD_BASE64_FUNC_VERSION > 3
   2782 #error Wrong MHD_BASE64_FUNC_VERSION value
   2783 #endif /* MHD_BASE64_FUNC_VERSION < 1 || MHD_BASE64_FUNC_VERSION > 3 */
   2784 
   2785 #if MHD_BASE64_FUNC_VERSION == 3
   2786 #define mhd_base64_map_type int
   2787 #else  /* MHD_BASE64_FUNC_VERSION < 3 */
   2788 #define mhd_base64_map_type int8_t
   2789 #endif /* MHD_BASE64_FUNC_VERSION < 3 */
   2790 
   2791 #if MHD_BASE64_FUNC_VERSION == 1
   2792 static mhd_base64_map_type
   2793 base64_char_to_value_ (uint8_t c)
   2794 {
   2795   if ('Z' >= c)
   2796   {
   2797     if ('A' <= c)
   2798       return (mhd_base64_map_type) ((c - 'A') + 0);
   2799     else if ('0' <= c)
   2800     {
   2801       if ('9' >= c)
   2802         return (mhd_base64_map_type) ((c - '0') + 52);
   2803       else if ('=' == c)
   2804         return -2;
   2805       else
   2806         return -1;
   2807     }
   2808     else if ('+' == c)
   2809       return 62;
   2810     else if ('/' == c)
   2811       return 63;
   2812     else
   2813       return -1;
   2814   }
   2815   else if (('z' >= c) && ('a' <= c))
   2816     return (mhd_base64_map_type) ((c - 'a') + 26);
   2817   return -1;
   2818 }
   2819 
   2820 
   2821 #endif /* MHD_BASE64_FUNC_VERSION == 1 */
   2822 
   2823 
   2824 mhd_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE
   2825 
   2826 
   2827 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   2828 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4) size_t
   2829 mhd_base64_to_bin_n (const char *base64,
   2830                      size_t base64_len,
   2831                      void *bin,
   2832                      size_t bin_size)
   2833 {
   2834 #if MHD_BASE64_FUNC_VERSION >= 2
   2835   static const mhd_base64_map_type map[] = {
   2836     /* -1 = invalid char, -2 = padding
   2837     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
   2838     NUL,  SOH,  STX,  ETX,  EOT,  ENQ,  ACK,  BEL,  */
   2839     -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   2840     /*
   2841     0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
   2842     BS,   HT,   LF,   VT,   FF,   CR,   SO,   SI,   */
   2843     -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   2844     /*
   2845     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
   2846     DLE,  DC1,  DC2,  DC3,  DC4,  NAK,  SYN,  ETB,  */
   2847     -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   2848     /*
   2849     0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
   2850     CAN,  EM,   SUB,  ESC,  FS,   GS,   RS,   US,   */
   2851     -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   2852     /*
   2853     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
   2854     ' ',  '!',  '"',  '#',  '$',  '%',  '&',  '\'', */
   2855     -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   2856     /*
   2857     0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
   2858     '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',  */
   2859     -1,   -1,   -1,   62,   -1,   -1,   -1,   63,
   2860     /*
   2861     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
   2862     '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  */
   2863     52,   53,   54,   55,   56,   57,   58,   59,
   2864     /*
   2865     0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
   2866     '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',  */
   2867     60,   61,   -1,   -1,   -1,   -2,   -1,   -1,
   2868     /*
   2869     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
   2870     '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  */
   2871     -1,    0,    1,    2,    3,    4,    5,    6,
   2872     /*
   2873     0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
   2874     'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',  */
   2875     7,     8,    9,   10,   11,   12,   13,   14,
   2876     /*
   2877     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
   2878     'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  */
   2879     15,   16,   17,   18,   19,   20,   21,   22,
   2880     /*
   2881      0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
   2882     'X',  'Y',  'Z',  '[',  '\',  ']',  '^',  '_',  */
   2883     23,   24,   25,   -1,   -1,   -1,   -1,   -1,
   2884     /*
   2885     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
   2886     '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',  */
   2887     -1,   26,   27,   28,   29,   30,   31,   32,
   2888     /*
   2889     0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
   2890     'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',  */
   2891     33,   34,   35,   36,   37,   38,   39,   40,
   2892     /*
   2893     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
   2894     'p',  'q',  'r',  's',  't',  'u',  'v',  'w',  */
   2895     41,   42,   43,   44,   45,   46,   47,   48,
   2896     /*
   2897     0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
   2898     'x',  'y',  'z',  '{',  '|',  '}',  '~',  DEL,  */
   2899     49,   50,   51,   -1,   -1,   -1,   -1,   -1
   2900 
   2901 #if MHD_BASE64_FUNC_VERSION == 3
   2902     ,
   2903     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 80..8F */
   2904     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 90..9F */
   2905     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* A0..AF */
   2906     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* B0..BF */
   2907     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* C0..CF */
   2908     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* D0..DF */
   2909     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* E0..EF */
   2910     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* F0..FF */
   2911 #endif /* ! MHD_BASE64_FUNC_VERSION == 3 */
   2912   };
   2913 #define base64_char_to_value_(c) map[(c)]
   2914 #endif /* MHD_BASE64_FUNC_VERSION >= 2 */
   2915   const uint8_t *const in = (const uint8_t *) base64;
   2916   uint8_t *const out = (uint8_t *) bin;
   2917   size_t i;
   2918   size_t j;
   2919   if (0 == base64_len)
   2920     return 0;  /* Nothing to decode */
   2921   if (0 != base64_len % 4)
   2922     return 0;  /* Wrong input length */
   2923   if (base64_len / 4 * 3 - 2 > bin_size)
   2924     return 0;
   2925 
   2926   j = 0;
   2927   for (i = 0; i < (base64_len - 4); i += 4)
   2928   {
   2929 #if MHD_BASE64_FUNC_VERSION == 2
   2930     if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3])))
   2931       return 0;
   2932 #endif /* MHD_BASE64_FUNC_VERSION == 2 */
   2933     if (1)
   2934     {
   2935       const mhd_base64_map_type v1 = base64_char_to_value_ (in[i + 0]);
   2936       const mhd_base64_map_type v2 = base64_char_to_value_ (in[i + 1]);
   2937       const mhd_base64_map_type v3 = base64_char_to_value_ (in[i + 2]);
   2938       const mhd_base64_map_type v4 = base64_char_to_value_ (in[i + 3]);
   2939       if ((0 > v1) || (0 > v2) || (0 > v3) || (0 > v4))
   2940         return 0;
   2941       out[j + 0] = (uint8_t) (((uint8_t) (((uint8_t) v1) << 2))
   2942                               | ((uint8_t) (((uint8_t) v2) >> 4)));
   2943       out[j + 1] = (uint8_t) (((uint8_t) (((uint8_t) v2) << 4))
   2944                               | ((uint8_t) (((uint8_t) v3) >> 2)));
   2945       out[j + 2] = (uint8_t) (((uint8_t) (((uint8_t) v3) << 6))
   2946                               | ((uint8_t) v4));
   2947     }
   2948     j += 3;
   2949   }
   2950 #if MHD_BASE64_FUNC_VERSION == 2
   2951   if (0 != (0x80 & (in[i] | in[i + 1] | in[i + 2] | in[i + 3])))
   2952     return 0;
   2953 #endif /* MHD_BASE64_FUNC_VERSION == 2 */
   2954   if (1)
   2955   { /* The last four chars block */
   2956     const mhd_base64_map_type v1 = base64_char_to_value_ (in[i + 0]);
   2957     const mhd_base64_map_type v2 = base64_char_to_value_ (in[i + 1]);
   2958     const mhd_base64_map_type v3 = base64_char_to_value_ (in[i + 2]);
   2959     const mhd_base64_map_type v4 = base64_char_to_value_ (in[i + 3]);
   2960     if ((0 > v1) || (0 > v2))
   2961       return 0; /* Invalid char or padding at first two positions */
   2962     mhd_assert (j < bin_size);
   2963     out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v1) << 2))
   2964                           | ((uint8_t) (((uint8_t) v2) >> 4)));
   2965     if (0 > v3)
   2966     { /* Third char is either padding or invalid */
   2967       if ((-2 != v3) || (-2 != v4))
   2968         return 0;  /* Both two last chars must be padding */
   2969       if (0 != (uint8_t) (((uint8_t) v2) << 4))
   2970         return 0;  /* Wrong last char */
   2971       return j;
   2972     }
   2973     if (j >= bin_size)
   2974       return 0; /* Not enough space */
   2975     out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v2) << 4))
   2976                           | ((uint8_t) (((uint8_t) v3) >> 2)));
   2977     if (0 > v4)
   2978     { /* Fourth char is either padding or invalid */
   2979       if (-2 != v4)
   2980         return 0;  /* The char must be padding */
   2981       if (0 != (uint8_t) (((uint8_t) v3) << 6))
   2982         return 0;  /* Wrong last char */
   2983       return j;
   2984     }
   2985     if (j >= bin_size)
   2986       return 0; /* Not enough space */
   2987     out[j++] = (uint8_t) (((uint8_t) (((uint8_t) v3) << 6))
   2988                           | ((uint8_t) v4));
   2989   }
   2990   return j;
   2991 #if MHD_BASE64_FUNC_VERSION >= 2
   2992 #undef base64_char_to_value_
   2993 #endif /* MHD_BASE64_FUNC_VERSION >= 2 */
   2994 }
   2995 
   2996 
   2997 mhd_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE
   2998 
   2999 
   3000 #undef mhd_base64_map_type
   3001 
   3002 #endif /* MHD_SUPPORT_AUTH_BASIC */
   3003 
   3004 
   3005 MHD_INTERNAL MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ bool
   3006 mhd_str_starts_with_token_opt_param (const struct MHD_String *restrict str,
   3007                                      const struct MHD_String *restrict token)
   3008 {
   3009   size_t i;
   3010 
   3011   mhd_assert (0 != token->len);
   3012   mhd_assert (NULL == memchr (token->cstr, '=', token->len));
   3013   mhd_assert (NULL == memchr (token->cstr, ' ', token->len));
   3014   mhd_assert (NULL == memchr (token->cstr, '\t', token->len));
   3015 
   3016   if (str->len < token->len)
   3017     return false; /* The string is too short to match */
   3018 
   3019   if (! mhd_str_equal_caseless_bin_n (str->cstr,
   3020                                       token->cstr,
   3021                                       token->len))
   3022     return false; /* The string does not start with the token */
   3023 
   3024   for (i = token->len; i < str->len; ++i)
   3025   {
   3026     const char c = str->cstr[i];
   3027     if ((' ' == c) || ('\t' == c))
   3028       continue;
   3029     if (';' == c)
   3030       return true; /* Found the start of the token parameters */
   3031     return false; /* The initial part of the string does not fully match the token */
   3032   }
   3033   mhd_assert (0 && "The string should not have whitespace at the end");
   3034   return true;
   3035 }
   3036 
   3037 
   3038 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
   3039 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2) MHD_FN_PAR_IN_ (3)
   3040 MHD_FN_PAR_OUT_ (4) MHD_FN_PAR_OUT_ (5) enum mhd_StingStartsWithTokenResult
   3041 mhd_str_starts_with_token_req_param (
   3042   const struct MHD_String *restrict str,
   3043   const struct MHD_String *restrict token,
   3044   const struct MHD_String *restrict par,
   3045   struct mhd_BufferConst *restrict par_value,
   3046   bool *restrict par_value_needs_unquote)
   3047 {
   3048   size_t i;
   3049   const char *const restrict cstr = str->cstr;
   3050   bool token_found;
   3051   bool param_found;
   3052 
   3053   mhd_assert (0 != token->len);
   3054   mhd_assert (NULL == memchr (token->cstr, '=', token->len));
   3055   mhd_assert (NULL == memchr (token->cstr, ' ', token->len));
   3056   mhd_assert (NULL == memchr (token->cstr, '\t', token->len));
   3057   mhd_assert (NULL == memchr (par->cstr, '=', par->len));
   3058   mhd_assert (NULL == memchr (par->cstr, ' ', par->len));
   3059   mhd_assert (NULL == memchr (par->cstr, '\t', par->len));
   3060 
   3061   par_value->data = NULL;
   3062   par_value->size = 0;
   3063 
   3064   if (str->len < token->len)
   3065     return mhd_STR_STARTS_W_TOKEN_NO_TOKEN; /* The string is too short to match */
   3066 
   3067   if (! mhd_str_equal_caseless_bin_n (cstr,
   3068                                       token->cstr,
   3069                                       token->len))
   3070     return mhd_STR_STARTS_W_TOKEN_NO_TOKEN; /* The string does not start with the token */
   3071   token_found = false;
   3072   param_found = false;
   3073 
   3074   i = token->len;
   3075   do
   3076   {
   3077     /* Find start of the next parameter */
   3078     for ((void) 0; i < str->len; ++i)
   3079     {
   3080       const char c = cstr[i];
   3081       if ((' ' == c) || ('\t' == c))
   3082         continue;
   3083       if (';' == c)
   3084       {
   3085         /* Found the start of the next token parameter */
   3086         if (param_found)
   3087           return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
   3088         ++i; /* Move to the next char */
   3089         break;
   3090       }
   3091       if (',' == c)
   3092         return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* Found the start of the next token */
   3093 
   3094       if (! token_found)
   3095       {
   3096         if (i == token->len)
   3097         {
   3098           /* The initial part of the string does not fully match the token or
   3099              formatting is not correct */
   3100           return mhd_STR_STARTS_W_TOKEN_NO_TOKEN;
   3101         }
   3102         /* The string has garbage after the token and whitespace */
   3103         return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT;
   3104       }
   3105       /* The garbage after the parameter */
   3106       return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT;
   3107     }
   3108     token_found = true;
   3109 
   3110     if (i == str->len)
   3111       return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
   3112 
   3113     /* 'i' is at the start of the parameter */
   3114 
   3115     while ((' ' == cstr[i]) || ('\t' == cstr[i]))
   3116     {
   3117       if (++i == str->len)
   3118         return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
   3119     }
   3120 
   3121     /* 'i' is at the start of the parameter name */
   3122 
   3123     if (par->len > str->len - i - 1)
   3124       return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* the token is found, but the parameter is not */
   3125     else
   3126     { /* Check the parameter */
   3127       bool val_needs_unquote;
   3128       size_t j;
   3129       const char *const prm_str = cstr + i;
   3130 
   3131       for (j = 0; j < par->len; ++j)
   3132         if (! charsequalcaseless (prm_str[j],
   3133                                   par->cstr[j]))
   3134           break;
   3135       i += j;
   3136       mhd_assert (str->len > i);
   3137       if ((j == par->len) &&
   3138           ('=' == cstr[i]))
   3139       {
   3140         /* The parameter name matches required parameter */
   3141         param_found = true;
   3142         par_value->data = cstr + i + 1;
   3143       }
   3144       else
   3145       {
   3146         /* i points to the char in the parameter name */
   3147         while ('=' != cstr[i])
   3148         {
   3149           if ((';' == cstr[i])      /* end of the parameter */
   3150               || (',' == cstr[i])   /* end of the token */
   3151               || (str->len == ++i)) /* end of the field string */
   3152           {
   3153             /* parameter without the value */
   3154             return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT;
   3155           }
   3156         }
   3157       }
   3158       mhd_assert (str->len > i);
   3159       mhd_assert ('=' == cstr[i]);
   3160 
   3161       /* 'i' points to '=' between parameter name and parameter value */
   3162 
   3163       ++i; /* Advance to the first char in the parameter value */
   3164       if (str->len == i)
   3165         return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN; /* Zero-length parameter value */
   3166 
   3167       val_needs_unquote = false;
   3168 
   3169       /* 'i' points to the char after '=' */
   3170 
   3171       if ('"' == cstr[i])
   3172       {
   3173         /* The value is quoted */
   3174         if (param_found)
   3175           ++(par_value->data); /* Point to the first quoted char */
   3176         do
   3177         {
   3178           ++i; /* Advance to the next char */
   3179           if (str->len == i)
   3180             return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT; /* No closing quote */
   3181           if ('\\' == cstr[i])
   3182           {
   3183             val_needs_unquote = true;
   3184             ++i; /* Skip quoted char */
   3185             if (str->len == i)
   3186               return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT; /* No closing quote */
   3187           }
   3188         } while ('"' != cstr[i]);
   3189         if (param_found)
   3190         {
   3191           par_value->size = (size_t) ((cstr + i) - par_value->data);
   3192           *par_value_needs_unquote = val_needs_unquote;
   3193         }
   3194         /* Complete value found */
   3195         /* Check for the garbage data at the end */
   3196         ++i; /* Advance to the next char */
   3197       }
   3198       else
   3199       {
   3200         /* The value is not quoted */
   3201         while ((' ' != cstr[i]) &&
   3202                ('\t' != cstr[i]))
   3203         {
   3204           if ((';' == cstr[i])      /* end of the parameter */
   3205               || (',' == cstr[i])   /* end of the token */
   3206               || (str->len == ++i)) /* end of the field string */
   3207             break;
   3208         }
   3209         /* The end parameter value */
   3210         if (param_found)
   3211         {
   3212           par_value->size = (size_t) ((cstr + i) - par_value->data);
   3213           *par_value_needs_unquote = false;
   3214         }
   3215         /* Check for the garbage data at the end */
   3216       }
   3217 
   3218       /* 'i' points to the next char after end of the parameter value */
   3219     }
   3220   } while (i < str->len);
   3221 
   3222   mhd_assert (token_found);
   3223   return mhd_STR_STARTS_W_TOKEN_HAS_TOKEN;
   3224 }