LCOV - code coverage report
Current view: top level - src/util - strencodings.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 90 303 29.7 %
Date: 2023-10-05 12:38:51 Functions: 14 40 35.0 %
Branches: 85 397 21.4 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2                 :            : // Copyright (c) 2009-2022 The Bitcoin Core developers
       3                 :            : // Distributed under the MIT software license, see the accompanying
       4                 :            : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5                 :            : 
       6                 :            : #include <span.h>
       7                 :            : #include <util/strencodings.h>
       8                 :            : 
       9                 :            : #include <array>
      10                 :            : #include <cassert>
      11                 :            : #include <cstring>
      12                 :            : #include <limits>
      13                 :            : #include <optional>
      14                 :            : #include <ostream>
      15                 :            : #include <string>
      16                 :            : #include <vector>
      17                 :            : 
      18         [ +  - ]:          2 : static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
      19                 :            : 
      20                 :          0 : static const std::string SAFE_CHARS[] =
      21                 :          2 : {
      22         [ +  - ]:          2 :     CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT
      23         [ +  - ]:          2 :     CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT
      24         [ +  - ]:          2 :     CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME
      25         [ +  - ]:          2 :     CHARS_ALPHA_NUM + "!*'();:@&=+$,/?#[]-_.~%", // SAFE_CHARS_URI
      26                 :            : };
      27                 :            : 
      28                 :          0 : std::string SanitizeString(std::string_view str, int rule)
      29                 :            : {
      30                 :          0 :     std::string result;
      31         [ #  # ]:          0 :     for (char c : str) {
      32         [ #  # ]:          0 :         if (SAFE_CHARS[rule].find(c) != std::string::npos) {
      33         [ #  # ]:          0 :             result.push_back(c);
      34                 :          0 :         }
      35                 :            :     }
      36                 :          0 :     return result;
      37         [ #  # ]:          0 : }
      38                 :            : 
      39                 :            : const signed char p_util_hexdigit[256] =
      40                 :            : { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      41                 :            :   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      42                 :            :   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      43                 :            :   0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
      44                 :            :   -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      45                 :            :   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      46                 :            :   -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      47                 :            :   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      48                 :            :   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      49                 :            :   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      50                 :            :   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      51                 :            :   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      52                 :            :   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      53                 :            :   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      54                 :            :   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      55                 :            :   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
      56                 :            : 
      57                 :       7758 : signed char HexDigit(char c)
      58                 :            : {
      59                 :       7758 :     return p_util_hexdigit[(unsigned char)c];
      60                 :            : }
      61                 :            : 
      62                 :          0 : bool IsHex(std::string_view str)
      63                 :            : {
      64         [ #  # ]:          0 :     for (char c : str) {
      65         [ #  # ]:          0 :         if (HexDigit(c) < 0) return false;
      66                 :            :     }
      67         [ #  # ]:          0 :     return (str.size() > 0) && (str.size()%2 == 0);
      68                 :          0 : }
      69                 :            : 
      70                 :          0 : bool IsHexNumber(std::string_view str)
      71                 :            : {
      72         [ #  # ]:          0 :     if (str.substr(0, 2) == "0x") str.remove_prefix(2);
      73         [ #  # ]:          0 :     for (char c : str) {
      74         [ #  # ]:          0 :         if (HexDigit(c) < 0) return false;
      75                 :            :     }
      76                 :            :     // Return false for empty string or "0x".
      77                 :          0 :     return str.size() > 0;
      78                 :          0 : }
      79                 :            : 
      80                 :            : template <typename Byte>
      81                 :          6 : std::optional<std::vector<Byte>> TryParseHex(std::string_view str)
      82                 :            : {
      83                 :          6 :     std::vector<Byte> vch;
      84                 :          6 :     auto it = str.begin();
      85   [ #  #  +  + ]:        402 :     while (it != str.end()) {
      86   [ #  #  -  + ]:        396 :         if (IsSpace(*it)) {
      87                 :          0 :             ++it;
      88                 :          0 :             continue;
      89                 :            :         }
      90                 :        396 :         auto c1 = HexDigit(*(it++));
      91   [ #  #  +  - ]:        396 :         if (it == str.end()) return std::nullopt;
      92                 :        396 :         auto c2 = HexDigit(*(it++));
      93   [ #  #  #  #  :        396 :         if (c1 < 0 || c2 < 0) return std::nullopt;
             +  -  -  + ]
      94   [ #  #  +  - ]:        396 :         vch.push_back(Byte(c1 << 4) | Byte(c2));
      95                 :            :     }
      96   [ #  #  +  - ]:          6 :     return vch;
      97                 :          6 : }
      98                 :            : template std::optional<std::vector<std::byte>> TryParseHex(std::string_view);
      99                 :            : template std::optional<std::vector<uint8_t>> TryParseHex(std::string_view);
     100                 :            : 
     101                 :       2354 : bool SplitHostPort(std::string_view in, uint16_t& portOut, std::string& hostOut)
     102                 :            : {
     103                 :       2354 :     bool valid = false;
     104                 :       2354 :     size_t colon = in.find_last_of(':');
     105                 :            :     // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
     106                 :       2354 :     bool fHaveColon = colon != in.npos;
     107   [ +  +  +  + ]:       3119 :     bool fBracketed = fHaveColon && (in[0] == '[' && in[colon - 1] == ']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
     108   [ +  +  +  + ]:       2354 :     bool fMultiColon{fHaveColon && colon != 0 && (in.find_last_of(':', colon - 1) != in.npos)};
     109   [ +  +  +  +  :       2354 :     if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) {
             +  +  +  + ]
     110                 :            :         uint16_t n;
     111         [ +  + ]:        725 :         if (ParseUInt16(in.substr(colon + 1), &n)) {
     112                 :        208 :             in = in.substr(0, colon);
     113                 :        208 :             portOut = n;
     114                 :        208 :             valid = (portOut != 0);
     115                 :        208 :         }
     116                 :        725 :     } else {
     117                 :       1629 :         valid = true;
     118                 :            :     }
     119   [ +  +  +  +  :       2354 :     if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']') {
                   +  + ]
     120                 :         39 :         hostOut = in.substr(1, in.size() - 2);
     121                 :         39 :     } else {
     122                 :       2315 :         hostOut = in;
     123                 :            :     }
     124                 :            : 
     125                 :       2354 :     return valid;
     126                 :            : }
     127                 :            : 
     128                 :          0 : std::string EncodeBase64(Span<const unsigned char> input)
     129                 :            : {
     130                 :            :     static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     131                 :            : 
     132                 :          0 :     std::string str;
     133         [ #  # ]:          0 :     str.reserve(((input.size() + 2) / 3) * 4);
     134         [ #  # ]:          0 :     ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, input.begin(), input.end());
     135   [ #  #  #  # ]:          0 :     while (str.size() % 4) str += '=';
     136                 :          0 :     return str;
     137         [ #  # ]:          0 : }
     138                 :            : 
     139                 :          0 : std::optional<std::vector<unsigned char>> DecodeBase64(std::string_view str)
     140                 :            : {
     141                 :            :     static const int8_t decode64_table[256]{
     142                 :            :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     143                 :            :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     144                 :            :         -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
     145                 :            :         -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
     146                 :            :         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
     147                 :            :         29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
     148                 :            :         49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     149                 :            :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     150                 :            :         -1, -1, -1, -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
     155                 :            :     };
     156                 :            : 
     157         [ #  # ]:          0 :     if (str.size() % 4 != 0) return {};
     158                 :            :     /* One or two = characters at the end are permitted. */
     159   [ #  #  #  # ]:          0 :     if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
     160   [ #  #  #  # ]:          0 :     if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
     161                 :            : 
     162                 :          0 :     std::vector<unsigned char> ret;
     163         [ #  # ]:          0 :     ret.reserve((str.size() * 3) / 4);
     164         [ #  # ]:          0 :     bool valid = ConvertBits<6, 8, false>(
     165                 :          0 :         [&](unsigned char c) { ret.push_back(c); },
     166                 :          0 :         str.begin(), str.end(),
     167                 :          0 :         [](char c) { return decode64_table[uint8_t(c)]; }
     168                 :            :     );
     169         [ #  # ]:          0 :     if (!valid) return {};
     170                 :            : 
     171         [ #  # ]:          0 :     return ret;
     172                 :          0 : }
     173                 :            : 
     174                 :       3130 : std::string EncodeBase32(Span<const unsigned char> input, bool pad)
     175                 :            : {
     176                 :            :     static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
     177                 :            : 
     178                 :       3130 :     std::string str;
     179         [ +  - ]:       3130 :     str.reserve(((input.size() + 4) / 5) * 8);
     180         [ +  - ]:     159030 :     ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, input.begin(), input.end());
     181         [ +  + ]:       3130 :     if (pad) {
     182         [ -  + ]:       3125 :         while (str.size() % 8) {
     183         [ #  # ]:          0 :             str += '=';
     184                 :            :         }
     185                 :       3125 :     }
     186                 :       3130 :     return str;
     187         [ +  - ]:       3130 : }
     188                 :            : 
     189                 :          0 : std::string EncodeBase32(std::string_view str, bool pad)
     190                 :            : {
     191                 :          0 :     return EncodeBase32(MakeUCharSpan(str), pad);
     192                 :            : }
     193                 :            : 
     194                 :       1907 : std::optional<std::vector<unsigned char>> DecodeBase32(std::string_view str)
     195                 :            : {
     196                 :            :     static const int8_t decode32_table[256]{
     197                 :            :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     198                 :            :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     199                 :            :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1,
     200                 :            :         -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
     201                 :            :         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1,  0,  1,  2,
     202                 :            :          3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
     203                 :            :         23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     204                 :            :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     205                 :            :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     206                 :            :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     207                 :            :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     208                 :            :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     209                 :            :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
     210                 :            :     };
     211                 :            : 
     212         [ +  + ]:       1907 :     if (str.size() % 8 != 0) return {};
     213                 :            :     /* 1, 3, 4, or 6 padding '=' suffix characters are permitted. */
     214   [ +  -  +  + ]:       1791 :     if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
     215   [ +  -  +  + ]:       1791 :     if (str.size() >= 2 && str.substr(str.size() - 2) == "==") str.remove_suffix(2);
     216   [ +  -  +  + ]:       1791 :     if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
     217   [ +  -  +  + ]:       1791 :     if (str.size() >= 2 && str.substr(str.size() - 2) == "==") str.remove_suffix(2);
     218                 :            : 
     219                 :       1791 :     std::vector<unsigned char> ret;
     220         [ +  - ]:       1791 :     ret.reserve((str.size() * 5) / 8);
     221         [ +  - ]:       1791 :     bool valid = ConvertBits<5, 8, false>(
     222                 :      58934 :         [&](unsigned char c) { ret.push_back(c); },
     223                 :       1791 :         str.begin(), str.end(),
     224                 :      91729 :         [](char c) { return decode32_table[uint8_t(c)]; }
     225                 :            :     );
     226                 :            : 
     227         [ +  + ]:       1791 :     if (!valid) return {};
     228                 :            : 
     229         [ +  - ]:       1558 :     return ret;
     230                 :       1907 : }
     231                 :            : 
     232                 :            : namespace {
     233                 :            : template <typename T>
     234                 :        725 : bool ParseIntegral(std::string_view str, T* out)
     235                 :            : {
     236                 :            :     static_assert(std::is_integral<T>::value);
     237                 :            :     // Replicate the exact behavior of strtol/strtoll/strtoul/strtoull when
     238                 :            :     // handling leading +/- for backwards compatibility.
     239   [ #  #  #  #  :        725 :     if (str.length() >= 2 && str[0] == '+' && str[1] == '-') {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  +  
          +  +  +  +  +  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     240                 :         11 :         return false;
     241                 :            :     }
     242   [ #  #  #  #  :        714 :     const std::optional<T> opt_int = ToIntegral<T>((!str.empty() && str[0] == '+') ? str.substr(1) : str);
          #  #  #  #  #  
          #  #  #  +  +  
          +  +  #  #  #  
             #  #  #  #  
                      # ]
     243   [ #  #  #  #  :        714 :     if (!opt_int) {
          #  #  +  +  #  
                #  #  # ]
     244                 :        506 :         return false;
     245                 :            :     }
     246   [ #  #  #  #  :        208 :     if (out != nullptr) {
          #  #  +  -  #  
                #  #  # ]
     247                 :        208 :         *out = *opt_int;
     248                 :        208 :     }
     249                 :        208 :     return true;
     250                 :        725 : }
     251                 :            : }; // namespace
     252                 :            : 
     253                 :          0 : bool ParseInt32(std::string_view str, int32_t* out)
     254                 :            : {
     255                 :          0 :     return ParseIntegral<int32_t>(str, out);
     256                 :            : }
     257                 :            : 
     258                 :          0 : bool ParseInt64(std::string_view str, int64_t* out)
     259                 :            : {
     260                 :          0 :     return ParseIntegral<int64_t>(str, out);
     261                 :            : }
     262                 :            : 
     263                 :          0 : bool ParseUInt8(std::string_view str, uint8_t* out)
     264                 :            : {
     265                 :          0 :     return ParseIntegral<uint8_t>(str, out);
     266                 :            : }
     267                 :            : 
     268                 :        725 : bool ParseUInt16(std::string_view str, uint16_t* out)
     269                 :            : {
     270                 :        725 :     return ParseIntegral<uint16_t>(str, out);
     271                 :            : }
     272                 :            : 
     273                 :          0 : bool ParseUInt32(std::string_view str, uint32_t* out)
     274                 :            : {
     275                 :          0 :     return ParseIntegral<uint32_t>(str, out);
     276                 :            : }
     277                 :            : 
     278                 :          0 : bool ParseUInt64(std::string_view str, uint64_t* out)
     279                 :            : {
     280                 :          0 :     return ParseIntegral<uint64_t>(str, out);
     281                 :            : }
     282                 :            : 
     283                 :          0 : std::string FormatParagraph(std::string_view in, size_t width, size_t indent)
     284                 :            : {
     285         [ #  # ]:          0 :     assert(width >= indent);
     286                 :          0 :     std::stringstream out;
     287                 :          0 :     size_t ptr = 0;
     288                 :          0 :     size_t indented = 0;
     289         [ #  # ]:          0 :     while (ptr < in.size())
     290                 :            :     {
     291                 :          0 :         size_t lineend = in.find_first_of('\n', ptr);
     292         [ #  # ]:          0 :         if (lineend == std::string::npos) {
     293                 :          0 :             lineend = in.size();
     294                 :          0 :         }
     295                 :          0 :         const size_t linelen = lineend - ptr;
     296                 :          0 :         const size_t rem_width = width - indented;
     297         [ #  # ]:          0 :         if (linelen <= rem_width) {
     298   [ #  #  #  # ]:          0 :             out << in.substr(ptr, linelen + 1);
     299                 :          0 :             ptr = lineend + 1;
     300                 :          0 :             indented = 0;
     301                 :          0 :         } else {
     302                 :          0 :             size_t finalspace = in.find_last_of(" \n", ptr + rem_width);
     303   [ #  #  #  # ]:          0 :             if (finalspace == std::string::npos || finalspace < ptr) {
     304                 :            :                 // No place to break; just include the entire word and move on
     305                 :          0 :                 finalspace = in.find_first_of("\n ", ptr);
     306         [ #  # ]:          0 :                 if (finalspace == std::string::npos) {
     307                 :            :                     // End of the string, just add it and break
     308   [ #  #  #  # ]:          0 :                     out << in.substr(ptr);
     309                 :          0 :                     break;
     310                 :            :                 }
     311                 :          0 :             }
     312   [ #  #  #  #  :          0 :             out << in.substr(ptr, finalspace - ptr) << "\n";
                   #  # ]
     313         [ #  # ]:          0 :             if (in[finalspace] == '\n') {
     314                 :          0 :                 indented = 0;
     315         [ #  # ]:          0 :             } else if (indent) {
     316   [ #  #  #  # ]:          0 :                 out << std::string(indent, ' ');
     317                 :          0 :                 indented = indent;
     318                 :          0 :             }
     319                 :          0 :             ptr = finalspace + 1;
     320                 :            :         }
     321                 :            :     }
     322         [ #  # ]:          0 :     return out.str();
     323                 :          0 : }
     324                 :            : 
     325                 :            : /** Upper bound for mantissa.
     326                 :            :  * 10^18-1 is the largest arbitrary decimal that will fit in a signed 64-bit integer.
     327                 :            :  * Larger integers cannot consist of arbitrary combinations of 0-9:
     328                 :            :  *
     329                 :            :  *   999999999999999999  1^18-1
     330                 :            :  *  9223372036854775807  (1<<63)-1  (max int64_t)
     331                 :            :  *  9999999999999999999  1^19-1     (would overflow)
     332                 :            :  */
     333                 :            : static const int64_t UPPER_BOUND = 1000000000000000000LL - 1LL;
     334                 :            : 
     335                 :            : /** Helper function for ParseFixedPoint */
     336                 :          0 : static inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantissa_tzeros)
     337                 :            : {
     338         [ #  # ]:          0 :     if(ch == '0')
     339                 :          0 :         ++mantissa_tzeros;
     340                 :            :     else {
     341         [ #  # ]:          0 :         for (int i=0; i<=mantissa_tzeros; ++i) {
     342         [ #  # ]:          0 :             if (mantissa > (UPPER_BOUND / 10LL))
     343                 :          0 :                 return false; /* overflow */
     344                 :          0 :             mantissa *= 10;
     345                 :          0 :         }
     346                 :          0 :         mantissa += ch - '0';
     347                 :          0 :         mantissa_tzeros = 0;
     348                 :            :     }
     349                 :          0 :     return true;
     350                 :          0 : }
     351                 :            : 
     352                 :          0 : bool ParseFixedPoint(std::string_view val, int decimals, int64_t *amount_out)
     353                 :            : {
     354                 :          0 :     int64_t mantissa = 0;
     355                 :          0 :     int64_t exponent = 0;
     356                 :          0 :     int mantissa_tzeros = 0;
     357                 :          0 :     bool mantissa_sign = false;
     358                 :          0 :     bool exponent_sign = false;
     359                 :          0 :     int ptr = 0;
     360                 :          0 :     int end = val.size();
     361                 :          0 :     int point_ofs = 0;
     362                 :            : 
     363   [ #  #  #  # ]:          0 :     if (ptr < end && val[ptr] == '-') {
     364                 :          0 :         mantissa_sign = true;
     365                 :          0 :         ++ptr;
     366                 :          0 :     }
     367         [ #  # ]:          0 :     if (ptr < end)
     368                 :            :     {
     369         [ #  # ]:          0 :         if (val[ptr] == '0') {
     370                 :            :             /* pass single 0 */
     371                 :          0 :             ++ptr;
     372   [ #  #  #  # ]:          0 :         } else if (val[ptr] >= '1' && val[ptr] <= '9') {
     373   [ #  #  #  # ]:          0 :             while (ptr < end && IsDigit(val[ptr])) {
     374         [ #  # ]:          0 :                 if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
     375                 :          0 :                     return false; /* overflow */
     376                 :          0 :                 ++ptr;
     377                 :            :             }
     378                 :          0 :         } else return false; /* missing expected digit */
     379                 :          0 :     } else return false; /* empty string or loose '-' */
     380   [ #  #  #  # ]:          0 :     if (ptr < end && val[ptr] == '.')
     381                 :            :     {
     382                 :          0 :         ++ptr;
     383   [ #  #  #  # ]:          0 :         if (ptr < end && IsDigit(val[ptr]))
     384                 :            :         {
     385   [ #  #  #  # ]:          0 :             while (ptr < end && IsDigit(val[ptr])) {
     386         [ #  # ]:          0 :                 if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
     387                 :          0 :                     return false; /* overflow */
     388                 :          0 :                 ++ptr;
     389                 :          0 :                 ++point_ofs;
     390                 :            :             }
     391                 :          0 :         } else return false; /* missing expected digit */
     392                 :          0 :     }
     393   [ #  #  #  #  :          0 :     if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E'))
                   #  # ]
     394                 :            :     {
     395                 :          0 :         ++ptr;
     396   [ #  #  #  # ]:          0 :         if (ptr < end && val[ptr] == '+')
     397                 :          0 :             ++ptr;
     398   [ #  #  #  # ]:          0 :         else if (ptr < end && val[ptr] == '-') {
     399                 :          0 :             exponent_sign = true;
     400                 :          0 :             ++ptr;
     401                 :          0 :         }
     402   [ #  #  #  # ]:          0 :         if (ptr < end && IsDigit(val[ptr])) {
     403   [ #  #  #  # ]:          0 :             while (ptr < end && IsDigit(val[ptr])) {
     404         [ #  # ]:          0 :                 if (exponent > (UPPER_BOUND / 10LL))
     405                 :          0 :                     return false; /* overflow */
     406                 :          0 :                 exponent = exponent * 10 + val[ptr] - '0';
     407                 :          0 :                 ++ptr;
     408                 :            :             }
     409                 :          0 :         } else return false; /* missing expected digit */
     410                 :          0 :     }
     411         [ #  # ]:          0 :     if (ptr != end)
     412                 :          0 :         return false; /* trailing garbage */
     413                 :            : 
     414                 :            :     /* finalize exponent */
     415         [ #  # ]:          0 :     if (exponent_sign)
     416                 :          0 :         exponent = -exponent;
     417                 :          0 :     exponent = exponent - point_ofs + mantissa_tzeros;
     418                 :            : 
     419                 :            :     /* finalize mantissa */
     420         [ #  # ]:          0 :     if (mantissa_sign)
     421                 :          0 :         mantissa = -mantissa;
     422                 :            : 
     423                 :            :     /* convert to one 64-bit fixed-point value */
     424                 :          0 :     exponent += decimals;
     425         [ #  # ]:          0 :     if (exponent < 0)
     426                 :          0 :         return false; /* cannot represent values smaller than 10^-decimals */
     427         [ #  # ]:          0 :     if (exponent >= 18)
     428                 :          0 :         return false; /* cannot represent values larger than or equal to 10^(18-decimals) */
     429                 :            : 
     430         [ #  # ]:          0 :     for (int i=0; i < exponent; ++i) {
     431   [ #  #  #  # ]:          0 :         if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL))
     432                 :          0 :             return false; /* overflow */
     433                 :          0 :         mantissa *= 10;
     434                 :          0 :     }
     435   [ #  #  #  # ]:          0 :     if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND)
     436                 :          0 :         return false; /* overflow */
     437                 :            : 
     438         [ #  # ]:          0 :     if (amount_out)
     439                 :          0 :         *amount_out = mantissa;
     440                 :            : 
     441                 :          0 :     return true;
     442                 :          0 : }
     443                 :            : 
     444                 :        284 : std::string ToLower(std::string_view str)
     445                 :            : {
     446                 :        284 :     std::string r;
     447   [ +  +  +  -  :       2556 :     for (auto ch : str) r += ToLower(ch);
                   +  - ]
     448                 :        284 :     return r;
     449         [ +  - ]:        284 : }
     450                 :            : 
     451                 :          0 : std::string ToUpper(std::string_view str)
     452                 :            : {
     453                 :          0 :     std::string r;
     454   [ #  #  #  #  :          0 :     for (auto ch : str) r += ToUpper(ch);
                   #  # ]
     455                 :          0 :     return r;
     456         [ #  # ]:          0 : }
     457                 :            : 
     458                 :          0 : std::string Capitalize(std::string str)
     459                 :            : {
     460         [ #  # ]:          0 :     if (str.empty()) return str;
     461                 :          0 :     str[0] = ToUpper(str.front());
     462                 :          0 :     return str;
     463                 :          0 : }
     464                 :            : 
     465                 :            : namespace {
     466                 :            : 
     467                 :            : using ByteAsHex = std::array<char, 2>;
     468                 :            : 
     469                 :            : constexpr std::array<ByteAsHex, 256> CreateByteToHexMap()
     470                 :            : {
     471                 :            :     constexpr char hexmap[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
     472                 :            : 
     473                 :            :     std::array<ByteAsHex, 256> byte_to_hex{};
     474                 :            :     for (size_t i = 0; i < byte_to_hex.size(); ++i) {
     475                 :            :         byte_to_hex[i][0] = hexmap[i >> 4];
     476                 :            :         byte_to_hex[i][1] = hexmap[i & 15];
     477                 :            :     }
     478                 :            :     return byte_to_hex;
     479                 :            : }
     480                 :            : 
     481                 :            : } // namespace
     482                 :            : 
     483                 :         14 : std::string HexStr(const Span<const uint8_t> s)
     484                 :            : {
     485         [ +  - ]:         14 :     std::string rv(s.size() * 2, '\0');
     486                 :            :     static constexpr auto byte_to_hex = CreateByteToHexMap();
     487                 :            :     static_assert(sizeof(byte_to_hex) == 512);
     488                 :            : 
     489                 :         14 :     char* it = rv.data();
     490         [ +  + ]:        366 :     for (uint8_t v : s) {
     491                 :        352 :         std::memcpy(it, byte_to_hex[v].data(), 2);
     492                 :        352 :         it += 2;
     493                 :            :     }
     494                 :            : 
     495         [ -  + ]:         14 :     assert(it == rv.data() + rv.size());
     496                 :         14 :     return rv;
     497         [ +  - ]:         14 : }
     498                 :            : 
     499                 :          0 : std::optional<uint64_t> ParseByteUnits(std::string_view str, ByteUnit default_multiplier)
     500                 :            : {
     501         [ #  # ]:          0 :     if (str.empty()) {
     502                 :          0 :         return std::nullopt;
     503                 :            :     }
     504                 :          0 :     auto multiplier = default_multiplier;
     505                 :          0 :     char unit = str.back();
     506   [ #  #  #  #  :          0 :     switch (unit) {
             #  #  #  #  
                      # ]
     507                 :            :     case 'k':
     508                 :          0 :         multiplier = ByteUnit::k;
     509                 :          0 :         break;
     510                 :            :     case 'K':
     511                 :          0 :         multiplier = ByteUnit::K;
     512                 :          0 :         break;
     513                 :            :     case 'm':
     514                 :          0 :         multiplier = ByteUnit::m;
     515                 :          0 :         break;
     516                 :            :     case 'M':
     517                 :          0 :         multiplier = ByteUnit::M;
     518                 :          0 :         break;
     519                 :            :     case 'g':
     520                 :          0 :         multiplier = ByteUnit::g;
     521                 :          0 :         break;
     522                 :            :     case 'G':
     523                 :          0 :         multiplier = ByteUnit::G;
     524                 :          0 :         break;
     525                 :            :     case 't':
     526                 :          0 :         multiplier = ByteUnit::t;
     527                 :          0 :         break;
     528                 :            :     case 'T':
     529                 :          0 :         multiplier = ByteUnit::T;
     530                 :          0 :         break;
     531                 :            :     default:
     532                 :          0 :         unit = 0;
     533                 :          0 :         break;
     534                 :            :     }
     535                 :            : 
     536                 :          0 :     uint64_t unit_amount = static_cast<uint64_t>(multiplier);
     537         [ #  # ]:          0 :     auto parsed_num = ToIntegral<uint64_t>(unit ? str.substr(0, str.size() - 1) : str);
     538   [ #  #  #  # ]:          0 :     if (!parsed_num || parsed_num > std::numeric_limits<uint64_t>::max() / unit_amount) { // check overflow
     539                 :          0 :         return std::nullopt;
     540                 :            :     }
     541                 :          0 :     return *parsed_num * unit_amount;
     542                 :          0 : }

Generated by: LCOV version 1.14