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