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