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