LCOV - code coverage report
Current view: top level - src - utilstrencodings.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 262 269 97.4 %
Date: 2025-02-23 09:33:43 Functions: 32 34 94.1 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2014 The Bitcoin developers
       3             : // Copyright (c) 2016-2022 The PIVX Core developers
       4             : // Distributed under the MIT software license, see the accompanying
       5             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       6             : 
       7             : #include "utilstrencodings.h"
       8             : #include "util/string.h"
       9             : 
      10             : #include "tinyformat.h"
      11             : 
      12             : #include <algorithm>
      13             : #include <cstdlib>
      14             : #include <cstring>
      15             : #include <errno.h>
      16             : #include <limits>
      17             : #include <regex>
      18             : 
      19             : 
      20             : 
      21             : static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
      22             : 
      23             : static const std::string SAFE_CHARS[] =
      24             : {
      25             :     CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT
      26             :     CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT
      27             :     CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME
      28             : };
      29             : 
      30      995764 : std::string SanitizeString(const std::string& str, int rule)
      31             : {
      32      995764 :     std::string strResult;
      33     8691110 :     for (std::string::size_type i = 0; i < str.size(); i++)
      34             :     {
      35     7695350 :         if (SAFE_CHARS[rule].find(str[i]) != std::string::npos)
      36     7695330 :             strResult.push_back(str[i]);
      37             :     }
      38      995764 :     return strResult;
      39             : }
      40             : 
      41          50 : bool validateURL(const std::string& strURL)
      42             : {
      43          50 :     std::string strErr;
      44          50 :     return validateURL(strURL, strErr);
      45             : }
      46             : 
      47          99 : bool validateURL(const std::string& strURL, std::string& strErr, unsigned int maxSize)
      48             : {
      49             :     // Check URL size
      50          99 :     if (strURL.size() > maxSize) {
      51           1 :         strErr = strprintf("Invalid URL: %d exceeds limit of %d characters.", strURL.size(), maxSize);
      52           1 :         return false;
      53             :     }
      54             : 
      55             :     // Validate URL
      56          98 :     std::regex url_regex(R"(^(https?)://[^\s/$.?#][^\s]*[^\s/.]\.[^\s/.][^\s]*[^\s.]$)");
      57          98 :     if (!std::regex_match(strURL, url_regex)) {
      58          98 :         strErr = "Invalid URL";
      59             :         return false;
      60             :     }
      61             : 
      62             :     return true;
      63             : }
      64             : 
      65             : const signed char p_util_hexdigit[256] =
      66             :     {
      67             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      68             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      69             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      70             :         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
      71             :         -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      72             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      73             :         -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      74             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      75             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      76             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      77             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      78             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      79             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      80             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      81             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      82             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      83             : };
      84             : 
      85   353157770 : signed char HexDigit(char c)
      86             : {
      87   353157770 :     return p_util_hexdigit[(unsigned char)c];
      88             : }
      89             : 
      90      220275 : bool IsHex(const std::string& str)
      91             : {
      92   163474409 :     for (std::string::const_iterator it(str.begin()); it != str.end(); ++it) {
      93   163253911 :         if (HexDigit(*it) < 0)
      94          11 :             return false;
      95             :     }
      96      220264 :     return (str.size() > 0) && (str.size() % 2 == 0);
      97             : }
      98             : 
      99      216487 : std::vector<unsigned char> ParseHex(const char* psz)
     100             : {
     101             :     // convert hex dump to vector
     102      216487 :     std::vector<unsigned char> vch;
     103   163618878 :     while (true) {
     104    81917832 :         while (isspace(*psz))
     105           8 :             psz++;
     106    81917824 :         signed char c = HexDigit(*psz++);
     107    81917824 :         if (c == (signed char)-1)
     108             :             break;
     109    81701346 :         unsigned char n = (c << 4);
     110    81701346 :         c = HexDigit(*psz++);
     111    81701346 :         if (c == (signed char)-1)
     112             :             break;
     113    81701346 :         n |= c;
     114    81701346 :         vch.push_back(n);
     115    81701346 :     }
     116      216487 :     return vch;
     117             : }
     118             : 
     119      215305 : std::vector<unsigned char> ParseHex(const std::string& str)
     120             : {
     121      215305 :     return ParseHex(str.c_str());
     122             : }
     123             : 
     124          35 : std::string EncodeBase64(Span<const unsigned char> input)
     125             : {
     126          35 :     static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     127             : 
     128          35 :     std::string str;
     129          35 :     str.reserve(((input.size() + 2) / 3) * 4);
     130        2540 :     ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, input.begin(), input.end());
     131          66 :     while (str.size() % 4) str += '=';
     132          35 :     return str;
     133             : }
     134             : 
     135          10 : std::string EncodeBase64(const std::string& str)
     136             : {
     137          10 :     return EncodeBase64(MakeUCharSpan(str));
     138             : }
     139             : 
     140      298191 : std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
     141             : {
     142      298191 :     static const int decode64_table[256] =
     143             :     {
     144             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     145             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     146             :         -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
     147             :         -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
     148             :         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
     149             :         29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
     150             :         49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     151             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     152             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     153             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     154             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     155             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     156             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
     157             :     };
     158             : 
     159      298191 :     const char* e = p;
     160      298191 :     std::vector<uint8_t> val;
     161      298191 :     val.reserve(strlen(p));
     162    30115137 :     while (*p != 0) {
     163    29817034 :         int x = decode64_table[(unsigned char)*p];
     164    29817034 :         if (x == -1) break;
     165    29816930 :         val.push_back(x);
     166    29816930 :         ++p;
     167             :     }
     168             : 
     169      298191 :     std::vector<unsigned char> ret;
     170      298191 :     ret.reserve((val.size() * 3) / 4);
     171    22660928 :     bool valid = ConvertBits<6, 8, false>([&](unsigned char c) { ret.push_back(c); }, val.begin(), val.end());
     172             : 
     173      298191 :     const char* q = p;
     174      298235 :     while (valid && *p != 0) {
     175          44 :         if (*p != '=') {
     176             :             valid = false;
     177             :             break;
     178             :         }
     179          44 :         ++p;
     180             :     }
     181      298191 :     valid = valid && (p - e) % 4 == 0 && p - q < 4;
     182      298191 :     if (pfInvalid) *pfInvalid = !valid;
     183             : 
     184      596381 :     return ret;
     185             : }
     186             : 
     187      298173 : std::string DecodeBase64(const std::string& str)
     188             : {
     189      298173 :     std::vector<unsigned char> vchRet = DecodeBase64(str.c_str());
     190      894518 :     return std::string((const char*)vchRet.data(), vchRet.size());
     191             : }
     192             : 
     193          25 : std::string EncodeBase32(Span<const unsigned char> input, bool pad)
     194             : {
     195          25 :     static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
     196             : 
     197          25 :     std::string str;
     198          25 :     str.reserve(((input.size() + 4) / 5) * 8);
     199         389 :     ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, input.begin(), input.end());
     200          25 :     if (pad) {
     201          37 :         while (str.size() % 8) {
     202          37 :             str += '=';
     203             :         }
     204             :     }
     205          25 :     return str;
     206             : }
     207             : 
     208          14 : std::string EncodeBase32(const std::string& str, bool pad)
     209             : {
     210          14 :     return EncodeBase32(MakeUCharSpan(str), pad);
     211             : }
     212             : 
     213             : 
     214          24 : std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
     215             : {
     216          24 :     static const int decode32_table[256] =
     217             :     {
     218             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     219             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     220             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1,
     221             :         -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
     222             :         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1,  0,  1,  2,
     223             :          3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
     224             :         23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     225             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     226             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     227             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     228             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     229             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     230             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
     231             :     };
     232             : 
     233          24 :     const char* e = p;
     234          24 :     std::vector<uint8_t> val;
     235          24 :     val.reserve(strlen(p));
     236         510 :     while (*p != 0) {
     237         492 :         int x = decode32_table[(unsigned char)*p];
     238         492 :         if (x == -1) break;
     239         486 :         val.push_back(x);
     240         486 :         ++p;
     241             :     }
     242             : 
     243          24 :     std::vector<unsigned char> ret;
     244          24 :     ret.reserve((val.size() * 5) / 8);
     245         326 :     bool valid = ConvertBits<5, 8, false>([&](unsigned char c) { ret.push_back(c); }, val.begin(), val.end());
     246             : 
     247          24 :     const char* q = p;
     248          44 :     while (valid && *p != 0) {
     249          20 :         if (*p != '=') {
     250             :             valid = false;
     251             :             break;
     252             :         }
     253          20 :         ++p;
     254             :     }
     255          24 :     valid = valid && (p - e) % 8 == 0 && p - q < 8;
     256          24 :     if (pfInvalid) *pfInvalid = !valid;
     257             : 
     258          47 :     return ret;
     259             : }
     260             : 
     261           7 : std::string DecodeBase32(const std::string& str)
     262             : {
     263           7 :     std::vector<unsigned char> vchRet = DecodeBase32(str.c_str());
     264          20 :     return std::string((const char*)vchRet.data(), vchRet.size());
     265             : }
     266             : 
     267        2701 : static bool ParsePrechecks(const std::string& str)
     268             : {
     269        2701 :     if (str.empty()) // No empty string allowed
     270             :         return false;
     271        2695 :     if (str.size() >= 1 && (isspace(str[0]) || isspace(str[str.size()-1]))) // No padding allowed
     272             :         return false;
     273        2683 :     if (!ValidAsCString(str)) // No embedded NUL characters allowed
     274           6 :         return false;
     275             :     return true;
     276             : }
     277             : 
     278        2406 : bool ParseInt32(const std::string& str, int32_t *out)
     279             : {
     280        2406 :     if (!ParsePrechecks(str))
     281             :         return false;
     282        2398 :     char *endp = nullptr;
     283        2398 :     errno = 0; // strtol will not set errno if valid
     284        2398 :     long int n = strtol(str.c_str(), &endp, 10);
     285        2398 :     if(out) *out = (int32_t)n;
     286             :     // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
     287             :     // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
     288             :     // platforms the size of these types may be different.
     289        2398 :     return endp && *endp == 0 && !errno &&
     290        4784 :         n >= std::numeric_limits<int32_t>::min() &&
     291             :         n <= std::numeric_limits<int32_t>::max();
     292             : }
     293             : 
     294          52 : bool ParseInt64(const std::string& str, int64_t *out)
     295             : {
     296          52 :     if (!ParsePrechecks(str))
     297             :         return false;
     298          44 :     char *endp = nullptr;
     299          44 :     errno = 0; // strtoll will not set errno if valid
     300          44 :     long long int n = strtoll(str.c_str(), &endp, 10);
     301          44 :     if(out) *out = (int64_t)n;
     302             :     // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow
     303             :     // we still have to check that the returned value is within the range of an *int64_t*.
     304          44 :     return endp && *endp == 0 && !errno &&
     305             :         n >= std::numeric_limits<int64_t>::min() &&
     306             :         n <= std::numeric_limits<int64_t>::max();
     307             : }
     308             : 
     309          81 : bool ParseUInt8(const std::string& str, uint8_t *out)
     310             : {
     311          81 :     uint32_t u32;
     312          81 :     if (!ParseUInt32(str, &u32) || u32 > std::numeric_limits<uint8_t>::max()) {
     313             :         return false;
     314             :     }
     315          35 :     if (out != nullptr) {
     316          35 :         *out = static_cast<uint8_t>(u32);
     317             :     }
     318             :     return true;
     319             : }
     320             : 
     321         146 : bool ParseUInt32(const std::string& str, uint32_t *out)
     322             : {
     323         146 :     if (!ParsePrechecks(str))
     324             :         return false;
     325         146 :     if (str.size() >= 1 && str[0] == '-') // Reject negative values, unfortunately strtoul accepts these by default if they fit in the range
     326             :         return false;
     327         144 :     char *endp = nullptr;
     328         144 :     errno = 0; // strtoul will not set errno if valid
     329         144 :     unsigned long int n = strtoul(str.c_str(), &endp, 10);
     330         144 :     if(out) *out = (uint32_t)n;
     331             :     // Note that strtoul returns a *unsigned long int*, so even if it doesn't report an over/underflow
     332             :     // we still have to check that the returned value is within the range of an *uint32_t*. On 64-bit
     333             :     // platforms the size of these types may be different.
     334         144 :     return endp && *endp == 0 && !errno &&
     335             :            n <= std::numeric_limits<uint32_t>::max();
     336             : }
     337             : 
     338          97 : bool ParseDouble(const std::string& str, double *out)
     339             : {
     340          97 :     if (!ParsePrechecks(str))
     341             :         return false;
     342          89 :     if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
     343             :         return false;
     344         174 :     std::istringstream text(str);
     345          87 :     text.imbue(std::locale::classic());
     346          87 :     double result;
     347          87 :     text >> result;
     348          87 :     if(out) *out = result;
     349          87 :     return text.eof() && !text.fail();
     350             : }
     351             : 
     352         141 : std::string FormatParagraph(const std::string in, size_t width, size_t indent)
     353             : {
     354         141 :     std::stringstream out;
     355             :     size_t col = 0;
     356             :     size_t ptr = 0;
     357        1718 :     while (ptr < in.size()) {
     358             :         // Find beginning of next word
     359        1579 :         ptr = in.find_first_not_of(' ', ptr);
     360        1579 :         if (ptr == std::string::npos)
     361             :             break;
     362             :         // Find end of next word
     363        1577 :         size_t endword = in.find_first_of(' ', ptr);
     364        1577 :         if (endword == std::string::npos)
     365         137 :             endword = in.size();
     366             :         // Add newline and indentation if this wraps over the allowed width
     367        1577 :         if (col > 0) {
     368        1438 :             if ((col + endword - ptr) > width) {
     369          75 :                 out << '\n';
     370         545 :                 for (size_t i = 0; i < indent; ++i)
     371         470 :                     out << ' ';
     372             :                 col = 0;
     373             :             } else
     374        1363 :                 out << ' ';
     375             :         }
     376             :         // Append word
     377        3154 :         out << in.substr(ptr, endword - ptr);
     378        1577 :         col += endword - ptr + 1;
     379        1577 :         ptr = endword;
     380             :     }
     381         141 :     return out.str();
     382             : }
     383             : 
     384      336571 : std::string i64tostr(int64_t n)
     385             : {
     386      336571 :     return strprintf("%d", n);
     387             : }
     388             : 
     389           0 : std::string itostr(int n)
     390             : {
     391           0 :     return strprintf("%d", n);
     392             : }
     393             : 
     394        6763 : int64_t atoi64(const char* psz)
     395             : {
     396             : #ifdef _MSC_VER
     397             :     return _atoi64(psz);
     398             : #else
     399        6763 :     return strtoll(psz, nullptr, 10);
     400             : #endif
     401             : }
     402             : 
     403       24132 : int64_t atoi64(const std::string& str)
     404             : {
     405             : #ifdef _MSC_VER
     406             :     return _atoi64(str.c_str());
     407             : #else
     408       24132 :     return strtoll(str.c_str(), nullptr, 10);
     409             : #endif
     410             : }
     411             : 
     412        3774 : int atoi(const std::string& str)
     413             : {
     414        3774 :     return atoi(str.c_str());
     415             : }
     416             : 
     417             : 
     418             : /** Upper bound for mantissa.
     419             : * 10^18-1 is the largest arbitrary decimal that will fit in a signed 64-bit integer.
     420             : * Larger integers cannot consist of arbitrary combinations of 0-9:
     421             : *
     422             : *   999999999999999999  1^18-1
     423             : *  9223372036854775807  (1<<63)-1  (max int64_t)
     424             : *  9999999999999999999  1^19-1     (would overflow)
     425             : */
     426             : static const int64_t UPPER_BOUND = 1000000000000000000LL - 1LL;
     427             : 
     428             : /** Helper function for ParseFixedPoint */
     429       54443 : static inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantissa_tzeros)
     430             : {
     431       54443 :     if(ch == '0')
     432        9373 :         ++mantissa_tzeros;
     433             :     else {
     434       90785 :         for (int i=0; i<=mantissa_tzeros; ++i) {
     435       45736 :             if (mantissa > (UPPER_BOUND / 10LL))
     436             :                 return false; /* overflow */
     437       45715 :             mantissa *= 10;
     438             :         }
     439       45049 :         mantissa += ch - '0';
     440       45049 :         mantissa_tzeros = 0;
     441             :     }
     442             :     return true;
     443             : }
     444             : 
     445        8073 : bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out)
     446             : {
     447        8073 :     int64_t mantissa = 0;
     448        8073 :     int64_t exponent = 0;
     449        8073 :     int mantissa_tzeros = 0;
     450        8073 :     bool mantissa_sign = false;
     451        8073 :     bool exponent_sign = false;
     452        8073 :     int ptr = 0;
     453        8073 :     int end = val.size();
     454        8073 :     int point_ofs = 0;
     455             : 
     456        8073 :     if (ptr < end && val[ptr] == '-') {
     457             :         mantissa_sign = true;
     458             :         ++ptr;
     459             :     }
     460        8073 :     if (ptr < end)
     461             :     {
     462        8069 :         if (val[ptr] == '0') {
     463             :             /* pass single 0 */
     464         377 :             ++ptr;
     465        7692 :         } else if (val[ptr] >= '1' && val[ptr] <= '9') {
     466       18022 :             while (ptr < end && IsDigit(val[ptr])) {
     467       20676 :                 if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
     468             :                     return false; /* overflow */
     469       10338 :                 ++ptr;
     470             :             }
     471             :         } else return false; /* missing expected digit */
     472             :     } else return false; /* empty string or loose '-' */
     473        8061 :     if (ptr < end && val[ptr] == '.')
     474             :     {
     475        7760 :         ++ptr;
     476        7760 :         if (ptr < end && IsDigit(val[ptr]))
     477             :         {
     478       51842 :             while (ptr < end && IsDigit(val[ptr])) {
     479       88210 :                 if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
     480             :                     return false; /* overflow */
     481       44084 :                 ++ptr;
     482       44084 :                 ++point_ofs;
     483             :             }
     484             :         } else return false; /* missing expected digit */
     485             :     }
     486        8038 :     if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E'))
     487             :     {
     488          20 :         ++ptr;
     489          20 :         if (ptr < end && val[ptr] == '+')
     490           3 :             ++ptr;
     491          17 :         else if (ptr < end && val[ptr] == '-') {
     492          11 :             exponent_sign = true;
     493          11 :             ++ptr;
     494             :         }
     495          20 :         if (ptr < end && IsDigit(val[ptr])) {
     496          37 :             while (ptr < end && IsDigit(val[ptr])) {
     497          21 :                 if (exponent > (UPPER_BOUND / 10LL))
     498             :                     return false; /* overflow */
     499          21 :                 exponent = exponent * 10 + val[ptr] - '0';
     500          21 :                 ++ptr;
     501             :             }
     502             :         } else return false; /* missing expected digit */
     503             :     }
     504        8034 :     if (ptr != end)
     505             :         return false; /* trailing garbage */
     506             : 
     507             :     /* finalize exponent */
     508        8028 :     if (exponent_sign)
     509           9 :         exponent = -exponent;
     510        8028 :     exponent = exponent - point_ofs + mantissa_tzeros;
     511             : 
     512             :     /* finalize mantissa */
     513        8028 :     if (mantissa_sign)
     514          13 :         mantissa = -mantissa;
     515             : 
     516             :     /* convert to one 64-bit fixed-point value */
     517        8028 :     exponent += decimals;
     518        8028 :     if (exponent < 0)
     519             :         return false; /* cannot represent values smaller than 10^-decimals */
     520        8019 :     if (exponent >= 18)
     521             :         return false; /* cannot represent values larger than or equal to 10^(18-decimals) */
     522             : 
     523       36967 :     for (int i=0; i < exponent; ++i) {
     524       28955 :         if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL))
     525             :             return false; /* overflow */
     526       28954 :         mantissa *= 10;
     527             :     }
     528        8012 :     if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND)
     529             :         return false; /* overflow */
     530             : 
     531        8012 :     if (amount_out)
     532        8012 :         *amount_out = mantissa;
     533             : 
     534             :     return true;
     535             : }
     536             : 
     537          23 : void Downcase(std::string& str)
     538             : {
     539         114 :     std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c){return ToLower(c);});
     540          23 : }
     541             : 
     542           0 : std::string ToLower(const std::string& str)
     543             : {
     544           0 :     std::string r;
     545           0 :     for (auto ch : str) r += ToLower((unsigned char)ch);
     546           0 :     return r;
     547             : }
     548             : 
     549           6 : std::string ToUpper(const std::string& str)
     550             : {
     551           6 :     std::string r;
     552          24 :     for (auto ch : str) r += ToUpper((unsigned char)ch);
     553           6 :     return r;
     554             : }
     555             : 
     556           6 : std::string Capitalize(std::string str)
     557             : {
     558           6 :     if (str.empty()) return str;
     559           4 :     str[0] = ToUpper(str.front());
     560           2 :     return str;
     561             : }
     562             : 
     563     9445754 : std::string HexStr(const Span<const uint8_t> s)
     564             : {
     565     9445754 :     std::string rv;
     566     9445754 :     static constexpr char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
     567             :                                          '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
     568     9445754 :     rv.reserve(s.size() * 2);
     569   398835627 :     for (uint8_t v: s) {
     570   389390303 :         rv.push_back(hexmap[v >> 4]);
     571   389390303 :         rv.push_back(hexmap[v & 15]);
     572             :     }
     573     9445754 :     return rv;
     574             : }
     575             : 
     576             : // Based on http://www.zedwood.com/article/cpp-is-valid-utf8-string-function
     577           3 : bool IsValidUTF8(const std::string& str)
     578             : {
     579           3 :     const unsigned int strLen = str.length();
     580           3 :     int c,n;
     581         141 :     for (unsigned i = 0; i < strLen; i++) {
     582         138 :         c = (unsigned char) str[i];
     583         138 :         if (0x00 <= c && c <= 0x7f)     n=0;      // 0bbbbbbb (ASCII)
     584           6 :         else if ((c & 0xE0) == 0xC0)    n=1;      // 110bbbbb
     585           6 :         else if ( c == 0xED && i < (strLen - 1) && ((unsigned char)str[i+1] & 0xA0) == 0xA0)
     586             :             return false;                         //U+d800 to U+dfff
     587           6 :         else if ((c & 0xF0) == 0xE0)    n=2;      // 1110bbbb
     588           0 :         else if ((c & 0xF8) == 0xF0)    n=3;      // 11110bbb
     589             :         else return false;
     590         150 :         for (int j=0; j < n && i < strLen; j++) { // n bytes matching 10bbbbbb follow ?
     591          12 :             if ((++i == strLen) || (( (unsigned char)str[i] & 0xC0) != 0x80))
     592             :                 return false;
     593             :         }
     594             :     }
     595             :     return true;
     596             : }
     597             : 

Generated by: LCOV version 1.14