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