Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14864706
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
96 KB
Subscribers
None
View Options
diff --git a/.arclint b/.arclint
index ac8dfb101..5043fbd8c 100644
--- a/.arclint
+++ b/.arclint
@@ -1,322 +1,322 @@
{
"linters": {
"generated": {
"type": "generated"
},
"clang-format": {
"type": "clang-format",
"version": ">=12.0",
"bin": [
"clang-format-12",
"clang-format"
],
"include": "(^(src|chronik)/.*\\.(h|c|cpp|mm)$)",
"exclude": [
- "(^src/(secp256k1|univalue|leveldb)/)",
+ "(^src/(secp256k1|leveldb)/)",
"(^src/bench/nanobench.h$)"
]
},
"black": {
"type": "black",
"version": ">=24.0.0",
"include": [
"(\\.py$)",
"(^electrum/electrum-abc$)"
],
"exclude": [
"(^contrib/apple-sdk-tools/)",
"(^electrum/electrumabc_gui/qt/icons.py)",
"(\\_pb2.py$)"
]
},
"flake8": {
"type": "flake8",
"version": ">=5.0",
"include": [
"(\\.py$)",
"(^electrum/electrum-abc$)"
],
"exclude": [
"(^contrib/apple-sdk-tools/)",
"(^electrum/electrumabc_gui/qt/icons.py)",
"(\\_pb2.py$)"
],
"flags": [
"--ignore=A003,E203,E303,E305,E501,E704,W503,W504",
"--require-plugins=flake8-comprehensions,flake8-builtins"
]
},
"lint-format-strings": {
"type": "lint-format-strings",
"include": "(^(src|chronik)/.*\\.(h|c|cpp)$)",
"exclude": [
"(^src/(secp256k1|leveldb)/)",
"(^src/bench/nanobench.h$)",
"(^src/test/fuzz/strprintf.cpp$)"
]
},
"check-doc": {
"type": "check-doc",
"include": "(^(src|chronik)/.*\\.(h|c|cpp)$)"
},
"lint-tests": {
"type": "lint-tests",
"include": "(^src/(seeder/|rpc/|wallet/)?test/.*\\.(cpp)$)"
},
"phpcs": {
"type": "phpcs",
"include": "(\\.php$)",
"exclude": [
"(^arcanist/__phutil_library_.+\\.php$)"
],
"phpcs.standard": "arcanist/phpcs.xml"
},
"lint-locale-dependence": {
"type": "lint-locale-dependence",
"include": "(^(src|chronik)/.*\\.(h|cpp)$)",
"exclude": [
"(^src/(crypto/ctaes/|leveldb/|secp256k1/|tinyformat.h))",
"(^src/bench/nanobench.h$)"
]
},
"lint-cheader": {
"type": "lint-cheader",
"include": "(^(src|chronik)/.*\\.(h|cpp)$)",
"exclude": [
"(^src/(crypto/ctaes|secp256k1|leveldb)/)",
"(^src/bench/nanobench.h$)"
]
},
"spelling": {
"type": "spelling",
"exclude": [
"(^build-aux/m4/)",
"(^depends/)",
"(^doc/release-notes/)",
"(^src/(qt/locale|secp256k1|leveldb)/)",
"(^test/lint/dictionary/)",
"(^web/e.cash/public/animations/)",
"(package-lock.json)",
"(^electrum/electrumabc/wordlist/)"
],
"spelling.dictionaries": [
"test/lint/dictionary/english.json"
]
},
"lint-assert-with-side-effects": {
"type": "lint-assert-with-side-effects",
"include": "(^(src|chronik)/.*\\.(h|cpp)$)",
"exclude": [
"(^src/(secp256k1|leveldb)/)",
"(^src/bench/nanobench.h$)"
]
},
"lint-include-quotes": {
"type": "lint-include-quotes",
"include": "(^(src|chronik)/.*\\.(h|cpp)$)",
"exclude": [
"(^src/(secp256k1|leveldb)/)",
"(^src/bench/nanobench.h$)"
]
},
"lint-include-guard": {
"type": "lint-include-guard",
"include": "(^(src|chronik)/.*\\.h$)",
"exclude": [
"(^src/(crypto/ctaes|secp256k1|leveldb)/)",
"(^src/bench/nanobench.h$)",
"(^src/tinyformat.h$)"
]
},
"lint-include-source": {
"type": "lint-include-source",
"include": "(^(src|chronik)/.*\\.(h|c|cpp)$)",
"exclude": [
"(^src/(secp256k1|leveldb)/)",
"(^src/bench/nanobench.h$)"
]
},
"lint-std-chrono": {
"type": "lint-std-chrono",
"include": "(^(src|chronik)/.*\\.(h|cpp)$)"
},
"lint-stdint": {
"type": "lint-stdint",
"include": "(^(src|chronik)/.*\\.(h|c|cpp)$)",
"exclude": [
"(^src/(secp256k1|leveldb)/)",
"(^src/bench/nanobench.h$)",
"(^src/compat/assumptions.h$)"
]
},
"check-files": {
"type": "check-files"
},
"lint-boost-dependencies": {
"type": "lint-boost-dependencies",
"include": "(^(src|chronik)/.*\\.(h|cpp)$)"
},
"lint-python-encoding": {
"type": "lint-python-encoding",
"include": "(\\.py$)",
"exclude": [
"(^contrib/apple-sdk-tools/)"
]
},
"shellcheck": {
"type": "shellcheck",
"version": ">=0.7.0",
"flags": [
"--external-sources",
"--source-path=SCRIPTDIR"
],
"include": "(\\.(sh|bash)$)",
"exclude": [
"(^src/(secp256k1)/)",
"(^electrum/)"
]
},
"lint-shell-locale": {
"type": "lint-shell-locale",
"include": "(\\.(sh|bash)$)",
"exclude": [
"(^src/(secp256k1)/)",
"(^cmake/utils/log-and-print-on-failure.sh)"
]
},
"lint-cpp-void-parameters": {
"type": "lint-cpp-void-parameters",
"include": "(^(src|chronik)/.*\\.(h|cpp)$)",
"exclude": [
"(^src/(crypto/ctaes|secp256k1|leveldb)/)",
"(^src/bench/nanobench.h$)",
"(^src/compat/glibc_compat.cpp$)"
]
},
"lint-logs": {
"type": "lint-logs",
"include": "(^(src|chronik)/.*\\.(h|cpp|rs)$)"
},
"lint-qt": {
"type": "lint-qt",
"include": "(^src/qt/.*\\.(h|cpp)$)",
"exclude": [
"(^src/qt/(locale|forms|res)/)"
]
},
"lint-doxygen": {
"type": "lint-doxygen",
"include": "(^(src|chronik)/.*\\.(h|c|cpp)$)",
"exclude": [
"(^src/(crypto/ctaes|secp256k1|leveldb)/)",
"(^src/bench/nanobench.h$)"
]
},
"lint-whitespace": {
"type": "lint-whitespace",
"include": "(\\.(ac|am|cmake|conf|in|include|json|m4|md|openrc|php|pl|rs|sh|txt|yml)$)",
"exclude": [
"(^src/(secp256k1|leveldb)/)",
"(^src/bench/nanobench.h$)"
]
},
"yamllint": {
"type": "yamllint",
"include": "(\\.(yml|yaml)$)",
"exclude": "(^src/(secp256k1|leveldb)/)"
},
"lint-check-nonfatal": {
"type": "lint-check-nonfatal",
"include": [
"(^src/rpc/.*\\.(h|c|cpp)$)",
"(^src/wallet/rpc*.*\\.(h|c|cpp)$)"
],
"exclude": "(^src/rpc/server.cpp)"
},
"lint-markdown": {
"type": "lint-markdown",
"include": [
"(\\.md$)"
],
"exclude": [
"(^modules/docs/chronik.e.cash/)"
]
},
"lint-python-mypy": {
"type": "lint-python-mypy",
"version": ">=0.910",
"include": "(\\.py$)",
"exclude": [
"(^contrib/apple-sdk-tools/)",
"(^contrib/macdeploy/)",
"(^electrum/)"
],
"flags": [
"--ignore-missing-imports",
"--install-types",
"--non-interactive"
]
},
"lint-python-mutable-default": {
"type": "lint-python-mutable-default",
"include": "(\\.py$)",
"exclude": [
"(^contrib/apple-sdk-tools/)"
]
},
"prettier": {
"type": "prettier",
"version": ">=2.6.0",
"include": [
"(^apps/.*\\.(css|html|js|json|jsx|md|scss|ts|tsx)$)",
"(^doc/standards/.*\\.(css|html|js|json|jsx|md|scss|ts|tsx)$)",
"(^cashtab/.*\\.(css|html|js|json|jsx|md|scss|ts|tsx)$)",
"(^modules/.*\\.(css|html|js|json|jsx|md|scss|ts|tsx)$)",
"(^web/.*\\.(css|html|js|json|jsx|md|scss|ts|tsx)$)"
],
"exclude": [
"(^web/.*/translations/.*\\.json$)",
"(^web/e.cash/public/animations/)"
]
},
"lint-python-isort": {
"type": "lint-python-isort",
"version": ">=5.6.4",
"include": [
"(\\.py$)",
"(^electrum/electrum-abc$)"
],
"exclude": [
"(^contrib/apple-sdk-tools/)",
"(^electrum/electrumabc_gui/qt/icons.py)",
"(\\_pb2.py$)"
]
},
"rustfmt": {
"type": "rustfmt",
"version": ">=1.5.1",
"include": "(\\.rs$)"
},
"eslint": {
"type": "eslint",
"version": ">=8.0.0",
"include": [
"(cashtab/.*\\.js$)",
"(apps/alias-server/.*\\.js$)",
"(modules/ecashaddrjs/.*\\.js$)",
"(apps/ecash-herald/.*\\.js$)",
"(modules/chronik-client/.*\\.(js|jsx|ts|tsx)$)",
"(^web/e.cash/.*\\.js$)"
]
},
"lint-python-flynt": {
"type": "lint-python-flynt",
"version": ">=0.78",
"include": "(\\.py$)",
"exclude": [
"(^contrib/apple-sdk-tools/)",
"(^electrum/)"
]
}
}
}
diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h
index 14d48d8e1..1fe46d6af 100644
--- a/src/univalue/include/univalue.h
+++ b/src/univalue/include/univalue.h
@@ -1,218 +1,224 @@
// Copyright 2014 BitPay Inc.
// Copyright 2015 Bitcoin Core Developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H
#define BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H
#include <charconv>
#include <cstddef>
#include <cstdint>
#include <map>
#include <stdexcept>
#include <string>
#include <string_view>
#include <system_error>
#include <type_traits>
#include <utility>
#include <vector>
namespace {
- struct UniValueStreamWriter;
+struct UniValueStreamWriter;
}
class UniValue {
friend struct ::UniValueStreamWriter;
public:
- enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
+ enum VType {
+ VNULL,
+ VOBJ,
+ VARR,
+ VSTR,
+ VNUM,
+ VBOOL,
+ };
- class type_error : public std::runtime_error
- {
+ class type_error : public std::runtime_error {
using std::runtime_error::runtime_error;
};
UniValue() : typ(VNULL) {}
- UniValue(UniValue::VType type, std::string str = {}) : typ(type), val(std::move(str)) {}
- template <typename Ref, typename T = std::remove_cv_t<std::remove_reference_t<Ref>>,
- std::enable_if_t<std::is_floating_point_v<T> || // setFloat
- std::is_same_v<bool, T> || // setBool
- std::is_signed_v<T> || std::is_unsigned_v<T> || // setInt
- std::is_constructible_v<std::string, T>, // setStr
- bool> = true>
- UniValue(Ref&& val)
- {
+ UniValue(UniValue::VType type, std::string str = {})
+ : typ(type), val(std::move(str)) {}
+ template <typename Ref,
+ typename T = std::remove_cv_t<std::remove_reference_t<Ref>>,
+ std::enable_if_t<
+ std::is_floating_point_v<T> || // setFloat
+ std::is_same_v<bool, T> || // setBool
+ std::is_signed_v<T> || std::is_unsigned_v<T> || // setInt
+ std::is_constructible_v<std::string, T>, // setStr
+ bool> = true>
+ UniValue(Ref &&val) {
if constexpr (std::is_floating_point_v<T>) {
setFloat(val);
} else if constexpr (std::is_same_v<bool, T>) {
setBool(val);
} else if constexpr (std::is_signed_v<T>) {
setInt(int64_t{val});
} else if constexpr (std::is_unsigned_v<T>) {
setInt(uint64_t{val});
} else {
setStr(std::string{std::forward<Ref>(val)});
}
}
void clear();
void reserve(size_t n) {
if (typ == VOBJ || typ == VARR) {
- if (typ == VOBJ)
- keys.reserve(n);
+ if (typ == VOBJ) keys.reserve(n);
values.reserve(n);
} else if (typ != VNULL) {
val.reserve(n);
}
}
void setNull();
void setBool(bool val);
void setNumStr(std::string str);
void setInt(uint64_t val);
void setInt(int64_t val);
void setInt(int val_) { return setInt(int64_t{val_}); }
void setFloat(double val);
void setStr(std::string str);
void setArray();
void setObject();
enum VType getType() const { return typ; }
- const std::string& getValStr() const { return val; }
+ const std::string &getValStr() const { return val; }
bool empty() const { return (values.size() == 0); }
size_t size() const { return values.size(); }
- void getObjMap(std::map<std::string,UniValue>& kv) const;
- bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes) const;
- const UniValue& operator[](const std::string& key) const;
- const UniValue& operator[](size_t index) const;
- bool exists(const std::string& key) const { size_t i; return findKey(key, i); }
+ void getObjMap(std::map<std::string, UniValue> &kv) const;
+ bool checkObject(
+ const std::map<std::string, UniValue::VType> &memberTypes) const;
+ const UniValue &operator[](const std::string &key) const;
+ const UniValue &operator[](size_t index) const;
+ bool exists(const std::string &key) const {
+ size_t i;
+ return findKey(key, i);
+ }
bool isNull() const { return (typ == VNULL); }
bool isTrue() const { return (typ == VBOOL) && (val == "1"); }
bool isFalse() const { return (typ == VBOOL) && (val != "1"); }
bool isBool() const { return (typ == VBOOL); }
bool isStr() const { return (typ == VSTR); }
bool isNum() const { return (typ == VNUM); }
bool isArray() const { return (typ == VARR); }
bool isObject() const { return (typ == VOBJ); }
void push_back(UniValue val);
- void push_backV(const std::vector<UniValue>& vec);
- template <class It>
- void push_backV(It first, It last);
+ void push_backV(const std::vector<UniValue> &vec);
+ template <class It> void push_backV(It first, It last);
void pushKVEnd(std::string key, UniValue val);
void pushKV(std::string key, UniValue val);
void pushKVs(UniValue obj);
std::string write(unsigned int prettyIndent = 0,
unsigned int indentLevel = 0) const;
bool read(std::string_view raw);
private:
UniValue::VType typ;
- std::string val; // numbers are stored as C++ strings
+ std::string val; // numbers are stored as C++ strings
std::vector<std::string> keys;
std::vector<UniValue> values;
- void checkType(const VType& expected) const;
- bool findKey(const std::string& key, size_t& retIdx) const;
+ void checkType(const VType &expected) const;
+ bool findKey(const std::string &key, size_t &retIdx) const;
public:
// Strict type-specific getters, these throw std::runtime_error if the
// value is of unexpected type
- const std::vector<std::string>& getKeys() const;
- const std::vector<UniValue>& getValues() const;
- template <typename Int>
- Int getInt() const;
+ const std::vector<std::string> &getKeys() const;
+ const std::vector<UniValue> &getValues() const;
+ template <typename Int> Int getInt() const;
bool get_bool() const;
- const std::string& get_str() const;
+ const std::string &get_str() const;
double get_real() const;
- const UniValue& get_obj() const;
- const UniValue& get_array() const;
+ const UniValue &get_obj() const;
+ const UniValue &get_array() const;
enum VType type() const { return getType(); }
- const UniValue& find_value(std::string_view key) const;
+ const UniValue &find_value(std::string_view key) const;
};
-template <class It>
-void UniValue::push_backV(It first, It last)
-{
+template <class It> void UniValue::push_backV(It first, It last) {
checkType(VARR);
values.insert(values.end(), first, last);
}
-template <typename Int>
-Int UniValue::getInt() const
-{
+template <typename Int> Int UniValue::getInt() const {
static_assert(std::is_integral<Int>::value);
checkType(VNUM);
Int result;
- const auto [first_nonmatching, error_condition] = std::from_chars(val.data(), val.data() + val.size(), result);
- if (first_nonmatching != val.data() + val.size() || error_condition != std::errc{}) {
+ const auto [first_nonmatching, error_condition] =
+ std::from_chars(val.data(), val.data() + val.size(), result);
+ if (first_nonmatching != val.data() + val.size() ||
+ error_condition != std::errc{}) {
throw std::runtime_error("JSON integer out of range");
}
return result;
}
enum jtokentype {
- JTOK_ERR = -1,
- JTOK_NONE = 0, // eof
+ JTOK_ERR = -1,
+ JTOK_NONE = 0, // eof
JTOK_OBJ_OPEN,
JTOK_OBJ_CLOSE,
JTOK_ARR_OPEN,
JTOK_ARR_CLOSE,
JTOK_COLON,
JTOK_COMMA,
JTOK_KW_NULL,
JTOK_KW_TRUE,
JTOK_KW_FALSE,
JTOK_NUMBER,
JTOK_STRING,
};
-extern enum jtokentype getJsonToken(std::string& tokenVal,
- unsigned int& consumed, const char *raw, const char *end);
+extern enum jtokentype getJsonToken(std::string &tokenVal,
+ unsigned int &consumed, const char *raw,
+ const char *end);
extern const char *uvTypeName(UniValue::VType t);
-static inline bool jsonTokenIsValue(enum jtokentype jtt)
-{
+static inline bool jsonTokenIsValue(enum jtokentype jtt) {
switch (jtt) {
- case JTOK_KW_NULL:
- case JTOK_KW_TRUE:
- case JTOK_KW_FALSE:
- case JTOK_NUMBER:
- case JTOK_STRING:
- return true;
-
- default:
- return false;
+ case JTOK_KW_NULL:
+ case JTOK_KW_TRUE:
+ case JTOK_KW_FALSE:
+ case JTOK_NUMBER:
+ case JTOK_STRING:
+ return true;
+
+ default:
+ return false;
}
// not reached
}
-static inline bool json_isspace(int ch)
-{
+static inline bool json_isspace(int ch) {
switch (ch) {
- case 0x20:
- case 0x09:
- case 0x0a:
- case 0x0d:
- return true;
-
- default:
- return false;
+ case 0x20:
+ case 0x09:
+ case 0x0a:
+ case 0x0d:
+ return true;
+
+ default:
+ return false;
}
// not reached
}
extern const UniValue NullUniValue;
#endif // BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H
diff --git a/src/univalue/include/univalue_escapes.h b/src/univalue/include/univalue_escapes.h
index 83767e8ac..c3f9605a8 100644
--- a/src/univalue/include/univalue_escapes.h
+++ b/src/univalue/include/univalue_escapes.h
@@ -1,261 +1,42 @@
#ifndef BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_ESCAPES_H
#define BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_ESCAPES_H
static const char *escapes[256] = {
- "\\u0000",
- "\\u0001",
- "\\u0002",
- "\\u0003",
- "\\u0004",
- "\\u0005",
- "\\u0006",
- "\\u0007",
- "\\b",
- "\\t",
- "\\n",
- "\\u000b",
- "\\f",
- "\\r",
- "\\u000e",
- "\\u000f",
- "\\u0010",
- "\\u0011",
- "\\u0012",
- "\\u0013",
- "\\u0014",
- "\\u0015",
- "\\u0016",
- "\\u0017",
- "\\u0018",
- "\\u0019",
- "\\u001a",
- "\\u001b",
- "\\u001c",
- "\\u001d",
- "\\u001e",
- "\\u001f",
- nullptr,
- nullptr,
- "\\\"",
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- "\\\\",
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- "\\u007f",
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
+ "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006",
+ "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r",
+ "\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014",
+ "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", "\\u001b",
+ "\\u001c", "\\u001d", "\\u001e", "\\u001f", nullptr, nullptr, "\\\"",
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, "\\\\", nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, "\\u007f", nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr,
};
#endif // BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_ESCAPES_H
diff --git a/src/univalue/include/univalue_utffilter.h b/src/univalue/include/univalue_utffilter.h
index f688eaaa3..37154dc7c 100644
--- a/src/univalue/include/univalue_utffilter.h
+++ b/src/univalue/include/univalue_utffilter.h
@@ -1,119 +1,115 @@
// Copyright 2016 Wladimir J. van der Laan
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_UTFFILTER_H
#define BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_UTFFILTER_H
#include <string>
/**
* Filter that generates and validates UTF-8, as well as collates UTF-16
* surrogate pairs as specified in RFC4627.
*/
-class JSONUTF8StringFilter
-{
+class JSONUTF8StringFilter {
public:
- explicit JSONUTF8StringFilter(std::string &s):
- str(s), is_valid(true), codepoint(0), state(0), surpair(0)
- {
- }
+ explicit JSONUTF8StringFilter(std::string &s)
+ : str(s), is_valid(true), codepoint(0), state(0), surpair(0) {}
// Write single 8-bit char (may be part of UTF-8 sequence)
- void push_back(unsigned char ch)
- {
+ void push_back(uint8_t ch) {
if (state == 0) {
if (ch < 0x80) // 7-bit ASCII, fast direct pass-through
str.push_back(ch);
else if (ch < 0xc0) // Mid-sequence character, invalid in this state
is_valid = false;
else if (ch < 0xe0) { // Start of 2-byte sequence
codepoint = (ch & 0x1f) << 6;
state = 6;
} else if (ch < 0xf0) { // Start of 3-byte sequence
codepoint = (ch & 0x0f) << 12;
state = 12;
} else if (ch < 0xf8) { // Start of 4-byte sequence
codepoint = (ch & 0x07) << 18;
state = 18;
} else // Reserved, invalid
is_valid = false;
} else {
if ((ch & 0xc0) != 0x80) // Not a continuation, invalid
is_valid = false;
state -= 6;
codepoint |= (ch & 0x3f) << state;
- if (state == 0)
- push_back_u(codepoint);
+ if (state == 0) push_back_u(codepoint);
}
}
// Write codepoint directly, possibly collating surrogate pairs
- void push_back_u(unsigned int codepoint_)
- {
+ void push_back_u(unsigned int codepoint_) {
if (state) // Only accept full codepoints in open state
is_valid = false;
- if (codepoint_ >= 0xD800 && codepoint_ < 0xDC00) { // First half of surrogate pair
+ if (codepoint_ >= 0xD800 &&
+ codepoint_ < 0xDC00) { // First half of surrogate pair
if (surpair) // Two subsequent surrogate pair openers - fail
is_valid = false;
else
surpair = codepoint_;
- } else if (codepoint_ >= 0xDC00 && codepoint_ < 0xE000) { // Second half of surrogate pair
+ } else if (codepoint_ >= 0xDC00 &&
+ codepoint_ < 0xE000) { // Second half of surrogate pair
if (surpair) { // Open surrogate pair, expect second half
// Compute code point from UTF-16 surrogate pair
- append_codepoint(0x10000 | ((surpair - 0xD800)<<10) | (codepoint_ - 0xDC00));
+ append_codepoint(0x10000 | ((surpair - 0xD800) << 10) |
+ (codepoint_ - 0xDC00));
surpair = 0;
} else // Second half doesn't follow a first half - fail
is_valid = false;
} else {
- if (surpair) // First half of surrogate pair not followed by second - fail
+ if (surpair) // First half of surrogate pair not followed by second
+ // - fail
is_valid = false;
else
append_codepoint(codepoint_);
}
}
// Check that we're in a state where the string can be ended
// No open sequences, no open surrogate pairs, etc
- bool finalize()
- {
- if (state || surpair)
- is_valid = false;
+ bool finalize() {
+ if (state || surpair) is_valid = false;
return is_valid;
}
+
private:
std::string &str;
bool is_valid;
// Current UTF-8 decoding state
unsigned int codepoint;
int state; // Top bit to be filled in for next UTF-8 byte, or 0
// Keep track of the following state to handle the following section of
// RFC4627:
//
// To escape an extended character that is not in the Basic Multilingual
// Plane, the character is represented as a twelve-character sequence,
// encoding the UTF-16 surrogate pair. So, for example, a string
// containing only the G clef character (U+1D11E) may be represented as
// "\uD834\uDD1E".
//
// Two subsequent \u.... may have to be replaced with one actual codepoint.
unsigned int surpair; // First half of open UTF-16 surrogate pair, or 0
- void append_codepoint(unsigned int codepoint_)
- {
+ void append_codepoint(unsigned int codepoint_) {
if (codepoint_ <= 0x7f)
str.push_back((char)codepoint_);
else if (codepoint_ <= 0x7FF) {
str.push_back((char)(0xC0 | (codepoint_ >> 6)));
str.push_back((char)(0x80 | (codepoint_ & 0x3F)));
} else if (codepoint_ <= 0xFFFF) {
str.push_back((char)(0xE0 | (codepoint_ >> 12)));
str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F)));
str.push_back((char)(0x80 | (codepoint_ & 0x3F)));
} else if (codepoint_ <= 0x1FFFFF) {
str.push_back((char)(0xF0 | (codepoint_ >> 18)));
str.push_back((char)(0x80 | ((codepoint_ >> 12) & 0x3F)));
str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F)));
str.push_back((char)(0x80 | (codepoint_ & 0x3F)));
}
}
};
#endif // BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_UTFFILTER_H
diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp
index 6ec1dcc54..cf007b396 100644
--- a/src/univalue/lib/univalue.cpp
+++ b/src/univalue/lib/univalue.cpp
@@ -1,242 +1,221 @@
// Copyright 2014 BitPay Inc.
// Copyright 2015 Bitcoin Core Developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://opensource.org/licenses/mit-license.php.
#include <univalue.h>
#include <iomanip>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
const UniValue NullUniValue;
-void UniValue::clear()
-{
+void UniValue::clear() {
typ = VNULL;
val.clear();
keys.clear();
values.clear();
}
-void UniValue::setNull()
-{
+void UniValue::setNull() {
clear();
}
-void UniValue::setBool(bool val_)
-{
+void UniValue::setBool(bool val_) {
clear();
typ = VBOOL;
- if (val_)
- val = "1";
+ if (val_) val = "1";
}
-static bool validNumStr(const std::string& s)
-{
+static bool validNumStr(const std::string &s) {
std::string tokenVal;
unsigned int consumed;
- enum jtokentype tt = getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size());
+ enum jtokentype tt =
+ getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size());
return (tt == JTOK_NUMBER);
}
-void UniValue::setNumStr(std::string str)
-{
+void UniValue::setNumStr(std::string str) {
if (!validNumStr(str)) {
- throw std::runtime_error{"The string '" + str + "' is not a valid JSON number"};
+ throw std::runtime_error{"The string '" + str +
+ "' is not a valid JSON number"};
}
clear();
typ = VNUM;
val = std::move(str);
}
-void UniValue::setInt(uint64_t val_)
-{
+void UniValue::setInt(uint64_t val_) {
std::ostringstream oss;
oss << val_;
return setNumStr(oss.str());
}
-void UniValue::setInt(int64_t val_)
-{
+void UniValue::setInt(int64_t val_) {
std::ostringstream oss;
oss << val_;
return setNumStr(oss.str());
}
-void UniValue::setFloat(double val_)
-{
+void UniValue::setFloat(double val_) {
std::ostringstream oss;
oss << std::setprecision(16) << val_;
return setNumStr(oss.str());
}
-void UniValue::setStr(std::string str)
-{
+void UniValue::setStr(std::string str) {
clear();
typ = VSTR;
val = std::move(str);
}
-void UniValue::setArray()
-{
+void UniValue::setArray() {
clear();
typ = VARR;
}
-void UniValue::setObject()
-{
+void UniValue::setObject() {
clear();
typ = VOBJ;
}
-void UniValue::push_back(UniValue val_)
-{
+void UniValue::push_back(UniValue val_) {
checkType(VARR);
values.push_back(std::move(val_));
}
-void UniValue::push_backV(const std::vector<UniValue>& vec)
-{
+void UniValue::push_backV(const std::vector<UniValue> &vec) {
checkType(VARR);
values.insert(values.end(), vec.begin(), vec.end());
}
-void UniValue::pushKVEnd(std::string key, UniValue val_)
-{
+void UniValue::pushKVEnd(std::string key, UniValue val_) {
checkType(VOBJ);
keys.push_back(std::move(key));
values.push_back(std::move(val_));
}
-void UniValue::pushKV(std::string key, UniValue val_)
-{
+void UniValue::pushKV(std::string key, UniValue val_) {
checkType(VOBJ);
size_t idx;
if (findKey(key, idx))
values[idx] = std::move(val_);
else
pushKVEnd(std::move(key), std::move(val_));
}
-void UniValue::pushKVs(UniValue obj)
-{
+void UniValue::pushKVs(UniValue obj) {
checkType(VOBJ);
obj.checkType(VOBJ);
for (size_t i = 0; i < obj.keys.size(); i++)
pushKVEnd(std::move(obj.keys.at(i)), std::move(obj.values.at(i)));
}
-void UniValue::getObjMap(std::map<std::string,UniValue>& kv) const
-{
- if (typ != VOBJ)
- return;
+void UniValue::getObjMap(std::map<std::string, UniValue> &kv) const {
+ if (typ != VOBJ) return;
kv.clear();
for (size_t i = 0; i < keys.size(); i++)
kv[keys[i]] = values[i];
}
-bool UniValue::findKey(const std::string& key, size_t& retIdx) const
-{
+bool UniValue::findKey(const std::string &key, size_t &retIdx) const {
for (size_t i = 0; i < keys.size(); i++) {
if (keys[i] == key) {
retIdx = i;
return true;
}
}
return false;
}
-bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t) const
-{
+bool UniValue::checkObject(
+ const std::map<std::string, UniValue::VType> &t) const {
if (typ != VOBJ) {
return false;
}
- for (const auto& object: t) {
+ for (const auto &object : t) {
size_t idx = 0;
if (!findKey(object.first, idx)) {
return false;
}
if (values.at(idx).getType() != object.second) {
return false;
}
}
return true;
}
-const UniValue& UniValue::operator[](const std::string& key) const
-{
- if (typ != VOBJ)
- return NullUniValue;
+const UniValue &UniValue::operator[](const std::string &key) const {
+ if (typ != VOBJ) return NullUniValue;
size_t index = 0;
- if (!findKey(key, index))
- return NullUniValue;
+ if (!findKey(key, index)) return NullUniValue;
return values.at(index);
}
-const UniValue& UniValue::operator[](size_t index) const
-{
- if (typ != VOBJ && typ != VARR)
- return NullUniValue;
- if (index >= values.size())
- return NullUniValue;
+const UniValue &UniValue::operator[](size_t index) const {
+ if (typ != VOBJ && typ != VARR) return NullUniValue;
+ if (index >= values.size()) return NullUniValue;
return values.at(index);
}
-void UniValue::checkType(const VType& expected) const
-{
+void UniValue::checkType(const VType &expected) const {
if (typ != expected) {
- throw type_error{"JSON value of type " + std::string{uvTypeName(typ)} + " is not of expected type " +
- std::string{uvTypeName(expected)}};
+ throw type_error{"JSON value of type " + std::string{uvTypeName(typ)} +
+ " is not of expected type " +
+ std::string{uvTypeName(expected)}};
}
}
-const char *uvTypeName(UniValue::VType t)
-{
+const char *uvTypeName(UniValue::VType t) {
switch (t) {
- case UniValue::VNULL: return "null";
- case UniValue::VBOOL: return "bool";
- case UniValue::VOBJ: return "object";
- case UniValue::VARR: return "array";
- case UniValue::VSTR: return "string";
- case UniValue::VNUM: return "number";
+ case UniValue::VNULL:
+ return "null";
+ case UniValue::VBOOL:
+ return "bool";
+ case UniValue::VOBJ:
+ return "object";
+ case UniValue::VARR:
+ return "array";
+ case UniValue::VSTR:
+ return "string";
+ case UniValue::VNUM:
+ return "number";
}
// not reached
return nullptr;
}
-const UniValue& UniValue::find_value(std::string_view key) const
-{
+const UniValue &UniValue::find_value(std::string_view key) const {
for (unsigned int i = 0; i < keys.size(); ++i) {
if (keys[i] == key) {
return values.at(i);
}
}
return NullUniValue;
}
-
diff --git a/src/univalue/lib/univalue_get.cpp b/src/univalue/lib/univalue_get.cpp
index 037449ca0..17533c7f5 100644
--- a/src/univalue/lib/univalue_get.cpp
+++ b/src/univalue/lib/univalue_get.cpp
@@ -1,91 +1,84 @@
// Copyright 2014 BitPay Inc.
// Copyright 2015 Bitcoin Core Developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://opensource.org/licenses/mit-license.php.
#include <univalue.h>
#include <cerrno>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <locale>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
-namespace
-{
-static bool ParsePrechecks(const std::string& str)
-{
+namespace {
+static bool ParsePrechecks(const std::string &str) {
if (str.empty()) // No empty string allowed
return false;
- if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed
+ if (str.size() >= 1 &&
+ (json_isspace(str[0]) ||
+ json_isspace(str[str.size() - 1]))) // No padding allowed
return false;
if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
return false;
return true;
}
-bool ParseDouble(const std::string& str, double *out)
-{
- if (!ParsePrechecks(str))
- return false;
- if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
+bool ParseDouble(const std::string &str, double *out) {
+ if (!ParsePrechecks(str)) return false;
+ if (str.size() >= 2 && str[0] == '0' &&
+ str[1] == 'x') // No hexadecimal floats allowed
return false;
std::istringstream text(str);
text.imbue(std::locale::classic());
double result;
text >> result;
- if(out) *out = result;
+ if (out) *out = result;
return text.eof() && !text.fail();
}
-}
+} // namespace
-const std::vector<std::string>& UniValue::getKeys() const
-{
+const std::vector<std::string> &UniValue::getKeys() const {
checkType(VOBJ);
return keys;
}
-const std::vector<UniValue>& UniValue::getValues() const
-{
+const std::vector<UniValue> &UniValue::getValues() const {
if (typ != VOBJ && typ != VARR)
- throw std::runtime_error("JSON value is not an object or array as expected");
+ throw std::runtime_error(
+ "JSON value is not an object or array as expected");
return values;
}
-bool UniValue::get_bool() const
-{
+bool UniValue::get_bool() const {
checkType(VBOOL);
return isTrue();
}
-const std::string& UniValue::get_str() const
-{
+const std::string &UniValue::get_str() const {
checkType(VSTR);
return getValStr();
}
-double UniValue::get_real() const
-{
+double UniValue::get_real() const {
checkType(VNUM);
double retval;
if (!ParseDouble(getValStr(), &retval))
throw std::runtime_error("JSON double out of range");
return retval;
}
-const UniValue& UniValue::get_obj() const
-{
+const UniValue &UniValue::get_obj() const {
checkType(VOBJ);
return *this;
}
-const UniValue& UniValue::get_array() const
-{
+const UniValue &UniValue::get_array() const {
checkType(VARR);
return *this;
}
diff --git a/src/univalue/lib/univalue_read.cpp b/src/univalue/lib/univalue_read.cpp
index 9eaf5f337..485b66846 100644
--- a/src/univalue/lib/univalue_read.cpp
+++ b/src/univalue/lib/univalue_read.cpp
@@ -1,469 +1,459 @@
// Copyright 2014 BitPay Inc.
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://opensource.org/licenses/mit-license.php.
#include <univalue.h>
#include <univalue_utffilter.h>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <string>
#include <string_view>
#include <vector>
/*
* According to stackexchange, the original json test suite wanted
* to limit depth to 22. Widely-deployed PHP bails at depth 512,
* so we will follow PHP's lead, which should be more than sufficient
* (further stackexchange comments indicate depth > 32 rarely occurs).
*/
static constexpr size_t MAX_JSON_DEPTH = 512;
-static bool json_isdigit(int ch)
-{
+static bool json_isdigit(int ch) {
return ((ch >= '0') && (ch <= '9'));
}
// convert hexadecimal string to unsigned integer
static const char *hatoui(const char *first, const char *last,
- unsigned int& out)
-{
+ unsigned int &out) {
unsigned int result = 0;
- for (; first != last; ++first)
- {
+ for (; first != last; ++first) {
int digit;
if (json_isdigit(*first))
digit = *first - '0';
else if (*first >= 'a' && *first <= 'f')
digit = *first - 'a' + 10;
else if (*first >= 'A' && *first <= 'F')
digit = *first - 'A' + 10;
else
break;
result = 16 * result + digit;
}
out = result;
return first;
}
-enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed,
- const char *raw, const char *end)
-{
+enum jtokentype getJsonToken(std::string &tokenVal, unsigned int &consumed,
+ const char *raw, const char *end) {
tokenVal.clear();
consumed = 0;
const char *rawStart = raw;
- while (raw < end && (json_isspace(*raw))) // skip whitespace
+ while (raw < end && (json_isspace(*raw))) // skip whitespace
raw++;
- if (raw >= end)
- return JTOK_NONE;
+ if (raw >= end) return JTOK_NONE;
switch (*raw) {
-
- case '{':
- raw++;
- consumed = (raw - rawStart);
- return JTOK_OBJ_OPEN;
- case '}':
- raw++;
- consumed = (raw - rawStart);
- return JTOK_OBJ_CLOSE;
- case '[':
- raw++;
- consumed = (raw - rawStart);
- return JTOK_ARR_OPEN;
- case ']':
- raw++;
- consumed = (raw - rawStart);
- return JTOK_ARR_CLOSE;
-
- case ':':
- raw++;
- consumed = (raw - rawStart);
- return JTOK_COLON;
- case ',':
- raw++;
- consumed = (raw - rawStart);
- return JTOK_COMMA;
-
- case 'n':
- case 't':
- case 'f':
- if (!strncmp(raw, "null", 4)) {
- raw += 4;
+ case '{':
+ raw++;
consumed = (raw - rawStart);
- return JTOK_KW_NULL;
- } else if (!strncmp(raw, "true", 4)) {
- raw += 4;
+ return JTOK_OBJ_OPEN;
+ case '}':
+ raw++;
consumed = (raw - rawStart);
- return JTOK_KW_TRUE;
- } else if (!strncmp(raw, "false", 5)) {
- raw += 5;
+ return JTOK_OBJ_CLOSE;
+ case '[':
+ raw++;
consumed = (raw - rawStart);
- return JTOK_KW_FALSE;
- } else
- return JTOK_ERR;
-
- case '-':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': {
- // part 1: int
- std::string numStr;
-
- const char *first = raw;
-
- const char *firstDigit = first;
- if (!json_isdigit(*firstDigit))
- firstDigit++;
- if ((*firstDigit == '0') && json_isdigit(firstDigit[1]))
- return JTOK_ERR;
-
- numStr += *raw; // copy first char
- raw++;
-
- if ((*first == '-') && (raw < end) && (!json_isdigit(*raw)))
- return JTOK_ERR;
+ return JTOK_ARR_OPEN;
+ case ']':
+ raw++;
+ consumed = (raw - rawStart);
+ return JTOK_ARR_CLOSE;
- while (raw < end && json_isdigit(*raw)) { // copy digits
- numStr += *raw;
+ case ':':
raw++;
- }
+ consumed = (raw - rawStart);
+ return JTOK_COLON;
+ case ',':
+ raw++;
+ consumed = (raw - rawStart);
+ return JTOK_COMMA;
+
+ case 'n':
+ case 't':
+ case 'f':
+ if (!strncmp(raw, "null", 4)) {
+ raw += 4;
+ consumed = (raw - rawStart);
+ return JTOK_KW_NULL;
+ } else if (!strncmp(raw, "true", 4)) {
+ raw += 4;
+ consumed = (raw - rawStart);
+ return JTOK_KW_TRUE;
+ } else if (!strncmp(raw, "false", 5)) {
+ raw += 5;
+ consumed = (raw - rawStart);
+ return JTOK_KW_FALSE;
+ } else
+ return JTOK_ERR;
+
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ // part 1: int
+ std::string numStr;
+
+ const char *first = raw;
+
+ const char *firstDigit = first;
+ if (!json_isdigit(*firstDigit)) firstDigit++;
+ if ((*firstDigit == '0') && json_isdigit(firstDigit[1]))
+ return JTOK_ERR;
- // part 2: frac
- if (raw < end && *raw == '.') {
- numStr += *raw; // copy .
+ numStr += *raw; // copy first char
raw++;
- if (raw >= end || !json_isdigit(*raw))
+ if ((*first == '-') && (raw < end) && (!json_isdigit(*raw)))
return JTOK_ERR;
+
while (raw < end && json_isdigit(*raw)) { // copy digits
numStr += *raw;
raw++;
}
- }
-
- // part 3: exp
- if (raw < end && (*raw == 'e' || *raw == 'E')) {
- numStr += *raw; // copy E
- raw++;
- if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/-
- numStr += *raw;
+ // part 2: frac
+ if (raw < end && *raw == '.') {
+ numStr += *raw; // copy .
raw++;
+
+ if (raw >= end || !json_isdigit(*raw)) return JTOK_ERR;
+ while (raw < end && json_isdigit(*raw)) { // copy digits
+ numStr += *raw;
+ raw++;
+ }
}
- if (raw >= end || !json_isdigit(*raw))
- return JTOK_ERR;
- while (raw < end && json_isdigit(*raw)) { // copy digits
- numStr += *raw;
+ // part 3: exp
+ if (raw < end && (*raw == 'e' || *raw == 'E')) {
+ numStr += *raw; // copy E
raw++;
- }
- }
- tokenVal = numStr;
- consumed = (raw - rawStart);
- return JTOK_NUMBER;
- }
+ if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/-
+ numStr += *raw;
+ raw++;
+ }
- case '"': {
- raw++; // skip "
+ if (raw >= end || !json_isdigit(*raw)) return JTOK_ERR;
+ while (raw < end && json_isdigit(*raw)) { // copy digits
+ numStr += *raw;
+ raw++;
+ }
+ }
- std::string valStr;
- JSONUTF8StringFilter writer(valStr);
+ tokenVal = numStr;
+ consumed = (raw - rawStart);
+ return JTOK_NUMBER;
+ }
- while (true) {
- if (raw >= end || (unsigned char)*raw < 0x20)
- return JTOK_ERR;
+ case '"': {
+ raw++; // skip "
- else if (*raw == '\\') {
- raw++; // skip backslash
+ std::string valStr;
+ JSONUTF8StringFilter writer(valStr);
- if (raw >= end)
+ while (true) {
+ if (raw >= end || (uint8_t)*raw < 0x20)
return JTOK_ERR;
- switch (*raw) {
- case '"': writer.push_back('\"'); break;
- case '\\': writer.push_back('\\'); break;
- case '/': writer.push_back('/'); break;
- case 'b': writer.push_back('\b'); break;
- case 'f': writer.push_back('\f'); break;
- case 'n': writer.push_back('\n'); break;
- case 'r': writer.push_back('\r'); break;
- case 't': writer.push_back('\t'); break;
-
- case 'u': {
- unsigned int codepoint;
- if (raw + 1 + 4 >= end ||
- hatoui(raw + 1, raw + 1 + 4, codepoint) !=
- raw + 1 + 4)
- return JTOK_ERR;
- writer.push_back_u(codepoint);
- raw += 4;
- break;
+ else if (*raw == '\\') {
+ raw++; // skip backslash
+
+ if (raw >= end) return JTOK_ERR;
+
+ switch (*raw) {
+ case '"':
+ writer.push_back('\"');
+ break;
+ case '\\':
+ writer.push_back('\\');
+ break;
+ case '/':
+ writer.push_back('/');
+ break;
+ case 'b':
+ writer.push_back('\b');
+ break;
+ case 'f':
+ writer.push_back('\f');
+ break;
+ case 'n':
+ writer.push_back('\n');
+ break;
+ case 'r':
+ writer.push_back('\r');
+ break;
+ case 't':
+ writer.push_back('\t');
+ break;
+
+ case 'u': {
+ unsigned int codepoint;
+ if (raw + 1 + 4 >= end ||
+ hatoui(raw + 1, raw + 1 + 4, codepoint) !=
+ raw + 1 + 4)
+ return JTOK_ERR;
+ writer.push_back_u(codepoint);
+ raw += 4;
+ break;
+ }
+ default:
+ return JTOK_ERR;
}
- default:
- return JTOK_ERR;
+ raw++; // skip esc'd char
}
- raw++; // skip esc'd char
- }
+ else if (*raw == '"') {
+ raw++; // skip "
+ break; // stop scanning
+ }
- else if (*raw == '"') {
- raw++; // skip "
- break; // stop scanning
+ else {
+ writer.push_back(static_cast<uint8_t>(*raw));
+ raw++;
+ }
}
- else {
- writer.push_back(static_cast<unsigned char>(*raw));
- raw++;
- }
+ if (!writer.finalize()) return JTOK_ERR;
+ tokenVal = valStr;
+ consumed = (raw - rawStart);
+ return JTOK_STRING;
}
- if (!writer.finalize())
+ default:
return JTOK_ERR;
- tokenVal = valStr;
- consumed = (raw - rawStart);
- return JTOK_STRING;
- }
-
- default:
- return JTOK_ERR;
}
}
enum expect_bits : unsigned {
EXP_OBJ_NAME = (1U << 0),
EXP_COLON = (1U << 1),
EXP_ARR_VALUE = (1U << 2),
EXP_VALUE = (1U << 3),
EXP_NOT_VALUE = (1U << 4),
};
#define expect(bit) (expectMask & (EXP_##bit))
#define setExpect(bit) (expectMask |= EXP_##bit)
#define clearExpect(bit) (expectMask &= ~EXP_##bit)
-bool UniValue::read(std::string_view str_in)
-{
+bool UniValue::read(std::string_view str_in) {
clear();
uint32_t expectMask = 0;
- std::vector<UniValue*> stack;
+ std::vector<UniValue *> stack;
std::string tokenVal;
unsigned int consumed;
enum jtokentype tok = JTOK_NONE;
enum jtokentype last_tok = JTOK_NONE;
- const char* raw{str_in.data()};
- const char* end{raw + str_in.size()};
+ const char *raw{str_in.data()};
+ const char *end{raw + str_in.size()};
do {
last_tok = tok;
tok = getJsonToken(tokenVal, consumed, raw, end);
- if (tok == JTOK_NONE || tok == JTOK_ERR)
- goto return_fail;
+ if (tok == JTOK_NONE || tok == JTOK_ERR) goto return_fail;
raw += consumed;
- bool isValueOpen = jsonTokenIsValue(tok) ||
- tok == JTOK_OBJ_OPEN || tok == JTOK_ARR_OPEN;
+ bool isValueOpen = jsonTokenIsValue(tok) || tok == JTOK_OBJ_OPEN ||
+ tok == JTOK_ARR_OPEN;
if (expect(VALUE)) {
- if (!isValueOpen)
- goto return_fail;
+ if (!isValueOpen) goto return_fail;
clearExpect(VALUE);
} else if (expect(ARR_VALUE)) {
bool isArrValue = isValueOpen || (tok == JTOK_ARR_CLOSE);
- if (!isArrValue)
- goto return_fail;
+ if (!isArrValue) goto return_fail;
clearExpect(ARR_VALUE);
} else if (expect(OBJ_NAME)) {
bool isObjName = (tok == JTOK_OBJ_CLOSE || tok == JTOK_STRING);
- if (!isObjName)
- goto return_fail;
+ if (!isObjName) goto return_fail;
} else if (expect(COLON)) {
- if (tok != JTOK_COLON)
- goto return_fail;
+ if (tok != JTOK_COLON) goto return_fail;
clearExpect(COLON);
} else if (!expect(COLON) && (tok == JTOK_COLON)) {
goto return_fail;
}
if (expect(NOT_VALUE)) {
- if (isValueOpen)
- goto return_fail;
+ if (isValueOpen) goto return_fail;
clearExpect(NOT_VALUE);
}
switch (tok) {
+ case JTOK_OBJ_OPEN:
+ case JTOK_ARR_OPEN: {
+ VType utyp = (tok == JTOK_OBJ_OPEN ? VOBJ : VARR);
+ if (!stack.size()) {
+ if (utyp == VOBJ)
+ setObject();
+ else
+ setArray();
+ stack.push_back(this);
+ } else {
+ UniValue tmpVal(utyp);
+ UniValue *top = stack.back();
+ top->values.push_back(tmpVal);
+
+ UniValue *newTop = &(top->values.back());
+ stack.push_back(newTop);
+ }
+
+ if (stack.size() > MAX_JSON_DEPTH) goto return_fail;
- case JTOK_OBJ_OPEN:
- case JTOK_ARR_OPEN: {
- VType utyp = (tok == JTOK_OBJ_OPEN ? VOBJ : VARR);
- if (!stack.size()) {
if (utyp == VOBJ)
- setObject();
+ setExpect(OBJ_NAME);
else
- setArray();
- stack.push_back(this);
- } else {
- UniValue tmpVal(utyp);
- UniValue *top = stack.back();
- top->values.push_back(tmpVal);
-
- UniValue *newTop = &(top->values.back());
- stack.push_back(newTop);
- }
-
- if (stack.size() > MAX_JSON_DEPTH)
- goto return_fail;
-
- if (utyp == VOBJ)
- setExpect(OBJ_NAME);
- else
- setExpect(ARR_VALUE);
- break;
+ setExpect(ARR_VALUE);
+ break;
}
- case JTOK_OBJ_CLOSE:
- case JTOK_ARR_CLOSE: {
- if (!stack.size() || (last_tok == JTOK_COMMA))
- goto return_fail;
+ case JTOK_OBJ_CLOSE:
+ case JTOK_ARR_CLOSE: {
+ if (!stack.size() || (last_tok == JTOK_COMMA)) goto return_fail;
- VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR);
- UniValue *top = stack.back();
- if (utyp != top->getType())
- goto return_fail;
+ VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR);
+ UniValue *top = stack.back();
+ if (utyp != top->getType()) goto return_fail;
- stack.pop_back();
- clearExpect(OBJ_NAME);
- setExpect(NOT_VALUE);
- break;
+ stack.pop_back();
+ clearExpect(OBJ_NAME);
+ setExpect(NOT_VALUE);
+ break;
}
- case JTOK_COLON: {
- if (!stack.size())
- goto return_fail;
+ case JTOK_COLON: {
+ if (!stack.size()) goto return_fail;
- UniValue *top = stack.back();
- if (top->getType() != VOBJ)
- goto return_fail;
+ UniValue *top = stack.back();
+ if (top->getType() != VOBJ) goto return_fail;
- setExpect(VALUE);
- break;
+ setExpect(VALUE);
+ break;
}
- case JTOK_COMMA: {
- if (!stack.size() ||
- (last_tok == JTOK_COMMA) || (last_tok == JTOK_ARR_OPEN))
- goto return_fail;
+ case JTOK_COMMA: {
+ if (!stack.size() || (last_tok == JTOK_COMMA) ||
+ (last_tok == JTOK_ARR_OPEN))
+ goto return_fail;
- UniValue *top = stack.back();
- if (top->getType() == VOBJ)
- setExpect(OBJ_NAME);
- else
- setExpect(ARR_VALUE);
- break;
+ UniValue *top = stack.back();
+ if (top->getType() == VOBJ)
+ setExpect(OBJ_NAME);
+ else
+ setExpect(ARR_VALUE);
+ break;
}
- case JTOK_KW_NULL:
- case JTOK_KW_TRUE:
- case JTOK_KW_FALSE: {
- UniValue tmpVal;
- switch (tok) {
case JTOK_KW_NULL:
- // do nothing more
- break;
case JTOK_KW_TRUE:
- tmpVal.setBool(true);
- break;
- case JTOK_KW_FALSE:
- tmpVal.setBool(false);
- break;
- default: /* impossible */ break;
- }
-
- if (!stack.size()) {
- *this = tmpVal;
- break;
- }
+ case JTOK_KW_FALSE: {
+ UniValue tmpVal;
+ switch (tok) {
+ case JTOK_KW_NULL:
+ // do nothing more
+ break;
+ case JTOK_KW_TRUE:
+ tmpVal.setBool(true);
+ break;
+ case JTOK_KW_FALSE:
+ tmpVal.setBool(false);
+ break;
+ default: /* impossible */
+ break;
+ }
- UniValue *top = stack.back();
- top->values.push_back(tmpVal);
+ if (!stack.size()) {
+ *this = tmpVal;
+ break;
+ }
- setExpect(NOT_VALUE);
- break;
- }
+ UniValue *top = stack.back();
+ top->values.push_back(tmpVal);
- case JTOK_NUMBER: {
- UniValue tmpVal(VNUM, tokenVal);
- if (!stack.size()) {
- *this = tmpVal;
+ setExpect(NOT_VALUE);
break;
}
- UniValue *top = stack.back();
- top->values.push_back(tmpVal);
-
- setExpect(NOT_VALUE);
- break;
- }
-
- case JTOK_STRING: {
- if (expect(OBJ_NAME)) {
- UniValue *top = stack.back();
- top->keys.push_back(tokenVal);
- clearExpect(OBJ_NAME);
- setExpect(COLON);
- } else {
- UniValue tmpVal(VSTR, tokenVal);
+ case JTOK_NUMBER: {
+ UniValue tmpVal(VNUM, tokenVal);
if (!stack.size()) {
*this = tmpVal;
break;
}
+
UniValue *top = stack.back();
top->values.push_back(tmpVal);
+
+ setExpect(NOT_VALUE);
+ break;
}
- setExpect(NOT_VALUE);
- break;
+ case JTOK_STRING: {
+ if (expect(OBJ_NAME)) {
+ UniValue *top = stack.back();
+ top->keys.push_back(tokenVal);
+ clearExpect(OBJ_NAME);
+ setExpect(COLON);
+ } else {
+ UniValue tmpVal(VSTR, tokenVal);
+ if (!stack.size()) {
+ *this = tmpVal;
+ break;
+ }
+ UniValue *top = stack.back();
+ top->values.push_back(tmpVal);
+ }
+
+ setExpect(NOT_VALUE);
+ break;
}
- default:
- goto return_fail;
+ default:
+ goto return_fail;
}
- } while (!stack.empty ());
+ } while (!stack.empty());
/* Check that nothing follows the initial construct (parsed above). */
tok = getJsonToken(tokenVal, consumed, raw, end);
- if (tok != JTOK_NONE)
- goto return_fail;
+ if (tok != JTOK_NONE) goto return_fail;
return true;
return_fail:
clear();
return false;
}
-
diff --git a/src/univalue/lib/univalue_write.cpp b/src/univalue/lib/univalue_write.cpp
index ee736274b..8d7c12707 100644
--- a/src/univalue/lib/univalue_write.cpp
+++ b/src/univalue/lib/univalue_write.cpp
@@ -1,163 +1,164 @@
// Copyright 2014 BitPay Inc.
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://opensource.org/licenses/mit-license.php.
#include <univalue.h>
#include <univalue_escapes.h>
#include <cstddef>
#include <string>
#include <utility>
namespace {
struct UniValueStreamWriter {
std::string str;
- UniValueStreamWriter() {
- str.reserve(1024);
- }
+ UniValueStreamWriter() { str.reserve(1024); }
std::string getString() {
#if __cplusplus >= 201103L
return std::move(str);
#else
std::string ret;
std::swap(ret, str);
return ret;
#endif
}
- void put(char c) {
- str.push_back(c);
- }
- void put(char c, size_t nFill) {
- str.append(nFill, c);
- }
- void write(const char *s) {
- str.append(s);
- }
- void write(const std::string &s) {
- str.append(s);
- }
+ void put(char c) { str.push_back(c); }
+ void put(char c, size_t nFill) { str.append(nFill, c); }
+ void write(const char *s) { str.append(s); }
+ void write(const std::string &s) { str.append(s); }
void indentStr(unsigned int prettyIndent, unsigned int indentLevel) {
put(' ', prettyIndent * indentLevel);
}
void escapeJson(const std::string &inS);
- void writeAny(unsigned int prettyIndent, unsigned int indentLevel, const UniValue &obj);
- void writeArray(unsigned int prettyIndent, unsigned int indentLevel, const UniValue &obj);
- void writeObject(unsigned int prettyIndent, unsigned int indentLevel, const UniValue &obj);
+ void writeAny(unsigned int prettyIndent, unsigned int indentLevel,
+ const UniValue &obj);
+ void writeArray(unsigned int prettyIndent, unsigned int indentLevel,
+ const UniValue &obj);
+ void writeObject(unsigned int prettyIndent, unsigned int indentLevel,
+ const UniValue &obj);
};
void UniValueStreamWriter::escapeJson(const std::string &inS) {
size_t len = inS.length();
for (size_t i = 0; i < len; i++) {
const char ch = inS[i];
- const char * const escStr = escapes[uint8_t(ch)];
+ const char *const escStr = escapes[uint8_t(ch)];
if (escStr) {
write(escStr);
} else {
put(ch);
}
}
}
-void UniValueStreamWriter::writeAny(unsigned int prettyIndent, unsigned int indentLevel, const UniValue &obj) {
+void UniValueStreamWriter::writeAny(unsigned int prettyIndent,
+ unsigned int indentLevel,
+ const UniValue &obj) {
unsigned int modIndent = indentLevel;
if (modIndent == 0) {
modIndent = 1;
}
switch (obj.typ) {
- case UniValue::VNULL:
- write("null");
- break;
- case UniValue::VOBJ:
- writeObject(prettyIndent, modIndent, obj);
- break;
- case UniValue::VARR:
- writeArray(prettyIndent, modIndent, obj);
- break;
- case UniValue::VSTR:
- put('"');
- escapeJson(obj.val);
- put('"');
- break;
- case UniValue::VNUM:
- write(obj.val);
- break;
- case UniValue::VBOOL:
- write(obj.val == "1" ? "true" : "false");
- break;
+ case UniValue::VNULL:
+ write("null");
+ break;
+ case UniValue::VOBJ:
+ writeObject(prettyIndent, modIndent, obj);
+ break;
+ case UniValue::VARR:
+ writeArray(prettyIndent, modIndent, obj);
+ break;
+ case UniValue::VSTR:
+ put('"');
+ escapeJson(obj.val);
+ put('"');
+ break;
+ case UniValue::VNUM:
+ write(obj.val);
+ break;
+ case UniValue::VBOOL:
+ write(obj.val == "1" ? "true" : "false");
+ break;
}
}
-void UniValueStreamWriter::writeArray(unsigned int prettyIndent, unsigned int indentLevel, const UniValue &obj) {
+void UniValueStreamWriter::writeArray(unsigned int prettyIndent,
+ unsigned int indentLevel,
+ const UniValue &obj) {
put('[');
if (prettyIndent) {
put('\n');
}
const size_t nValues = obj.values.size();
for (size_t i = 0; i < nValues; ++i) {
if (prettyIndent) {
indentStr(prettyIndent, indentLevel);
}
writeAny(prettyIndent, indentLevel + 1, obj.values[i]);
if (i != nValues - 1) {
put(',');
}
if (prettyIndent) {
put('\n');
}
}
if (prettyIndent) {
indentStr(prettyIndent, indentLevel - 1);
}
put(']');
}
-void UniValueStreamWriter::writeObject(unsigned int prettyIndent, unsigned int indentLevel, const UniValue &obj) {
+void UniValueStreamWriter::writeObject(unsigned int prettyIndent,
+ unsigned int indentLevel,
+ const UniValue &obj) {
put('{');
if (prettyIndent) {
put('\n');
}
// Note: if typ == VOBJ, then keys.size() == values.size() always, so we can
- // use the non-bounds-checking operator[]() for both keys and values here safely.
+ // use the non-bounds-checking operator[]() for both keys and values here
+ // safely.
const size_t nItems = obj.keys.size();
for (size_t i = 0; i < nItems; ++i) {
if (prettyIndent) {
indentStr(prettyIndent, indentLevel);
}
put('"');
escapeJson(obj.keys[i]);
write("\":");
if (prettyIndent) {
put(' ');
}
writeAny(prettyIndent, indentLevel + 1, obj.values[i]);
if (i != nItems - 1) {
put(',');
}
if (prettyIndent) {
put('\n');
}
}
if (prettyIndent) {
indentStr(prettyIndent, indentLevel - 1);
}
put('}');
}
-}
+} // namespace
-std::string UniValue::write(unsigned int prettyIndent, unsigned int indentLevel) const {
+std::string UniValue::write(unsigned int prettyIndent,
+ unsigned int indentLevel) const {
UniValueStreamWriter ss;
ss.writeAny(prettyIndent, indentLevel, *this);
return ss.getString();
}
diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp
index e72cc90fa..51e334ba8 100644
--- a/src/univalue/test/object.cpp
+++ b/src/univalue/test/object.cpp
@@ -1,472 +1,465 @@
// Copyright (c) 2014 BitPay Inc.
// Copyright (c) 2014-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://opensource.org/licenses/mit-license.php.
#include <univalue.h>
#include <cassert>
#include <cstdint>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
#define BOOST_CHECK(expr) assert(expr)
#define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2))
-#define BOOST_CHECK_THROW(stmt, excMatch) { \
- try { \
- (stmt); \
- assert(0 && "No exception caught"); \
- } catch (excMatch & e) { \
- } catch (...) { \
- assert(0 && "Wrong exception caught"); \
- } \
+#define BOOST_CHECK_THROW(stmt, excMatch) \
+ { \
+ try { \
+ (stmt); \
+ assert(0 && "No exception caught"); \
+ } catch (excMatch & e) { \
+ } catch (...) { \
+ assert(0 && "Wrong exception caught"); \
+ } \
}
-#define BOOST_CHECK_NO_THROW(stmt) { \
- try { \
- (stmt); \
- } catch (...) { \
- assert(0); \
- } \
+#define BOOST_CHECK_NO_THROW(stmt) \
+ { \
+ try { \
+ (stmt); \
+ } catch (...) { \
+ assert(0); \
+ } \
}
-void univalue_constructor()
-{
+void univalue_constructor() {
UniValue v1;
BOOST_CHECK(v1.isNull());
UniValue v2(UniValue::VSTR);
BOOST_CHECK(v2.isStr());
UniValue v3(UniValue::VSTR, "foo");
BOOST_CHECK(v3.isStr());
BOOST_CHECK_EQUAL(v3.getValStr(), "foo");
UniValue numTest;
numTest.setNumStr("82");
BOOST_CHECK(numTest.isNum());
BOOST_CHECK_EQUAL(numTest.getValStr(), "82");
uint64_t vu64 = 82;
UniValue v4(vu64);
BOOST_CHECK(v4.isNum());
BOOST_CHECK_EQUAL(v4.getValStr(), "82");
int64_t vi64 = -82;
UniValue v5(vi64);
BOOST_CHECK(v5.isNum());
BOOST_CHECK_EQUAL(v5.getValStr(), "-82");
int vi = -688;
UniValue v6(vi);
BOOST_CHECK(v6.isNum());
BOOST_CHECK_EQUAL(v6.getValStr(), "-688");
double vd = -7.21;
UniValue v7(vd);
BOOST_CHECK(v7.isNum());
BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");
std::string vs("yawn");
UniValue v8(vs);
BOOST_CHECK(v8.isStr());
BOOST_CHECK_EQUAL(v8.getValStr(), "yawn");
const char *vcs = "zappa";
UniValue v9(vcs);
BOOST_CHECK(v9.isStr());
BOOST_CHECK_EQUAL(v9.getValStr(), "zappa");
}
-void univalue_push_throw()
-{
+void univalue_push_throw() {
UniValue j;
BOOST_CHECK_THROW(j.push_back(1), std::runtime_error);
BOOST_CHECK_THROW(j.push_backV({1}), std::runtime_error);
BOOST_CHECK_THROW(j.pushKVEnd("k", 1), std::runtime_error);
BOOST_CHECK_THROW(j.pushKV("k", 1), std::runtime_error);
BOOST_CHECK_THROW(j.pushKVs({}), std::runtime_error);
}
-void univalue_typecheck()
-{
+void univalue_typecheck() {
UniValue v1;
v1.setNumStr("1");
BOOST_CHECK(v1.isNum());
BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error);
{
UniValue v_negative;
v_negative.setNumStr("-1");
BOOST_CHECK_THROW(v_negative.getInt<uint8_t>(), std::runtime_error);
BOOST_CHECK_EQUAL(v_negative.getInt<int8_t>(), -1);
}
UniValue v2;
v2.setBool(true);
BOOST_CHECK_EQUAL(v2.get_bool(), true);
BOOST_CHECK_THROW(v2.getInt<int>(), std::runtime_error);
UniValue v3;
v3.setNumStr("32482348723847471234");
BOOST_CHECK_THROW(v3.getInt<int64_t>(), std::runtime_error);
v3.setNumStr("1000");
BOOST_CHECK_EQUAL(v3.getInt<int64_t>(), 1000);
UniValue v4;
v4.setNumStr("2147483648");
BOOST_CHECK_EQUAL(v4.getInt<int64_t>(), 2147483648);
BOOST_CHECK_THROW(v4.getInt<int>(), std::runtime_error);
v4.setNumStr("1000");
BOOST_CHECK_EQUAL(v4.getInt<int>(), 1000);
BOOST_CHECK_THROW(v4.get_str(), std::runtime_error);
BOOST_CHECK_EQUAL(v4.get_real(), 1000);
BOOST_CHECK_THROW(v4.get_array(), std::runtime_error);
BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error);
BOOST_CHECK_THROW(v4.getValues(), std::runtime_error);
BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error);
UniValue v5;
BOOST_CHECK(v5.read("[true, 10]"));
BOOST_CHECK_NO_THROW(v5.get_array());
std::vector<UniValue> vals = v5.getValues();
BOOST_CHECK_THROW(vals[0].getInt<int>(), std::runtime_error);
BOOST_CHECK_EQUAL(vals[0].get_bool(), true);
BOOST_CHECK_EQUAL(vals[1].getInt<int>(), 10);
BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error);
}
-void univalue_set()
-{
+void univalue_set() {
UniValue v(UniValue::VSTR, "foo");
v.clear();
BOOST_CHECK(v.isNull());
BOOST_CHECK_EQUAL(v.getValStr(), "");
v.setObject();
BOOST_CHECK(v.isObject());
BOOST_CHECK_EQUAL(v.size(), 0);
BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);
BOOST_CHECK(v.empty());
v.setArray();
BOOST_CHECK(v.isArray());
BOOST_CHECK_EQUAL(v.size(), 0);
v.setStr("zum");
BOOST_CHECK(v.isStr());
BOOST_CHECK_EQUAL(v.getValStr(), "zum");
{
std::string_view sv{"ab\0c", 4};
UniValue j{sv};
BOOST_CHECK(j.isStr());
BOOST_CHECK_EQUAL(j.getValStr(), sv);
BOOST_CHECK_EQUAL(j.write(), "\"ab\\u0000c\"");
}
v.setFloat(-1.01);
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
v.setInt(int{1023});
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "1023");
v.setInt(int64_t{-1023LL});
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "-1023");
v.setInt(uint64_t{1023ULL});
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "1023");
v.setNumStr("-688");
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "-688");
v.setBool(false);
BOOST_CHECK_EQUAL(v.isBool(), true);
BOOST_CHECK_EQUAL(v.isTrue(), false);
BOOST_CHECK_EQUAL(v.isFalse(), true);
BOOST_CHECK_EQUAL(v.get_bool(), false);
v.setBool(true);
BOOST_CHECK_EQUAL(v.isBool(), true);
BOOST_CHECK_EQUAL(v.isTrue(), true);
BOOST_CHECK_EQUAL(v.isFalse(), false);
BOOST_CHECK_EQUAL(v.get_bool(), true);
BOOST_CHECK_THROW(v.setNumStr("zombocom"), std::runtime_error);
v.setNull();
BOOST_CHECK(v.isNull());
}
-void univalue_array()
-{
+void univalue_array() {
UniValue arr(UniValue::VARR);
arr.reserve(9);
UniValue v((int64_t)1023LL);
arr.push_back(v);
std::string vStr("zippy");
arr.push_back(vStr);
const char *s = "pippy";
arr.push_back(s);
std::vector<UniValue> vec;
v.setStr("boing");
vec.push_back(v);
v.setStr("going");
vec.push_back(v);
arr.push_backV(vec);
arr.push_back(uint64_t{400ULL});
arr.push_back(int64_t{-400LL});
arr.push_back(int{-401});
arr.push_back(-40.1);
arr.push_back(true);
BOOST_CHECK_EQUAL(arr.empty(), false);
BOOST_CHECK_EQUAL(arr.size(), 10);
BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023");
BOOST_CHECK_EQUAL(arr[0].getType(), UniValue::VNUM);
BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy");
BOOST_CHECK_EQUAL(arr[1].getType(), UniValue::VSTR);
BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy");
BOOST_CHECK_EQUAL(arr[2].getType(), UniValue::VSTR);
BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing");
BOOST_CHECK_EQUAL(arr[3].getType(), UniValue::VSTR);
BOOST_CHECK_EQUAL(arr[4].getValStr(), "going");
BOOST_CHECK_EQUAL(arr[4].getType(), UniValue::VSTR);
BOOST_CHECK_EQUAL(arr[5].getValStr(), "400");
BOOST_CHECK_EQUAL(arr[5].getType(), UniValue::VNUM);
BOOST_CHECK_EQUAL(arr[6].getValStr(), "-400");
BOOST_CHECK_EQUAL(arr[6].getType(), UniValue::VNUM);
BOOST_CHECK_EQUAL(arr[7].getValStr(), "-401");
BOOST_CHECK_EQUAL(arr[7].getType(), UniValue::VNUM);
BOOST_CHECK_EQUAL(arr[8].getValStr(), "-40.1");
BOOST_CHECK_EQUAL(arr[8].getType(), UniValue::VNUM);
BOOST_CHECK_EQUAL(arr[9].getValStr(), "1");
BOOST_CHECK_EQUAL(arr[9].getType(), UniValue::VBOOL);
BOOST_CHECK_EQUAL(arr[999].getValStr(), "");
arr.clear();
BOOST_CHECK(arr.empty());
BOOST_CHECK_EQUAL(arr.size(), 0);
}
-void univalue_object()
-{
+void univalue_object() {
UniValue obj(UniValue::VOBJ);
std::string strKey, strVal;
UniValue v;
obj.reserve(11);
strKey = "age";
v.setInt(100);
obj.pushKV(strKey, v);
strKey = "first";
strVal = "John";
obj.pushKV(strKey, strVal);
strKey = "last";
- const char* cVal = "Smith";
+ const char *cVal = "Smith";
obj.pushKV(strKey, cVal);
strKey = "distance";
obj.pushKV(strKey, int64_t{25});
strKey = "time";
obj.pushKV(strKey, uint64_t{3600});
strKey = "calories";
obj.pushKV(strKey, int{12});
strKey = "temperature";
obj.pushKV(strKey, double{90.012});
strKey = "moon";
obj.pushKV(strKey, true);
strKey = "spoon";
obj.pushKV(strKey, false);
UniValue obj2(UniValue::VOBJ);
obj2.pushKV("cat1", 9000);
obj2.pushKV("cat2", 12345);
obj.pushKVs(obj2);
BOOST_CHECK_EQUAL(obj.empty(), false);
BOOST_CHECK_EQUAL(obj.size(), 11);
BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100");
BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John");
BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith");
BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25");
BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600");
BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12");
BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012");
BOOST_CHECK_EQUAL(obj["moon"].getValStr(), "1");
BOOST_CHECK_EQUAL(obj["spoon"].getValStr(), "");
BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000");
BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345");
BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), "");
BOOST_CHECK(obj.exists("age"));
BOOST_CHECK(obj.exists("first"));
BOOST_CHECK(obj.exists("last"));
BOOST_CHECK(obj.exists("distance"));
BOOST_CHECK(obj.exists("time"));
BOOST_CHECK(obj.exists("calories"));
BOOST_CHECK(obj.exists("temperature"));
BOOST_CHECK(obj.exists("moon"));
BOOST_CHECK(obj.exists("spoon"));
BOOST_CHECK(obj.exists("cat1"));
BOOST_CHECK(obj.exists("cat2"));
BOOST_CHECK(!obj.exists("nyuknyuknyuk"));
std::map<std::string, UniValue::VType> objTypes;
objTypes["age"] = UniValue::VNUM;
objTypes["first"] = UniValue::VSTR;
objTypes["last"] = UniValue::VSTR;
objTypes["distance"] = UniValue::VNUM;
objTypes["time"] = UniValue::VNUM;
objTypes["calories"] = UniValue::VNUM;
objTypes["temperature"] = UniValue::VNUM;
objTypes["moon"] = UniValue::VBOOL;
objTypes["spoon"] = UniValue::VBOOL;
objTypes["cat1"] = UniValue::VNUM;
objTypes["cat2"] = UniValue::VNUM;
BOOST_CHECK(obj.checkObject(objTypes));
objTypes["cat2"] = UniValue::VSTR;
BOOST_CHECK(!obj.checkObject(objTypes));
obj.clear();
BOOST_CHECK(obj.empty());
BOOST_CHECK_EQUAL(obj.size(), 0);
BOOST_CHECK_EQUAL(obj.getType(), UniValue::VNULL);
obj.setObject();
UniValue uv;
uv.setInt(42);
obj.pushKVEnd("age", uv);
BOOST_CHECK_EQUAL(obj.size(), 1);
BOOST_CHECK_EQUAL(obj["age"].getValStr(), "42");
uv.setInt(43);
obj.pushKV("age", uv);
BOOST_CHECK_EQUAL(obj.size(), 1);
BOOST_CHECK_EQUAL(obj["age"].getValStr(), "43");
obj.pushKV("name", "foo bar");
- std::map<std::string,UniValue> kv;
+ std::map<std::string, UniValue> kv;
obj.getObjMap(kv);
BOOST_CHECK_EQUAL(kv["age"].getValStr(), "43");
BOOST_CHECK_EQUAL(kv["name"].getValStr(), "foo bar");
-
}
-static const char *json1 =
-"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]";
+static const char *json1 = "[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,"
+ "\"key3\":{\"name\":\"martian http://test.com\"}}]";
-void univalue_readwrite()
-{
+void univalue_readwrite() {
UniValue v;
BOOST_CHECK(v.read(json1));
std::string strJson1(json1);
BOOST_CHECK(v.read(strJson1));
BOOST_CHECK(v.isArray());
BOOST_CHECK_EQUAL(v.size(), 2);
BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000");
UniValue obj = v[1];
BOOST_CHECK(obj.isObject());
BOOST_CHECK_EQUAL(obj.size(), 3);
BOOST_CHECK(obj["key1"].isStr());
std::string correctValue("str");
correctValue.push_back('\0');
BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue);
BOOST_CHECK(obj["key2"].isNum());
BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800");
BOOST_CHECK(obj["key3"].isObject());
BOOST_CHECK_EQUAL(strJson1, v.write());
// Valid
BOOST_CHECK(v.read("1.0") && (v.get_real() == 1.0));
BOOST_CHECK(v.read("true") && v.get_bool());
BOOST_CHECK(v.read("[false]") && !v[0].get_bool());
BOOST_CHECK(v.read("{\"a\": true}") && v["a"].get_bool());
BOOST_CHECK(v.read("{\"1\": \"true\"}") && (v["1"].get_str() == "true"));
// Valid, with leading or trailing whitespace
BOOST_CHECK(v.read(" 1.0") && (v.get_real() == 1.0));
BOOST_CHECK(v.read("1.0 ") && (v.get_real() == 1.0));
BOOST_CHECK(v.read("0.00000000000000000000000000000000000001e+30 "));
- //should fail, missing leading 0, therefore invalid JSON
+ // should fail, missing leading 0, therefore invalid JSON
BOOST_CHECK(!v.read(".19e-6"));
// Invalid, initial garbage
BOOST_CHECK(!v.read("[1.0"));
BOOST_CHECK(!v.read("a1.0"));
// Invalid, trailing garbage
BOOST_CHECK(!v.read("1.0sds"));
BOOST_CHECK(!v.read("1.0]"));
// Invalid, keys have to be names
BOOST_CHECK(!v.read("{1: \"true\"}"));
BOOST_CHECK(!v.read("{true: 1}"));
BOOST_CHECK(!v.read("{[1]: 1}"));
BOOST_CHECK(!v.read("{{\"a\": \"a\"}: 1}"));
// BTC addresses should fail parsing
BOOST_CHECK(!v.read("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"));
BOOST_CHECK(!v.read("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"));
/* Check for (correctly reporting) a parsing error if the initial
JSON construct is followed by more stuff. Note that whitespace
is, of course, exempt. */
BOOST_CHECK(v.read(" {}\n "));
BOOST_CHECK(v.isObject());
BOOST_CHECK(v.read(" []\n "));
BOOST_CHECK(v.isArray());
BOOST_CHECK(!v.read("@{}"));
BOOST_CHECK(!v.read("{} garbage"));
BOOST_CHECK(!v.read("[]{}"));
BOOST_CHECK(!v.read("{}[]"));
BOOST_CHECK(!v.read("{} 42"));
}
-int main(int argc, char* argv[])
-{
+int main(int argc, char *argv[]) {
univalue_constructor();
univalue_push_throw();
univalue_typecheck();
univalue_set();
univalue_array();
univalue_object();
univalue_readwrite();
return 0;
}
diff --git a/src/univalue/test/test_json.cpp b/src/univalue/test/test_json.cpp
index f8c10238d..deabfa3cf 100644
--- a/src/univalue/test/test_json.cpp
+++ b/src/univalue/test/test_json.cpp
@@ -1,26 +1,25 @@
// Test program that can be called by the JSON test suite at
// https://github.com/nst/JSONTestSuite.
//
// It reads JSON input from stdin and exits with code 0 if it can be parsed
// successfully. It also pretty prints the parsed JSON value to stdout.
#include <univalue.h>
#include <iostream>
#include <iterator>
#include <string>
using namespace std;
-int main (int argc, char *argv[])
-{
+int main(int argc, char *argv[]) {
UniValue val;
if (val.read(string(istreambuf_iterator<char>(cin),
istreambuf_iterator<char>()))) {
cout << val.write(1 /* prettyIndent */, 4 /* indentLevel */) << endl;
return 0;
} else {
cerr << "JSON Parse Error." << endl;
return 1;
}
}
diff --git a/src/univalue/test/unitester.cpp b/src/univalue/test/unitester.cpp
index d27e647e5..b9ff91d6d 100644
--- a/src/univalue/test/unitester.cpp
+++ b/src/univalue/test/unitester.cpp
@@ -1,170 +1,135 @@
// Copyright 2014 BitPay Inc.
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or https://opensource.org/licenses/mit-license.php.
#include <univalue.h>
#include <cassert>
#include <cstdio>
#include <string>
#ifndef JSON_TEST_SRC
#error JSON_TEST_SRC must point to test source directory
#endif
std::string srcdir(JSON_TEST_SRC);
-static std::string rtrim(std::string s)
-{
- s.erase(s.find_last_not_of(" \n\r\t")+1);
+static std::string rtrim(std::string s) {
+ s.erase(s.find_last_not_of(" \n\r\t") + 1);
return s;
}
-static void runtest(std::string filename, const std::string& jdata)
-{
- std::string prefix = filename.substr(0, 4);
+static void runtest(std::string filename, const std::string &jdata) {
+ std::string prefix = filename.substr(0, 4);
- bool wantPass = (prefix == "pass") || (prefix == "roun");
- bool wantFail = (prefix == "fail");
- bool wantRoundTrip = (prefix == "roun");
- assert(wantPass || wantFail);
+ bool wantPass = (prefix == "pass") || (prefix == "roun");
+ bool wantFail = (prefix == "fail");
+ bool wantRoundTrip = (prefix == "roun");
+ assert(wantPass || wantFail);
- UniValue val;
- bool testResult = val.read(jdata);
+ UniValue val;
+ bool testResult = val.read(jdata);
- if (wantPass) {
- assert(testResult == true);
- } else {
- assert(testResult == false);
- }
+ if (wantPass) {
+ assert(testResult == true);
+ } else {
+ assert(testResult == false);
+ }
- if (wantRoundTrip) {
- std::string odata = val.write(0, 0);
- assert(odata == rtrim(jdata));
- }
+ if (wantRoundTrip) {
+ std::string odata = val.write(0, 0);
+ assert(odata == rtrim(jdata));
+ }
}
-static void runtest_file(const char *filename_)
-{
- std::string basename(filename_);
- std::string filename = srcdir + "/" + basename;
- FILE *f = fopen(filename.c_str(), "r");
- assert(f != nullptr);
+static void runtest_file(const char *filename_) {
+ std::string basename(filename_);
+ std::string filename = srcdir + "/" + basename;
+ FILE *f = fopen(filename.c_str(), "r");
+ assert(f != nullptr);
- std::string jdata;
+ std::string jdata;
- char buf[4096];
- while (!feof(f)) {
- int bread = fread(buf, 1, sizeof(buf), f);
- assert(!ferror(f));
+ char buf[4096];
+ while (!feof(f)) {
+ int bread = fread(buf, 1, sizeof(buf), f);
+ assert(!ferror(f));
- std::string s(buf, bread);
- jdata += s;
- }
+ std::string s(buf, bread);
+ jdata += s;
+ }
- assert(!ferror(f));
- fclose(f);
+ assert(!ferror(f));
+ fclose(f);
- runtest(basename, jdata);
+ runtest(basename, jdata);
}
static const char *filenames[] = {
- "fail10.json",
- "fail11.json",
- "fail12.json",
- "fail13.json",
- "fail14.json",
- "fail15.json",
- "fail16.json",
- "fail17.json",
- //"fail18.json", // investigate
- "fail19.json",
- "fail1.json",
- "fail20.json",
- "fail21.json",
- "fail22.json",
- "fail23.json",
- "fail24.json",
- "fail25.json",
- "fail26.json",
- "fail27.json",
- "fail28.json",
- "fail29.json",
- "fail2.json",
- "fail30.json",
- "fail31.json",
- "fail32.json",
- "fail33.json",
- "fail34.json",
- "fail35.json",
- "fail36.json",
- "fail37.json",
- "fail38.json", // invalid unicode: only first half of surrogate pair
- "fail39.json", // invalid unicode: only second half of surrogate pair
- "fail40.json", // invalid unicode: broken UTF-8
- "fail41.json", // invalid unicode: unfinished UTF-8
- "fail42.json", // valid json with garbage following a nul byte
- "fail44.json", // unterminated string
- "fail45.json", // nested beyond max depth
- "fail3.json",
- "fail4.json", // extra comma
- "fail5.json",
- "fail6.json",
- "fail7.json",
- "fail8.json",
- "fail9.json", // extra comma
- "pass1.json",
- "pass2.json",
- "pass3.json",
- "pass4.json",
- "round1.json", // round-trip test
- "round2.json", // unicode
- "round3.json", // bare string
- "round4.json", // bare number
- "round5.json", // bare true
- "round6.json", // bare false
- "round7.json", // bare null
+ "fail10.json", "fail11.json", "fail12.json", "fail13.json", "fail14.json",
+ "fail15.json", "fail16.json", "fail17.json",
+ //"fail18.json", // investigate
+ "fail19.json", "fail1.json", "fail20.json", "fail21.json", "fail22.json",
+ "fail23.json", "fail24.json", "fail25.json", "fail26.json", "fail27.json",
+ "fail28.json", "fail29.json", "fail2.json", "fail30.json", "fail31.json",
+ "fail32.json", "fail33.json", "fail34.json", "fail35.json", "fail36.json",
+ "fail37.json",
+ "fail38.json", // invalid unicode: only first half of surrogate pair
+ "fail39.json", // invalid unicode: only second half of surrogate pair
+ "fail40.json", // invalid unicode: broken UTF-8
+ "fail41.json", // invalid unicode: unfinished UTF-8
+ "fail42.json", // valid json with garbage following a nul byte
+ "fail44.json", // unterminated string
+ "fail45.json", // nested beyond max depth
+ "fail3.json",
+ "fail4.json", // extra comma
+ "fail5.json", "fail6.json", "fail7.json", "fail8.json",
+ "fail9.json", // extra comma
+ "pass1.json", "pass2.json", "pass3.json", "pass4.json",
+ "round1.json", // round-trip test
+ "round2.json", // unicode
+ "round3.json", // bare string
+ "round4.json", // bare number
+ "round5.json", // bare true
+ "round6.json", // bare false
+ "round7.json", // bare null
};
// Test \u handling
-void unescape_unicode_test()
-{
+void unescape_unicode_test() {
UniValue val;
bool testResult;
// Escaped ASCII (quote)
testResult = val.read("[\"\\u0022\"]");
assert(testResult);
assert(val[0].get_str() == "\"");
// Escaped Basic Plane character, two-byte UTF-8
testResult = val.read("[\"\\u0191\"]");
assert(testResult);
assert(val[0].get_str() == "\xc6\x91");
// Escaped Basic Plane character, three-byte UTF-8
testResult = val.read("[\"\\u2191\"]");
assert(testResult);
assert(val[0].get_str() == "\xe2\x86\x91");
// Escaped Supplementary Plane character U+1d161
testResult = val.read("[\"\\ud834\\udd61\"]");
assert(testResult);
assert(val[0].get_str() == "\xf0\x9d\x85\xa1");
}
-void no_nul_test()
-{
+void no_nul_test() {
char buf[] = "___[1,2,3]___";
UniValue val;
assert(val.read({buf + 3, 7}));
}
-int main (int argc, char *argv[])
-{
- for (const auto& f: filenames) {
+int main(int argc, char *argv[]) {
+ for (const auto &f : filenames) {
runtest_file(f);
}
unescape_unicode_test();
no_nul_test();
return 0;
}
-
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, May 21, 21:43 (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5865994
Default Alt Text
(96 KB)
Attached To
rABC Bitcoin ABC
Event Timeline
Log In to Comment