Blame src/microhttpd/mhd_str.c

Packit 875988
/*
Packit 875988
  This file is part of libmicrohttpd
Packit 875988
  Copyright (C) 2015, 2016 Karlson2k (Evgeny Grin)
Packit 875988
Packit 875988
  This library is free software; you can redistribute it and/or
Packit 875988
  modify it under the terms of the GNU Lesser General Public
Packit 875988
  License as published by the Free Software Foundation; either
Packit 875988
  version 2.1 of the License, or (at your option) any later version.
Packit 875988
Packit 875988
  This library is distributed in the hope that it will be useful,
Packit 875988
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 875988
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 875988
  Lesser General Public License for more details.
Packit 875988
Packit 875988
  You should have received a copy of the GNU Lesser General Public
Packit 875988
  License along with this library; if not, write to the Free Software
Packit 875988
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit 875988
*/
Packit 875988
Packit 875988
/**
Packit 875988
 * @file microhttpd/mhd_str.c
Packit 875988
 * @brief  Functions implementations for string manipulating
Packit 875988
 * @author Karlson2k (Evgeny Grin)
Packit 875988
 */
Packit 875988
Packit 875988
#include "mhd_str.h"
Packit 875988
Packit 875988
#ifdef HAVE_STDBOOL_H
Packit 875988
#include <stdbool.h>
Packit 875988
#endif
Packit 875988
Packit 875988
#include "mhd_limits.h"
Packit 875988
Packit 875988
#ifdef MHD_FAVOR_SMALL_CODE
Packit 875988
#ifdef _MHD_static_inline
Packit 875988
#undef _MHD_static_inline
Packit 875988
#endif /* _MHD_static_inline */
Packit 875988
/* Do not force inlining and do not use macro functions, use normal static
Packit 875988
   functions instead.
Packit 875988
   This may give more flexibility for size optimizations. */
Packit 875988
#define _MHD_static_inline static
Packit 875988
#ifndef INLINE_FUNC
Packit 875988
#define INLINE_FUNC 1
Packit 875988
#endif /* !INLINE_FUNC */
Packit 875988
#endif /* MHD_FAVOR_SMALL_CODE */
Packit 875988
Packit 875988
/*
Packit 875988
 * Block of functions/macros that use US-ASCII charset as required by HTTP
Packit 875988
 * standards. Not affected by current locale settings.
Packit 875988
 */
Packit 875988
Packit 875988
#ifdef INLINE_FUNC
Packit 875988
Packit 875988
#if 0 /* Disable unused functions. */
Packit 875988
/**
Packit 875988
 * Check whether character is lower case letter in US-ASCII
Packit 875988
 *
Packit 875988
 * @param c character to check
Packit 875988
 * @return non-zero if character is lower case letter, zero otherwise
Packit 875988
 */
Packit 875988
_MHD_static_inline bool
Packit 875988
isasciilower (char c)
Packit 875988
{
Packit 875988
  return (c >= 'a') && (c <= 'z');
Packit 875988
}
Packit 875988
#endif /* Disable unused functions. */
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Check whether character is upper case letter in US-ASCII
Packit 875988
 *
Packit 875988
 * @param c character to check
Packit 875988
 * @return non-zero if character is upper case letter, zero otherwise
Packit 875988
 */
Packit 875988
_MHD_static_inline bool
Packit 875988
isasciiupper (char c)
Packit 875988
{
Packit 875988
  return (c >= 'A') && (c <= 'Z');
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
#if 0 /* Disable unused functions. */
Packit 875988
/**
Packit 875988
 * Check whether character is letter in US-ASCII
Packit 875988
 *
Packit 875988
 * @param c character to check
Packit 875988
 * @return non-zero if character is letter in US-ASCII, zero otherwise
Packit 875988
 */
Packit 875988
_MHD_static_inline bool
Packit 875988
isasciialpha (char c)
Packit 875988
{
Packit 875988
  return isasciilower (c) || isasciiupper (c);
Packit 875988
}
Packit 875988
#endif /* Disable unused functions. */
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Check whether character is decimal digit in US-ASCII
Packit 875988
 *
Packit 875988
 * @param c character to check
Packit 875988
 * @return non-zero if character is decimal digit, zero otherwise
Packit 875988
 */
Packit 875988
_MHD_static_inline bool
Packit 875988
isasciidigit (char c)
Packit 875988
{
Packit 875988
  return (c >= '0') && (c <= '9');
Packit 875988
}
Packit 875988
Packit 875988
#if 0 /* Disable unused functions. */
Packit 875988
/**
Packit 875988
 * Check whether character is hexadecimal digit in US-ASCII
Packit 875988
 *
Packit 875988
 * @param c character to check
Packit 875988
 * @return non-zero if character is decimal digit, zero otherwise
Packit 875988
 */
Packit 875988
_MHD_static_inline bool
Packit 875988
isasciixdigit (char c)
Packit 875988
{
Packit 875988
  return isasciidigit (c) ||
Packit 875988
    ( (c >= 'A') && (c <= 'F') ) ||
Packit 875988
    ( (c >= 'a') && (c <= 'f') );
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Check whether character is decimal digit or letter in US-ASCII
Packit 875988
 *
Packit 875988
 * @param c character to check
Packit 875988
 * @return non-zero if character is decimal digit or letter, zero otherwise
Packit 875988
 */
Packit 875988
_MHD_static_inline bool
Packit 875988
isasciialnum (char c)
Packit 875988
{
Packit 875988
  return isasciialpha (c) || isasciidigit (c);
Packit 875988
}
Packit 875988
#endif /* Disable unused functions. */
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Convert US-ASCII character to lower case.
Packit 875988
 * If character is upper case letter in US-ASCII than it's converted to lower
Packit 875988
 * case analog. If character is NOT upper case letter than it's returned
Packit 875988
 * unmodified.
Packit 875988
 *
Packit 875988
 * @param c character to convert
Packit 875988
 * @return converted to lower case character
Packit 875988
 */
Packit 875988
_MHD_static_inline char
Packit 875988
toasciilower (char c)
Packit 875988
{
Packit 875988
  return isasciiupper (c) ? (c - 'A' + 'a') : c;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
#if 0 /* Disable unused functions. */
Packit 875988
/**
Packit 875988
 * Convert US-ASCII character to upper case.
Packit 875988
 * If character is lower case letter in US-ASCII than it's converted to upper
Packit 875988
 * case analog. If character is NOT lower case letter than it's returned
Packit 875988
 * unmodified.
Packit 875988
 *
Packit 875988
 * @param c character to convert
Packit 875988
 * @return converted to upper case character
Packit 875988
 */
Packit 875988
_MHD_static_inline char
Packit 875988
toasciiupper (char c)
Packit 875988
{
Packit 875988
  return isasciilower (c) ? (c - 'a' + 'A') : c;
Packit 875988
}
Packit 875988
#endif /* Disable unused functions. */
Packit 875988
Packit 875988
Packit 875988
#if defined(MHD_FAVOR_SMALL_CODE) /* Used only in MHD_str_to_uvalue_n_() */
Packit 875988
/**
Packit 875988
 * Convert US-ASCII decimal digit to its value.
Packit 875988
 *
Packit 875988
 * @param c character to convert
Packit 875988
 * @return value of decimal digit or -1 if @ c is not decimal digit
Packit 875988
 */
Packit 875988
_MHD_static_inline int
Packit 875988
todigitvalue (char c)
Packit 875988
{
Packit 875988
  if (isasciidigit (c))
Packit 875988
    return (unsigned char)(c - '0');
Packit 875988
Packit 875988
  return -1;
Packit 875988
}
Packit 875988
#endif /* MHD_FAVOR_SMALL_CODE */
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Convert US-ASCII hexadecimal digit to its value.
Packit 875988
 *
Packit 875988
 * @param c character to convert
Packit 875988
 * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
Packit 875988
 */
Packit 875988
_MHD_static_inline int
Packit 875988
toxdigitvalue (char c)
Packit 875988
{
Packit 875988
  if (isasciidigit (c))
Packit 875988
    return (unsigned char)(c - '0');
Packit 875988
  if ( (c >= 'A') && (c <= 'F') )
Packit 875988
    return (unsigned char)(c - 'A' + 10);
Packit 875988
  if ( (c >= 'a') && (c <= 'f') )
Packit 875988
    return (unsigned char)(c - 'a' + 10);
Packit 875988
Packit 875988
  return -1;
Packit 875988
}
Packit 875988
#else  /* !INLINE_FUNC */
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Checks whether character is lower case letter in US-ASCII
Packit 875988
 *
Packit 875988
 * @param c character to check
Packit 875988
 * @return boolean true if character is lower case letter,
Packit 875988
 *         boolean false otherwise
Packit 875988
 */
Packit 875988
#define isasciilower(c) (((char)(c)) >= 'a' && ((char)(c)) <= 'z')
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Checks whether character is upper case letter in US-ASCII
Packit 875988
 *
Packit 875988
 * @param c character to check
Packit 875988
 * @return boolean true if character is upper case letter,
Packit 875988
 *         boolean false otherwise
Packit 875988
 */
Packit 875988
#define isasciiupper(c) (((char)(c)) >= 'A' && ((char)(c)) <= 'Z')
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Checks whether character is letter in US-ASCII
Packit 875988
 *
Packit 875988
 * @param c character to check
Packit 875988
 * @return boolean true if character is letter, boolean false
Packit 875988
 *         otherwise
Packit 875988
 */
Packit 875988
#define isasciialpha(c) (isasciilower(c) || isasciiupper(c))
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Check whether character is decimal digit in US-ASCII
Packit 875988
 *
Packit 875988
 * @param c character to check
Packit 875988
 * @return boolean true if character is decimal digit, boolean false
Packit 875988
 *         otherwise
Packit 875988
 */
Packit 875988
#define isasciidigit(c) (((char)(c)) >= '0' && ((char)(c)) <= '9')
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Check whether character is hexadecimal digit in US-ASCII
Packit 875988
 *
Packit 875988
 * @param c character to check
Packit 875988
 * @return boolean true if character is hexadecimal digit,
Packit 875988
 *         boolean false otherwise
Packit 875988
 */
Packit 875988
#define isasciixdigit(c) (isasciidigit((c)) || \
Packit 875988
                          (((char)(c)) >= 'A' && ((char)(c)) <= 'F') || \
Packit 875988
                          (((char)(c)) >= 'a' && ((char)(c)) <= 'f') )
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Check whether character is decimal digit or letter in US-ASCII
Packit 875988
 *
Packit 875988
 * @param c character to check
Packit 875988
 * @return boolean true if character is decimal digit or letter,
Packit 875988
 *         boolean false otherwise
Packit 875988
 */
Packit 875988
#define isasciialnum(c) (isasciialpha(c) || isasciidigit(c))
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Convert US-ASCII character to lower case.
Packit 875988
 * If character is upper case letter in US-ASCII than it's converted to lower
Packit 875988
 * case analog. If character is NOT upper case letter than it's returned
Packit 875988
 * unmodified.
Packit 875988
 *
Packit 875988
 * @param c character to convert
Packit 875988
 * @return converted to lower case character
Packit 875988
 */
Packit 875988
#define toasciilower(c) ((isasciiupper(c)) ? (((char)(c)) - 'A' + 'a') : ((char)(c)))
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Convert US-ASCII character to upper case.
Packit 875988
 * If character is lower case letter in US-ASCII than it's converted to upper
Packit 875988
 * case analog. If character is NOT lower case letter than it's returned
Packit 875988
 * unmodified.
Packit 875988
 *
Packit 875988
 * @param c character to convert
Packit 875988
 * @return converted to upper case character
Packit 875988
 */
Packit 875988
#define toasciiupper(c) ((isasciilower(c)) ? (((char)(c)) - 'a' + 'A') : ((char)(c)))
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Convert US-ASCII decimal digit to its value.
Packit 875988
 *
Packit 875988
 * @param c character to convert
Packit 875988
 * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
Packit 875988
 */
Packit 875988
#define todigitvalue(c) (isasciidigit(c) ? (int)(((char)(c)) - '0') : (int)(-1))
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Convert US-ASCII hexadecimal digit to its value.
Packit 875988
 * @param c character to convert
Packit 875988
 * @return value of hexadecimal digit or -1 if @ c is not hexadecimal digit
Packit 875988
 */
Packit 875988
#define toxdigitvalue(c) ( isasciidigit(c) ? (int)(((char)(c)) - '0') : \
Packit 875988
                           ( (((char)(c)) >= 'A' && ((char)(c)) <= 'F') ? \
Packit 875988
                             (int)(((unsigned char)(c)) - 'A' + 10) : \
Packit 875988
                             ( (((char)(c)) >= 'a' && ((char)(c)) <= 'f') ? \
Packit 875988
                               (int)(((unsigned char)(c)) - 'a' + 10) : (int)(-1) )))
Packit 875988
#endif /* !INLINE_FUNC */
Packit 875988
Packit 875988
Packit 875988
#ifndef MHD_FAVOR_SMALL_CODE
Packit 875988
/**
Packit 875988
 * Check two string for equality, ignoring case of US-ASCII letters.
Packit 875988
 *
Packit 875988
 * @param str1 first string to compare
Packit 875988
 * @param str2 second string to compare
Packit 875988
 * @return non-zero if two strings are equal, zero otherwise.
Packit 875988
 */
Packit 875988
int
Packit 875988
MHD_str_equal_caseless_ (const char * str1,
Packit 875988
                         const char * str2)
Packit 875988
{
Packit 875988
  while (0 != (*str1))
Packit 875988
    {
Packit 875988
      const char c1 = *str1;
Packit 875988
      const char c2 = *str2;
Packit 875988
      if ( (c1 != c2) &&
Packit 875988
           (toasciilower (c1) != toasciilower (c2)) )
Packit 875988
        return 0;
Packit 875988
      str1++;
Packit 875988
      str2++;
Packit 875988
    }
Packit 875988
  return 0 == (*str2);
Packit 875988
}
Packit 875988
#endif /* ! MHD_FAVOR_SMALL_CODE */
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Check two string for equality, ignoring case of US-ASCII letters and
Packit 875988
 * checking not more than @a maxlen characters.
Packit 875988
 * Compares up to first terminating null character, but not more than
Packit 875988
 * first @a maxlen characters.
Packit 875988
 *
Packit 875988
 * @param str1 first string to compare
Packit 875988
 * @param str2 second string to compare
Packit 875988
 * @param maxlen maximum number of characters to compare
Packit 875988
 * @return non-zero if two strings are equal, zero otherwise.
Packit 875988
 */
Packit 875988
int
Packit 875988
MHD_str_equal_caseless_n_ (const char * const str1,
Packit 875988
                           const char * const str2,
Packit 875988
                           size_t maxlen)
Packit 875988
{
Packit 875988
  size_t i;
Packit 875988
Packit 875988
  for (i = 0; i < maxlen; ++i)
Packit 875988
    {
Packit 875988
      const char c1 = str1[i];
Packit 875988
      const char c2 = str2[i];
Packit 875988
      if (0 == c2)
Packit 875988
        return 0 == c1;
Packit 875988
      if ( (c1 != c2) &&
Packit 875988
           (toasciilower (c1) != toasciilower (c2)) )
Packit 875988
        return 0;
Packit 875988
    }
Packit 875988
  return !0;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Check whether @a str has case-insensitive @a token.
Packit 875988
 * Token could be surrounded by spaces and tabs and delimited by comma.
Packit 875988
 * Match succeed if substring between start, end (of string) or comma
Packit 875988
 * contains only case-insensitive token and optional spaces and tabs.
Packit 875988
 * @warning token must not contain null-charters except optional
Packit 875988
 *          terminating null-character.
Packit 875988
 * @param str the string to check
Packit 875988
 * @param token the token to find
Packit 875988
 * @param token_len length of token, not including optional terminating
Packit 875988
 *                  null-character.
Packit 875988
 * @return non-zero if two strings are equal, zero otherwise.
Packit 875988
 */
Packit 875988
bool
Packit 875988
MHD_str_has_token_caseless_ (const char * str,
Packit 875988
                             const char * const token,
Packit 875988
                             size_t token_len)
Packit 875988
{
Packit 875988
  if (0 == token_len)
Packit 875988
    return false;
Packit 875988
Packit 875988
  while (0 != *str)
Packit 875988
    {
Packit 875988
      size_t i;
Packit 875988
      /* Skip all whitespaces and empty tokens. */
Packit 875988
      while (' ' == *str || '\t' == *str || ',' == *str) str++;
Packit 875988
Packit 875988
      /* Check for token match. */
Packit 875988
      i = 0;
Packit 875988
      while (1)
Packit 875988
        {
Packit 875988
          const char sc = *(str++);
Packit 875988
          const char tc = token[i++];
Packit 875988
Packit 875988
          if (0 == sc)
Packit 875988
            return false;
Packit 875988
          if ( (sc != tc) &&
Packit 875988
               (toasciilower (sc) != toasciilower (tc)) )
Packit 875988
            break;
Packit 875988
          if (i >= token_len)
Packit 875988
            {
Packit 875988
              /* Check whether substring match token fully or
Packit 875988
               * has additional unmatched chars at tail. */
Packit 875988
              while (' ' == *str || '\t' == *str) str++;
Packit 875988
              /* End of (sub)string? */
Packit 875988
              if (0 == *str || ',' == *str)
Packit 875988
                return true;
Packit 875988
              /* Unmatched chars at end of substring. */
Packit 875988
              break;
Packit 875988
            }
Packit 875988
        }
Packit 875988
       /* Find next substring. */
Packit 875988
      while (0 != *str && ',' != *str) str++;
Packit 875988
    }
Packit 875988
  return false;
Packit 875988
}
Packit 875988
Packit 875988
#ifndef MHD_FAVOR_SMALL_CODE
Packit 875988
/* Use individual function for each case */
Packit 875988
Packit 875988
/**
Packit 875988
 * Convert decimal US-ASCII digits in string to number in uint64_t.
Packit 875988
 * Conversion stopped at first non-digit character.
Packit 875988
 *
Packit 875988
 * @param str string to convert
Packit 875988
 * @param[out] out_val pointer to uint64_t to store result of conversion
Packit 875988
 * @return non-zero number of characters processed on succeed,
Packit 875988
 *         zero if no digit is found, resulting value is larger
Packit 875988
 *         then possible to store in uint64_t or @a out_val is NULL
Packit 875988
 */
Packit 875988
size_t
Packit 875988
MHD_str_to_uint64_ (const char *str,
Packit 875988
                    uint64_t *out_val)
Packit 875988
{
Packit 875988
  const char * const start = str;
Packit 875988
  uint64_t res;
Packit 875988
Packit 875988
  if (!str || !out_val || !isasciidigit(str[0]))
Packit 875988
    return 0;
Packit 875988
Packit 875988
  res = 0;
Packit 875988
  do
Packit 875988
    {
Packit 875988
      const int digit = (unsigned char)(*str) - '0';
Packit 875988
      if ( (res > (UINT64_MAX / 10)) ||
Packit 875988
           ( (res == (UINT64_MAX / 10)) &&
Packit 875988
             ((uint64_t)digit > (UINT64_MAX % 10)) ) )
Packit 875988
        return 0;
Packit 875988
Packit 875988
      res *= 10;
Packit 875988
      res += digit;
Packit 875988
      str++;
Packit 875988
    } while (isasciidigit (*str));
Packit 875988
Packit 875988
  *out_val = res;
Packit 875988
  return str - start;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Convert not more then @a maxlen decimal US-ASCII digits in string to
Packit 875988
 * number in uint64_t.
Packit 875988
 * Conversion stopped at first non-digit character or after @a maxlen
Packit 875988
 * digits.
Packit 875988
 *
Packit 875988
 * @param str string to convert
Packit 875988
 * @param maxlen maximum number of characters to process
Packit 875988
 * @param[out] out_val pointer to uint64_t to store result of conversion
Packit 875988
 * @return non-zero number of characters processed on succeed,
Packit 875988
 *         zero if no digit is found, resulting value is larger
Packit 875988
 *         then possible to store in uint64_t or @a out_val is NULL
Packit 875988
 */
Packit 875988
size_t
Packit 875988
MHD_str_to_uint64_n_ (const char * str,
Packit 875988
                      size_t maxlen,
Packit 875988
                      uint64_t *out_val)
Packit 875988
{
Packit 875988
  uint64_t res;
Packit 875988
  size_t i;
Packit 875988
Packit 875988
  if (!str || !maxlen || !out_val || !isasciidigit (str[0]))
Packit 875988
    return 0;
Packit 875988
Packit 875988
  res = 0;
Packit 875988
  i = 0;
Packit 875988
  do
Packit 875988
    {
Packit 875988
      const int digit = (unsigned char)str[i] - '0';
Packit 875988
Packit 875988
      if ( (res > (UINT64_MAX / 10)) ||
Packit 875988
           ( (res == (UINT64_MAX / 10)) &&
Packit 875988
             ((uint64_t)digit > (UINT64_MAX % 10)) ) )
Packit 875988
        return 0;
Packit 875988
Packit 875988
      res *= 10;
Packit 875988
      res += digit;
Packit 875988
      i++;
Packit 875988
    } while ( (i < maxlen) &&
Packit 875988
              isasciidigit (str[i]) );
Packit 875988
Packit 875988
  *out_val= res;
Packit 875988
  return i;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Convert hexadecimal US-ASCII digits in string to number in uint32_t.
Packit 875988
 * Conversion stopped at first non-digit character.
Packit 875988
 *
Packit 875988
 * @param str string to convert
Packit 875988
 * @param[out] out_val pointer to uint32_t to store result of conversion
Packit 875988
 * @return non-zero number of characters processed on succeed,
Packit 875988
 *         zero if no digit is found, resulting value is larger
Packit 875988
 *         then possible to store in uint32_t or @a out_val is NULL
Packit 875988
 */
Packit 875988
size_t
Packit 875988
MHD_strx_to_uint32_ (const char * str,
Packit 875988
                     uint32_t *out_val)
Packit 875988
{
Packit 875988
  const char * const start = str;
Packit 875988
  uint32_t res;
Packit 875988
  int digit;
Packit 875988
Packit 875988
  if (!str || !out_val)
Packit 875988
    return 0;
Packit 875988
Packit 875988
  res = 0;
Packit 875988
  digit = toxdigitvalue (*str);
Packit 875988
  while (digit >= 0)
Packit 875988
    {
Packit 875988
      if ( (res < (UINT32_MAX / 16)) ||
Packit 875988
           (res == (UINT32_MAX / 16) && (uint32_t)digit <= (UINT32_MAX % 16)) )
Packit 875988
        {
Packit 875988
          res *= 16;
Packit 875988
          res += digit;
Packit 875988
        }
Packit 875988
      else
Packit 875988
        return 0;
Packit 875988
      str++;
Packit 875988
      digit = toxdigitvalue (*str);
Packit 875988
    }
Packit 875988
Packit 875988
  if (str - start > 0)
Packit 875988
    *out_val = res;
Packit 875988
  return str - start;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
Packit 875988
 * to number in uint32_t.
Packit 875988
 * Conversion stopped at first non-digit character or after @a maxlen
Packit 875988
 * digits.
Packit 875988
 *
Packit 875988
 * @param str string to convert
Packit 875988
 * @param maxlen maximum number of characters to process
Packit 875988
 * @param[out] out_val pointer to uint32_t to store result of conversion
Packit 875988
 * @return non-zero number of characters processed on succeed,
Packit 875988
 *         zero if no digit is found, resulting value is larger
Packit 875988
 *         then possible to store in uint32_t or @a out_val is NULL
Packit 875988
 */
Packit 875988
size_t
Packit 875988
MHD_strx_to_uint32_n_ (const char *str,
Packit 875988
                       size_t maxlen,
Packit 875988
                       uint32_t *out_val)
Packit 875988
{
Packit 875988
  size_t i;
Packit 875988
  uint32_t res;
Packit 875988
  int digit;
Packit 875988
  if (!str || !out_val)
Packit 875988
    return 0;
Packit 875988
Packit 875988
  res = 0;
Packit 875988
  i = 0;
Packit 875988
  while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0)
Packit 875988
    {
Packit 875988
      if ( (res > (UINT32_MAX / 16)) ||
Packit 875988
           (res == (UINT32_MAX / 16) && (uint32_t)digit > (UINT32_MAX % 16)) )
Packit 875988
        return 0;
Packit 875988
Packit 875988
      res *= 16;
Packit 875988
      res += digit;
Packit 875988
      i++;
Packit 875988
    }
Packit 875988
Packit 875988
  if (i)
Packit 875988
    *out_val = res;
Packit 875988
  return i;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Convert hexadecimal US-ASCII digits in string to number in uint64_t.
Packit 875988
 * Conversion stopped at first non-digit character.
Packit 875988
 *
Packit 875988
 * @param str string to convert
Packit 875988
 * @param[out] out_val pointer to uint64_t to store result of conversion
Packit 875988
 * @return non-zero number of characters processed on succeed,
Packit 875988
 *         zero if no digit is found, resulting value is larger
Packit 875988
 *         then possible to store in uint64_t or @a out_val is NULL
Packit 875988
 */
Packit 875988
size_t
Packit 875988
MHD_strx_to_uint64_ (const char *str,
Packit 875988
                     uint64_t *out_val)
Packit 875988
{
Packit 875988
  const char * const start = str;
Packit 875988
  uint64_t res;
Packit 875988
  int digit;
Packit 875988
  if (!str || !out_val)
Packit 875988
    return 0;
Packit 875988
Packit 875988
  res = 0;
Packit 875988
  digit = toxdigitvalue (*str);
Packit 875988
  while (digit >= 0)
Packit 875988
    {
Packit 875988
      if ( (res < (UINT64_MAX / 16)) ||
Packit 875988
           (res == (UINT64_MAX / 16) && (uint64_t)digit <= (UINT64_MAX % 16)) )
Packit 875988
        {
Packit 875988
          res *= 16;
Packit 875988
          res += digit;
Packit 875988
        }
Packit 875988
      else
Packit 875988
        return 0;
Packit 875988
      str++;
Packit 875988
      digit = toxdigitvalue (*str);
Packit 875988
    }
Packit 875988
Packit 875988
  if (str - start > 0)
Packit 875988
    *out_val = res;
Packit 875988
  return str - start;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
/**
Packit 875988
 * Convert not more then @a maxlen hexadecimal US-ASCII digits in string
Packit 875988
 * to number in uint64_t.
Packit 875988
 * Conversion stopped at first non-digit character or after @a maxlen
Packit 875988
 * digits.
Packit 875988
 *
Packit 875988
 * @param str string to convert
Packit 875988
 * @param maxlen maximum number of characters to process
Packit 875988
 * @param[out] out_val pointer to uint64_t to store result of conversion
Packit 875988
 * @return non-zero number of characters processed on succeed,
Packit 875988
 *         zero if no digit is found, resulting value is larger
Packit 875988
 *         then possible to store in uint64_t or @a out_val is NULL
Packit 875988
 */
Packit 875988
size_t
Packit 875988
MHD_strx_to_uint64_n_ (const char * str,
Packit 875988
                       size_t maxlen,
Packit 875988
                       uint64_t *out_val)
Packit 875988
{
Packit 875988
  size_t i;
Packit 875988
  uint64_t res;
Packit 875988
  int digit;
Packit 875988
  if (!str || !out_val)
Packit 875988
    return 0;
Packit 875988
Packit 875988
  res = 0;
Packit 875988
  i = 0;
Packit 875988
  while (i < maxlen && (digit = toxdigitvalue (str[i])) >= 0)
Packit 875988
    {
Packit 875988
      if ( (res > (UINT64_MAX / 16)) ||
Packit 875988
           (res == (UINT64_MAX / 16) && (uint64_t)digit > (UINT64_MAX % 16)) )
Packit 875988
        return 0;
Packit 875988
Packit 875988
      res *= 16;
Packit 875988
      res += digit;
Packit 875988
      i++;
Packit 875988
    }
Packit 875988
Packit 875988
  if (i)
Packit 875988
    *out_val = res;
Packit 875988
  return i;
Packit 875988
}
Packit 875988
Packit 875988
#else  /* MHD_FAVOR_SMALL_CODE */
Packit 875988
Packit 875988
/**
Packit 875988
 * Generic function for converting not more then @a maxlen
Packit 875988
 * hexadecimal or decimal US-ASCII digits in string to number.
Packit 875988
 * Conversion stopped at first non-digit character or after @a maxlen
Packit 875988
 * digits.
Packit 875988
 * To be used only within macro.
Packit 875988
 *
Packit 875988
 * @param str the string to convert
Packit 875988
 * @param maxlen the maximum number of characters to process
Packit 875988
 * @param out_val the pointer to variable to store result of conversion
Packit 875988
 * @param val_size the size of variable pointed by @a out_val, in bytes, 4 or 8
Packit 875988
 * @param max_val the maximum decoded number
Packit 875988
 * @param base the numeric base, 10 or 16
Packit 875988
 * @return non-zero number of characters processed on succeed,
Packit 875988
 *         zero if no digit is found, resulting value is larger
Packit 875988
 *         then @max_val, @val_size is not 16/32 or @a out_val is NULL
Packit 875988
 */
Packit 875988
size_t
Packit 875988
MHD_str_to_uvalue_n_ (const char *str,
Packit 875988
                      size_t maxlen,
Packit 875988
                      void * out_val,
Packit 875988
                      size_t val_size,
Packit 875988
                      uint64_t max_val,
Packit 875988
                      int base)
Packit 875988
{
Packit 875988
  size_t i;
Packit 875988
  uint64_t res;
Packit 875988
  int digit;
Packit 875988
  const uint64_t max_v_div_b = max_val / base;
Packit 875988
  const uint64_t max_v_mod_b = max_val % base;
Packit 875988
  /* 'digit->value' must be function, not macro */
Packit 875988
  int (*const dfunc)(char) = (base == 16) ?
Packit 875988
                              toxdigitvalue : todigitvalue;
Packit 875988
Packit 875988
  if ( !str || !out_val ||
Packit 875988
       (base != 16 && base != 10) )
Packit 875988
    return 0;
Packit 875988
Packit 875988
  res = 0;
Packit 875988
  i = 0;
Packit 875988
  while (maxlen > i && 0 <= (digit = dfunc (str[i])))
Packit 875988
    {
Packit 875988
      if ( ((max_v_div_b) < res) ||
Packit 875988
          ((max_v_div_b) == res && (max_v_mod_b) < (uint64_t)digit) )
Packit 875988
        return 0;
Packit 875988
Packit 875988
      res *= base;
Packit 875988
      res += digit;
Packit 875988
      i++;
Packit 875988
    }
Packit 875988
Packit 875988
  if (i)
Packit 875988
    {
Packit 875988
      if (8 == val_size)
Packit 875988
        *(uint64_t*)out_val = res;
Packit 875988
      else if (4 == val_size)
Packit 875988
        *(uint32_t*)out_val = (uint32_t)res;
Packit 875988
      else
Packit 875988
        return 0;
Packit 875988
    }
Packit 875988
  return i;
Packit 875988
}
Packit 875988
#endif /* MHD_FAVOR_SMALL_CODE */