| 39 | |
| 40 | |
| 41 | std::optional<CAmount> ParseMoney(const std::string& money_string) |
| 42 | { |
| 43 | if (!ValidAsCString(money_string)) { |
| 44 | return std::nullopt; |
| 45 | } |
| 46 | const std::string str = TrimString(money_string); |
| 47 | if (str.empty()) { |
| 48 | return std::nullopt; |
| 49 | } |
| 50 | |
| 51 | std::string strWhole; |
| 52 | int64_t nUnits = 0; |
| 53 | const char* p = str.c_str(); |
| 54 | for (; *p; p++) |
| 55 | { |
| 56 | if (*p == '.') |
| 57 | { |
| 58 | p++; |
| 59 | int64_t nMult = COIN / 10; |
| 60 | while (IsDigit(*p) && (nMult > 0)) |
| 61 | { |
| 62 | nUnits += nMult * (*p++ - '0'); |
| 63 | nMult /= 10; |
| 64 | } |
| 65 | break; |
| 66 | } |
| 67 | if (IsSpace(*p)) |
| 68 | return std::nullopt; |
| 69 | if (!IsDigit(*p)) |
| 70 | return std::nullopt; |
| 71 | strWhole.insert(strWhole.end(), *p); |
| 72 | } |
| 73 | if (*p) { |
| 74 | return std::nullopt; |
| 75 | } |
| 76 | if (strWhole.size() > 10) // guard against 63 bit overflow |
| 77 | return std::nullopt; |
| 78 | if (nUnits < 0 || nUnits > COIN) |
| 79 | return std::nullopt; |
| 80 | int64_t nWhole = LocaleIndependentAtoi<int64_t>(strWhole); |
| 81 | CAmount value = nWhole * COIN + nUnits; |
| 82 | |
| 83 | if (!MoneyRange(value)) { |
| 84 | return std::nullopt; |
| 85 | } |
| 86 | |
| 87 | return value; |
| 88 | } |