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