LCOV - code coverage report
Current view: top level - src/util - strencodings.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 416 424 98.1 %
Date: 2022-04-21 14:51:19 Functions: 38 38 100.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 304 328 92.7 %

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

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a