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 : :
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 : 545745 : std::string SanitizeString(std::string_view str, int rule)
31 : : {
32 : 545745 : std::string result;
33 [ + + ]: 4923565 : for (char c : str) {
34 [ + + ]: 4377820 : if (SAFE_CHARS[rule].find(c) != std::string::npos) {
35 [ + - ]: 4377679 : result.push_back(c);
36 : : }
37 : : }
38 : 545745 : return result;
39 : 0 : }
40 : :
41 : 115365 : bool IsHex(std::string_view str)
42 : : {
43 [ + + ]: 3290298360 : for (char c : str) {
44 [ + + ]: 3290183863 : if (HexDigit(c) < 0) return false;
45 : : }
46 [ + + + + ]: 114497 : return (str.size() > 0) && (str.size()%2 == 0);
47 : : }
48 : :
49 : : template <typename Byte>
50 : 89841 : std::optional<std::vector<Byte>> TryParseHex(std::string_view str)
51 : : {
52 [ + - ]: 89841 : std::vector<Byte> vch;
53 [ + - ]: 89841 : vch.reserve(str.size() / 2); // two hex characters form a single byte
54 : :
55 : 89841 : auto it = str.begin();
56 : 89841 : while (it != str.end()) {
57 [ + + ]: 1668398951 : if (IsSpace(*it)) {
58 : 116 : ++it;
59 : 116 : continue;
60 : : }
61 [ + - ]: 1668398835 : auto c1 = HexDigit(*(it++));
62 [ + + ]: 1668398835 : if (it == str.end()) return std::nullopt;
63 [ + - ]: 1668398828 : auto c2 = HexDigit(*(it++));
64 [ + + ]: 1668398828 : if (c1 < 0 || c2 < 0) return std::nullopt;
65 [ + - + + ]: 3336887589 : vch.push_back(Byte(c1 << 4) | Byte(c2));
66 : : }
67 : 89822 : return vch;
68 : 89841 : }
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 : 571383 : bool SplitHostPort(std::string_view in, uint16_t& portOut, std::string& hostOut)
73 : : {
74 : 571383 : bool valid = false;
75 [ + + ]: 571383 : 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 : 571383 : bool fHaveColon = colon != in.npos;
78 [ + + + + : 571383 : 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 [ + + + + ]: 571383 : bool fMultiColon{fHaveColon && colon != 0 && (in.find_last_of(':', colon - 1) != in.npos)};
80 [ + + + + : 571383 : if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) {
+ + ]
81 [ + + ]: 923 : if (const auto n{ToIntegral<uint16_t>(in.substr(colon + 1))}) {
82 : 828 : in = in.substr(0, colon);
83 : 828 : portOut = *n;
84 : 828 : valid = (portOut != 0);
85 : : }
86 : : } else {
87 : : valid = true;
88 : : }
89 [ + + + + : 571383 : if (in.size() > 0 && in[0] == '[' && in[in.size() - 1] == ']') {
+ + ]
90 : 18 : hostOut = in.substr(1, in.size() - 2);
91 : : } else {
92 : 571365 : hostOut = in;
93 : : }
94 : :
95 : 571383 : return valid;
96 : : }
97 : :
98 : 1408 : std::string EncodeBase64(std::span<const unsigned char> input)
99 : : {
100 : 1408 : static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
101 : :
102 [ + - ]: 1408 : std::string str;
103 [ + - ]: 1408 : str.reserve(((input.size() + 2) / 3) * 4);
104 [ + - ]: 3441538 : ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, input.begin(), input.end());
105 [ + - + + ]: 2050 : while (str.size() % 4) str += '=';
106 : 1408 : return str;
107 : 0 : }
108 : :
109 : 187406 : std::optional<std::vector<unsigned char>> DecodeBase64(std::string_view str)
110 : : {
111 : 187406 : static const int8_t decode64_table[256]{
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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
114 : : -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
115 : : -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
116 : : 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
117 : : 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
118 : : 49, 50, 51, -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, -1, -1, -1, -1,
124 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
125 : : };
126 : :
127 [ + + ]: 187406 : if (str.size() % 4 != 0) return {};
128 : : /* One or two = characters at the end are permitted. */
129 [ + + + + ]: 187397 : if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
130 [ + + + + ]: 187397 : if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
131 : :
132 : 187397 : std::vector<unsigned char> ret;
133 [ + - ]: 187397 : ret.reserve((str.size() * 3) / 4);
134 [ + - ]: 187397 : bool valid = ConvertBits<6, 8, false>(
135 : 18091351 : [&](unsigned char c) { ret.push_back(c); },
136 : : str.begin(), str.end(),
137 [ + + ]: 24122133 : [](char c) { return decode64_table[uint8_t(c)]; }
138 : : );
139 [ + + ]: 187397 : if (!valid) return {};
140 : :
141 : 187392 : return ret;
142 : 187397 : }
143 : :
144 : 156 : std::string EncodeBase32(std::span<const unsigned char> input, bool pad)
145 : : {
146 : 156 : static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
147 : :
148 [ + - ]: 156 : std::string str;
149 [ + - ]: 156 : str.reserve(((input.size() + 4) / 5) * 8);
150 [ + - ]: 7868 : ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, input.begin(), input.end());
151 [ + + ]: 156 : if (pad) {
152 : 123 : while (str.size() % 8) {
153 [ + - + + ]: 123 : str += '=';
154 : : }
155 : : }
156 : 156 : return str;
157 : 0 : }
158 : :
159 : 15 : std::string EncodeBase32(std::string_view str, bool pad)
160 : : {
161 : 15 : return EncodeBase32(MakeUCharSpan(str), pad);
162 : : }
163 : :
164 : 89 : std::optional<std::vector<unsigned char>> DecodeBase32(std::string_view str)
165 : : {
166 : 89 : static const int8_t decode32_table[256]{
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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
169 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1,
170 : : -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
171 : : 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2,
172 : : 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
173 : : 23, 24, 25, -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, -1, -1, -1, -1,
179 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
180 : : };
181 : :
182 [ + + ]: 89 : if (str.size() % 8 != 0) return {};
183 : : /* 1, 3, 4, or 6 padding '=' suffix characters are permitted. */
184 [ + + + + ]: 88 : if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
185 [ + + + + ]: 88 : if (str.size() >= 2 && str.substr(str.size() - 2) == "==") str.remove_suffix(2);
186 [ + + + + ]: 88 : if (str.size() >= 1 && str.back() == '=') str.remove_suffix(1);
187 [ + + + + ]: 88 : if (str.size() >= 2 && str.substr(str.size() - 2) == "==") str.remove_suffix(2);
188 : :
189 : 88 : std::vector<unsigned char> ret;
190 [ + - ]: 88 : ret.reserve((str.size() * 5) / 8);
191 [ + - ]: 88 : bool valid = ConvertBits<5, 8, false>(
192 : 2293 : [&](unsigned char c) { ret.push_back(c); },
193 : : str.begin(), str.end(),
194 [ + + ]: 3703 : [](char c) { return decode32_table[uint8_t(c)]; }
195 : : );
196 : :
197 [ + + ]: 88 : if (!valid) return {};
198 : :
199 : 80 : return ret;
200 : 88 : }
201 : :
202 : 174 : std::string FormatParagraph(std::string_view in, size_t width, size_t indent)
203 : : {
204 [ - + ]: 174 : assert(width >= indent);
205 : 174 : std::stringstream out;
206 : 174 : size_t ptr = 0;
207 : 174 : size_t indented = 0;
208 [ + + ]: 797 : while (ptr < in.size())
209 : : {
210 [ + + ]: 451 : size_t lineend = in.find_first_of('\n', ptr);
211 [ + + ]: 451 : if (lineend == std::string::npos) {
212 : 417 : lineend = in.size();
213 : : }
214 : 451 : const size_t linelen = lineend - ptr;
215 : 451 : const size_t rem_width = width - indented;
216 [ + + ]: 451 : if (linelen <= rem_width) {
217 [ + - ]: 194 : out << in.substr(ptr, linelen + 1);
218 : 194 : ptr = lineend + 1;
219 : 194 : indented = 0;
220 : : } else {
221 : 257 : size_t finalspace = in.find_last_of(" \n", ptr + rem_width);
222 [ + + ]: 257 : if (finalspace == std::string::npos || finalspace < ptr) {
223 : : // No place to break; just include the entire word and move on
224 : 8 : finalspace = in.find_first_of("\n ", ptr);
225 [ + + ]: 8 : if (finalspace == std::string::npos) {
226 : : // End of the string, just add it and break
227 [ + - ]: 2 : out << in.substr(ptr);
228 : : break;
229 : : }
230 : : }
231 [ + - + - ]: 510 : out << in.substr(ptr, finalspace - ptr) << "\n";
232 [ + + ]: 255 : if (in[finalspace] == '\n') {
233 : : indented = 0;
234 [ + + ]: 253 : } else if (indent) {
235 [ + - + - ]: 233 : out << std::string(indent, ' ');
236 : 233 : indented = indent;
237 : : }
238 : 255 : ptr = finalspace + 1;
239 : : }
240 : : }
241 [ + - ]: 348 : return out.str();
242 : 174 : }
243 : :
244 : : /** Upper bound for mantissa.
245 : : * 10^18-1 is the largest arbitrary decimal that will fit in a signed 64-bit integer.
246 : : * Larger integers cannot consist of arbitrary combinations of 0-9:
247 : : *
248 : : * 999999999999999999 1^18-1
249 : : * 9223372036854775807 (1<<63)-1 (max int64_t)
250 : : * 9999999999999999999 1^19-1 (would overflow)
251 : : */
252 : : static const int64_t UPPER_BOUND = 1000000000000000000LL - 1LL;
253 : :
254 : : /** Helper function for ParseFixedPoint */
255 : 39662 : static inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantissa_tzeros)
256 : : {
257 [ + + ]: 39662 : if(ch == '0')
258 : 10239 : ++mantissa_tzeros;
259 : : else {
260 [ + + ]: 62173 : for (int i=0; i<=mantissa_tzeros; ++i) {
261 [ + + ]: 32781 : if (mantissa > (UPPER_BOUND / 10LL))
262 : : return false; /* overflow */
263 : 32750 : mantissa *= 10;
264 : : }
265 : 29392 : mantissa += ch - '0';
266 : 29392 : mantissa_tzeros = 0;
267 : : }
268 : : return true;
269 : : }
270 : :
271 : 38154 : bool ParseFixedPoint(std::string_view val, int decimals, int64_t *amount_out)
272 : : {
273 : 38154 : int64_t mantissa = 0;
274 : 38154 : int64_t exponent = 0;
275 : 38154 : int mantissa_tzeros = 0;
276 : 38154 : bool mantissa_sign = false;
277 : 38154 : bool exponent_sign = false;
278 : 38154 : int ptr = 0;
279 [ + + ]: 38154 : int end = val.size();
280 : 38154 : int point_ofs = 0;
281 : :
282 [ + + + + ]: 38154 : if (ptr < end && val[ptr] == '-') {
283 : : mantissa_sign = true;
284 : : ++ptr;
285 : : }
286 [ + + ]: 38154 : if (ptr < end)
287 : : {
288 [ + + ]: 38142 : if (val[ptr] == '0') {
289 : : /* pass single 0 */
290 : 31701 : ++ptr;
291 [ + + + + ]: 6441 : } else if (val[ptr] >= '1' && val[ptr] <= '9') {
292 [ + + + + ]: 15562 : while (ptr < end && IsDigit(val[ptr])) {
293 [ + - ]: 9131 : if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
294 : : return false; /* overflow */
295 : 9131 : ++ptr;
296 : : }
297 : : } else return false; /* missing expected digit */
298 : : } else return false; /* empty string or loose '-' */
299 [ + + + + ]: 38132 : if (ptr < end && val[ptr] == '.')
300 : : {
301 : 17877 : ++ptr;
302 [ + + + - ]: 17877 : if (ptr < end && IsDigit(val[ptr]))
303 : : {
304 [ + + + + ]: 48375 : while (ptr < end && IsDigit(val[ptr])) {
305 [ + + ]: 30531 : if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
306 : : return false; /* overflow */
307 : 30500 : ++ptr;
308 : 30500 : ++point_ofs;
309 : : }
310 : : } else return false; /* missing expected digit */
311 : : }
312 [ + + + + : 38099 : if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E'))
+ + ]
313 : : {
314 : 3660 : ++ptr;
315 [ + + + + ]: 3660 : if (ptr < end && val[ptr] == '+')
316 : 4 : ++ptr;
317 [ + + + + ]: 3656 : else if (ptr < end && val[ptr] == '-') {
318 : 3650 : exponent_sign = true;
319 : 3650 : ++ptr;
320 : : }
321 [ + + + - ]: 3660 : if (ptr < end && IsDigit(val[ptr])) {
322 [ + + + - ]: 10955 : while (ptr < end && IsDigit(val[ptr])) {
323 [ + - ]: 7299 : if (exponent > (UPPER_BOUND / 10LL))
324 : : return false; /* overflow */
325 : 7299 : exponent = exponent * 10 + val[ptr] - '0';
326 : 7299 : ++ptr;
327 : : }
328 : : } else return false; /* missing expected digit */
329 : : }
330 [ + + ]: 38095 : if (ptr != end)
331 : : return false; /* trailing garbage */
332 : :
333 : : /* finalize exponent */
334 [ + + ]: 38087 : if (exponent_sign)
335 : 3648 : exponent = -exponent;
336 : 38087 : exponent = exponent - point_ofs + mantissa_tzeros;
337 : :
338 : : /* finalize mantissa */
339 [ + + ]: 38087 : if (mantissa_sign)
340 : 24 : mantissa = -mantissa;
341 : :
342 : : /* convert to one 64-bit fixed-point value */
343 : 38087 : exponent += decimals;
344 [ + + ]: 38087 : if (exponent < 0)
345 : : return false; /* cannot represent values smaller than 10^-decimals */
346 [ + + ]: 38022 : if (exponent >= 18)
347 : : return false; /* cannot represent values larger than or equal to 10^(18-decimals) */
348 : :
349 [ + + ]: 299479 : for (int i=0; i < exponent; ++i) {
350 [ + + ]: 261472 : if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL))
351 : : return false; /* overflow */
352 : 261463 : mantissa *= 10;
353 : : }
354 [ + - ]: 38007 : if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND)
355 : : return false; /* overflow */
356 : :
357 [ + - ]: 38007 : if (amount_out)
358 : 38007 : *amount_out = mantissa;
359 : :
360 : : return true;
361 : : }
362 : :
363 : 23922 : std::string ToLower(std::string_view str)
364 : : {
365 [ + - ]: 23922 : std::string r;
366 [ + - ]: 23922 : r.reserve(str.size());
367 [ + + + - : 128761 : for (auto ch : str) r += ToLower(ch);
+ + ]
368 : 23922 : return r;
369 : 0 : }
370 : :
371 : 247 : std::string ToUpper(std::string_view str)
372 : : {
373 [ + - ]: 247 : std::string r;
374 [ + - ]: 247 : r.reserve(str.size());
375 [ + + + - : 4140 : for (auto ch : str) r += ToUpper(ch);
+ + ]
376 : 247 : return r;
377 : 0 : }
378 : :
379 : 74 : std::string Capitalize(std::string str)
380 : : {
381 [ + + ]: 74 : if (str.empty()) return str;
382 [ + - ]: 144 : str[0] = ToUpper(str.front());
383 : 72 : return str;
384 : : }
385 : :
386 : 1060 : std::optional<uint64_t> ParseByteUnits(std::string_view str, ByteUnit default_multiplier)
387 : : {
388 [ + + ]: 1060 : if (str.empty()) {
389 : 1 : return std::nullopt;
390 : : }
391 : 1059 : auto multiplier = default_multiplier;
392 [ + + + + : 1059 : char unit = str.back();
+ + + +
+ ]
393 [ + + + + : 1059 : switch (unit) {
+ + + +
+ ]
394 : : case 'k':
395 : : multiplier = ByteUnit::k;
396 : : break;
397 : 1 : case 'K':
398 : 1 : multiplier = ByteUnit::K;
399 : 1 : break;
400 : 4 : case 'm':
401 : 4 : multiplier = ByteUnit::m;
402 : 4 : break;
403 : 1039 : case 'M':
404 : 1039 : multiplier = ByteUnit::M;
405 : 1039 : break;
406 : 2 : case 'g':
407 : 2 : multiplier = ByteUnit::g;
408 : 2 : break;
409 : 1 : case 'G':
410 : 1 : multiplier = ByteUnit::G;
411 : 1 : break;
412 : 1 : case 't':
413 : 1 : multiplier = ByteUnit::t;
414 : 1 : break;
415 : 2 : case 'T':
416 : 2 : multiplier = ByteUnit::T;
417 : 2 : break;
418 : 8 : default:
419 : 8 : unit = 0;
420 : 8 : break;
421 : : }
422 : :
423 : 2109 : uint64_t unit_amount = static_cast<uint64_t>(multiplier);
424 : 1059 : auto parsed_num = ToIntegral<uint64_t>(unit ? str.substr(0, str.size() - 1) : str);
425 [ + + + + ]: 1059 : if (!parsed_num || parsed_num > std::numeric_limits<uint64_t>::max() / unit_amount) { // check overflow
426 : 9 : return std::nullopt;
427 : : }
428 : 1050 : return *parsed_num * unit_amount;
429 : : }
|