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