]>
Commit | Line | Data |
---|---|---|
ad49c256 | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
f914f1a7 | 2 | // Copyright (c) 2009-2014 The Bitcoin Core developers |
c63a73d1 | 3 | // Distributed under the MIT software license, see the accompanying |
bc909a7a | 4 | // file COPYING or https://www.opensource.org/licenses/mit-license.php . |
ad49c256 WL |
5 | |
6 | #include "utilstrencodings.h" | |
7 | ||
8 | #include "tinyformat.h" | |
9 | ||
352058e8 CF |
10 | #include <cstdlib> |
11 | #include <cstring> | |
771d5002 | 12 | #include <errno.h> |
b174b7e3 | 13 | #include <iomanip> |
771d5002 | 14 | #include <limits> |
611116d4 | 15 | |
ad49c256 WL |
16 | using namespace std; |
17 | ||
3c1db170 M |
18 | static const string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; |
19 | ||
20 | static const string SAFE_CHARS[] = | |
21 | { | |
22 | CHARS_ALPHA_NUM + " .,;_/:?@()", // SAFE_CHARS_DEFAULT | |
5efc2365 AD |
23 | CHARS_ALPHA_NUM + " .,;_?@", // SAFE_CHARS_UA_COMMENT |
24 | CHARS_ALPHA_NUM + "!*'();:@&=+$,/?#[]-_.~%" // SAFE_CHARS_URI | |
3c1db170 M |
25 | }; |
26 | ||
27 | string SanitizeString(const string& str, int rule) | |
ad49c256 WL |
28 | { |
29 | string strResult; | |
30 | for (std::string::size_type i = 0; i < str.size(); i++) | |
31 | { | |
3c1db170 | 32 | if (SAFE_CHARS[rule].find(str[i]) != std::string::npos) |
ad49c256 WL |
33 | strResult.push_back(str[i]); |
34 | } | |
35 | return strResult; | |
36 | } | |
37 | ||
9064d73b S |
38 | string SanitizeFilename(const string& str) |
39 | { | |
40 | /** | |
41 | * safeChars chosen to restrict filename, keeping it simple to avoid cross-platform issues. | |
42 | * http://stackoverflow.com/a/2306003 | |
43 | */ | |
44 | static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890"); | |
45 | string strResult; | |
46 | for (std::string::size_type i = 0; i < str.size(); i++) | |
47 | { | |
48 | if (safeChars.find(str[i]) != std::string::npos) | |
49 | strResult.push_back(str[i]); | |
50 | } | |
51 | return strResult; | |
52 | } | |
53 | ||
b174b7e3 JG |
54 | std::string HexInt(uint32_t val) |
55 | { | |
56 | std::stringstream ss; | |
57 | ss << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex << val; | |
58 | return ss.str(); | |
59 | } | |
60 | ||
072099d7 S |
61 | uint32_t ParseHexToUInt32(const std::string& str) { |
62 | std::istringstream converter(str); | |
63 | uint32_t value; | |
64 | converter >> std::hex >> value; | |
65 | return value; | |
66 | } | |
67 | ||
ad49c256 WL |
68 | const signed char p_util_hexdigit[256] = |
69 | { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
70 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
71 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
72 | 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, | |
73 | -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
74 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
75 | -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
76 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
77 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
78 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
79 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
80 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
81 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
82 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
83 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, | |
84 | -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; | |
85 | ||
86 | signed char HexDigit(char c) | |
87 | { | |
88 | return p_util_hexdigit[(unsigned char)c]; | |
89 | } | |
90 | ||
91 | bool IsHex(const string& str) | |
92 | { | |
352058e8 | 93 | for(std::string::const_iterator it(str.begin()); it != str.end(); ++it) |
ad49c256 | 94 | { |
352058e8 | 95 | if (HexDigit(*it) < 0) |
ad49c256 WL |
96 | return false; |
97 | } | |
98 | return (str.size() > 0) && (str.size()%2 == 0); | |
99 | } | |
100 | ||
101 | vector<unsigned char> ParseHex(const char* psz) | |
102 | { | |
103 | // convert hex dump to vector | |
104 | vector<unsigned char> vch; | |
105 | while (true) | |
106 | { | |
107 | while (isspace(*psz)) | |
108 | psz++; | |
109 | signed char c = HexDigit(*psz++); | |
110 | if (c == (signed char)-1) | |
111 | break; | |
112 | unsigned char n = (c << 4); | |
113 | c = HexDigit(*psz++); | |
114 | if (c == (signed char)-1) | |
115 | break; | |
116 | n |= c; | |
117 | vch.push_back(n); | |
118 | } | |
119 | return vch; | |
120 | } | |
121 | ||
122 | vector<unsigned char> ParseHex(const string& str) | |
123 | { | |
124 | return ParseHex(str.c_str()); | |
125 | } | |
126 | ||
127 | string EncodeBase64(const unsigned char* pch, size_t len) | |
128 | { | |
129 | static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
130 | ||
6a2cc8dd PW |
131 | std::string str; |
132 | str.reserve(((len + 2) / 3) * 4); | |
133 | ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, pch, pch + len); | |
134 | while (str.size() % 4) str += '='; | |
135 | return str; | |
ad49c256 WL |
136 | } |
137 | ||
138 | string EncodeBase64(const string& str) | |
139 | { | |
140 | return EncodeBase64((const unsigned char*)str.c_str(), str.size()); | |
141 | } | |
142 | ||
143 | vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid) | |
144 | { | |
145 | static const int decode64_table[256] = | |
146 | { | |
147 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
148 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
149 | -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, | |
150 | -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | |
151 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, | |
152 | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, | |
153 | 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
154 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
155 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
156 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
157 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
158 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
159 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 | |
160 | }; | |
161 | ||
6a2cc8dd PW |
162 | const char* e = p; |
163 | std::vector<uint8_t> val; | |
164 | val.reserve(strlen(p)); | |
165 | while (*p != 0) { | |
166 | int x = decode64_table[(unsigned char)*p]; | |
167 | if (x == -1) break; | |
168 | val.push_back(x); | |
169 | ++p; | |
ad49c256 WL |
170 | } |
171 | ||
6a2cc8dd PW |
172 | std::vector<unsigned char> ret; |
173 | ret.reserve((val.size() * 3) / 4); | |
174 | bool valid = ConvertBits<6, 8, false>([&](unsigned char c) { ret.push_back(c); }, val.begin(), val.end()); | |
175 | ||
176 | const char* q = p; | |
177 | while (valid && *p != 0) { | |
178 | if (*p != '=') { | |
179 | valid = false; | |
180 | break; | |
ad49c256 | 181 | } |
6a2cc8dd PW |
182 | ++p; |
183 | } | |
184 | valid = valid && (p - e) % 4 == 0 && p - q < 4; | |
185 | if (pfInvalid) *pfInvalid = !valid; | |
ad49c256 | 186 | |
6a2cc8dd | 187 | return ret; |
ad49c256 WL |
188 | } |
189 | ||
190 | string DecodeBase64(const string& str) | |
191 | { | |
192 | vector<unsigned char> vchRet = DecodeBase64(str.c_str()); | |
018cec7c | 193 | return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size()); |
ad49c256 WL |
194 | } |
195 | ||
196 | string EncodeBase32(const unsigned char* pch, size_t len) | |
197 | { | |
198 | static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; | |
199 | ||
6a2cc8dd PW |
200 | std::string str; |
201 | str.reserve(((len + 4) / 5) * 8); | |
202 | ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, pch, pch + len); | |
203 | while (str.size() % 8) str += '='; | |
204 | return str; | |
ad49c256 WL |
205 | } |
206 | ||
207 | string EncodeBase32(const string& str) | |
208 | { | |
209 | return EncodeBase32((const unsigned char*)str.c_str(), str.size()); | |
210 | } | |
211 | ||
212 | vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid) | |
213 | { | |
214 | static const int decode32_table[256] = | |
215 | { | |
216 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
217 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
218 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, | |
219 | -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | |
220 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2, | |
221 | 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, | |
222 | 23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
223 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
224 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
225 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
226 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
227 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
228 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 | |
229 | }; | |
230 | ||
6a2cc8dd PW |
231 | const char* e = p; |
232 | std::vector<uint8_t> val; | |
233 | val.reserve(strlen(p)); | |
234 | while (*p != 0) { | |
235 | int x = decode32_table[(unsigned char)*p]; | |
236 | if (x == -1) break; | |
237 | val.push_back(x); | |
238 | ++p; | |
ad49c256 WL |
239 | } |
240 | ||
6a2cc8dd PW |
241 | std::vector<unsigned char> ret; |
242 | ret.reserve((val.size() * 5) / 8); | |
243 | bool valid = ConvertBits<5, 8, false>([&](unsigned char c) { ret.push_back(c); }, val.begin(), val.end()); | |
244 | ||
245 | const char* q = p; | |
246 | while (valid && *p != 0) { | |
247 | if (*p != '=') { | |
248 | valid = false; | |
249 | break; | |
ad49c256 | 250 | } |
6a2cc8dd PW |
251 | ++p; |
252 | } | |
253 | valid = valid && (p - e) % 8 == 0 && p - q < 8; | |
254 | if (pfInvalid) *pfInvalid = !valid; | |
ad49c256 | 255 | |
6a2cc8dd | 256 | return ret; |
ad49c256 WL |
257 | } |
258 | ||
259 | string DecodeBase32(const string& str) | |
260 | { | |
261 | vector<unsigned char> vchRet = DecodeBase32(str.c_str()); | |
018cec7c | 262 | return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size()); |
ad49c256 WL |
263 | } |
264 | ||
5960d700 WL |
265 | static bool ParsePrechecks(const std::string& str) |
266 | { | |
267 | if (str.empty()) // No empty string allowed | |
268 | return false; | |
269 | if (str.size() >= 1 && (isspace(str[0]) || isspace(str[str.size()-1]))) // No padding allowed | |
270 | return false; | |
271 | if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed | |
272 | return false; | |
273 | return true; | |
274 | } | |
275 | ||
ad49c256 WL |
276 | bool ParseInt32(const std::string& str, int32_t *out) |
277 | { | |
5960d700 WL |
278 | if (!ParsePrechecks(str)) |
279 | return false; | |
ad49c256 WL |
280 | char *endp = NULL; |
281 | errno = 0; // strtol will not set errno if valid | |
282 | long int n = strtol(str.c_str(), &endp, 10); | |
5960d700 | 283 | if(out) *out = (int32_t)n; |
ad49c256 WL |
284 | // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow |
285 | // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit | |
286 | // platforms the size of these types may be different. | |
287 | return endp && *endp == 0 && !errno && | |
288 | n >= std::numeric_limits<int32_t>::min() && | |
289 | n <= std::numeric_limits<int32_t>::max(); | |
290 | } | |
291 | ||
5960d700 WL |
292 | bool ParseInt64(const std::string& str, int64_t *out) |
293 | { | |
294 | if (!ParsePrechecks(str)) | |
295 | return false; | |
296 | char *endp = NULL; | |
297 | errno = 0; // strtoll will not set errno if valid | |
298 | long long int n = strtoll(str.c_str(), &endp, 10); | |
299 | if(out) *out = (int64_t)n; | |
300 | // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow | |
301 | // we still have to check that the returned value is within the range of an *int64_t*. | |
302 | return endp && *endp == 0 && !errno && | |
303 | n >= std::numeric_limits<int64_t>::min() && | |
304 | n <= std::numeric_limits<int64_t>::max(); | |
305 | } | |
306 | ||
307 | bool ParseDouble(const std::string& str, double *out) | |
308 | { | |
309 | if (!ParsePrechecks(str)) | |
310 | return false; | |
311 | if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed | |
312 | return false; | |
a8c22cc4 WL |
313 | std::istringstream text(str); |
314 | text.imbue(std::locale::classic()); | |
315 | double result; | |
316 | text >> result; | |
317 | if(out) *out = result; | |
318 | return text.eof() && !text.fail(); | |
5960d700 WL |
319 | } |
320 | ||
db954a65 | 321 | std::string FormatParagraph(const std::string& in, size_t width, size_t indent) |
ad49c256 WL |
322 | { |
323 | std::stringstream out; | |
324 | size_t col = 0; | |
325 | size_t ptr = 0; | |
326 | while(ptr < in.size()) | |
327 | { | |
328 | // Find beginning of next word | |
329 | ptr = in.find_first_not_of(' ', ptr); | |
330 | if (ptr == std::string::npos) | |
331 | break; | |
332 | // Find end of next word | |
333 | size_t endword = in.find_first_of(' ', ptr); | |
334 | if (endword == std::string::npos) | |
335 | endword = in.size(); | |
336 | // Add newline and indentation if this wraps over the allowed width | |
337 | if (col > 0) | |
338 | { | |
339 | if ((col + endword - ptr) > width) | |
340 | { | |
341 | out << '\n'; | |
342 | for(size_t i=0; i<indent; ++i) | |
343 | out << ' '; | |
344 | col = 0; | |
345 | } else | |
346 | out << ' '; | |
347 | } | |
348 | // Append word | |
349 | out << in.substr(ptr, endword - ptr); | |
83b81f6c | 350 | col += endword - ptr + 1; |
ad49c256 WL |
351 | ptr = endword; |
352 | } | |
353 | return out.str(); | |
354 | } | |
355 | ||
356 | std::string i64tostr(int64_t n) | |
357 | { | |
358 | return strprintf("%d", n); | |
359 | } | |
360 | ||
361 | std::string itostr(int n) | |
362 | { | |
363 | return strprintf("%d", n); | |
364 | } | |
365 | ||
366 | int64_t atoi64(const char* psz) | |
367 | { | |
368 | #ifdef _MSC_VER | |
369 | return _atoi64(psz); | |
370 | #else | |
371 | return strtoll(psz, NULL, 10); | |
372 | #endif | |
373 | } | |
374 | ||
375 | int64_t atoi64(const std::string& str) | |
376 | { | |
377 | #ifdef _MSC_VER | |
378 | return _atoi64(str.c_str()); | |
379 | #else | |
380 | return strtoll(str.c_str(), NULL, 10); | |
381 | #endif | |
382 | } | |
383 | ||
384 | int atoi(const std::string& str) | |
385 | { | |
386 | return atoi(str.c_str()); | |
387 | } | |
fed500e2 WL |
388 | |
389 | /** Upper bound for mantissa. | |
390 | * 10^18-1 is the largest arbitrary decimal that will fit in a signed 64-bit integer. | |
391 | * Larger integers cannot consist of arbitrary combinations of 0-9: | |
392 | * | |
393 | * 999999999999999999 1^18-1 | |
394 | * 9223372036854775807 (1<<63)-1 (max int64_t) | |
395 | * 9999999999999999999 1^19-1 (would overflow) | |
396 | */ | |
397 | static const int64_t UPPER_BOUND = 1000000000000000000LL - 1LL; | |
398 | ||
399 | /** Helper function for ParseFixedPoint */ | |
400 | static inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantissa_tzeros) | |
401 | { | |
402 | if(ch == '0') | |
403 | ++mantissa_tzeros; | |
404 | else { | |
405 | for (int i=0; i<=mantissa_tzeros; ++i) { | |
406 | if (mantissa > (UPPER_BOUND / 10LL)) | |
407 | return false; /* overflow */ | |
408 | mantissa *= 10; | |
409 | } | |
410 | mantissa += ch - '0'; | |
411 | mantissa_tzeros = 0; | |
412 | } | |
413 | return true; | |
414 | } | |
415 | ||
416 | bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out) | |
417 | { | |
418 | int64_t mantissa = 0; | |
419 | int64_t exponent = 0; | |
420 | int mantissa_tzeros = 0; | |
421 | bool mantissa_sign = false; | |
422 | bool exponent_sign = false; | |
423 | int ptr = 0; | |
424 | int end = val.size(); | |
425 | int point_ofs = 0; | |
426 | ||
427 | if (ptr < end && val[ptr] == '-') { | |
428 | mantissa_sign = true; | |
429 | ++ptr; | |
430 | } | |
431 | if (ptr < end) | |
432 | { | |
433 | if (val[ptr] == '0') { | |
434 | /* pass single 0 */ | |
435 | ++ptr; | |
436 | } else if (val[ptr] >= '1' && val[ptr] <= '9') { | |
437 | while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { | |
438 | if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros)) | |
439 | return false; /* overflow */ | |
440 | ++ptr; | |
441 | } | |
442 | } else return false; /* missing expected digit */ | |
443 | } else return false; /* empty string or loose '-' */ | |
444 | if (ptr < end && val[ptr] == '.') | |
445 | { | |
446 | ++ptr; | |
447 | if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') | |
448 | { | |
449 | while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { | |
450 | if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros)) | |
451 | return false; /* overflow */ | |
452 | ++ptr; | |
453 | ++point_ofs; | |
454 | } | |
455 | } else return false; /* missing expected digit */ | |
456 | } | |
457 | if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E')) | |
458 | { | |
459 | ++ptr; | |
460 | if (ptr < end && val[ptr] == '+') | |
461 | ++ptr; | |
462 | else if (ptr < end && val[ptr] == '-') { | |
463 | exponent_sign = true; | |
464 | ++ptr; | |
465 | } | |
466 | if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { | |
467 | while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') { | |
468 | if (exponent > (UPPER_BOUND / 10LL)) | |
469 | return false; /* overflow */ | |
470 | exponent = exponent * 10 + val[ptr] - '0'; | |
471 | ++ptr; | |
472 | } | |
473 | } else return false; /* missing expected digit */ | |
474 | } | |
475 | if (ptr != end) | |
476 | return false; /* trailing garbage */ | |
477 | ||
478 | /* finalize exponent */ | |
479 | if (exponent_sign) | |
480 | exponent = -exponent; | |
481 | exponent = exponent - point_ofs + mantissa_tzeros; | |
482 | ||
483 | /* finalize mantissa */ | |
484 | if (mantissa_sign) | |
485 | mantissa = -mantissa; | |
486 | ||
487 | /* convert to one 64-bit fixed-point value */ | |
488 | exponent += decimals; | |
489 | if (exponent < 0) | |
490 | return false; /* cannot represent values smaller than 10^-decimals */ | |
491 | if (exponent >= 18) | |
492 | return false; /* cannot represent values larger than or equal to 10^(18-decimals) */ | |
493 | ||
494 | for (int i=0; i < exponent; ++i) { | |
495 | if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL)) | |
496 | return false; /* overflow */ | |
497 | mantissa *= 10; | |
498 | } | |
499 | if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND) | |
500 | return false; /* overflow */ | |
501 | ||
502 | if (amount_out) | |
503 | *amount_out = mantissa; | |
504 | ||
505 | return true; | |
506 | } | |
507 |