libmicrohttpd2

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

mhd_str.h (39789B)


      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 src/mhd2/mhd_str.h
     41  * @brief  Header for string manipulating helpers
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 
     45 #ifndef MHD_STR_H
     46 #define MHD_STR_H 1
     47 
     48 #include "mhd_sys_options.h"
     49 
     50 #include "sys_base_types.h"
     51 #include "sys_bool_type.h"
     52 
     53 #include "mhd_str_types.h"
     54 #include "mhd_buffer.h"
     55 
     56 #include "mhd_str_macros.h"
     57 
     58 #ifdef MHD_FAVOR_SMALL_CODE
     59 #  include "mhd_limits.h"
     60 #endif
     61 
     62 #ifndef mhd_HAVE_STR_TO_UPPER
     63 #  ifdef MHD_SUPPORT_GNUTLS
     64 #    define mhd_HAVE_STR_TO_UPPER       1
     65 #  endif
     66 #endif
     67 
     68 /*
     69  * Block of functions/macros that use US-ASCII charset as required by HTTP
     70  * standards. Not affected by current locale settings.
     71  */
     72 
     73 #ifndef MHD_FAVOR_SMALL_CODE
     74 /**
     75  * Check two strings for equality, ignoring case of US-ASCII letters.
     76  *
     77  * @param str1 first string to compare
     78  * @param str2 second string to compare
     79  * @return 'true' if two strings are equal, 'false' otherwise.
     80  */
     81 MHD_INTERNAL bool
     82 mhd_str_equal_caseless (const char *str1,
     83                         const char *str2)
     84 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1) MHD_FN_PAR_CSTR_ (2);
     85 
     86 #else  /* MHD_FAVOR_SMALL_CODE */
     87 /* Reuse mhd_str_equal_caseless_n() to reduce size */
     88 #define mhd_str_equal_caseless(s1,s2) \
     89         mhd_str_equal_caseless_n ((s1),(s2), SIZE_MAX)
     90 #endif /* MHD_FAVOR_SMALL_CODE */
     91 
     92 
     93 /**
     94  * Check two string for equality, ignoring case of US-ASCII letters and
     95  * checking not more than @a maxlen characters.
     96  * Compares up to first terminating null character, but not more than
     97  * first @a maxlen characters.
     98  * @param str1 first string to compare
     99  * @param str2 second string to compare
    100  * @param maxlen maximum number of characters to compare
    101  * @return 'true' if two strings are equal, 'false' otherwise.
    102  */
    103 MHD_INTERNAL bool
    104 mhd_str_equal_caseless_n (const char *const str1,
    105                           const char *const str2,
    106                           size_t maxlen)
    107 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2);
    108 
    109 
    110 /**
    111  * Check two string for equality, ignoring case of US-ASCII letters and
    112  * checking not more than @a len bytes.
    113  * Compares not more first than @a len bytes, including binary zero characters.
    114  * Comparison stops at first unmatched byte.
    115  * @param str1 first string to compare
    116  * @param str2 second string to compare
    117  * @param len number of characters to compare
    118  * @return 'true' if two strings are equal, 'false' otherwise.
    119  */
    120 MHD_INTERNAL bool
    121 mhd_str_equal_caseless_bin_n (const char *const str1,
    122                               const char *const str2,
    123                               size_t len)
    124 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2);
    125 
    126 
    127 /**
    128  * Check whether string is equal statically allocated another string,
    129  * ignoring case of US-ASCII letters and checking not more than @a len bytes.
    130  *
    131  * If strings have different sizes (lengths) then macro returns boolean false
    132  * without checking the content.
    133  *
    134  * Compares not more first than @a len bytes, including binary zero characters.
    135  * Comparison stops at first unmatched byte.
    136  * @param arr the statically allocated string to compare
    137  * @param str the string to compare
    138  * @param l the number of characters in the @a s string
    139  * @return 'true' if two strings are equal, 'false' otherwise.
    140  */
    141 #define mhd_str_equal_caseless_n_st(arr,str,l) \
    142         ((mhd_SSTR_LEN (arr) == (l)) \
    143          && mhd_str_equal_caseless_bin_n (arr,str,l))
    144 
    145 /**
    146  * Check two string for equality, converting first string to US-ASCII lower case
    147  * before comparing and checking not more than @a len bytes.
    148  * Compares not more first than @a len bytes, including binary zero characters.
    149  * Comparison stops at first unmatched byte.
    150  * @param mixstr mixed case string to compare
    151  * @param lowstr lower case string to compare,
    152  *               must have no US-ASCII uppercase characters
    153  * @param len number of characters to compare
    154  * @return 'true' if two strings are equal, 'false' otherwise.
    155  */
    156 MHD_INTERNAL bool
    157 mhd_str_equal_lowercase_bin_n (const char *const mixstr,
    158                                const char *const lowstr,
    159                                size_t len)
    160 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2);
    161 
    162 /**
    163  * Convert sequence of bytes to lower case US-ASCII letters.
    164  * @param size the size of the data in the @a inbuff
    165  * @param inbuff the input data, does not need to be zero-terminated;
    166  *               if it is zero-terminated and zero-termination of @a outbuff
    167  *               is needed, make sure that @a size includes zero-termination
    168  * @param[out] outbuff the output buffer; should have at least @a size bytes
    169  *                     available
    170  */
    171 MHD_INTERNAL void
    172 mhd_str_to_lowercase_bin_n (size_t size,
    173                             const char *restrict inbuff,
    174                             char *restrict outbuff)
    175 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (2,1) MHD_FN_PAR_OUT_SIZE_ (3,1);
    176 
    177 /**
    178  * Check whether the string does not contain US-ASCII upper case letters.
    179  * @param len the length of the @a str
    180  * @param str the string to check, does not need to be zero terminated
    181  * @return 'true' if not US-ASCII letter found in the string,
    182  *         'false' otherwise.
    183  */
    184 MHD_INTERNAL bool
    185 mhd_str_is_lowercase_bin_n (size_t len,
    186                             const char *restrict str)
    187 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (2,1);
    188 
    189 
    190 #ifdef mhd_HAVE_STR_TO_UPPER
    191 /**
    192  * Convert sequence of bytes to upper case US-ASCII letters.
    193  * @param size the size of the data in the @a inbuff
    194  * @param inbuff the input data, does not need to be zero-terminated;
    195  *               if it is zero-terminated and zero-termination of @a outbuff
    196  *               is needed, make sure that @a size includes zero-termination
    197  * @param[out] outbuff the output buffer; should have at least @a size bytes
    198  *                     available
    199  */
    200 MHD_INTERNAL void
    201 mhd_str_to_uppercase_bin_n (size_t size,
    202                             const char *restrict inbuff,
    203                             char *restrict outbuff)
    204 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (2,1) MHD_FN_PAR_OUT_SIZE_ (3,1);
    205 #endif /* mhd_HAVE_STR_TO_UPPER */
    206 
    207 /**
    208  * Check whether @a str has case-insensitive @a token.
    209  * Token could be surrounded by spaces and tabs and delimited by comma.
    210  * Match succeed if substring between start, end (of string) or comma
    211  * contains only case-insensitive token and optional spaces and tabs.
    212  * @warning token must not contain null-characters except optional
    213  *          terminating null-character.
    214  * @param str the string to check
    215  * @param token the token to find
    216  * @param token_len length of token, not including optional terminating
    217  *                  null-character.
    218  * @return non-zero if two strings are equal, zero otherwise.
    219  */
    220 MHD_INTERNAL bool
    221 mhd_str_has_token_caseless (const char *restrict str,
    222                             const char *const restrict token,
    223                             size_t token_len)
    224 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1)
    225 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_IN_ (2);
    226 
    227 /**
    228  * Check whether @a str has case-insensitive static @a tkn.
    229  * Token could be surrounded by spaces and tabs and delimited by comma.
    230  * Match succeed if substring between start, end of string or comma
    231  * contains only case-insensitive token and optional spaces and tabs.
    232  * @warning tkn must be static string
    233  * @param str the string to check
    234  * @param tkn the static string of token to find
    235  * @return non-zero if two strings are equal, zero otherwise.
    236  */
    237 #define mhd_str_has_s_token_caseless(str,tkn) \
    238         mhd_str_has_token_caseless ((str),(tkn),mhd_SSTR_LEN (tkn))
    239 
    240 
    241 /**
    242  * Remove case-insensitive @a token from the @a str and put result
    243  * to the output @a buf.
    244  *
    245  * Tokens in @a str could be surrounded by spaces and tabs and delimited by
    246  * comma. The token match succeed if substring between start, end (of string)
    247  * or comma contains only case-insensitive token and optional spaces and tabs.
    248  * The quoted strings and comments are not supported by this function.
    249  *
    250  * The output string is normalised: empty tokens and repeated whitespaces
    251  * are removed, no whitespaces before commas, exactly one space is used after
    252  * each comma.
    253  *
    254  * @param str the string to process
    255  * @param str_len the length of the @a str, not including optional
    256  *                terminating null-character.
    257  * @param token the token to find
    258  * @param token_len the length of @a token, not including optional
    259  *                  terminating null-character.
    260  * @param[out] buf the output buffer, not null-terminated.
    261  * @param[in,out] buf_size pointer to the size variable, at input it
    262  *                         is the size of allocated buffer, at output
    263  *                         it is the size of the resulting string (can
    264  *                         be up to 50% larger than input) or negative value
    265  *                         if there is not enough space for the result
    266  * @return 'true' if token has been removed,
    267  *         'false' otherwise.
    268  */
    269 MHD_INTERNAL bool
    270 mhd_str_remove_token_caseless (const char *restrict str,
    271                                size_t str_len,
    272                                const char *const restrict token,
    273                                const size_t token_len,
    274                                char *restrict buf,
    275                                ssize_t *restrict buf_size)
    276 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4)
    277 MHD_FN_PAR_OUT_ (5) MHD_FN_PAR_INOUT_ (6);
    278 
    279 
    280 /**
    281  * Perform in-place case-insensitive removal of @a tokens from the @a str.
    282  *
    283  * Token could be surrounded by spaces and tabs and delimited by comma.
    284  * The token match succeed if substring between start, end (of the string), or
    285  * comma contains only case-insensitive token and optional spaces and tabs.
    286  * The quoted strings and comments are not supported by this function.
    287  *
    288  * The input string must be normalised: empty tokens and repeated whitespaces
    289  * are removed, no whitespaces before commas, exactly one space is used after
    290  * each comma. The string is updated in-place.
    291  *
    292  * Behavior is undefined is the input string in not normalised.
    293  *
    294  * @param[in,out] str the string to update
    295  * @param[in,out] str_len the length of the @a str, not including optional
    296  *                        terminating null-character, not null-terminated
    297  * @param tkns the token to find
    298  * @param tkns_len the length of @a tokens, not including optional
    299  *                   terminating null-character.
    300  * @return 'true' if any token has been removed,
    301  *         'false' otherwise.
    302  */
    303 MHD_INTERNAL bool
    304 mhd_str_remove_tokens_caseless (char *restrict str,
    305                                 size_t *restrict str_len,
    306                                 const char *const restrict tkns,
    307                                 const size_t tkns_len)
    308 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1) MHD_FN_PAR_INOUT_ (2)
    309 MHD_FN_PAR_IN_SIZE_ (3,4);
    310 
    311 
    312 #ifndef MHD_FAVOR_SMALL_CODE
    313 /* Use individual function for each case to improve speed */
    314 
    315 /**
    316  * Convert decimal US-ASCII digits in string to number in uint_fast64_t.
    317  * Conversion stopped at first non-digit character.
    318  *
    319  * @param str string to convert
    320  * @param[out] out_val pointer to uint_fast64_t to store result of conversion
    321  * @return non-zero number of characters processed on succeed,
    322  *         zero if no digit is found or resulting value is larger
    323  *         then possible to store in uint_fast64_t
    324  */
    325 MHD_INTERNAL size_t
    326 mhd_str_to_uint64 (const char *restrict str,
    327                    uint_fast64_t *restrict out_val)
    328 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1) MHD_FN_PAR_IN_ (1)
    329 MHD_FN_PAR_OUT_ (2);
    330 
    331 /**
    332  * Convert not more then @a maxlen decimal US-ASCII digits in string to
    333  * number in uint_fast64_t.
    334  * Conversion stopped at first non-digit character or after @a maxlen
    335  * digits.
    336  *
    337  * @param str string to convert
    338  * @param maxlen maximum number of characters to process
    339  * @param[out] out_val pointer to uint_fast64_t to store result of conversion
    340  * @return non-zero number of characters processed on succeed,
    341  *         zero if no digit is found or resulting value is larger
    342  *         then possible to store in uint_fast64_t
    343  */
    344 MHD_INTERNAL size_t
    345 mhd_str_to_uint64_n (const char *restrict str,
    346                      size_t maxlen,
    347                      uint_fast64_t *restrict out_val)
    348 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3);
    349 
    350 
    351 /**
    352  * Convert hexadecimal US-ASCII digits in string to number in uint_fast32_t.
    353  * Conversion stopped at first non-digit character.
    354  *
    355  * @param str string to convert
    356  * @param[out] out_val pointer to uint_fast32_t to store result of conversion
    357  * @return non-zero number of characters processed on succeed,
    358  *         zero if no digit is found or resulting value is larger
    359  *         then possible to store in uint_fast32_t
    360  */
    361 MHD_INTERNAL size_t
    362 mhd_strx_to_uint32 (const char *restrict str,
    363                     uint_fast32_t *restrict out_val)
    364 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1)
    365 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_OUT_ (2);
    366 
    367 
    368 /**
    369  * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
    370  * to number in uint_fast32_t.
    371  * Conversion stopped at first non-digit character or after @a maxlen
    372  * digits.
    373  *
    374  * @param str string to convert
    375  * @param maxlen maximum number of characters to process
    376  * @param[out] out_val pointer to uint_fast32_t to store result of conversion
    377  * @return non-zero number of characters processed on succeed,
    378  *         zero if no digit is found or resulting value is larger
    379  *         then possible to store in uint_fast32_t
    380  */
    381 MHD_INTERNAL size_t
    382 mhd_strx_to_uint32_n (const char *restrict str,
    383                       size_t maxlen,
    384                       uint_fast32_t *restrict out_val)
    385 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3);
    386 
    387 
    388 /**
    389  * Convert hexadecimal US-ASCII digits in string to number in uint_fast64_t.
    390  * Conversion stopped at first non-digit character.
    391  *
    392  * @param str string to convert
    393  * @param[out] out_val pointer to uint_fast64_t to store result of conversion
    394  * @return non-zero number of characters processed on succeed,
    395  *         zero if no digit is found or resulting value is larger
    396  *         then possible to store in uint_fast64_t
    397  */
    398 MHD_INTERNAL size_t
    399 mhd_strx_to_uint64 (const char *restrict str,
    400                     uint_fast64_t *restrict out_val)
    401 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1)
    402 MHD_FN_PAR_IN_ (1) MHD_FN_PAR_OUT_ (2);
    403 
    404 
    405 /**
    406  * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
    407  * to number in uint_fast64_t.
    408  * Conversion stopped at first non-digit character or after @a maxlen
    409  * digits.
    410  *
    411  * @param str string to convert
    412  * @param maxlen maximum number of characters to process
    413  * @param[out] out_val pointer to uint_fast64_t to store result of conversion
    414  * @return non-zero number of characters processed on succeed,
    415  *         zero if no digit is found or resulting value is larger
    416  *         then possible to store in uint_fast64_t
    417  */
    418 MHD_INTERNAL size_t
    419 mhd_strx_to_uint64_n (const char *restrict str,
    420                       size_t maxlen,
    421                       uint_fast64_t *restrict out_val)
    422 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3);
    423 
    424 #else  /* MHD_FAVOR_SMALL_CODE */
    425 /* Use one universal function and macros to reduce size */
    426 
    427 /**
    428  * Generic function for converting not more then @a maxlen
    429  * hexadecimal or decimal US-ASCII digits in string to number.
    430  * Conversion stopped at first non-digit character or after @a maxlen
    431  * digits.
    432  * To be used only within macro.
    433  *
    434  * @param str the string to convert
    435  * @param maxlen the maximum number of characters to process
    436  * @param out_val the pointer to variable to store result of conversion
    437  * @param val_size the size of variable pointed by @a out_val, in bytes, 4 or 8
    438  * @param max_val the maximum decoded number
    439  * @param base the numeric base, 10 or 16
    440  * @return non-zero number of characters processed on succeed,
    441  *         zero if no digit is found, resulting value is larger
    442  *         then @a max_val, @a val_size is not 4 or 8
    443  *         or @a base is not 10 or 16
    444  */
    445 MHD_INTERNAL size_t
    446 mhd_str_to_uvalue_n (const char *restrict str,
    447                      size_t maxlen,
    448                      void *restrict out_val,
    449                      size_t val_size,
    450                      uint_fast64_t max_val,
    451                      unsigned int base)
    452 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4);
    453 
    454 #define mhd_str_to_uint64(s,ov) \
    455         mhd_str_to_uvalue_n ((s),SIZE_MAX,(ov), \
    456                              sizeof(uint_fast64_t), \
    457                              UINT64_MAX,10)
    458 
    459 #define mhd_str_to_uint64_n(s,ml,ov) \
    460         mhd_str_to_uvalue_n ((s),(ml),(ov), \
    461                              sizeof(uint_fast64_t), \
    462                              UINT64_MAX,10)
    463 
    464 #define mhd_strx_to_sizet(s,ov) \
    465         mhd_str_to_uvalue_n ((s),SIZE_MAX,(ov), \
    466                              sizeof(size_t),SIZE_MAX, \
    467                              16)
    468 
    469 #define mhd_strx_to_sizet_n(s,ml,ov) \
    470         mhd_str_to_uvalue_n ((s),(ml),(ov), \
    471                              sizeof(size_t), \
    472                              SIZE_MAX,16)
    473 
    474 #define mhd_strx_to_uint32(s,ov) \
    475         mhd_str_to_uvalue_n ((s),SIZE_MAX,(ov), \
    476                              sizeof(uint_fast32_t), \
    477                              UINT32_MAX,16)
    478 
    479 #define mhd_strx_to_uint32_n(s,ml,ov) \
    480         mhd_str_to_uvalue_n ((s),(ml),(ov), \
    481                              sizeof(uint_fast32_t), \
    482                              UINT32_MAX,16)
    483 
    484 #define mhd_strx_to_uint64(s,ov) \
    485         mhd_str_to_uvalue_n ((s),SIZE_MAX,(ov), \
    486                              sizeof(uint_fast64_t), \
    487                              UINT64_MAX,16)
    488 
    489 #define mhd_strx_to_uint64_n(s,ml,ov) \
    490         mhd_str_to_uvalue_n ((s),(ml),(ov), \
    491                              sizeof(uint_fast64_t), \
    492                              UINT64_MAX,16)
    493 
    494 #endif /* MHD_FAVOR_SMALL_CODE */
    495 
    496 
    497 /**
    498  * Convert uint_fast32_t value to hexdecimal US-ASCII string.
    499  * @note: result is NOT zero-terminated.
    500  * @param val the value to convert
    501  * @param buf the buffer to result to
    502  * @param buf_size size of the @a buffer
    503  * @return number of characters has been put to the @a buf,
    504  *         zero if buffer is too small (buffer may be modified).
    505  */
    506 MHD_INTERNAL size_t
    507 mhd_uint32_to_strx (uint_fast32_t val,
    508                     char *buf,
    509                     size_t buf_size)
    510 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (2,3);
    511 
    512 
    513 #ifndef MHD_FAVOR_SMALL_CODE
    514 /**
    515  * Convert uint_least16_t value to decimal US-ASCII string.
    516  * @note: result is NOT zero-terminated.
    517  * @param val the value to convert
    518  * @param buf the buffer to result to
    519  * @param buf_size size of the @a buffer
    520  * @return number of characters has been put to the @a buf,
    521  *         zero if buffer is too small (buffer may be modified).
    522  */
    523 MHD_INTERNAL size_t
    524 mhd_uint16_to_str (uint_least16_t val,
    525                    char *buf,
    526                    size_t buf_size)
    527 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (2,3);
    528 
    529 #else  /* MHD_FAVOR_SMALL_CODE */
    530 #define mhd_uint16_to_str(v,b,s) mhd_uint64_to_str (v,b,s)
    531 #endif /* MHD_FAVOR_SMALL_CODE */
    532 
    533 
    534 /**
    535  * Convert uint_fast64_t value to decimal US-ASCII string.
    536  * @note: result is NOT zero-terminated.
    537  * @param val the value to convert
    538  * @param buf the buffer to result to
    539  * @param buf_size size of the @a buffer
    540  * @return number of characters has been put to the @a buf,
    541  *         zero if buffer is too small (buffer may be modified).
    542  */
    543 MHD_INTERNAL size_t
    544 mhd_uint64_to_str (uint_fast64_t val,
    545                    char *buf,
    546                    size_t buf_size)
    547 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (2,3);
    548 
    549 
    550 /**
    551  * Convert uint_least16_t value to decimal US-ASCII string padded with
    552  * zeros on the left side.
    553  *
    554  * @note: result is NOT zero-terminated.
    555  * @param val the value to convert
    556  * @param min_digits the minimal number of digits to print,
    557  *                   output padded with zeros on the left side,
    558  *                   'zero' value is interpreted as 'one',
    559  *                   valid values are 3, 2, 1, 0
    560  * @param buf the buffer to result to
    561  * @param buf_size size of the @a buffer
    562  * @return number of characters has been put to the @a buf,
    563  *         zero if buffer is too small (buffer may be modified).
    564  */
    565 MHD_INTERNAL size_t
    566 mhd_uint8_to_str_pad (uint8_t val,
    567                       uint8_t min_digits,
    568                       char *buf,
    569                       size_t buf_size)
    570 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (3,4);
    571 
    572 
    573 /**
    574  * Convert @a size bytes from input binary data to lower case
    575  * hexadecimal digits.
    576  * Result is NOT zero-terminated
    577  * @param bin the pointer to the binary data to convert
    578  * @param size the size in bytes of the binary data to convert
    579  * @param[out] hex the output buffer, should be at least 2 * @a size
    580  * @return The number of characters written to the output buffer.
    581  */
    582 MHD_INTERNAL size_t
    583 mhd_bin_to_hex (const void *restrict bin,
    584                 size_t size,
    585                 char *restrict hex)
    586 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3);
    587 
    588 /**
    589  * Convert @a size bytes from input binary data to lower case
    590  * hexadecimal digits, zero-terminate the result.
    591  * @param bin the pointer to the binary data to convert
    592  * @param size the size in bytes of the binary data to convert
    593  * @param[out] hex the output buffer, should be at least 2 * @a size + 1
    594  * @return The number of characters written to the output buffer,
    595  *         not including terminating zero.
    596  */
    597 MHD_INTERNAL size_t
    598 mhd_bin_to_hex_z (const void *restrict bin,
    599                   size_t size,
    600                   char *restrict hex)
    601 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1, 2) MHD_FN_PAR_OUT_ (3);
    602 
    603 /**
    604  * Convert hexadecimal digits to binary data.
    605  *
    606  * The input decoded byte-by-byte (each byte is two hexadecimal digits).
    607  * If length is an odd number, extra leading zero is assumed.
    608  *
    609  * @param hex the input string with hexadecimal digits
    610  * @param len the length of the input string
    611  * @param[out] bin the output buffer, must be at least len/2 bytes long (or
    612  *                 len/2 + 1 if @a len is not even number)
    613  * @return the number of bytes written to the output buffer,
    614  *         zero if found any character which is not hexadecimal digits
    615  */
    616 MHD_INTERNAL size_t
    617 mhd_hex_to_bin (const char *restrict hex,
    618                 size_t len,
    619                 void *restrict bin)
    620 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_ (3);
    621 
    622 /**
    623  * Decode string with percent-encoded characters as defined by
    624  * RFC 3986 #section-2.1.
    625  *
    626  * This function decode string by converting percent-encoded characters to
    627  * their decoded versions and copying all other characters without extra
    628  * processing.
    629  *
    630  * @param pct_encoded the input string to be decoded
    631  * @param pct_encoded_len the length of the @a pct_encoded
    632  * @param[out] decoded the output buffer, NOT zero-terminated, can point
    633  *                     to the same buffer as @a pct_encoded
    634  * @param buf_size the size of the output buffer
    635  * @return the number of characters written to the output buffer or
    636  *         zero if any percent-encoded characters is broken ('%' followed
    637  *         by less than two hexadecimal digits) or output buffer is too
    638  *         small to hold the result
    639  */
    640 MHD_INTERNAL size_t
    641 mhd_str_pct_decode_strict_n (const char *pct_encoded,
    642                              size_t pct_encoded_len,
    643                              char *decoded,
    644                              size_t buf_size)
    645 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4);
    646 
    647 /**
    648  * Decode string with percent-encoded characters as defined by
    649  * RFC 3986 #section-2.1.
    650  *
    651  * This function decode string by converting percent-encoded characters to
    652  * their decoded versions and copying all other characters without extra
    653  * processing.
    654  *
    655  * Any invalid percent-encoding sequences ('%' symbol not followed by two
    656  * valid hexadecimal digits) are copied to the output string without decoding.
    657  *
    658  * @param pct_encoded the input string to be decoded
    659  * @param pct_encoded_len the length of the @a pct_encoded
    660  * @param[out] decoded the output buffer, NOT zero-terminated, can point
    661  *                     to the same buffer as @a pct_encoded
    662  * @param buf_size the size of the output buffer
    663  * @param[out] broken_encoding will be set to true if any '%' symbol is not
    664  *                             followed by two valid hexadecimal digits,
    665  *                             optional, can be NULL
    666  * @return the number of characters written to the output buffer or
    667  *         zero if output buffer is too small to hold the result
    668  */
    669 MHD_INTERNAL size_t
    670 mhd_str_pct_decode_lenient_n (const char *pct_encoded,
    671                               size_t pct_encoded_len,
    672                               char *decoded,
    673                               size_t buf_size,
    674                               bool *restrict broken_encoding)
    675 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3)
    676 MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4);
    677 
    678 
    679 /**
    680  * Decode string in-place with percent-encoded characters as defined by
    681  * RFC 3986 #section-2.1.
    682  *
    683  * This function decode string by converting percent-encoded characters to
    684  * their decoded versions and copying back all other characters without extra
    685  * processing.
    686  *
    687  * @param[in,out] str the string to be updated in-place, must be zero-terminated
    688  *                    on input, the output is zero-terminated; the string is
    689  *                    truncated to zero length if broken encoding is found
    690  * @return the number of character in decoded string
    691  */
    692 MHD_INTERNAL size_t
    693 mhd_str_pct_decode_in_place_strict (char *str)
    694 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_CSTR_ (1);
    695 
    696 
    697 /**
    698  * Decode string in-place with percent-encoded characters as defined by
    699  * RFC 3986 #section-2.1.
    700  *
    701  * This function decode string by converting percent-encoded characters to
    702  * their decoded versions and copying back all other characters without extra
    703  * processing.
    704  *
    705  * Any invalid percent-encoding sequences ('%' symbol not followed by two
    706  * valid hexadecimal digits) are copied to the output string without decoding.
    707  *
    708  * @param[in,out] str the string to be updated in-place, must be zero-terminated
    709  *                    on input, the output is zero-terminated
    710  * @param[out] broken_encoding will be set to true if any '%' symbol is not
    711  *                             followed by two valid hexadecimal digits,
    712  *                             optional, can be NULL
    713  * @return the number of character in decoded string
    714  */
    715 MHD_INTERNAL size_t
    716 mhd_str_pct_decode_in_place_lenient (char *restrict str,
    717                                      bool *restrict broken_encoding)
    718 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_CSTR_ (1);
    719 
    720 MHD_INTERNAL size_t
    721 mhd_str_dec_norm_uri_path (size_t str_len,
    722                            char *restrict str)
    723 MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_INOUT_SIZE_ (2,1);
    724 
    725 
    726 #ifdef MHD_SUPPORT_AUTH_DIGEST
    727 /**
    728  * Check two strings for equality, "unquoting" the first string from quoted
    729  * form as specified by RFC7230#section-3.2.6 and RFC7694#quoted.strings.
    730  *
    731  * Null-termination for input strings is not required, binary zeros compared
    732  * like other characters.
    733  *
    734  * @param quoted the quoted string to compare, must NOT include leading and
    735  *               closing DQUOTE chars, does not need to be zero-terminated
    736  * @param quoted_len the length in chars of the @a quoted string
    737  * @param unquoted the unquoted string to compare, does not need to be
    738  *                 zero-terminated
    739  * @param unquoted_len the length in chars of the @a unquoted string
    740  * @return zero if quoted form is broken (no character after the last escaping
    741  *         backslash), zero if strings are not equal after unquoting of the
    742  *         first string,
    743  *         non-zero if two strings are equal after unquoting of the
    744  *         first string.
    745  */
    746 MHD_INTERNAL bool
    747 mhd_str_equal_quoted_bin_n (const char *quoted,
    748                             size_t quoted_len,
    749                             const char *unquoted,
    750                             size_t unquoted_len)
    751 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
    752   MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4);
    753 
    754 /**
    755  * Check whether the string after "unquoting" equals static string.
    756  *
    757  * Null-termination for input string is not required, binary zeros compared
    758  * like other characters.
    759  *
    760  * @param q the quoted string to compare, must NOT include leading and
    761  *          closing DQUOTE chars, does not need to be zero-terminated
    762  * @param l the length in chars of the @a q string
    763  * @param u the unquoted static string to compare
    764  * @return zero if quoted form is broken (no character after the last escaping
    765  *         backslash), zero if strings are not equal after unquoting of the
    766  *         first string,
    767  *         non-zero if two strings are equal after unquoting of the
    768  *         first string.
    769  */
    770 #define mhd_str_equal_quoted_s_bin_n(q,l,u) \
    771         mhd_str_equal_quoted_bin_n (q,l,u,mhd_SSTR_LEN (u))
    772 
    773 /**
    774  * Check two strings for equality, "unquoting" the first string from quoted
    775  * form as specified by RFC7230#section-3.2.6 and RFC7694#quoted.strings and
    776  * ignoring case of US-ASCII letters.
    777  *
    778  * Null-termination for input strings is not required, binary zeros compared
    779  * like other characters.
    780  *
    781  * @param quoted the quoted string to compare, must NOT include leading and
    782  *               closing DQUOTE chars, does not need to be zero-terminated
    783  * @param quoted_len the length in chars of the @a quoted string
    784  * @param unquoted the unquoted string to compare, does not need to be
    785  *                 zero-terminated
    786  * @param unquoted_len the length in chars of the @a unquoted string
    787  * @return zero if quoted form is broken (no character after the last escaping
    788  *         backslash), zero if strings are not equal after unquoting of the
    789  *         first string,
    790  *         non-zero if two strings are caseless equal after unquoting of the
    791  *         first string.
    792  */
    793 MHD_INTERNAL bool
    794 mhd_str_equal_caseless_quoted_bin_n (const char *quoted,
    795                                      size_t quoted_len,
    796                                      const char *unquoted,
    797                                      size_t unquoted_len)
    798 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_
    799   MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_IN_SIZE_ (3,4);
    800 
    801 /**
    802  * Check whether the string after "unquoting" equals static string, ignoring
    803  * case of US-ASCII letters.
    804  *
    805  * Null-termination for input string is not required, binary zeros compared
    806  * like other characters.
    807  *
    808  * @param q the quoted string to compare, must NOT include leading and
    809  *          closing DQUOTE chars, does not need to be zero-terminated
    810  * @param l the length in chars of the @a q string
    811  * @param u the unquoted static string to compare
    812  * @return zero if quoted form is broken (no character after the last escaping
    813  *         backslash), zero if strings are not equal after unquoting of the
    814  *         first string,
    815  *         non-zero if two strings are caseless equal after unquoting of the
    816  *         first string.
    817  */
    818 #define mhd_str_equal_caseless_quoted_s_bin_n(q,l,u) \
    819         mhd_str_equal_caseless_quoted_bin_n (q,l,u,mhd_SSTR_LEN (u))
    820 
    821 #endif /* MHD_SUPPORT_AUTH_DIGEST */
    822 
    823 #if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_POST_PARSER)
    824 
    825 /**
    826  * Convert string from quoted to unquoted form as specified by
    827  * RFC7230#section-3.2.6 and RFC7694#quoted.strings.
    828  *
    829  * @param quoted the quoted string, must NOT include leading and closing
    830  *               DQUOTE chars, does not need to be zero-terminated
    831  * @param quoted_len the length in chars of the @a quoted string
    832  * @param[out] result the pointer to the buffer to put the result, must
    833  *                    be at least @a size character long. May be modified even
    834  *                    if @a quoted is invalid sequence. The result is NOT
    835  *                    zero-terminated.
    836  * @return The number of characters written to the output buffer,
    837  *         zero if last backslash is not followed by any character (or
    838  *         @a quoted_len is zero).
    839  */
    840 MHD_INTERNAL size_t
    841 mhd_str_unquote (const char *quoted,
    842                  size_t quoted_len,
    843                  char *result)
    844 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,2);
    845 
    846 #endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_POST_PARSER */
    847 
    848 #if defined(MHD_SUPPORT_AUTH_DIGEST) || defined(MHD_SUPPORT_AUTH_BASIC)
    849 
    850 /**
    851  * Convert string from unquoted to quoted form as specified by
    852  * RFC7230#section-3.2.6 and RFC7694#quoted.strings.
    853  *
    854  * @param unquoted the unquoted string, does not need to be zero-terminated
    855  * @param unquoted_len the length in chars of the @a unquoted string
    856  * @param[out] result the pointer to the buffer to put the result. May be
    857  *                    modified even if function failed due to insufficient
    858  *                    space. The result is NOT zero-terminated and does not
    859  *                    have opening and closing DQUOTE chars.
    860  * @param buf_size the size of the allocated memory for @a result
    861  * @return The number of copied characters, can be up to two times more than
    862  *         @a unquoted_len, zero if @a unquoted_len is zero or if quoted
    863  *         string is larger than @a buf_size.
    864  */
    865 MHD_INTERNAL size_t
    866 mhd_str_quote (const char *unquoted,
    867                size_t unquoted_len,
    868                char *result,
    869                size_t buf_size)
    870 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4);
    871 
    872 #endif /* MHD_SUPPORT_AUTH_DIGEST || MHD_SUPPORT_AUTH_BASIC */
    873 
    874 #ifdef MHD_SUPPORT_AUTH_BASIC
    875 
    876 /**
    877  * Returns the maximum possible size of the Base64 decoded data.
    878  * The real recoded size could be up to two bytes smaller.
    879  * @param enc_size the size of encoded data, in characters
    880  * @return the maximum possible size of the decoded data, in bytes, if
    881  *         @a enc_size is valid (properly padded),
    882  *         undefined value smaller then @a enc_size if @a enc_size is not valid
    883  */
    884 #define mhd_base64_max_dec_size(enc_size) (((enc_size) / 4) * 3)
    885 
    886 /**
    887  * Convert Base64 encoded string to binary data.
    888  * @param base64 the input string with Base64 encoded data, could be NOT zero
    889  *               terminated
    890  * @param base64_len the number of characters to decode in @a base64 string,
    891  *                   valid number must be a multiple of four
    892  * @param[out] bin the pointer to the output buffer, the buffer may be altered
    893  *                 even if decoding failed
    894  * @param bin_size the size of the @a bin buffer in bytes, if the size is
    895  *                 at least @a base64_len / 4 * 3 then result will always
    896  *                 fit, regardless of the amount of the padding characters
    897  * @return 0 if @a base64_len is zero, or input string has wrong data (not
    898  *         valid Base64 sequence), or @a bin_size is too small;
    899  *         non-zero number of bytes written to the @a bin, the number must be
    900  *         (base64_len / 4 * 3 - 2), (base64_len / 4 * 3 - 1) or
    901  *         (base64_len / 4 * 3), depending on the number of padding characters.
    902  */
    903 MHD_INTERNAL size_t
    904 mhd_base64_to_bin_n (const char *base64,
    905                      size_t base64_len,
    906                      void *bin,
    907                      size_t bin_size)
    908 MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (1,2) MHD_FN_PAR_OUT_SIZE_ (3,4);
    909 
    910 #endif /* MHD_SUPPORT_AUTH_BASIC */
    911 
    912 
    913 /**
    914  * Check whether the given field value string starts with given token.
    915  * Token matched case-insensitive.
    916  *
    917  * Matched considered successful if string has given token at the first
    918  * position. The token may be followed by optional whitespaces and the semicolon
    919  * symbol. The string is not checked after the semicolon (if any).
    920  *
    921  * @param str the string to check
    922  * @param token the token to find, must not be empty
    923  * @return 'true' if match is successful,
    924  *         'false' otherwise
    925  */
    926 MHD_INTERNAL bool
    927 mhd_str_starts_with_token_opt_param (const struct MHD_String *restrict str,
    928                                      const struct MHD_String *restrict token)
    929 MHD_FN_PURE_ MHD_FN_PAR_NONNULL_ALL_;
    930 
    931 
    932 /**
    933  * The result of check for token with parameter
    934  */
    935 enum MHD_FIXED_ENUM_ mhd_StingStartsWithTokenResult
    936 {
    937   /**
    938    * The string does not start with the specified token
    939    */
    940   mhd_STR_STARTS_W_TOKEN_NO_TOKEN = 0
    941   ,
    942   /**
    943    * The string has specified token at the initial position
    944    * @note While formatting problems are not detected, it does not guarantee
    945    *       that string has a perfect format.
    946    */
    947   mhd_STR_STARTS_W_TOKEN_HAS_TOKEN = 1
    948   ,
    949   /**
    950    * The string has specified token at the initial position, but broken
    951    * formatting is detected.
    952    */
    953   mhd_STR_STARTS_W_TOKEN_HAS_TOKEN_BAD_FORMAT = -1
    954 };
    955 
    956 /**
    957  * Check whether the given field value string starts with given token, find
    958  * required parameter.
    959  * Token and parameter matched case-insensitive.
    960  *
    961  * Matched considered successful if string has given token at the first
    962  * position. The token should be followed by optional whitespaces and
    963  * one or more parameters, delimited by the semicolon symbol.
    964  *
    965  * @param str the string to check
    966  * @param token the token to find, must not be empty
    967  * @param par the name of the parameter, must not be empty
    968  * @param[out] par_value set to the found parameter value or @a data member
    969  *                       set to NULL if parameter is not found
    970  * @param par_value_needs_unquote set to 'true' if @a par_value
    971  *                                needs to be "unquoted"
    972  * @return result of token detection and string parsing; if token is found
    973  *         the presence of the required parameter is indicated only
    974  *         by @a par_value
    975  *
    976  */
    977 MHD_INTERNAL enum mhd_StingStartsWithTokenResult
    978 mhd_str_starts_with_token_req_param (
    979   const struct MHD_String *restrict str,
    980   const struct MHD_String *restrict token,
    981   const struct MHD_String *restrict par,
    982   struct mhd_BufferConst *restrict par_value,
    983   bool *restrict par_value_needs_unquote)
    984 MHD_FN_PAR_NONNULL_ALL_
    985 MHD_FN_PAR_IN_(1) MHD_FN_PAR_IN_(2) MHD_FN_PAR_IN_(3)
    986 MHD_FN_PAR_OUT_(4) MHD_FN_PAR_OUT_ (5);
    987 
    988 #endif /* MHD_STR_H */