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