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 : }
|