libmicrohttpd2

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

mhd_str.h (39950B)


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