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/overflow.h>
11 : :
12 : : #include <array>
13 : : #include <cassert>
14 : : #include <cstring>
15 : : #include <limits>
16 : : #include <optional>
17 : : #include <ostream>
18 : : #include <string>
19 : : #include <vector>
20 : :
21 : : static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
22 : :
23 : : static const std::string SAFE_CHARS[] =
24 : : {
25 : : CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT
26 : : CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT
27 : : CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME
28 : : CHARS_ALPHA_NUM + "!*'();:@&=+$,/?#[]-_.~%", // SAFE_CHARS_URI
29 : : };
30 : :
31 : 7 : std::string SanitizeString(std::string_view str, int rule)
32 : : {
33 : 7 : std::string result;
34 [ + + ]: 117 : for (char c : str) {
35 [ + + ]: 110 : if (SAFE_CHARS[rule].find(c) != std::string::npos) {
36 [ + - ]: 62 : result.push_back(c);
37 : : }
38 : : }
39 : 7 : return result;
40 : 0 : }
41 : :
42 : 3649 : bool IsHex(std::string_view str)
43 : : {
44 [ + + ]: 142966 : for (char c : str) {
45 [ + + ]: 139950 : if (HexDigit(c) < 0) return false;
46 : : }
47 [ + + + + ]: 3016 : return (str.size() > 0) && (str.size()%2 == 0);
48 : : }
49 : :
50 : : template <typename Byte>
51 : 5861 : std::optional<std::vector<Byte>> TryParseHex(std::string_view str)
52 : : {
53 [ + - ]: 5861 : std::vector<Byte> vch;
54 [ + - ]: 5861 : vch.reserve(str.size() / 2); // two hex characters form a single byte
55 : :
56 : 5861 : auto it = str.begin();
57 : 5861 : while (it != str.end()) {
58 [ + + ]: 257969 : if (IsSpace(*it)) {
59 : 116 : ++it;
60 : 116 : continue;
61 : : }
62 [ + - ]: 257853 : auto c1 = HexDigit(*(it++));
63 [ + + ]: 257853 : if (it == str.end()) return std::nullopt;
64 [ + - ]: 257847 : auto c2 = HexDigit(*(it++));
65 [ + + ]: 257847 : if (c1 < 0 || c2 < 0) return std::nullopt;
66 [ + - + + ]: 521647 : vch.push_back(Byte(c1 << 4) | Byte(c2));
67 : : }
68 : 5843 : return vch;
69 : 5861 : }
70 : : template std::optional<std::vector<std::byte>> TryParseHex(std::string_view);
71 : : template std::optional<std::vector<uint8_t>> TryParseHex(std::string_view);
72 : :
73 : 6793 : bool SplitHostPort(std::string_view in, uint16_t& portOut, std::string& hostOut)
74 : : {
75 : 6793 : bool valid = false;
76 [ + + ]: 6793 : size_t colon = in.find_last_of(':');
77 : : // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
78 : 6793 : bool fHaveColon = colon != in.npos;
79 [ + + + + : 6793 : 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
+ + ]
80 [ + + + + ]: 6793 : bool fMultiColon{fHaveColon && colon != 0 && (in.find_last_of(':', colon - 1) != in.npos)};
81 [ + + + + : 6793 : if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) {
+ + ]
82 [ + + ]: 79 : if (const auto n{ToIntegral<uint16_t>(in.substr(colon + 1))}) {
83 : 66 : in = in.substr(0, colon);
84 : 66 : portOut = *n;
85 : 66 : valid = (portOut != 0);
86 : : }
87 : : } else {
88 : : valid = true;
89 : : }
90 [ + + + + : 6793 : if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']') {
+ + ]
91 : 17 : hostOut = in.substr(1, in.size() - 2);
92 : : } else {
93 : 6776 : hostOut = in;
94 : : }
95 : :
96 : 6793 : return valid;
97 : : }
98 : :
99 : 22 : std::string EncodeBase64(std::span<const unsigned char> input)
100 : : {
101 : 22 : static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
102 : :
103 [ + - ]: 22 : std::string str;
104 [ + - ]: 22 : str.reserve(CeilDiv(input.size(), 3u) * 4);
105 [ + - ]: 6248 : ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, input.begin(), input.end());
106 [ + - - + : 44 : while (str.size() % 4) str += '=';
+ + ]
107 : 22 : return str;
108 : 0 : }
109 : :
110 : 26 : std::optional<std::vector<unsigned char>> DecodeBase64(std::string_view str)
111 : : {
112 : 26 : 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 [ + + ]: 26 : if (str.size() % 4 != 0) return {};
129 : : /* One or two = characters at the end are permitted. */
130 [ + + + + ]: 20 : if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
131 [ + + + + ]: 20 : if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
132 : :
133 : 20 : std::vector<unsigned char> ret;
134 [ + - ]: 20 : ret.reserve((str.size() * 3) / 4);
135 [ + - ]: 20 : bool valid = ConvertBits<6, 8, false>(
136 : 983 : [&](unsigned char c) { ret.push_back(c); },
137 : : str.begin(), str.end(),
138 [ + + ]: 1323 : [](char c) { return decode64_table[uint8_t(c)]; }
139 : : );
140 [ + + ]: 20 : if (!valid) return {};
141 : :
142 : 15 : return ret;
143 : 20 : }
144 : :
145 : 68 : std::string EncodeBase32(std::span<const unsigned char> input, bool pad)
146 : : {
147 : 68 : static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
148 : :
149 [ + - ]: 68 : std::string str;
150 [ + - ]: 68 : str.reserve(CeilDiv(input.size(), 5u) * 8);
151 [ + - ]: 2916 : ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, input.begin(), input.end());
152 [ + + ]: 68 : if (pad) {
153 [ + + ]: 51 : while (str.size() % 8) {
154 [ + - - + ]: 71 : str += '=';
155 : : }
156 : : }
157 : 68 : return str;
158 : 0 : }
159 : :
160 : 15 : std::string EncodeBase32(std::string_view str, bool pad)
161 : : {
162 : 15 : return EncodeBase32(MakeUCharSpan(str), pad);
163 : : }
164 : :
165 : 57 : std::optional<std::vector<unsigned char>> DecodeBase32(std::string_view str)
166 : : {
167 : 57 : 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 [ + + ]: 57 : if (str.size() % 8 != 0) return {};
184 : : /* 1, 3, 4, or 6 padding '=' suffix characters are permitted. */
185 [ + + + + ]: 56 : if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
186 [ + + + + ]: 56 : if (str.size() >= 2 && str.substr(str.size() - 2) == "==") str.remove_suffix(2);
187 [ + + + + ]: 56 : if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
188 [ + + + + ]: 56 : if (str.size() >= 2 && str.substr(str.size() - 2) == "==") str.remove_suffix(2);
189 : :
190 : 56 : std::vector<unsigned char> ret;
191 [ + - ]: 56 : ret.reserve((str.size() * 5) / 8);
192 [ + - ]: 56 : bool valid = ConvertBits<5, 8, false>(
193 : 1203 : [&](unsigned char c) { ret.push_back(c); },
194 : : str.begin(), str.end(),
195 [ + + ]: 1951 : [](char c) { return decode32_table[uint8_t(c)]; }
196 : : );
197 : :
198 [ + + ]: 56 : if (!valid) return {};
199 : :
200 : 48 : return ret;
201 : 56 : }
202 : :
203 : 32 : std::string FormatParagraph(std::string_view in, size_t width, size_t indent)
204 : : {
205 [ - + ]: 32 : assert(width >= indent);
206 : 32 : std::stringstream out;
207 : 32 : size_t ptr = 0;
208 : 32 : size_t indented = 0;
209 [ + + ]: 130 : while (ptr < in.size())
210 : : {
211 [ + + ]: 68 : size_t lineend = in.find_first_of('\n', ptr);
212 [ + + ]: 68 : if (lineend == std::string::npos) {
213 : 52 : lineend = in.size();
214 : : }
215 : 68 : const size_t linelen = lineend - ptr;
216 : 68 : const size_t rem_width = width - indented;
217 [ + + ]: 68 : if (linelen <= rem_width) {
218 [ + - ]: 40 : out << in.substr(ptr, linelen + 1);
219 : 40 : ptr = lineend + 1;
220 : 40 : indented = 0;
221 : : } else {
222 : 28 : size_t finalspace = in.find_last_of(" \n", ptr + rem_width);
223 [ + + ]: 28 : if (finalspace == std::string::npos || finalspace < ptr) {
224 : : // No place to break; just include the entire word and move on
225 : 8 : finalspace = in.find_first_of("\n ", ptr);
226 [ + + ]: 8 : if (finalspace == std::string::npos) {
227 : : // End of the string, just add it and break
228 [ + - ]: 2 : out << in.substr(ptr);
229 : : break;
230 : : }
231 : : }
232 [ + - + - ]: 52 : out << in.substr(ptr, finalspace - ptr) << "\n";
233 [ + + ]: 26 : if (in[finalspace] == '\n') {
234 : : indented = 0;
235 [ + + ]: 24 : } else if (indent) {
236 [ + - - + ]: 16 : out << std::string(indent, ' ');
237 : 8 : indented = indent;
238 : : }
239 : 26 : ptr = finalspace + 1;
240 : : }
241 : : }
242 [ + - ]: 64 : return out.str();
243 : 32 : }
244 : :
245 : : /** Upper bound for mantissa.
246 : : * 10^18-1 is the largest arbitrary decimal that will fit in a signed 64-bit integer.
247 : : * Larger integers cannot consist of arbitrary combinations of 0-9:
248 : : *
249 : : * 999999999999999999 1^18-1
250 : : * 9223372036854775807 (1<<63)-1 (max int64_t)
251 : : * 9999999999999999999 1^19-1 (would overflow)
252 : : */
253 : : static const int64_t UPPER_BOUND = 1000000000000000000LL - 1LL;
254 : :
255 : : /** Helper function for ParseFixedPoint */
256 : 2241 : static inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantissa_tzeros)
257 : : {
258 [ + + ]: 2241 : if(ch == '0')
259 : 1630 : ++mantissa_tzeros;
260 : : else {
261 [ + + ]: 2327 : for (int i=0; i<=mantissa_tzeros; ++i) {
262 [ + + ]: 1739 : if (mantissa > (UPPER_BOUND / 10LL))
263 : : return false; /* overflow */
264 : 1716 : mantissa *= 10;
265 : : }
266 : 588 : mantissa += ch - '0';
267 : 588 : mantissa_tzeros = 0;
268 : : }
269 : : return true;
270 : : }
271 : :
272 : 241 : bool ParseFixedPoint(std::string_view val, int decimals, int64_t *amount_out)
273 : : {
274 : 241 : int64_t mantissa = 0;
275 : 241 : int64_t exponent = 0;
276 : 241 : int mantissa_tzeros = 0;
277 : 241 : bool mantissa_sign = false;
278 : 241 : bool exponent_sign = false;
279 : 241 : int ptr = 0;
280 [ + + ]: 241 : int end = val.size();
281 : 241 : int point_ofs = 0;
282 : :
283 [ + + + + ]: 241 : if (ptr < end && val[ptr] == '-') {
284 : : mantissa_sign = true;
285 : : ++ptr;
286 : : }
287 [ + + ]: 241 : if (ptr < end)
288 : : {
289 [ + + ]: 237 : if (val[ptr] == '0') {
290 : : /* pass single 0 */
291 : 155 : ++ptr;
292 [ + + + + ]: 82 : } else if (val[ptr] >= '1' && val[ptr] <= '9') {
293 [ + + + + ]: 561 : while (ptr < end && IsDigit(val[ptr])) {
294 [ + - ]: 488 : if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
295 : : return false; /* overflow */
296 : 488 : ++ptr;
297 : : }
298 : : } else return false; /* missing expected digit */
299 : : } else return false; /* empty string or loose '-' */
300 [ + + + + ]: 228 : if (ptr < end && val[ptr] == '.')
301 : : {
302 : 204 : ++ptr;
303 [ + + + - ]: 204 : if (ptr < end && IsDigit(val[ptr]))
304 : : {
305 [ + + + + ]: 1932 : while (ptr < end && IsDigit(val[ptr])) {
306 [ + + ]: 1753 : if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
307 : : return false; /* overflow */
308 : 1730 : ++ptr;
309 : 1730 : ++point_ofs;
310 : : }
311 : : } else return false; /* missing expected digit */
312 : : }
313 [ + + + + : 203 : if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E'))
- + ]
314 : : {
315 : 21 : ++ptr;
316 [ + + + + ]: 21 : if (ptr < end && val[ptr] == '+')
317 : 4 : ++ptr;
318 [ + + + + ]: 17 : else if (ptr < end && val[ptr] == '-') {
319 : 11 : exponent_sign = true;
320 : 11 : ++ptr;
321 : : }
322 [ + + + - ]: 21 : if (ptr < end && IsDigit(val[ptr])) {
323 [ + + + - ]: 40 : while (ptr < end && IsDigit(val[ptr])) {
324 [ + - ]: 23 : if (exponent > (UPPER_BOUND / 10LL))
325 : : return false; /* overflow */
326 : 23 : exponent = exponent * 10 + val[ptr] - '0';
327 : 23 : ++ptr;
328 : : }
329 : : } else return false; /* missing expected digit */
330 : : }
331 [ + + ]: 199 : if (ptr != end)
332 : : return false; /* trailing garbage */
333 : :
334 : : /* finalize exponent */
335 [ + + ]: 192 : if (exponent_sign)
336 : 9 : exponent = -exponent;
337 : 192 : exponent = exponent - point_ofs + mantissa_tzeros;
338 : :
339 : : /* finalize mantissa */
340 [ + + ]: 192 : if (mantissa_sign)
341 : 13 : mantissa = -mantissa;
342 : :
343 : : /* convert to one 64-bit fixed-point value */
344 : 192 : exponent += decimals;
345 [ + + ]: 192 : if (exponent < 0)
346 : : return false; /* cannot represent values smaller than 10^-decimals */
347 [ + + ]: 175 : if (exponent >= 18)
348 : : return false; /* cannot represent values larger than or equal to 10^(18-decimals) */
349 : :
350 [ + + ]: 626 : for (int i=0; i < exponent; ++i) {
351 [ + + ]: 458 : if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL))
352 : : return false; /* overflow */
353 : 457 : mantissa *= 10;
354 : : }
355 [ + - ]: 168 : if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND)
356 : : return false; /* overflow */
357 : :
358 [ + - ]: 168 : if (amount_out)
359 : 168 : *amount_out = mantissa;
360 : :
361 : : return true;
362 : : }
363 : :
364 : 518 : std::string ToLower(std::string_view str)
365 : : {
366 [ + - ]: 518 : std::string r;
367 [ + - ]: 518 : r.reserve(str.size());
368 [ + + + - : 2914 : for (auto ch : str) r += ToLower(ch);
+ + ]
369 : 518 : return r;
370 : 0 : }
371 : :
372 : 10 : std::string ToUpper(std::string_view str)
373 : : {
374 [ + - ]: 10 : std::string r;
375 [ + - ]: 10 : r.reserve(str.size());
376 [ + + + - : 58 : for (auto ch : str) r += ToUpper(ch);
+ + ]
377 : 10 : return r;
378 : 0 : }
379 : :
380 : 8 : std::string Capitalize(std::string str)
381 : : {
382 [ + + ]: 8 : if (str.empty()) return str;
383 [ + - ]: 12 : str[0] = ToUpper(str.front());
384 : 6 : return str;
385 : : }
386 : :
387 : 22 : std::optional<uint64_t> ParseByteUnits(std::string_view str, ByteUnit default_multiplier)
388 : : {
389 [ + + ]: 22 : if (str.empty()) {
390 : 1 : return std::nullopt;
391 : : }
392 : 21 : auto multiplier = default_multiplier;
393 [ + + + + : 21 : char unit = str.back();
+ + + +
+ ]
394 [ + + + + : 21 : switch (unit) {
+ + + +
+ ]
395 : : case 'k':
396 : : multiplier = ByteUnit::k;
397 : : break;
398 : 1 : case 'K':
399 : 1 : multiplier = ByteUnit::K;
400 : 1 : break;
401 : 4 : case 'm':
402 : 4 : multiplier = ByteUnit::m;
403 : 4 : break;
404 : 3 : case 'M':
405 : 3 : multiplier = ByteUnit::M;
406 : 3 : break;
407 : 2 : case 'g':
408 : 2 : multiplier = ByteUnit::g;
409 : 2 : break;
410 : 1 : case 'G':
411 : 1 : multiplier = ByteUnit::G;
412 : 1 : break;
413 : 1 : case 't':
414 : 1 : multiplier = ByteUnit::t;
415 : 1 : break;
416 : 2 : case 'T':
417 : 2 : multiplier = ByteUnit::T;
418 : 2 : break;
419 : 6 : default:
420 : 6 : unit = 0;
421 : 6 : break;
422 : : }
423 : :
424 : 35 : uint64_t unit_amount = static_cast<uint64_t>(multiplier);
425 : 21 : auto parsed_num = ToIntegral<uint64_t>(unit ? str.substr(0, str.size() - 1) : str);
426 [ + + + + ]: 21 : if (!parsed_num || parsed_num > std::numeric_limits<uint64_t>::max() / unit_amount) { // check overflow
427 : 8 : return std::nullopt;
428 : : }
429 : 13 : return *parsed_num * unit_amount;
430 : : }
|