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