1#include <xrpl/basics/StringUtilities.h>
2#include <xrpl/basics/base_uint.h>
3#include <xrpl/basics/contract.h>
4#include <xrpl/basics/safe_cast.h>
5#include <xrpl/beast/core/LexicalCast.h>
6#include <xrpl/json/json_forwards.h>
7#include <xrpl/json/json_value.h>
8#include <xrpl/protocol/AccountID.h>
9#include <xrpl/protocol/ErrorCodes.h>
10#include <xrpl/protocol/LedgerFormats.h>
11#include <xrpl/protocol/Permissions.h>
12#include <xrpl/protocol/SField.h>
13#include <xrpl/protocol/STAccount.h>
14#include <xrpl/protocol/STAmount.h>
15#include <xrpl/protocol/STArray.h>
16#include <xrpl/protocol/STBitString.h>
17#include <xrpl/protocol/STBlob.h>
18#include <xrpl/protocol/STCurrency.h>
19#include <xrpl/protocol/STInteger.h>
20#include <xrpl/protocol/STIssue.h>
21#include <xrpl/protocol/STNumber.h>
22#include <xrpl/protocol/STParsedJSON.h>
23#include <xrpl/protocol/STPathSet.h>
24#include <xrpl/protocol/STVector256.h>
25#include <xrpl/protocol/STXChainBridge.h>
26#include <xrpl/protocol/TER.h>
27#include <xrpl/protocol/TxFormats.h>
28#include <xrpl/protocol/UintTypes.h>
29#include <xrpl/protocol/detail/STVar.h>
46namespace STParsedJSONDetail {
47template <
typename U,
typename S>
52 Throw<std::runtime_error>(
"Value out of range");
53 return static_cast<U
>(value);
56template <
typename U1,
typename U2>
61 Throw<std::runtime_error>(
"Value out of range");
62 return static_cast<U1
>(value);
72 return object +
"." + field;
155 "]' must be an object with a single key/object value.");
163 "Object '" + sField.
getName() +
"' contents did not meet requirements for that type.");
172 " is not an object. Arrays may only contain objects.");
176template <
class STResult,
class Integer>
192 ret = detail::make_stvar<STResult>(
194 safe_cast<typename STResult::value_type>(
195 beast::lexicalCastThrow<Integer>(value.
asString())));
197 else if (value.
isInt())
199 ret = detail::make_stvar<STResult>(
200 field, to_unsigned<typename STResult::value_type>(value.
asInt()));
204 ret = detail::make_stvar<STResult>(
205 field, to_unsigned<typename STResult::value_type>(value.
asUInt()));
209 error =
bad_type(json_name, fieldName);
222template <
class STResult,
class Integer = std::u
int16_t>
240 if (!strValue.
empty() && ((strValue[0] <
'0') || (strValue[0] >
'9')))
242 if (field == sfTransactionType)
244 ret = detail::make_stvar<STResult>(
246 safe_cast<typename STResult::value_type>(
static_cast<Integer
>(
250 name = &sfTransaction;
252 else if (field == sfLedgerEntryType)
254 ret = detail::make_stvar<STResult>(
256 safe_cast<typename STResult::value_type>(
static_cast<Integer
>(
260 name = &sfLedgerEntry;
271 return parseUnsigned<STResult, Integer>(
272 field, json_name, fieldName, name, value, error);
284template <
class STResult,
class Integer = std::u
int32_t>
300 if (field == sfPermissionValue)
303 auto const granularPermission =
305 if (granularPermission)
307 ret = detail::make_stvar<STResult>(field, *granularPermission);
312 ret = detail::make_stvar<STResult>(
318 ret = detail::make_stvar<STResult>(
320 safe_cast<typename STResult::value_type>(
321 beast::lexicalCastThrow<Integer>(value.
asString())));
326 return parseUnsigned<STResult, Integer>(
327 field, json_name, fieldName, name, value, error);
362 switch (field.fieldType)
373 if (!strValue.
empty() && ((strValue[0] <
'0') || (strValue[0] >
'9')))
375 if (field == sfTransactionResult)
385 ret = detail::make_stvar<STUInt8>(
390 error =
bad_type(json_name, fieldName);
396 ret = detail::make_stvar<STUInt8>(
397 field, beast::lexicalCastThrow<std::uint8_t>(strValue));
400 else if (value.
isInt())
402 if (value.
asInt() < minValue || value.
asInt() > maxValue)
408 ret = detail::make_stvar<STUInt8>(
413 if (value.
asUInt() > maxValue)
419 ret = detail::make_stvar<STUInt8>(
424 error =
bad_type(json_name, fieldName);
436 ret = parseUint16<STUInt16>(field, json_name, fieldName, name, value, error);
443 ret = parseUint32<STUInt32>(field, json_name, fieldName, name, value, error);
462 str.data(), str.data() + str.size(), val, useBase10 ? 10 : 16);
464 if (ec !=
std::errc() || (p != str.data() + str.size()))
465 Throw<std::invalid_argument>(
"invalid data");
467 ret = detail::make_stvar<STUInt64>(field, val);
469 else if (value.
isInt())
471 ret = detail::make_stvar<STUInt64>(
472 field, to_unsigned<std::uint64_t>(value.
asInt()));
476 ret = detail::make_stvar<STUInt64>(
477 field, safe_cast<std::uint64_t>(value.
asUInt()));
481 error =
bad_type(json_name, fieldName);
496 error =
bad_type(json_name, fieldName);
513 ret = detail::make_stvar<STUInt128>(field, num);
520 error =
bad_type(json_name, fieldName);
537 ret = detail::make_stvar<STUInt160>(field, num);
544 error =
bad_type(json_name, fieldName);
561 ret = detail::make_stvar<STUInt192>(field, num);
568 error =
bad_type(json_name, fieldName);
585 ret = detail::make_stvar<STUInt256>(field, num);
594 ret = detail::make_stvar<STInt32>(
595 field, beast::lexicalCastThrow<std::int32_t>(value.
asString()));
597 else if (value.
isInt())
603 ret = detail::make_stvar<STInt32>(field, value.
asInt());
607 auto const uintValue = value.
asUInt();
614 ret = detail::make_stvar<STInt32>(field,
static_cast<std::int32_t>(uintValue));
618 error =
bad_type(json_name, fieldName);
633 error =
bad_type(json_name, fieldName);
641 ret = detail::make_stvar<STBlob>(field, vBlob->data(), vBlob->size());
645 Throw<std::invalid_argument>(
"invalid data");
696 Throw<std::invalid_argument>(
"invalid data");
699 ret = detail::make_stvar<STVector256>(std::move(tail));
724 if (!value[i].isArrayOrNull())
727 ss << fieldName <<
"[" << i <<
"]";
735 ss << fieldName <<
"[" << i <<
"][" << j <<
"]";
752 bool hasCurrency =
false;
756 if (!account && !currency && !issuer)
765 if (!account.isString())
773 if (!uAccount.
parseHex(account.asString()))
775 auto const a = parseBase58<AccountID>(account.asString());
817 auto const a = parseBase58<AccountID>(issuer.
asString());
827 p.
emplace_back(uAccount, uCurrency, uIssuer, hasCurrency);
832 ret = detail::make_stvar<STPathSet>(std::move(tail));
845 error =
bad_type(json_name, fieldName);
853 if (
AccountID account; account.parseHex(strValue))
854 return detail::make_stvar<STAccount>(field, account);
856 if (
auto result = parseBase58<AccountID>(strValue))
857 return detail::make_stvar<STAccount>(field, *result);
873 ret = detail::make_stvar<STIssue>(
issueFromJson(field, value));
882 case STI_XCHAIN_BRIDGE:
885 ret = detail::make_stvar<STXChainBridge>(
STXChainBridge(field, value));
907 error =
bad_type(json_name, fieldName);
961 switch (field.fieldType)
965 case STI_TRANSACTION:
966 case STI_LEDGERENTRY:
977 json_name +
"." + fieldName, value, field, depth + 1, error);
980 data.emplace_back(std::move(*ret));
995 parseArray(json_name +
"." + fieldName, value, field, depth + 1, error);
996 if (!array.has_value())
998 data.emplace_back(std::move(*array));
1010 auto leaf =
parseLeaf(json_name, fieldName, &inName, value, error);
1015 data.emplace_back(std::move(*leaf));
1023 data.applyTemplateFromSField(inName);
1065 bool const isObjectOrNull(json[i].isObjectOrNull());
1066 bool const singleKey(isObjectOrNull ? json[i].size() == 1 :
true);
1068 if (!isObjectOrNull || !singleKey)
1078 std::string const memberName(json[i].getMemberNames()[0]);
1088 Json::Value const objectFields(json[i][memberName]);
1091 ss << json_name <<
"." <<
"[" << i <<
"]." << memberName;
1093 auto ret =
parseObject(ss.
str(), objectFields, nameField, depth + 1, error);
1096 std::string const errMsg = error[
"error_message"].asString();
1097 error[
"error_message"] =
"Error at '" + ss.
str() +
"'. " + errMsg;
1101 if (ret->getFName().fieldType != STI_OBJECT)
1103 ss <<
"Field type: " << ret->getFName().fieldType <<
" ";
1111 return detail::make_stvar<STArray>(std::move(tail));
1126 using namespace STParsedJSONDetail;
bool isObjectOrNull() const
Members getMemberNames() const
Return a list of the member names.
bool isValidIndex(UInt index) const
Return true if index < size().
std::string asString() const
Returns the unquoted string value.
bool isArrayOrNull() const
std::optional< std::uint32_t > getGranularValue(std::string const &name) const
static Permission const & getInstance()
static SField const & getField(int fieldCode)
std::string const & getName() const
void push_back(STObject const &object)
Json::Value error
On failure, an appropriate set of error values.
STParsedJSONObject()=delete
void push_back(STPath const &e)
void emplace_back(Args &&... args)
void push_back(uint256 const &v)
Integers of any length that is a multiple of 32-bits.
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
constexpr std::enable_if_t< std::is_unsigned< U >::value &&std::is_signed< S >::value, U > to_unsigned(S value)
static Json::Value invalid_data(std::string const &object, std::string const &field)
static Json::Value unknown_field(std::string const &object, std::string const &field)
static std::optional< STObject > parseObject(std::string const &json_name, Json::Value const &json, SField const &inName, int depth, Json::Value &error)
static std::string make_name(std::string const &object, std::string const &field)
static int const maxDepth
static Json::Value out_of_range(std::string const &object, std::string const &field)
static Json::Value bad_type(std::string const &object, std::string const &field)
static std::optional< detail::STVar > parseUnsigned(SField const &field, std::string const &json_name, std::string const &fieldName, SField const *name, Json::Value const &value, Json::Value &error)
static Json::Value too_deep(std::string const &object)
static std::optional< detail::STVar > parseUint32(SField const &field, std::string const &json_name, std::string const &fieldName, SField const *name, Json::Value const &value, Json::Value &error)
static Json::Value not_an_array(std::string const &object)
static Json::Value array_expected(std::string const &object, std::string const &field)
static std::optional< detail::STVar > parseArray(std::string const &json_name, Json::Value const &json, SField const &inName, int depth, Json::Value &error)
static std::optional< detail::STVar > parseLeaf(std::string const &json_name, std::string const &fieldName, SField const *name, Json::Value const &value, Json::Value &error)
static std::optional< detail::STVar > parseUint16(SField const &field, std::string const &json_name, std::string const &fieldName, SField const *name, Json::Value const &value, Json::Value &error)
static Json::Value not_an_object(std::string const &object, std::string const &field)
static Json::Value string_expected(std::string const &object, std::string const &field)
static Json::Value singleton_expected(std::string const &object, unsigned int index)
static Json::Value non_object_in_array(std::string const &item, Json::UInt index)
static Json::Value template_mismatch(SField const &sField)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
STCurrency currencyFromJson(SField const &name, Json::Value const &v)
STAmount amountFromJson(SField const &name, Json::Value const &v)
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Issue issueFromJson(Json::Value const &v)
constexpr TERUnderlyingType TERtoInt(TELcodes v)
STNumber numberFromJson(SField const &field, Json::Value const &value)
std::optional< TER > transCode(std::string const &token)
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.