LCOV - code coverage report
Current view: top level - src/util - strencodings.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 97.9 % 235 230
Test Date: 2026-06-13 06:51:50 Functions: 100.0 % 20 20
Branches: 86.8 % 304 264

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2                 :             : // Copyright (c) 2009-present 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                 :             : #include <util/check.h>
      11                 :             : #include <util/overflow.h>
      12                 :             : 
      13                 :             : #include <limits>
      14                 :             : #include <optional>
      15                 :             : #include <sstream>
      16                 :             : #include <string>
      17                 :             : #include <vector>
      18                 :             : 
      19                 :             : static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
      20                 :             : 
      21                 :             : static const std::string SAFE_CHARS[] =
      22                 :             : {
      23                 :             :     CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT
      24                 :             :     CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT
      25                 :             :     CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME
      26                 :             :     CHARS_ALPHA_NUM + "!*'();:@&=+$,/?#[]-_.~%", // SAFE_CHARS_URI
      27                 :             : };
      28                 :             : 
      29                 :       56332 : std::string SanitizeString(std::string_view str, int rule)
      30                 :             : {
      31                 :       56332 :     std::string result;
      32         [ +  + ]:      458969 :     for (char c : str) {
      33         [ +  + ]:      402637 :         if (SAFE_CHARS[rule].find(c) != std::string::npos) {
      34         [ +  - ]:      181998 :             result.push_back(c);
      35                 :             :         }
      36                 :             :     }
      37                 :       56332 :     return result;
      38                 :           0 : }
      39                 :             : 
      40                 :      424227 : bool IsHex(std::string_view str)
      41                 :             : {
      42         [ +  + ]:   380023161 :     for (char c : str) {
      43         [ +  + ]:   379734654 :         if (HexDigit(c) < 0) return false;
      44                 :             :     }
      45   [ +  +  +  + ]:      288507 :     return (str.size() > 0) && (str.size()%2 == 0);
      46                 :             : }
      47                 :             : 
      48                 :             : template <typename Byte>
      49                 :      770942 : std::optional<std::vector<Byte>> TryParseHex(std::string_view str)
      50                 :             : {
      51         [ +  - ]:      770942 :     std::vector<Byte> vch;
      52         [ +  - ]:      770942 :     vch.reserve(str.size() / 2); // two hex characters form a single byte
      53                 :             : 
      54                 :      770942 :     auto it = str.begin();
      55                 :      770942 :     while (it != str.end()) {
      56         [ +  + ]:   190244052 :         if (IsSpace(*it)) {
      57                 :        6354 :             ++it;
      58                 :        6354 :             continue;
      59                 :             :         }
      60         [ +  - ]:   190237698 :         auto c1 = HexDigit(*(it++));
      61         [ +  + ]:   190237698 :         if (it == str.end()) return std::nullopt;
      62         [ +  - ]:   190237654 :         auto c2 = HexDigit(*(it++));
      63         [ +  + ]:   190237654 :         if (c1 < 0 || c2 < 0) return std::nullopt;
      64   [ +  -  +  + ]:   381252440 :         vch.push_back(Byte(c1 << 4) | Byte(c2));
      65                 :             :     }
      66                 :      770816 :     return vch;
      67                 :      770942 : }
      68                 :             : template std::optional<std::vector<std::byte>> TryParseHex(std::string_view);
      69                 :             : template std::optional<std::vector<uint8_t>> TryParseHex(std::string_view);
      70                 :             : 
      71                 :       22660 : bool SplitHostPort(std::string_view in, uint16_t& portOut, std::string& hostOut)
      72                 :             : {
      73                 :       22660 :     bool valid = false;
      74         [ +  + ]:       22660 :     size_t colon = in.find_last_of(':');
      75                 :             :     // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
      76                 :       22660 :     bool fHaveColon = colon != in.npos;
      77   [ +  +  +  +  :       22660 :     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
                   +  + ]
      78   [ +  +  +  + ]:       22660 :     bool fMultiColon{fHaveColon && colon != 0 && (in.find_last_of(':', colon - 1) != in.npos)};
      79   [ +  +  +  +  :       22660 :     if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) {
                   +  + ]
      80         [ +  + ]:        2418 :         if (const auto n{ToIntegral<uint16_t>(in.substr(colon + 1))}) {
      81                 :         195 :             in = in.substr(0, colon);
      82                 :         195 :             portOut = *n;
      83                 :         195 :             valid = (portOut != 0);
      84                 :             :         }
      85                 :             :     } else {
      86                 :             :         valid = true;
      87                 :             :     }
      88   [ +  +  +  +  :       22660 :     if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']') {
                   +  + ]
      89                 :         110 :         hostOut = in.substr(1, in.size() - 2);
      90                 :             :     } else {
      91                 :       22550 :         hostOut = in;
      92                 :             :     }
      93                 :             : 
      94                 :       22660 :     return valid;
      95                 :             : }
      96                 :             : 
      97                 :       38927 : std::string EncodeBase64(std::span<const unsigned char> input)
      98                 :             : {
      99                 :       38927 :     static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     100                 :             : 
     101         [ +  - ]:       38927 :     std::string str;
     102         [ +  - ]:       38927 :     str.reserve(CeilDiv(input.size(), 3u) * 4);
     103         [ +  - ]:    33036246 :     ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, input.begin(), input.end());
     104   [ +  -  -  +  :       77788 :     while (str.size() % 4) str += '=';
                   +  + ]
     105                 :       38927 :     return str;
     106                 :           0 : }
     107                 :             : 
     108                 :       18916 : std::optional<std::vector<unsigned char>> DecodeBase64(std::string_view str)
     109                 :             : {
     110                 :       18916 :     static const int8_t decode64_table[256]{
     111                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     112                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     113                 :             :         -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
     114                 :             :         -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
     115                 :             :         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
     116                 :             :         29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
     117                 :             :         49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     118                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     119                 :             :         -1, -1, -1, -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
     124                 :             :     };
     125                 :             : 
     126         [ +  + ]:       18916 :     if (str.size() % 4 != 0) return {};
     127                 :             :     /* One or two = characters at the end are permitted. */
     128   [ +  +  +  + ]:       18749 :     if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
     129   [ +  +  +  + ]:       18749 :     if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
     130                 :             : 
     131                 :       18749 :     std::vector<unsigned char> ret;
     132         [ +  - ]:       18749 :     ret.reserve((str.size() * 3) / 4);
     133         [ +  - ]:       18749 :     bool valid = ConvertBits<6, 8, false>(
     134                 :    45560766 :         [&](unsigned char c) { ret.push_back(c); },
     135                 :             :         str.begin(), str.end(),
     136         [ +  + ]:    60753188 :         [](char c) { return decode64_table[uint8_t(c)]; }
     137                 :             :     );
     138         [ +  + ]:       18749 :     if (!valid) return {};
     139                 :             : 
     140                 :       18660 :     return ret;
     141                 :       18749 : }
     142                 :             : 
     143                 :      207269 : std::string EncodeBase32(std::span<const unsigned char> input, bool pad)
     144                 :             : {
     145                 :      207269 :     static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
     146                 :             : 
     147         [ +  - ]:      207269 :     std::string str;
     148         [ +  - ]:      207269 :     str.reserve(CeilDiv(input.size(), 5u) * 8);
     149         [ +  - ]:    13931099 :     ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, input.begin(), input.end());
     150         [ +  + ]:      207269 :     if (pad) {
     151         [ +  + ]:       78203 :         while (str.size() % 8) {
     152   [ +  -  -  + ]:       96021 :             str += '=';
     153                 :             :         }
     154                 :             :     }
     155                 :      207269 :     return str;
     156                 :           0 : }
     157                 :             : 
     158                 :        7029 : std::string EncodeBase32(std::string_view str, bool pad)
     159                 :             : {
     160                 :        7029 :     return EncodeBase32(MakeUCharSpan(str), pad);
     161                 :             : }
     162                 :             : 
     163                 :       28769 : std::optional<std::vector<unsigned char>> DecodeBase32(std::string_view str)
     164                 :             : {
     165                 :       28769 :     static const int8_t decode32_table[256]{
     166                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     167                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     168                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1,
     169                 :             :         -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
     170                 :             :         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1,  0,  1,  2,
     171                 :             :          3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
     172                 :             :         23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     173                 :             :         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     174                 :             :         -1, -1, -1, -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
     179                 :             :     };
     180                 :             : 
     181         [ +  + ]:       28769 :     if (str.size() % 8 != 0) return {};
     182                 :             :     /* 1, 3, 4, or 6 padding '=' suffix characters are permitted. */
     183   [ +  +  +  + ]:       10256 :     if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
     184   [ +  +  +  + ]:       10256 :     if (str.size() >= 2 && str.substr(str.size() - 2) == "==") str.remove_suffix(2);
     185   [ +  +  +  + ]:       10256 :     if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
     186   [ +  +  +  + ]:       10256 :     if (str.size() >= 2 && str.substr(str.size() - 2) == "==") str.remove_suffix(2);
     187                 :             : 
     188                 :       10256 :     std::vector<unsigned char> ret;
     189         [ +  - ]:       10256 :     ret.reserve((str.size() * 5) / 8);
     190         [ +  - ]:       10256 :     bool valid = ConvertBits<5, 8, false>(
     191                 :      388027 :         [&](unsigned char c) { ret.push_back(c); },
     192                 :             :         str.begin(), str.end(),
     193         [ +  + ]:      628050 :         [](char c) { return decode32_table[uint8_t(c)]; }
     194                 :             :     );
     195                 :             : 
     196         [ +  + ]:       10256 :     if (!valid) return {};
     197                 :             : 
     198                 :        9334 :     return ret;
     199                 :       10256 : }
     200                 :             : 
     201                 :        5464 : std::string FormatParagraph(std::string_view in, size_t width, size_t indent)
     202                 :             : {
     203         [ -  + ]:        5464 :     assert(width >= indent);
     204                 :        5464 :     std::stringstream out;
     205                 :        5464 :     size_t ptr = 0;
     206                 :        5464 :     size_t indented = 0;
     207         [ +  + ]:       13541 :     while (ptr < in.size())
     208                 :             :     {
     209         [ +  + ]:        3702 :         size_t lineend = in.find_first_of('\n', ptr);
     210         [ +  + ]:        3702 :         if (lineend == std::string::npos) {
     211                 :        3238 :             lineend = in.size();
     212                 :             :         }
     213                 :        3702 :         const size_t linelen = lineend - ptr;
     214                 :        3702 :         const size_t rem_width = width - indented;
     215         [ +  + ]:        3702 :         if (linelen <= rem_width) {
     216         [ +  - ]:        2179 :             out << in.substr(ptr, linelen + 1);
     217                 :        2179 :             ptr = lineend + 1;
     218                 :        2179 :             indented = 0;
     219                 :             :         } else {
     220                 :        1523 :             size_t finalspace = in.find_last_of(" \n", ptr + rem_width);
     221         [ +  + ]:        1523 :             if (finalspace == std::string::npos || finalspace < ptr) {
     222                 :             :                 // No place to break; just include the entire word and move on
     223                 :        1230 :                 finalspace = in.find_first_of("\n ", ptr);
     224         [ +  + ]:        1230 :                 if (finalspace == std::string::npos) {
     225                 :             :                     // End of the string, just add it and break
     226         [ +  - ]:        1089 :                     out << in.substr(ptr);
     227                 :             :                     break;
     228                 :             :                 }
     229                 :             :             }
     230   [ +  -  +  - ]:         868 :             out << in.substr(ptr, finalspace - ptr) << "\n";
     231         [ +  + ]:         434 :             if (in[finalspace] == '\n') {
     232                 :             :                 indented = 0;
     233         [ +  + ]:         370 :             } else if (indent) {
     234   [ +  -  -  + ]:         512 :                 out << std::string(indent, ' ');
     235                 :         256 :                 indented = indent;
     236                 :             :             }
     237                 :         434 :             ptr = finalspace + 1;
     238                 :             :         }
     239                 :             :     }
     240         [ +  - ]:       10928 :     return out.str();
     241                 :        5464 : }
     242                 :             : 
     243                 :             : /** Upper bound for mantissa.
     244                 :             :  * 10^18-1 is the largest arbitrary decimal that will fit in a signed 64-bit integer.
     245                 :             :  * Larger integers cannot consist of arbitrary combinations of 0-9:
     246                 :             :  *
     247                 :             :  *   999999999999999999  1^18-1
     248                 :             :  *  9223372036854775807  (1<<63)-1  (max int64_t)
     249                 :             :  *  9999999999999999999  1^19-1     (would overflow)
     250                 :             :  */
     251                 :             : static const int64_t UPPER_BOUND = 1000000000000000000LL - 1LL;
     252                 :             : 
     253                 :             : /** Helper function for ParseFixedPoint */
     254                 :     2205814 : static inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantissa_tzeros)
     255                 :             : {
     256         [ +  + ]:     2205814 :     if(ch == '0')
     257                 :     2203271 :         ++mantissa_tzeros;
     258                 :             :     else {
     259         [ +  + ]:      507766 :         for (int i=0; i<=mantissa_tzeros; ++i) {
     260         [ +  + ]:      505279 :             if (mantissa > (UPPER_BOUND / 10LL))
     261                 :             :                 return false; /* overflow */
     262                 :      505223 :             mantissa *= 10;
     263                 :             :         }
     264                 :        2487 :         mantissa += ch - '0';
     265                 :        2487 :         mantissa_tzeros = 0;
     266                 :             :     }
     267                 :             :     return true;
     268                 :             : }
     269                 :             : 
     270                 :        5468 : bool ParseFixedPoint(std::string_view val, int decimals, int64_t *amount_out)
     271                 :             : {
     272                 :        5468 :     int64_t mantissa = 0;
     273                 :        5468 :     int64_t exponent = 0;
     274                 :        5468 :     int mantissa_tzeros = 0;
     275                 :        5468 :     bool mantissa_sign = false;
     276                 :        5468 :     bool exponent_sign = false;
     277                 :        5468 :     int ptr = 0;
     278         [ +  + ]:        5468 :     int end = val.size();
     279                 :        5468 :     int point_ofs = 0;
     280                 :             : 
     281   [ +  +  +  + ]:        5468 :     if (ptr < end && val[ptr] == '-') {
     282                 :             :         mantissa_sign = true;
     283                 :             :         ++ptr;
     284                 :             :     }
     285         [ +  + ]:        5468 :     if (ptr < end)
     286                 :             :     {
     287         [ +  + ]:        5433 :         if (val[ptr] == '0') {
     288                 :             :             /* pass single 0 */
     289                 :         675 :             ++ptr;
     290   [ +  +  +  + ]:        4758 :         } else if (val[ptr] >= '1' && val[ptr] <= '9') {
     291   [ +  +  +  + ]:     1597849 :             while (ptr < end && IsDigit(val[ptr])) {
     292         [ +  + ]:     1597547 :                 if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
     293                 :             :                     return false; /* overflow */
     294                 :     1597509 :                 ++ptr;
     295                 :             :             }
     296                 :             :         } else return false; /* missing expected digit */
     297                 :             :     } else return false; /* empty string or loose '-' */
     298   [ +  +  +  + ]:         977 :     if (ptr < end && val[ptr] == '.')
     299                 :             :     {
     300                 :         740 :         ++ptr;
     301   [ +  +  +  + ]:         740 :         if (ptr < end && IsDigit(val[ptr]))
     302                 :             :         {
     303   [ +  +  +  + ]:      608960 :             while (ptr < end && IsDigit(val[ptr])) {
     304         [ +  + ]:      608267 :                 if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
     305                 :             :                     return false; /* overflow */
     306                 :      608249 :                 ++ptr;
     307                 :      608249 :                 ++point_ofs;
     308                 :             :             }
     309                 :             :         } else return false; /* missing expected digit */
     310                 :             :     }
     311   [ +  +  +  +  :         930 :     if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E'))
                   +  + ]
     312                 :             :     {
     313                 :         153 :         ++ptr;
     314   [ +  +  +  + ]:         153 :         if (ptr < end && val[ptr] == '+')
     315                 :          12 :             ++ptr;
     316   [ +  +  +  + ]:         141 :         else if (ptr < end && val[ptr] == '-') {
     317                 :          26 :             exponent_sign = true;
     318                 :          26 :             ++ptr;
     319                 :             :         }
     320   [ +  +  +  + ]:         153 :         if (ptr < end && IsDigit(val[ptr])) {
     321   [ +  +  +  + ]:       32758 :             while (ptr < end && IsDigit(val[ptr])) {
     322         [ +  + ]:       32650 :                 if (exponent > (UPPER_BOUND / 10LL))
     323                 :             :                     return false; /* overflow */
     324                 :       32639 :                 exponent = exponent * 10 + val[ptr] - '0';
     325                 :       32639 :                 ++ptr;
     326                 :             :             }
     327                 :             :         } else return false; /* missing expected digit */
     328                 :             :     }
     329         [ +  + ]:         885 :     if (ptr != end)
     330                 :             :         return false; /* trailing garbage */
     331                 :             : 
     332                 :             :     /* finalize exponent */
     333         [ +  + ]:         782 :     if (exponent_sign)
     334                 :          19 :         exponent = -exponent;
     335                 :         782 :     exponent = exponent - point_ofs + mantissa_tzeros;
     336                 :             : 
     337                 :             :     /* finalize mantissa */
     338         [ +  + ]:         782 :     if (mantissa_sign)
     339                 :          37 :         mantissa = -mantissa;
     340                 :             : 
     341                 :             :     /* convert to one 64-bit fixed-point value */
     342                 :         782 :     exponent += decimals;
     343         [ +  + ]:         782 :     if (exponent < 0)
     344                 :             :         return false; /* cannot represent values smaller than 10^-decimals */
     345         [ +  + ]:         743 :     if (exponent >= 18)
     346                 :             :         return false; /* cannot represent values larger than or equal to 10^(18-decimals) */
     347                 :             : 
     348         [ +  + ]:        5468 :     for (int i=0; i < exponent; ++i) {
     349         [ +  + ]:        4795 :         if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL))
     350                 :             :             return false; /* overflow */
     351                 :        4758 :         mantissa *= 10;
     352                 :             :     }
     353         [ +  - ]:         673 :     if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND)
     354                 :             :         return false; /* overflow */
     355                 :             : 
     356         [ +  - ]:         673 :     if (amount_out)
     357                 :         673 :         *amount_out = mantissa;
     358                 :             : 
     359                 :             :     return true;
     360                 :             : }
     361                 :             : 
     362                 :       24020 : std::string ToLower(std::string_view str)
     363                 :             : {
     364         [ +  - ]:       24020 :     std::string r;
     365         [ +  - ]:       24020 :     r.reserve(str.size());
     366   [ +  +  +  -  :    44047506 :     for (auto ch : str) r += ToLower(ch);
                   +  + ]
     367                 :       24020 :     return r;
     368                 :           0 : }
     369                 :             : 
     370                 :        6187 : std::string ToUpper(std::string_view str)
     371                 :             : {
     372         [ +  - ]:        6187 :     std::string r;
     373         [ +  - ]:        6187 :     r.reserve(str.size());
     374   [ +  +  +  -  :      110525 :     for (auto ch : str) r += ToUpper(ch);
                   +  + ]
     375                 :        6187 :     return r;
     376                 :           0 : }
     377                 :             : 
     378                 :        1501 : std::string Capitalize(std::string str)
     379                 :             : {
     380         [ +  + ]:        1501 :     if (str.empty()) return str;
     381         [ +  + ]:        2614 :     str[0] = ToUpper(str.front());
     382                 :        1472 :     return str;
     383                 :             : }
     384                 :             : 
     385                 :        1238 : std::optional<uint64_t> ParseByteUnits(std::string_view str, ByteUnit default_multiplier)
     386                 :             : {
     387         [ +  + ]:        1238 :     if (str.empty()) {
     388                 :          29 :         return std::nullopt;
     389                 :             :     }
     390                 :        1209 :     auto multiplier = default_multiplier;
     391   [ +  +  +  +  :        1209 :     char unit = str.back();
             +  +  +  +  
                      + ]
     392   [ +  +  +  +  :        1209 :     switch (unit) {
             +  +  +  +  
                      + ]
     393                 :             :     case 'k':
     394                 :             :         multiplier = ByteUnit::k;
     395                 :             :         break;
     396                 :           1 :     case 'K':
     397                 :           1 :         multiplier = ByteUnit::K;
     398                 :           1 :         break;
     399                 :           3 :     case 'm':
     400                 :           3 :         multiplier = ByteUnit::m;
     401                 :           3 :         break;
     402                 :           2 :     case 'M':
     403                 :           2 :         multiplier = ByteUnit::M;
     404                 :           2 :         break;
     405                 :           9 :     case 'g':
     406                 :           9 :         multiplier = ByteUnit::g;
     407                 :           9 :         break;
     408                 :           3 :     case 'G':
     409                 :           3 :         multiplier = ByteUnit::G;
     410                 :           3 :         break;
     411                 :          23 :     case 't':
     412                 :          23 :         multiplier = ByteUnit::t;
     413                 :          23 :         break;
     414                 :           1 :     case 'T':
     415                 :           1 :         multiplier = ByteUnit::T;
     416                 :           1 :         break;
     417                 :        1164 :     default:
     418                 :        1164 :         unit = 0;
     419                 :        1164 :         break;
     420                 :             :     }
     421                 :             : 
     422                 :        1251 :     uint64_t unit_amount = static_cast<uint64_t>(multiplier);
     423                 :        1209 :     auto parsed_num = ToIntegral<uint64_t>(unit ? str.substr(0, str.size() - 1) : str);
     424   [ +  +  +  + ]:        1209 :     if (!parsed_num || parsed_num > std::numeric_limits<uint64_t>::max() / unit_amount) { // check overflow
     425                 :        1192 :         return std::nullopt;
     426                 :             :     }
     427                 :          17 :     return *parsed_num * unit_amount;
     428                 :             : }
     429                 :             : 
     430                 :          31 : bool CaseInsensitiveEqual(std::string_view s1, std::string_view s2)
     431                 :             : {
     432         [ +  - ]:          31 :     if (s1.size() != s2.size()) return false;
     433         [ +  + ]:         709 :     for (size_t i = 0; i < s1.size(); ++i) {
     434         [ +  + ]:         678 :         char c1 = s1[i];
     435         [ +  + ]:         678 :         if (c1 >= 'A' && c1 <= 'Z') c1 -= ('A' - 'a');
     436         [ -  + ]:         678 :         char c2 = s2[i];
     437         [ -  + ]:         678 :         if (c2 >= 'A' && c2 <= 'Z') c2 -= ('A' - 'a');
     438         [ +  - ]:         678 :         if (c1 != c2) return false;
     439                 :             :     }
     440                 :             :     return true;
     441                 :             : }
        

Generated by: LCOV version 2.0-1