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