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_UINT192: {
567 if (!value.isString())
568 {
569 error = bad_type(json_name, fieldName);
570 return ret;
571 }
572
573 uint192 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<STUInt192>(field, num);
587 break;
588 }
589
590 case STI_UINT160: {
591 if (!value.isString())
592 {
593 error = bad_type(json_name, fieldName);
594 return ret;
595 }
596
597 uint160 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<STUInt160>(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_VL:
639 if (!value.isString())
640 {
641 error = bad_type(json_name, fieldName);
642 return ret;
643 }
644
645 try
646 {
647 if (auto vBlob = strUnHex(value.asString()))
648 {
649 ret = detail::make_stvar<STBlob>(
650 field, vBlob->data(), vBlob->size());
651 }
652 else
653 {
654 Throw<std::invalid_argument>("invalid data");
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_AMOUNT:
666 try
667 {
668 ret =
669 detail::make_stvar<STAmount>(amountFromJson(field, value));
670 }
671 catch (std::exception const&)
672 {
673 error = invalid_data(json_name, fieldName);
674 return ret;
675 }
676
677 break;
678
679 case STI_NUMBER:
680 try
681 {
682 ret =
683 detail::make_stvar<STNumber>(numberFromJson(field, value));
684 }
685 catch (std::exception const&)
686 {
687 error = invalid_data(json_name, fieldName);
688 return ret;
689 }
690
691 break;
692
693 case STI_VECTOR256:
694 if (!value.isArrayOrNull())
695 {
696 error = array_expected(json_name, fieldName);
697 return ret;
698 }
699
700 try
701 {
702 STVector256 tail(field);
703 for (Json::UInt i = 0; value.isValidIndex(i); ++i)
704 {
705 uint256 s;
706 if (!s.parseHex(value[i].asString()))
707 Throw<std::invalid_argument>("invalid data");
708 tail.push_back(s);
709 }
710 ret = detail::make_stvar<STVector256>(std::move(tail));
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_PATHSET:
721 if (!value.isArrayOrNull())
722 {
723 error = array_expected(json_name, fieldName);
724 return ret;
725 }
726
727 try
728 {
729 STPathSet tail(field);
730
731 for (Json::UInt i = 0; value.isValidIndex(i); ++i)
732 {
733 STPath p;
734
735 if (!value[i].isArrayOrNull())
736 {
738 ss << fieldName << "[" << i << "]";
739 error = array_expected(json_name, ss.str());
740 return ret;
741 }
742
743 for (Json::UInt j = 0; value[i].isValidIndex(j); ++j)
744 {
746 ss << fieldName << "[" << i << "][" << j << "]";
747 std::string const element_name(
748 json_name + "." + ss.str());
749
750 // each element in this path has some combination of
751 // account, currency, or issuer
752
753 Json::Value pathEl = value[i][j];
754
755 if (!pathEl.isObject())
756 {
757 error = not_an_object(element_name);
758 return ret;
759 }
760
761 Json::Value const& account = pathEl["account"];
762 Json::Value const& currency = pathEl["currency"];
763 Json::Value const& issuer = pathEl["issuer"];
764 bool hasCurrency = false;
765 AccountID uAccount, uIssuer;
766 Currency uCurrency;
767
768 if (!account && !currency && !issuer)
769 {
770 error = invalid_data(element_name);
771 return ret;
772 }
773
774 if (account)
775 {
776 // human account id
777 if (!account.isString())
778 {
779 error =
780 string_expected(element_name, "account");
781 return ret;
782 }
783
784 // If we have what looks like a 160-bit hex value,
785 // we set it, otherwise, we assume it's an AccountID
786 if (!uAccount.parseHex(account.asString()))
787 {
788 auto const a =
789 parseBase58<AccountID>(account.asString());
790 if (!a)
791 {
792 error =
793 invalid_data(element_name, "account");
794 return ret;
795 }
796 uAccount = *a;
797 }
798 }
799
800 if (currency)
801 {
802 // human currency
803 if (!currency.isString())
804 {
805 error =
806 string_expected(element_name, "currency");
807 return ret;
808 }
809
810 hasCurrency = true;
811
812 if (!uCurrency.parseHex(currency.asString()))
813 {
814 if (!to_currency(
815 uCurrency, currency.asString()))
816 {
817 error =
818 invalid_data(element_name, "currency");
819 return ret;
820 }
821 }
822 }
823
824 if (issuer)
825 {
826 // human account id
827 if (!issuer.isString())
828 {
829 error = string_expected(element_name, "issuer");
830 return ret;
831 }
832
833 if (!uIssuer.parseHex(issuer.asString()))
834 {
835 auto const a =
836 parseBase58<AccountID>(issuer.asString());
837 if (!a)
838 {
839 error =
840 invalid_data(element_name, "issuer");
841 return ret;
842 }
843 uIssuer = *a;
844 }
845 }
846
847 p.emplace_back(
848 uAccount, uCurrency, uIssuer, hasCurrency);
849 }
850
851 tail.push_back(p);
852 }
853 ret = detail::make_stvar<STPathSet>(std::move(tail));
854 }
855 catch (std::exception const&)
856 {
857 error = invalid_data(json_name, fieldName);
858 return ret;
859 }
860
861 break;
862
863 case STI_ACCOUNT: {
864 if (!value.isString())
865 {
866 error = bad_type(json_name, fieldName);
867 return ret;
868 }
869
870 std::string const strValue = value.asString();
871
872 try
873 {
874 if (AccountID account; account.parseHex(strValue))
875 return detail::make_stvar<STAccount>(field, account);
876
877 if (auto result = parseBase58<AccountID>(strValue))
878 return detail::make_stvar<STAccount>(field, *result);
879
880 error = invalid_data(json_name, fieldName);
881 return ret;
882 }
883 catch (std::exception const&)
884 {
885 error = invalid_data(json_name, fieldName);
886 return ret;
887 }
888 }
889 break;
890
891 case STI_ISSUE:
892 try
893 {
894 ret = detail::make_stvar<STIssue>(issueFromJson(field, value));
895 }
896 catch (std::exception const&)
897 {
898 error = invalid_data(json_name, fieldName);
899 return ret;
900 }
901 break;
902
903 case STI_XCHAIN_BRIDGE:
904 try
905 {
906 ret = detail::make_stvar<STXChainBridge>(
907 STXChainBridge(field, value));
908 }
909 catch (std::exception const&)
910 {
911 error = invalid_data(json_name, fieldName);
912 return ret;
913 }
914 break;
915
916 case STI_CURRENCY:
917 try
918 {
919 ret = detail::make_stvar<STCurrency>(
920 currencyFromJson(field, value));
921 }
922 catch (std::exception const&)
923 {
924 error = invalid_data(json_name, fieldName);
925 return ret;
926 }
927 break;
928
929 default:
930 error = bad_type(json_name, fieldName);
931 return ret;
932 }
933
934 return ret;
935}
936
937static int const maxDepth = 64;
938
939// Forward declaration since parseObject() and parseArray() call each other.
942 std::string const& json_name,
943 Json::Value const& json,
944 SField const& inName,
945 int depth,
946 Json::Value& error);
947
950 std::string const& json_name,
951 Json::Value const& json,
952 SField const& inName,
953 int depth,
954 Json::Value& error)
955{
956 if (!json.isObjectOrNull())
957 {
958 error = not_an_object(json_name);
959 return std::nullopt;
960 }
961
962 if (depth > maxDepth)
963 {
964 error = too_deep(json_name);
965 return std::nullopt;
966 }
967
968 try
969 {
970 STObject data(inName);
971
972 for (auto const& fieldName : json.getMemberNames())
973 {
974 Json::Value const& value = json[fieldName];
975
976 auto const& field = SField::getField(fieldName);
977
978 if (field == sfInvalid)
979 {
980 error = unknown_field(json_name, fieldName);
981 return std::nullopt;
982 }
983
984 switch (field.fieldType)
985 {
986 // Object-style containers (which recurse).
987 case STI_OBJECT:
988 case STI_TRANSACTION:
989 case STI_LEDGERENTRY:
990 case STI_VALIDATION:
991 if (!value.isObject())
992 {
993 error = not_an_object(json_name, fieldName);
994 return std::nullopt;
995 }
996
997 try
998 {
999 auto ret = parseObject(
1000 json_name + "." + fieldName,
1001 value,
1002 field,
1003 depth + 1,
1004 error);
1005 if (!ret)
1006 return std::nullopt;
1007 data.emplace_back(std::move(*ret));
1008 }
1009 catch (std::exception const&)
1010 {
1011 error = invalid_data(json_name, fieldName);
1012 return std::nullopt;
1013 }
1014
1015 break;
1016
1017 // Array-style containers (which recurse).
1018 case STI_ARRAY:
1019 try
1020 {
1021 auto array = parseArray(
1022 json_name + "." + fieldName,
1023 value,
1024 field,
1025 depth + 1,
1026 error);
1027 if (!array.has_value())
1028 return std::nullopt;
1029 data.emplace_back(std::move(*array));
1030 }
1031 catch (std::exception const&)
1032 {
1033 error = invalid_data(json_name, fieldName);
1034 return std::nullopt;
1035 }
1036
1037 break;
1038
1039 // Everything else (types that don't recurse).
1040 default: {
1041 auto leaf =
1042 parseLeaf(json_name, fieldName, &inName, value, error);
1043
1044 if (!leaf)
1045 return std::nullopt;
1046
1047 data.emplace_back(std::move(*leaf));
1048 }
1049
1050 break;
1051 }
1052 }
1053
1054 // Some inner object types have templates. Attempt to apply that.
1055 data.applyTemplateFromSField(inName); // May throw
1056
1057 return data;
1058 }
1059 catch (STObject::FieldErr const& e)
1060 {
1061 std::cerr << "template_mismatch: " << e.what() << "\n";
1062 error = template_mismatch(inName);
1063 }
1064 catch (std::exception const&)
1065 {
1066 error = invalid_data(json_name);
1067 }
1068 return std::nullopt;
1069}
1070
1073 std::string const& json_name,
1074 Json::Value const& json,
1075 SField const& inName,
1076 int depth,
1077 Json::Value& error)
1078{
1079 if (!json.isArrayOrNull())
1080 {
1081 error = not_an_array(json_name);
1082 return std::nullopt;
1083 }
1084
1085 if (depth > maxDepth)
1086 {
1087 error = too_deep(json_name);
1088 return std::nullopt;
1089 }
1090
1091 try
1092 {
1093 STArray tail(inName);
1094
1095 for (Json::UInt i = 0; json.isValidIndex(i); ++i)
1096 {
1097 bool const isObjectOrNull(json[i].isObjectOrNull());
1098 bool const singleKey(isObjectOrNull ? json[i].size() == 1 : true);
1099
1100 if (!isObjectOrNull || !singleKey)
1101 {
1102 // null values are !singleKey
1103 error = singleton_expected(json_name, i);
1104 return std::nullopt;
1105 }
1106
1107 // TODO: There doesn't seem to be a nice way to get just the
1108 // first/only key in an object without copying all keys into
1109 // a vector
1110 std::string const objectName(json[i].getMemberNames()[0]);
1111 ;
1112 auto const& nameField(SField::getField(objectName));
1113
1114 if (nameField == sfInvalid)
1115 {
1116 error = unknown_field(json_name, objectName);
1117 return std::nullopt;
1118 }
1119
1120 Json::Value const objectFields(json[i][objectName]);
1121
1123 ss << json_name << "."
1124 << "[" << i << "]." << objectName;
1125
1126 auto ret = parseObject(
1127 ss.str(), objectFields, nameField, depth + 1, error);
1128 if (!ret)
1129 {
1130 std::string errMsg = error["error_message"].asString();
1131 error["error_message"] =
1132 "Error at '" + ss.str() + "'. " + errMsg;
1133 return std::nullopt;
1134 }
1135
1136 if (ret->getFName().fieldType != STI_OBJECT)
1137 {
1138 ss << "Field type: " << ret->getFName().fieldType << " ";
1139 error = non_object_in_array(ss.str(), i);
1140 return std::nullopt;
1141 }
1142
1143 tail.push_back(std::move(*ret));
1144 }
1145
1146 return detail::make_stvar<STArray>(std::move(tail));
1147 }
1148 catch (std::exception const&)
1149 {
1150 error = invalid_data(json_name);
1151 return std::nullopt;
1152 }
1153}
1154
1155} // namespace STParsedJSONDetail
1156
1157//------------------------------------------------------------------------------
1158
1160 std::string const& name,
1161 Json::Value const& json)
1162{
1163 using namespace STParsedJSONDetail;
1164 object = parseObject(name, json, sfGeneric, 0, error);
1165}
1166
1167} // 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:144
std::string const & getName() const
Definition SField.h:209
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:371
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)