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