LCOV - code coverage report
Current view: top level - src/util - strencodings.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 89.2 % 296 264
Test Date: 2024-09-01 05:20:30 Functions: 97.1 % 35 34
Branches: 81.4 % 414 337

             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 <util/strencodings.h>
       7                 :             : 
       8                 :             : #include <crypto/hex_base.h>
       9                 :             : #include <span.h>
      10                 :             : 
      11                 :             : #include <array>
      12                 :             : #include <cassert>
      13                 :             : #include <cstring>
      14                 :             : #include <limits>
      15                 :             : #include <optional>
      16                 :             : #include <ostream>
      17                 :             : #include <string>
      18                 :             : #include <vector>
      19                 :             : 
      20         [ +  - ]:           1 : static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
      21                 :             : 
      22                 :           0 : static const std::string SAFE_CHARS[] =
      23                 :           1 : {
      24         [ +  - ]:           1 :     CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT
      25         [ +  - ]:           1 :     CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT
      26         [ +  - ]:           1 :     CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME
      27         [ +  - ]:           1 :     CHARS_ALPHA_NUM + "!*'();:@&=+$,/?#[]-_.~%", // SAFE_CHARS_URI
      28                 :             : };
      29                 :             : 
      30                 :       56802 : std::string SanitizeString(std::string_view str, int rule)
      31                 :             : {
      32                 :       56802 :     std::string result;
      33         [ +  + ]:      489517 :     for (char c : str) {
      34         [ +  + ]:      432715 :         if (SAFE_CHARS[rule].find(c) != std::string::npos) {
      35         [ +  - ]:      187162 :             result.push_back(c);
      36                 :      187162 :         }
      37                 :      432715 :     }
      38                 :       56802 :     return result;
      39         [ +  - ]:       56802 : }
      40                 :             : 
      41                 :      229227 : bool IsHex(std::string_view str)
      42                 :             : {
      43   [ +  +  -  +  :   390987862 :     for (char c : str) {
                      + ]
      44         [ +  + ]:   390758635 :         if (HexDigit(c) < 0) return false;
      45         [ +  + ]:   390758635 :     }
      46         [ +  + ]:      153333 :     return (str.size() > 0) && (str.size()%2 == 0);
      47                 :      229227 : }
      48                 :             : 
      49                 :             : template <typename Byte>
      50                 :      759492 : std::optional<std::vector<Byte>> TryParseHex(std::string_view str)
      51                 :             : {
      52                 :      759492 :     std::vector<Byte> vch;
      53   [ +  -  +  - ]:      759492 :     vch.reserve(str.size() / 2); // two hex characters form a single byte
      54                 :             : 
      55                 :      759492 :     auto it = str.begin();
      56   [ +  +  +  + ]:   191993241 :     while (it != str.end()) {
      57   [ +  +  +  + ]:   191234974 :         if (IsSpace(*it)) {
      58                 :        9931 :             ++it;
      59                 :        9931 :             continue;
      60                 :             :         }
      61   [ +  -  +  - ]:   191225043 :         auto c1 = HexDigit(*(it++));
      62   [ +  +  +  + ]:   191225043 :         if (it == str.end()) return std::nullopt;
      63   [ -  +  -  + ]:   191224963 :         auto c2 = HexDigit(*(it++));
      64   [ +  +  +  +  :   191224963 :         if (c1 < 0 || c2 < 0) return std::nullopt;
             +  +  +  + ]
      65   [ +  -  +  - ]:   191223818 :         vch.push_back(Byte(c1 << 4) | Byte(c2));
      66   [ +  +  +  + ]:   191225043 :     }
      67                 :      758267 :     return vch;
      68                 :      759492 : }
      69                 :             : template std::optional<std::vector<std::byte>> TryParseHex(std::string_view);
      70                 :             : template std::optional<std::vector<uint8_t>> TryParseHex(std::string_view);
      71                 :             : 
      72                 :     1135003 : bool SplitHostPort(std::string_view in, uint16_t& portOut, std::string& hostOut)
      73                 :             : {
      74                 :     1135003 :     bool valid = false;
      75                 :     1135003 :     size_t colon = in.find_last_of(':');
      76                 :             :     // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
      77                 :     1135003 :     bool fHaveColon = colon != in.npos;
      78   [ +  +  +  + ]:     1455622 :     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
      79   [ +  +  +  + ]:     1135003 :     bool fMultiColon{fHaveColon && colon != 0 && (in.find_last_of(':', colon - 1) != in.npos)};
      80   [ +  +  +  +  :     1135003 :     if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) {
             +  +  +  + ]
      81                 :      226245 :         uint16_t n;
      82         [ +  + ]:      226245 :         if (ParseUInt16(in.substr(colon + 1), &n)) {
      83                 :      129784 :             in = in.substr(0, colon);
      84                 :      129784 :             portOut = n;
      85                 :      129784 :             valid = (portOut != 0);
      86                 :      129784 :         }
      87                 :      226245 :     } else {
      88                 :      908758 :         valid = true;
      89                 :             :     }
      90   [ +  +  +  +  :     1135003 :     if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']') {
                   +  + ]
      91                 :        3413 :         hostOut = in.substr(1, in.size() - 2);
      92                 :        3413 :     } else {
      93                 :     1131590 :         hostOut = in;
      94                 :             :     }
      95                 :             : 
      96                 :     2270006 :     return valid;
      97                 :     1135003 : }
      98                 :             : 
      99                 :       79627 : std::string EncodeBase64(Span<const unsigned char> input)
     100                 :             : {
     101                 :             :     static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     102                 :             : 
     103                 :       79627 :     std::string str;
     104         [ +  - ]:       79627 :     str.reserve(((input.size() + 2) / 3) * 4);
     105         [ +  - ]:   132540207 :     ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, input.begin(), input.end());
     106   [ +  +  +  - ]:      159571 :     while (str.size() % 4) str += '=';
     107                 :       79627 :     return str;
     108         [ +  - ]:       79627 : }
     109                 :             : 
     110                 :       34122 : std::optional<std::vector<unsigned char>> DecodeBase64(std::string_view str)
     111                 :             : {
     112                 :             :     static const int8_t decode64_table[256]{
     113                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     114                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     115                 :             :         -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
     116                 :             :         -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
     117                 :             :         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
     118                 :             :         29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
     119                 :             :         49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     120                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     121                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     122                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     123                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     124                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     125                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
     126                 :             :     };
     127                 :             : 
     128         [ +  + ]:       34122 :     if (str.size() % 4 != 0) return {};
     129                 :             :     /* One or two = characters at the end are permitted. */
     130   [ +  +  +  + ]:       33758 :     if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
     131   [ +  +  +  + ]:       33758 :     if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
     132                 :             : 
     133                 :       33758 :     std::vector<unsigned char> ret;
     134         [ +  - ]:       33758 :     ret.reserve((str.size() * 3) / 4);
     135   [ +  -  +  - ]:       67516 :     bool valid = ConvertBits<6, 8, false>(
     136                 :    84632942 :         [&](unsigned char c) { ret.push_back(c); },
     137                 :       33758 :         str.begin(), str.end(),
     138                 :   112809204 :         [](char c) { return decode64_table[uint8_t(c)]; }
     139                 :             :     );
     140         [ +  + ]:       33758 :     if (!valid) return {};
     141                 :             : 
     142                 :       33568 :     return ret;
     143                 :       34122 : }
     144                 :             : 
     145                 :      179242 : std::string EncodeBase32(Span<const unsigned char> input, bool pad)
     146                 :             : {
     147                 :             :     static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
     148                 :             : 
     149                 :      179242 :     std::string str;
     150         [ +  - ]:      179242 :     str.reserve(((input.size() + 4) / 5) * 8);
     151         [ +  - ]:    17067269 :     ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, input.begin(), input.end());
     152         [ +  + ]:      179242 :     if (pad) {
     153         [ +  + ]:       99868 :         while (str.size() % 8) {
     154         [ +  - ]:       35993 :             str += '=';
     155                 :             :         }
     156                 :       63875 :     }
     157                 :      179242 :     return str;
     158         [ +  - ]:      179242 : }
     159                 :             : 
     160                 :       12957 : std::string EncodeBase32(std::string_view str, bool pad)
     161                 :             : {
     162                 :       12957 :     return EncodeBase32(MakeUCharSpan(str), pad);
     163                 :             : }
     164                 :             : 
     165                 :      157410 : std::optional<std::vector<unsigned char>> DecodeBase32(std::string_view str)
     166                 :             : {
     167                 :             :     static const int8_t decode32_table[256]{
     168                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     169                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     170                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1,
     171                 :             :         -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
     172                 :             :         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1,  0,  1,  2,
     173                 :             :          3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
     174                 :             :         23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     175                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     176                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     177                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     178                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     179                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     180                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
     181                 :             :     };
     182                 :             : 
     183         [ +  + ]:      157410 :     if (str.size() % 8 != 0) return {};
     184                 :             :     /* 1, 3, 4, or 6 padding '=' suffix characters are permitted. */
     185   [ +  +  +  + ]:       95132 :     if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
     186   [ +  +  +  + ]:       95132 :     if (str.size() >= 2 && str.substr(str.size() - 2) == "==") str.remove_suffix(2);
     187   [ +  +  +  + ]:       95132 :     if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
     188   [ +  +  +  + ]:       95132 :     if (str.size() >= 2 && str.substr(str.size() - 2) == "==") str.remove_suffix(2);
     189                 :             : 
     190                 :       95132 :     std::vector<unsigned char> ret;
     191         [ +  - ]:       95132 :     ret.reserve((str.size() * 5) / 8);
     192   [ +  -  +  - ]:      190264 :     bool valid = ConvertBits<5, 8, false>(
     193                 :     2618592 :         [&](unsigned char c) { ret.push_back(c); },
     194                 :       95132 :         str.begin(), str.end(),
     195                 :     4115843 :         [](char c) { return decode32_table[uint8_t(c)]; }
     196                 :             :     );
     197                 :             : 
     198         [ +  + ]:       95132 :     if (!valid) return {};
     199                 :             : 
     200                 :       69209 :     return ret;
     201                 :      157410 : }
     202                 :             : 
     203                 :             : namespace {
     204                 :             : template <typename T>
     205                 :      946005 : bool ParseIntegral(std::string_view str, T* out)
     206                 :             : {
     207                 :             :     static_assert(std::is_integral<T>::value);
     208                 :             :     // Replicate the exact behavior of strtol/strtoll/strtoul/strtoull when
     209                 :             :     // handling leading +/- for backwards compatibility.
     210   [ +  +  +  +  :      946005 :     if (str.length() >= 2 && str[0] == '+' && str[1] == '-') {
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
                   +  + ]
     211                 :        1907 :         return false;
     212                 :             :     }
     213   [ +  +  +  +  :      944098 :     const std::optional<T> opt_int = ToIntegral<T>((!str.empty() && str[0] == '+') ? str.substr(1) : str);
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
             +  +  +  +  
                      + ]
     214   [ +  +  +  +  :      944098 :     if (!opt_int) {
          +  +  +  +  +  
                +  +  + ]
     215                 :       98447 :         return false;
     216                 :             :     }
     217   [ -  +  -  +  :      845651 :     if (out != nullptr) {
          -  +  -  +  -  
                +  -  + ]
     218                 :      845651 :         *out = *opt_int;
     219                 :      845651 :     }
     220                 :      845651 :     return true;
     221                 :      946005 : }
     222                 :             : }; // namespace
     223                 :             : 
     224                 :        4005 : bool ParseInt32(std::string_view str, int32_t* out)
     225                 :             : {
     226                 :        4005 :     return ParseIntegral<int32_t>(str, out);
     227                 :             : }
     228                 :             : 
     229                 :         354 : bool ParseInt64(std::string_view str, int64_t* out)
     230                 :             : {
     231                 :         354 :     return ParseIntegral<int64_t>(str, out);
     232                 :             : }
     233                 :             : 
     234                 :       44461 : bool ParseUInt8(std::string_view str, uint8_t* out)
     235                 :             : {
     236                 :       44461 :     return ParseIntegral<uint8_t>(str, out);
     237                 :             : }
     238                 :             : 
     239                 :      226479 : bool ParseUInt16(std::string_view str, uint16_t* out)
     240                 :             : {
     241                 :      226479 :     return ParseIntegral<uint16_t>(str, out);
     242                 :             : }
     243                 :             : 
     244                 :      670472 : bool ParseUInt32(std::string_view str, uint32_t* out)
     245                 :             : {
     246                 :      670472 :     return ParseIntegral<uint32_t>(str, out);
     247                 :             : }
     248                 :             : 
     249                 :         234 : bool ParseUInt64(std::string_view str, uint64_t* out)
     250                 :             : {
     251                 :         234 :     return ParseIntegral<uint64_t>(str, out);
     252                 :             : }
     253                 :             : 
     254                 :        6880 : std::string FormatParagraph(std::string_view in, size_t width, size_t indent)
     255                 :             : {
     256         [ +  - ]:        6880 :     assert(width >= indent);
     257                 :        6880 :     std::stringstream out;
     258                 :        6880 :     size_t ptr = 0;
     259                 :        6880 :     size_t indented = 0;
     260         [ +  + ]:       12641 :     while (ptr < in.size())
     261                 :             :     {
     262                 :        6827 :         size_t lineend = in.find_first_of('\n', ptr);
     263         [ +  + ]:        6827 :         if (lineend == std::string::npos) {
     264                 :        5878 :             lineend = in.size();
     265                 :        5878 :         }
     266                 :        6827 :         const size_t linelen = lineend - ptr;
     267                 :        6827 :         const size_t rem_width = width - indented;
     268         [ +  + ]:        6827 :         if (linelen <= rem_width) {
     269   [ +  -  +  - ]:        5049 :             out << in.substr(ptr, linelen + 1);
     270                 :        5049 :             ptr = lineend + 1;
     271                 :        5049 :             indented = 0;
     272                 :        5049 :         } else {
     273                 :        1778 :             size_t finalspace = in.find_last_of(" \n", ptr + rem_width);
     274   [ +  +  +  + ]:        1778 :             if (finalspace == std::string::npos || finalspace < ptr) {
     275                 :             :                 // No place to break; just include the entire word and move on
     276                 :        1252 :                 finalspace = in.find_first_of("\n ", ptr);
     277         [ +  + ]:        1252 :                 if (finalspace == std::string::npos) {
     278                 :             :                     // End of the string, just add it and break
     279   [ +  -  +  - ]:        1066 :                     out << in.substr(ptr);
     280                 :        1066 :                     break;
     281                 :             :                 }
     282                 :         186 :             }
     283   [ +  -  +  -  :         712 :             out << in.substr(ptr, finalspace - ptr) << "\n";
                   +  - ]
     284         [ +  + ]:         712 :             if (in[finalspace] == '\n') {
     285                 :          87 :                 indented = 0;
     286         [ +  + ]:         712 :             } else if (indent) {
     287   [ +  -  +  - ]:         451 :                 out << std::string(indent, ' ');
     288                 :         451 :                 indented = indent;
     289                 :         451 :             }
     290                 :         712 :             ptr = finalspace + 1;
     291         [ +  + ]:        1778 :         }
     292      [ -  +  + ]:        6827 :     }
     293         [ +  - ]:        6880 :     return out.str();
     294                 :        6880 : }
     295                 :             : 
     296                 :             : /** Upper bound for mantissa.
     297                 :             :  * 10^18-1 is the largest arbitrary decimal that will fit in a signed 64-bit integer.
     298                 :             :  * Larger integers cannot consist of arbitrary combinations of 0-9:
     299                 :             :  *
     300                 :             :  *   999999999999999999  1^18-1
     301                 :             :  *  9223372036854775807  (1<<63)-1  (max int64_t)
     302                 :             :  *  9999999999999999999  1^19-1     (would overflow)
     303                 :             :  */
     304                 :             : static const int64_t UPPER_BOUND = 1000000000000000000LL - 1LL;
     305                 :             : 
     306                 :             : /** Helper function for ParseFixedPoint */
     307                 :     4617394 : static inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantissa_tzeros)
     308                 :             : {
     309         [ +  + ]:     4617394 :     if(ch == '0')
     310                 :     4613848 :         ++mantissa_tzeros;
     311                 :             :     else {
     312   [ +  +  -  +  :      626581 :         for (int i=0; i<=mantissa_tzeros; ++i) {
                      + ]
     313         [ +  + ]:      623035 :             if (mantissa > (UPPER_BOUND / 10LL))
     314                 :          72 :                 return false; /* overflow */
     315                 :      622963 :             mantissa *= 10;
     316                 :      622963 :         }
     317                 :        3474 :         mantissa += ch - '0';
     318                 :        3474 :         mantissa_tzeros = 0;
     319                 :             :     }
     320                 :     4617322 :     return true;
     321                 :     4617394 : }
     322                 :             : 
     323                 :        5502 : bool ParseFixedPoint(std::string_view val, int decimals, int64_t *amount_out)
     324                 :             : {
     325                 :        5502 :     int64_t mantissa = 0;
     326                 :        5502 :     int64_t exponent = 0;
     327                 :        5502 :     int mantissa_tzeros = 0;
     328                 :        5502 :     bool mantissa_sign = false;
     329                 :        5502 :     bool exponent_sign = false;
     330                 :        5502 :     int ptr = 0;
     331                 :        5502 :     int end = val.size();
     332                 :        5502 :     int point_ofs = 0;
     333                 :             : 
     334   [ +  +  +  + ]:        5502 :     if (ptr < end && val[ptr] == '-') {
     335                 :          70 :         mantissa_sign = true;
     336                 :          70 :         ++ptr;
     337                 :          70 :     }
     338         [ +  + ]:        5502 :     if (ptr < end)
     339                 :             :     {
     340         [ +  + ]:        5451 :         if (val[ptr] == '0') {
     341                 :             :             /* pass single 0 */
     342                 :         837 :             ++ptr;
     343   [ +  +  +  + ]:        5451 :         } else if (val[ptr] >= '1' && val[ptr] <= '9') {
     344   [ +  +  +  + ]:     3419007 :             while (ptr < end && IsDigit(val[ptr])) {
     345         [ +  + ]:     3418603 :                 if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
     346                 :          43 :                     return false; /* overflow */
     347                 :     3418560 :                 ++ptr;
     348                 :             :             }
     349                 :        4571 :         } else return false; /* missing expected digit */
     350                 :        1292 :     } else return false; /* empty string or loose '-' */
     351   [ +  +  +  + ]:        1241 :     if (ptr < end && val[ptr] == '.')
     352                 :             :     {
     353                 :         937 :         ++ptr;
     354   [ +  +  +  + ]:         937 :         if (ptr < end && IsDigit(val[ptr]))
     355                 :             :         {
     356   [ +  +  +  + ]:     1199671 :             while (ptr < end && IsDigit(val[ptr])) {
     357         [ +  + ]:     1198791 :                 if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
     358                 :          29 :                     return false; /* overflow */
     359                 :     1198762 :                 ++ptr;
     360                 :     1198762 :                 ++point_ofs;
     361                 :             :             }
     362                 :         908 :         } else return false; /* missing expected digit */
     363                 :         880 :     }
     364   [ +  +  +  +  :        1184 :     if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E'))
                   +  + ]
     365                 :             :     {
     366                 :         192 :         ++ptr;
     367   [ +  +  +  + ]:         192 :         if (ptr < end && val[ptr] == '+')
     368                 :           5 :             ++ptr;
     369   [ +  +  +  + ]:         187 :         else if (ptr < end && val[ptr] == '-') {
     370                 :          33 :             exponent_sign = true;
     371                 :          33 :             ++ptr;
     372                 :          33 :         }
     373   [ +  +  +  + ]:         192 :         if (ptr < end && IsDigit(val[ptr])) {
     374   [ +  +  +  + ]:       81046 :             while (ptr < end && IsDigit(val[ptr])) {
     375         [ +  + ]:       80908 :                 if (exponent > (UPPER_BOUND / 10LL))
     376                 :          17 :                     return false; /* overflow */
     377                 :       80891 :                 exponent = exponent * 10 + val[ptr] - '0';
     378                 :       80891 :                 ++ptr;
     379                 :             :             }
     380                 :         175 :         } else return false; /* missing expected digit */
     381                 :         138 :     }
     382         [ +  + ]:        1130 :     if (ptr != end)
     383                 :         122 :         return false; /* trailing garbage */
     384                 :             : 
     385                 :             :     /* finalize exponent */
     386         [ +  + ]:        1008 :     if (exponent_sign)
     387                 :          21 :         exponent = -exponent;
     388                 :        1008 :     exponent = exponent - point_ofs + mantissa_tzeros;
     389                 :             : 
     390                 :             :     /* finalize mantissa */
     391         [ +  + ]:        1008 :     if (mantissa_sign)
     392                 :          47 :         mantissa = -mantissa;
     393                 :             : 
     394                 :             :     /* convert to one 64-bit fixed-point value */
     395                 :        1008 :     exponent += decimals;
     396         [ +  + ]:        1008 :     if (exponent < 0)
     397                 :          53 :         return false; /* cannot represent values smaller than 10^-decimals */
     398         [ +  + ]:         955 :     if (exponent >= 18)
     399                 :          50 :         return false; /* cannot represent values larger than or equal to 10^(18-decimals) */
     400                 :             : 
     401   [ +  +  +  + ]:        7101 :     for (int i=0; i < exponent; ++i) {
     402   [ +  +  +  + ]:        6196 :         if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL))
     403                 :          56 :             return false; /* overflow */
     404                 :        6140 :         mantissa *= 10;
     405                 :        6140 :     }
     406   [ +  -  -  + ]:         849 :     if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND)
     407                 :           0 :         return false; /* overflow */
     408                 :             : 
     409         [ -  + ]:         849 :     if (amount_out)
     410                 :         849 :         *amount_out = mantissa;
     411                 :             : 
     412                 :         849 :     return true;
     413                 :        5502 : }
     414                 :             : 
     415                 :      101543 : std::string ToLower(std::string_view str)
     416                 :             : {
     417                 :      101543 :     std::string r;
     418         [ +  - ]:      101543 :     r.reserve(str.size());
     419   [ +  +  +  -  :   124874514 :     for (auto ch : str) r += ToLower(ch);
                   +  - ]
     420                 :      101543 :     return r;
     421         [ +  - ]:      101543 : }
     422                 :             : 
     423                 :        6532 : std::string ToUpper(std::string_view str)
     424                 :             : {
     425                 :        6532 :     std::string r;
     426         [ +  - ]:        6532 :     r.reserve(str.size());
     427   [ +  +  +  -  :       68511 :     for (auto ch : str) r += ToUpper(ch);
                   +  - ]
     428                 :        6532 :     return r;
     429         [ +  - ]:        6532 : }
     430                 :             : 
     431                 :        1573 : std::string Capitalize(std::string str)
     432                 :             : {
     433         [ +  + ]:        1573 :     if (str.empty()) return str;
     434                 :        1529 :     str[0] = ToUpper(str.front());
     435                 :        1529 :     return str;
     436                 :        1573 : }
     437                 :             : 
     438                 :           0 : std::optional<uint64_t> ParseByteUnits(std::string_view str, ByteUnit default_multiplier)
     439                 :             : {
     440         [ #  # ]:           0 :     if (str.empty()) {
     441                 :           0 :         return std::nullopt;
     442                 :             :     }
     443                 :           0 :     auto multiplier = default_multiplier;
     444                 :           0 :     char unit = str.back();
     445   [ #  #  #  #  :           0 :     switch (unit) {
             #  #  #  #  
                      # ]
     446                 :             :     case 'k':
     447                 :           0 :         multiplier = ByteUnit::k;
     448                 :           0 :         break;
     449                 :             :     case 'K':
     450                 :           0 :         multiplier = ByteUnit::K;
     451                 :           0 :         break;
     452                 :             :     case 'm':
     453                 :           0 :         multiplier = ByteUnit::m;
     454                 :           0 :         break;
     455                 :             :     case 'M':
     456                 :           0 :         multiplier = ByteUnit::M;
     457                 :           0 :         break;
     458                 :             :     case 'g':
     459                 :           0 :         multiplier = ByteUnit::g;
     460                 :           0 :         break;
     461                 :             :     case 'G':
     462                 :           0 :         multiplier = ByteUnit::G;
     463                 :           0 :         break;
     464                 :             :     case 't':
     465                 :           0 :         multiplier = ByteUnit::t;
     466                 :           0 :         break;
     467                 :             :     case 'T':
     468                 :           0 :         multiplier = ByteUnit::T;
     469                 :           0 :         break;
     470                 :             :     default:
     471                 :           0 :         unit = 0;
     472                 :           0 :         break;
     473                 :             :     }
     474                 :             : 
     475                 :           0 :     uint64_t unit_amount = static_cast<uint64_t>(multiplier);
     476         [ #  # ]:           0 :     auto parsed_num = ToIntegral<uint64_t>(unit ? str.substr(0, str.size() - 1) : str);
     477   [ #  #  #  # ]:           0 :     if (!parsed_num || parsed_num > std::numeric_limits<uint64_t>::max() / unit_amount) { // check overflow
     478                 :           0 :         return std::nullopt;
     479                 :             :     }
     480                 :           0 :     return *parsed_num * unit_amount;
     481                 :           0 : }
        

Generated by: LCOV version 2.0-1