rippled
Loading...
Searching...
No Matches
STParsedJSON.cpp
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>
30
31#include <charconv>
32#include <cstdint>
33#include <exception>
34#include <iostream>
35#include <limits>
36#include <optional>
37#include <sstream>
38#include <stdexcept>
39#include <string>
40#include <system_error>
41#include <type_traits>
42#include <utility>
43
44namespace xrpl {
45
46namespace STParsedJSONDetail {
47template <typename U, typename S>
50{
51 if (value < 0 || std::numeric_limits<U>::max() < value)
52 Throw<std::runtime_error>("Value out of range");
53 return static_cast<U>(value);
54}
55
56template <typename U1, typename U2>
58to_unsigned(U2 value)
59{
60 if (std::numeric_limits<U1>::max() < value)
61 Throw<std::runtime_error>("Value out of range");
62 return static_cast<U1>(value);
63}
64
65// LCOV_EXCL_START
66static inline std::string
67make_name(std::string const& object, std::string const& field)
68{
69 if (field.empty())
70 return object;
71
72 return object + "." + field;
73}
74
75static inline Json::Value
76not_an_object(std::string const& object, std::string const& field)
77{
78 return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' is not a JSON object.");
79}
80
81static inline Json::Value
83{
84 return not_an_object(object, "");
85}
86
87static inline Json::Value
89{
90 return RPC::make_error(rpcINVALID_PARAMS, "Field '" + object + "' is not a JSON array.");
91}
92
93static inline Json::Value
94unknown_field(std::string const& object, std::string const& field)
95{
96 return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' is unknown.");
97}
98
99static inline Json::Value
100out_of_range(std::string const& object, std::string const& field)
101{
102 return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' is out of range.");
103}
104
105static inline Json::Value
106bad_type(std::string const& object, std::string const& field)
107{
108 return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' has bad type.");
109}
110
111static inline Json::Value
112invalid_data(std::string const& object, std::string const& field)
113{
114 return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' has invalid data.");
115}
116
117static inline Json::Value
119{
120 return invalid_data(object, "");
121}
122
123static inline Json::Value
124array_expected(std::string const& object, std::string const& field)
125{
126 return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' must be a JSON array.");
127}
128
129static inline Json::Value
130string_expected(std::string const& object, std::string const& field)
131{
132 return RPC::make_error(rpcINVALID_PARAMS, "Field '" + make_name(object, field) + "' must be a string.");
133}
134
135static inline Json::Value
136too_deep(std::string const& object)
137{
138 return RPC::make_error(rpcINVALID_PARAMS, "Field '" + object + "' exceeds nesting depth limit.");
139}
140
141static inline Json::Value
142singleton_expected(std::string const& object, unsigned int index)
143{
144 return RPC::make_error(
146 "Field '" + object + "[" + std::to_string(index) + "]' must be an object with a single key/object value.");
147}
148
149static inline Json::Value
151{
152 return RPC::make_error(
153 rpcINVALID_PARAMS, "Object '" + sField.getName() + "' contents did not meet requirements for that type.");
154}
155
156static inline Json::Value
158{
159 return RPC::make_error(
161 "Item '" + item + "' at index " + std::to_string(index) +
162 " is not an object. Arrays may only contain objects.");
163}
164// LCOV_EXCL_STOP
165
166template <class STResult, class Integer>
169 SField const& field,
170 std::string const& json_name,
171 std::string const& fieldName,
172 SField const* name,
173 Json::Value const& value,
174 Json::Value& error)
175{
177
178 try
179 {
180 if (value.isString())
181 {
182 ret = detail::make_stvar<STResult>(
183 field, safe_cast<typename STResult::value_type>(beast::lexicalCastThrow<Integer>(value.asString())));
184 }
185 else if (value.isInt())
186 {
187 ret = detail::make_stvar<STResult>(field, to_unsigned<typename STResult::value_type>(value.asInt()));
188 }
189 else if (value.isUInt())
190 {
191 ret = detail::make_stvar<STResult>(field, to_unsigned<typename STResult::value_type>(value.asUInt()));
192 }
193 else
194 {
195 error = bad_type(json_name, fieldName);
196 return ret;
197 }
198 }
199 catch (std::exception const&)
200 {
201 error = invalid_data(json_name, fieldName);
202 return ret;
203 }
204
205 return ret;
206}
207
208template <class STResult, class Integer = std::uint16_t>
211 SField const& field,
212 std::string const& json_name,
213 std::string const& fieldName,
214 SField const* name,
215 Json::Value const& value,
216 Json::Value& error)
217{
219
220 try
221 {
222 if (value.isString())
223 {
224 std::string const strValue = value.asString();
225
226 if (!strValue.empty() && ((strValue[0] < '0') || (strValue[0] > '9')))
227 {
228 if (field == sfTransactionType)
229 {
230 ret = detail::make_stvar<STResult>(
231 field,
232 safe_cast<typename STResult::value_type>(
233 static_cast<Integer>(TxFormats::getInstance().findTypeByName(strValue))));
234
235 if (*name == sfGeneric)
236 name = &sfTransaction;
237 }
238 else if (field == sfLedgerEntryType)
239 {
240 ret = detail::make_stvar<STResult>(
241 field,
242 safe_cast<typename STResult::value_type>(
243 static_cast<Integer>(LedgerFormats::getInstance().findTypeByName(strValue))));
244
245 if (*name == sfGeneric)
246 name = &sfLedgerEntry;
247 }
248 else
249 {
250 error = invalid_data(json_name, fieldName);
251 return ret;
252 }
253 }
254 }
255 if (!ret)
256 return parseUnsigned<STResult, Integer>(field, json_name, fieldName, name, value, error);
257 }
258 catch (std::exception const&)
259 {
260 error = invalid_data(json_name, fieldName);
261 return ret;
262 }
263
264 return ret;
265}
266
267template <class STResult, class Integer = std::uint32_t>
270 SField const& field,
271 std::string const& json_name,
272 std::string const& fieldName,
273 SField const* name,
274 Json::Value const& value,
275 Json::Value& error)
276{
278
279 try
280 {
281 if (value.isString())
282 {
283 if (field == sfPermissionValue)
284 {
285 std::string const strValue = value.asString();
286 auto const granularPermission = Permission::getInstance().getGranularValue(strValue);
287 if (granularPermission)
288 {
289 ret = detail::make_stvar<STResult>(field, *granularPermission);
290 }
291 else
292 {
293 auto const& txType = TxFormats::getInstance().findTypeByName(strValue);
294 ret = detail::make_stvar<STResult>(field, Permission::getInstance().txToPermissionType(txType));
295 }
296 }
297 else
298 {
299 ret = detail::make_stvar<STResult>(
300 field,
301 safe_cast<typename STResult::value_type>(beast::lexicalCastThrow<Integer>(value.asString())));
302 }
303 }
304 if (!ret)
305 return parseUnsigned<STResult, Integer>(field, json_name, fieldName, name, value, error);
306 }
307 catch (std::exception const&)
308 {
309 error = invalid_data(json_name, fieldName);
310 return ret;
311 }
312
313 return ret;
314}
315
316// This function is used by parseObject to parse any JSON type that doesn't
317// recurse. Everything represented here is a leaf-type.
320 std::string const& json_name,
321 std::string const& fieldName,
322 SField const* name,
323 Json::Value const& value,
324 Json::Value& error)
325{
327
328 auto const& field = SField::getField(fieldName);
329
330 // checked in parseObject
331 if (field == sfInvalid)
332 {
333 // LCOV_EXCL_START
334 error = unknown_field(json_name, fieldName);
335 return ret;
336 // LCOV_EXCL_STOP
337 }
338
339 switch (field.fieldType)
340 {
341 case STI_UINT8:
342 try
343 {
344 constexpr auto minValue = std::numeric_limits<std::uint8_t>::min();
345 constexpr auto maxValue = std::numeric_limits<std::uint8_t>::max();
346 if (value.isString())
347 {
348 std::string const strValue = value.asString();
349
350 if (!strValue.empty() && ((strValue[0] < '0') || (strValue[0] > '9')))
351 {
352 if (field == sfTransactionResult)
353 {
354 auto ter = transCode(strValue);
355
356 if (!ter || TERtoInt(*ter) < minValue || TERtoInt(*ter) > maxValue)
357 {
358 error = out_of_range(json_name, fieldName);
359 return ret;
360 }
361
362 ret = detail::make_stvar<STUInt8>(field, static_cast<std::uint8_t>(TERtoInt(*ter)));
363 }
364 else
365 {
366 error = bad_type(json_name, fieldName);
367 return ret;
368 }
369 }
370 else
371 {
372 ret = detail::make_stvar<STUInt8>(field, beast::lexicalCastThrow<std::uint8_t>(strValue));
373 }
374 }
375 else if (value.isInt())
376 {
377 if (value.asInt() < minValue || value.asInt() > maxValue)
378 {
379 error = out_of_range(json_name, fieldName);
380 return ret;
381 }
382
383 ret = detail::make_stvar<STUInt8>(field, static_cast<std::uint8_t>(value.asInt()));
384 }
385 else if (value.isUInt())
386 {
387 if (value.asUInt() > maxValue)
388 {
389 error = out_of_range(json_name, fieldName);
390 return ret;
391 }
392
393 ret = detail::make_stvar<STUInt8>(field, static_cast<std::uint8_t>(value.asUInt()));
394 }
395 else
396 {
397 error = bad_type(json_name, fieldName);
398 return ret;
399 }
400 }
401 catch (std::exception const&)
402 {
403 error = invalid_data(json_name, fieldName);
404 return ret;
405 }
406 break;
407
408 case STI_UINT16:
409 ret = parseUint16<STUInt16>(field, json_name, fieldName, name, value, error);
410 if (!ret)
411 return ret;
412
413 break;
414
415 case STI_UINT32:
416 ret = parseUint32<STUInt32>(field, json_name, fieldName, name, value, error);
417 if (!ret)
418 return ret;
419
420 break;
421
422 case STI_UINT64:
423 try
424 {
425 if (value.isString())
426 {
427 auto const str = value.asString();
428
429 std::uint64_t val;
430
431 bool const useBase10 = field.shouldMeta(SField::sMD_BaseTen);
432
433 // if the field is amount, serialize as base 10
434 auto [p, ec] = std::from_chars(str.data(), str.data() + str.size(), val, useBase10 ? 10 : 16);
435
436 if (ec != std::errc() || (p != str.data() + str.size()))
437 Throw<std::invalid_argument>("invalid data");
438
439 ret = detail::make_stvar<STUInt64>(field, val);
440 }
441 else if (value.isInt())
442 {
443 ret = detail::make_stvar<STUInt64>(field, to_unsigned<std::uint64_t>(value.asInt()));
444 }
445 else if (value.isUInt())
446 {
447 ret = detail::make_stvar<STUInt64>(field, safe_cast<std::uint64_t>(value.asUInt()));
448 }
449 else
450 {
451 error = bad_type(json_name, fieldName);
452 return ret;
453 }
454 }
455 catch (std::exception const&)
456 {
457 error = invalid_data(json_name, fieldName);
458 return ret;
459 }
460
461 break;
462
463 case STI_UINT128: {
464 if (!value.isString())
465 {
466 error = bad_type(json_name, fieldName);
467 return ret;
468 }
469
470 uint128 num;
471
472 if (auto const s = value.asString(); !num.parseHex(s))
473 {
474 if (!s.empty())
475 {
476 error = invalid_data(json_name, fieldName);
477 return ret;
478 }
479
480 num.zero();
481 }
482
483 ret = detail::make_stvar<STUInt128>(field, num);
484 break;
485 }
486
487 case STI_UINT160: {
488 if (!value.isString())
489 {
490 error = bad_type(json_name, fieldName);
491 return ret;
492 }
493
494 uint160 num;
495
496 if (auto const s = value.asString(); !num.parseHex(s))
497 {
498 if (!s.empty())
499 {
500 error = invalid_data(json_name, fieldName);
501 return ret;
502 }
503
504 num.zero();
505 }
506
507 ret = detail::make_stvar<STUInt160>(field, num);
508 break;
509 }
510
511 case STI_UINT192: {
512 if (!value.isString())
513 {
514 error = bad_type(json_name, fieldName);
515 return ret;
516 }
517
518 uint192 num;
519
520 if (auto const s = value.asString(); !num.parseHex(s))
521 {
522 if (!s.empty())
523 {
524 error = invalid_data(json_name, fieldName);
525 return ret;
526 }
527
528 num.zero();
529 }
530
531 ret = detail::make_stvar<STUInt192>(field, num);
532 break;
533 }
534
535 case STI_UINT256: {
536 if (!value.isString())
537 {
538 error = bad_type(json_name, fieldName);
539 return ret;
540 }
541
542 uint256 num;
543
544 if (auto const s = value.asString(); !num.parseHex(s))
545 {
546 if (!s.empty())
547 {
548 error = invalid_data(json_name, fieldName);
549 return ret;
550 }
551
552 num.zero();
553 }
554
555 ret = detail::make_stvar<STUInt256>(field, num);
556 break;
557 }
558
559 case STI_INT32:
560 try
561 {
562 if (value.isString())
563 {
564 ret = detail::make_stvar<STInt32>(field, beast::lexicalCastThrow<std::int32_t>(value.asString()));
565 }
566 else if (value.isInt())
567 {
568 // future-proofing - a static assert failure if the JSON
569 // library ever supports larger ints
570 // In such case, we will need additional bounds checks here
571 static_assert(std::is_same_v<decltype(value.asInt()), std::int32_t>);
572 ret = detail::make_stvar<STInt32>(field, value.asInt());
573 }
574 else if (value.isUInt())
575 {
576 auto const uintValue = value.asUInt();
577 if (uintValue > static_cast<std::uint32_t>(std::numeric_limits<std::int32_t>::max()))
578 {
579 error = out_of_range(json_name, fieldName);
580 return ret;
581 }
582 ret = detail::make_stvar<STInt32>(field, static_cast<std::int32_t>(uintValue));
583 }
584 else
585 {
586 error = bad_type(json_name, fieldName);
587 return ret;
588 }
589 }
590 catch (std::exception const&)
591 {
592 error = invalid_data(json_name, fieldName);
593 return ret;
594 }
595
596 break;
597
598 case STI_VL:
599 if (!value.isString())
600 {
601 error = bad_type(json_name, fieldName);
602 return ret;
603 }
604
605 try
606 {
607 if (auto vBlob = strUnHex(value.asString()))
608 {
609 ret = detail::make_stvar<STBlob>(field, vBlob->data(), vBlob->size());
610 }
611 else
612 {
613 Throw<std::invalid_argument>("invalid data");
614 }
615 }
616 catch (std::exception const&)
617 {
618 error = invalid_data(json_name, fieldName);
619 return ret;
620 }
621
622 break;
623
624 case STI_AMOUNT:
625 try
626 {
627 ret = detail::make_stvar<STAmount>(amountFromJson(field, value));
628 }
629 catch (std::exception const&)
630 {
631 error = invalid_data(json_name, fieldName);
632 return ret;
633 }
634
635 break;
636
637 case STI_NUMBER:
638 try
639 {
640 ret = detail::make_stvar<STNumber>(numberFromJson(field, value));
641 }
642 catch (std::exception const&)
643 {
644 error = invalid_data(json_name, fieldName);
645 return ret;
646 }
647
648 break;
649
650 case STI_VECTOR256:
651 if (!value.isArrayOrNull())
652 {
653 error = array_expected(json_name, fieldName);
654 return ret;
655 }
656
657 try
658 {
659 STVector256 tail(field);
660 for (Json::UInt i = 0; value.isValidIndex(i); ++i)
661 {
662 uint256 s;
663 if (!s.parseHex(value[i].asString()))
664 Throw<std::invalid_argument>("invalid data");
665 tail.push_back(s);
666 }
667 ret = detail::make_stvar<STVector256>(std::move(tail));
668 }
669 catch (std::exception const&)
670 {
671 error = invalid_data(json_name, fieldName);
672 return ret;
673 }
674
675 break;
676
677 case STI_PATHSET:
678 if (!value.isArrayOrNull())
679 {
680 error = array_expected(json_name, fieldName);
681 return ret;
682 }
683
684 try
685 {
686 STPathSet tail(field);
687
688 for (Json::UInt i = 0; value.isValidIndex(i); ++i)
689 {
690 STPath p;
691
692 if (!value[i].isArrayOrNull())
693 {
695 ss << fieldName << "[" << i << "]";
696 error = array_expected(json_name, ss.str());
697 return ret;
698 }
699
700 for (Json::UInt j = 0; value[i].isValidIndex(j); ++j)
701 {
703 ss << fieldName << "[" << i << "][" << j << "]";
704 std::string const element_name(json_name + "." + ss.str());
705
706 // each element in this path has some combination of
707 // account, currency, or issuer
708
709 Json::Value pathEl = value[i][j];
710
711 if (!pathEl.isObject())
712 {
713 error = not_an_object(element_name);
714 return ret;
715 }
716
717 Json::Value const& account = pathEl["account"];
718 Json::Value const& currency = pathEl["currency"];
719 Json::Value const& issuer = pathEl["issuer"];
720 bool hasCurrency = false;
721 AccountID uAccount, uIssuer;
722 Currency uCurrency;
723
724 if (!account && !currency && !issuer)
725 {
726 error = invalid_data(element_name);
727 return ret;
728 }
729
730 if (account)
731 {
732 // human account id
733 if (!account.isString())
734 {
735 error = string_expected(element_name, "account");
736 return ret;
737 }
738
739 // If we have what looks like a 160-bit hex value,
740 // we set it, otherwise, we assume it's an AccountID
741 if (!uAccount.parseHex(account.asString()))
742 {
743 auto const a = parseBase58<AccountID>(account.asString());
744 if (!a)
745 {
746 error = invalid_data(element_name, "account");
747 return ret;
748 }
749 uAccount = *a;
750 }
751 }
752
753 if (currency)
754 {
755 // human currency
756 if (!currency.isString())
757 {
758 error = string_expected(element_name, "currency");
759 return ret;
760 }
761
762 hasCurrency = true;
763
764 if (!uCurrency.parseHex(currency.asString()))
765 {
766 if (!to_currency(uCurrency, currency.asString()))
767 {
768 error = invalid_data(element_name, "currency");
769 return ret;
770 }
771 }
772 }
773
774 if (issuer)
775 {
776 // human account id
777 if (!issuer.isString())
778 {
779 error = string_expected(element_name, "issuer");
780 return ret;
781 }
782
783 if (!uIssuer.parseHex(issuer.asString()))
784 {
785 auto const a = parseBase58<AccountID>(issuer.asString());
786 if (!a)
787 {
788 error = invalid_data(element_name, "issuer");
789 return ret;
790 }
791 uIssuer = *a;
792 }
793 }
794
795 p.emplace_back(uAccount, uCurrency, uIssuer, hasCurrency);
796 }
797
798 tail.push_back(p);
799 }
800 ret = detail::make_stvar<STPathSet>(std::move(tail));
801 }
802 catch (std::exception const&)
803 {
804 error = invalid_data(json_name, fieldName);
805 return ret;
806 }
807
808 break;
809
810 case STI_ACCOUNT: {
811 if (!value.isString())
812 {
813 error = bad_type(json_name, fieldName);
814 return ret;
815 }
816
817 std::string const strValue = value.asString();
818
819 try
820 {
821 if (AccountID account; account.parseHex(strValue))
822 return detail::make_stvar<STAccount>(field, account);
823
824 if (auto result = parseBase58<AccountID>(strValue))
825 return detail::make_stvar<STAccount>(field, *result);
826
827 error = invalid_data(json_name, fieldName);
828 return ret;
829 }
830 catch (std::exception const&)
831 {
832 error = invalid_data(json_name, fieldName);
833 return ret;
834 }
835 }
836 break;
837
838 case STI_ISSUE:
839 try
840 {
841 ret = detail::make_stvar<STIssue>(issueFromJson(field, value));
842 }
843 catch (std::exception const&)
844 {
845 error = invalid_data(json_name, fieldName);
846 return ret;
847 }
848 break;
849
850 case STI_XCHAIN_BRIDGE:
851 try
852 {
853 ret = detail::make_stvar<STXChainBridge>(STXChainBridge(field, value));
854 }
855 catch (std::exception const&)
856 {
857 error = invalid_data(json_name, fieldName);
858 return ret;
859 }
860 break;
861
862 case STI_CURRENCY:
863 try
864 {
865 ret = detail::make_stvar<STCurrency>(currencyFromJson(field, value));
866 }
867 catch (std::exception const&)
868 {
869 error = invalid_data(json_name, fieldName);
870 return ret;
871 }
872 break;
873
874 default:
875 error = bad_type(json_name, fieldName);
876 return ret;
877 }
878
879 return ret;
880}
881
882static int const maxDepth = 64;
883
884// Forward declaration since parseObject() and parseArray() call each other.
886parseArray(std::string const& json_name, Json::Value const& json, SField const& inName, int depth, Json::Value& error);
887
889parseObject(std::string const& json_name, Json::Value const& json, SField const& inName, int depth, Json::Value& error)
890{
891 if (!json.isObjectOrNull())
892 {
893 error = not_an_object(json_name);
894 return std::nullopt;
895 }
896
897 if (depth > maxDepth)
898 {
899 error = too_deep(json_name);
900 return std::nullopt;
901 }
902
903 try
904 {
905 STObject data(inName);
906
907 for (auto const& fieldName : json.getMemberNames())
908 {
909 Json::Value const& value = json[fieldName];
910
911 auto const& field = SField::getField(fieldName);
912
913 if (field == sfInvalid)
914 {
915 error = unknown_field(json_name, fieldName);
916 return std::nullopt;
917 }
918
919 switch (field.fieldType)
920 {
921 // Object-style containers (which recurse).
922 case STI_OBJECT:
923 case STI_TRANSACTION:
924 case STI_LEDGERENTRY:
925 case STI_VALIDATION:
926 if (!value.isObject())
927 {
928 error = not_an_object(json_name, fieldName);
929 return std::nullopt;
930 }
931
932 try
933 {
934 auto ret = parseObject(json_name + "." + fieldName, value, field, depth + 1, error);
935 if (!ret)
936 return std::nullopt;
937 data.emplace_back(std::move(*ret));
938 }
939 catch (std::exception const&)
940 {
941 error = invalid_data(json_name, fieldName);
942 return std::nullopt;
943 }
944
945 break;
946
947 // Array-style containers (which recurse).
948 case STI_ARRAY:
949 try
950 {
951 auto array = parseArray(json_name + "." + fieldName, value, field, depth + 1, error);
952 if (!array.has_value())
953 return std::nullopt;
954 data.emplace_back(std::move(*array));
955 }
956 catch (std::exception const&)
957 {
958 error = invalid_data(json_name, fieldName);
959 return std::nullopt;
960 }
961
962 break;
963
964 // Everything else (types that don't recurse).
965 default: {
966 auto leaf = parseLeaf(json_name, fieldName, &inName, value, error);
967
968 if (!leaf)
969 return std::nullopt;
970
971 data.emplace_back(std::move(*leaf));
972 }
973
974 break;
975 }
976 }
977
978 // Some inner object types have templates. Attempt to apply that.
979 data.applyTemplateFromSField(inName); // May throw
980
981 return data;
982 }
983 catch (STObject::FieldErr const& e)
984 {
985 std::cerr << "template_mismatch: " << e.what() << "\n";
986 error = template_mismatch(inName);
987 }
988 catch (std::exception const&)
989 {
990 error = invalid_data(json_name);
991 }
992 return std::nullopt;
993}
994
996parseArray(std::string const& json_name, Json::Value const& json, SField const& inName, int depth, Json::Value& error)
997{
998 if (!json.isArrayOrNull())
999 {
1000 error = not_an_array(json_name);
1001 return std::nullopt;
1002 }
1003
1004 if (depth > maxDepth)
1005 {
1006 error = too_deep(json_name);
1007 return std::nullopt;
1008 }
1009
1010 try
1011 {
1012 STArray tail(inName);
1013
1014 for (Json::UInt i = 0; json.isValidIndex(i); ++i)
1015 {
1016 bool const isObjectOrNull(json[i].isObjectOrNull());
1017 bool const singleKey(isObjectOrNull ? json[i].size() == 1 : true);
1018
1019 if (!isObjectOrNull || !singleKey)
1020 {
1021 // null values are !singleKey
1022 error = singleton_expected(json_name, i);
1023 return std::nullopt;
1024 }
1025
1026 // TODO: There doesn't seem to be a nice way to get just the
1027 // first/only key in an object without copying all keys into
1028 // a vector
1029 std::string const objectName(json[i].getMemberNames()[0]);
1030 ;
1031 auto const& nameField(SField::getField(objectName));
1032
1033 if (nameField == sfInvalid)
1034 {
1035 error = unknown_field(json_name, objectName);
1036 return std::nullopt;
1037 }
1038
1039 Json::Value const objectFields(json[i][objectName]);
1040
1042 ss << json_name << "." << "[" << i << "]." << objectName;
1043
1044 auto ret = parseObject(ss.str(), objectFields, nameField, depth + 1, error);
1045 if (!ret)
1046 {
1047 std::string errMsg = error["error_message"].asString();
1048 error["error_message"] = "Error at '" + ss.str() + "'. " + errMsg;
1049 return std::nullopt;
1050 }
1051
1052 if (ret->getFName().fieldType != STI_OBJECT)
1053 {
1054 ss << "Field type: " << ret->getFName().fieldType << " ";
1055 error = non_object_in_array(ss.str(), i);
1056 return std::nullopt;
1057 }
1058
1059 tail.push_back(std::move(*ret));
1060 }
1061
1062 return detail::make_stvar<STArray>(std::move(tail));
1063 }
1064 catch (std::exception const&)
1065 {
1066 error = invalid_data(json_name);
1067 return std::nullopt;
1068 }
1069}
1070
1071} // namespace STParsedJSONDetail
1072
1073//------------------------------------------------------------------------------
1074
1076{
1077 using namespace STParsedJSONDetail;
1078 object = parseObject(name, json, sfGeneric, 0, error);
1079}
1080
1081} // namespace xrpl
Represents a JSON value.
Definition json_value.h:131
bool isObjectOrNull() const
Int asInt() const
bool isString() const
UInt asUInt() const
Members getMemberNames() const
Return a list of the member names.
bool isObject() const
bool isValidIndex(UInt index) const
Return true if index < size().
std::string asString() const
Returns the unquoted string value.
bool isUInt() const
bool isArrayOrNull() const
bool isInt() const
KeyType findTypeByName(std::string const &name) const
Retrieve the type for a format specified by name.
static LedgerFormats const & getInstance()
std::optional< std::uint32_t > getGranularValue(std::string const &name) const
static Permission const & getInstance()
Identifies fields.
Definition SField.h:127
static SField const & getField(int fieldCode)
Definition SField.cpp:94
std::string const & getName() const
Definition SField.h:194
void push_back(STObject const &object)
Definition STArray.h:188
Json::Value error
On failure, an appropriate set of error values.
void push_back(STPath const &e)
Definition STPathSet.h:474
void emplace_back(Args &&... args)
Definition STPathSet.h:377
void push_back(uint256 const &v)
static TxFormats const & getInstance()
Definition TxFormats.cpp:51
Integers of any length that is a multiple of 32-bits.
Definition base_uint.h:67
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:472
T empty(T... args)
T from_chars(T... args)
T is_same_v
T max(T... args)
T min(T... args)
unsigned int 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.
Definition algorithm.h:6
STCurrency currencyFromJson(SField const &name, Json::Value const &v)
STAmount amountFromJson(SField const &name, Json::Value const &v)
Definition STAmount.cpp:948
SField const sfGeneric
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Issue issueFromJson(Json::Value const &v)
Definition Issue.cpp:82
constexpr TERUnderlyingType TERtoInt(TELcodes v)
Definition TER.h:356
SField const sfInvalid
STNumber numberFromJson(SField const &field, Json::Value const &value)
Definition STNumber.cpp:205
std::optional< TER > transCode(std::string const &token)
Definition TER.cpp:261
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
Definition UintTypes.cpp:62
@ rpcINVALID_PARAMS
Definition ErrorCodes.h:65
T str(T... args)
T to_string(T... args)
T what(T... args)