mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32:48 +01:00
Merge #11420: Bump univalue subtree and fix json formatting in tests
619bb05
Squashed 'src/univalue/' changes from 16a1f7f6e..fe805ea74 (MarcoFalke)
Pull request description:
The subtree-merge commit also fixes the whitespace for failing tests, such that bisect doesn't break.
Finally, the bump also includes the changes that accidentally modified our subtree, such that the subtree check should work fine now:
```sh
./contrib/devtools/git-subtree-check.sh src/univalue
Tree-SHA512: 3009d1e52b6f41ef89ecc8a000649f08e44395538703f294995a6e913e3fbfb7813d6bd31fdb4acb6127fd4af99c095bf980a12f1f026bb27cacc66e1487cd1e
This commit is contained in:
parent
7f2ebba617
commit
36bb302f80
@ -12,6 +12,7 @@ pkgconfig_DATA = pc/libunivalue.pc
|
|||||||
|
|
||||||
libunivalue_la_SOURCES = \
|
libunivalue_la_SOURCES = \
|
||||||
lib/univalue.cpp \
|
lib/univalue.cpp \
|
||||||
|
lib/univalue_get.cpp \
|
||||||
lib/univalue_read.cpp \
|
lib/univalue_read.cpp \
|
||||||
lib/univalue_write.cpp
|
lib/univalue_write.cpp
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ libunivalue_la_LDFLAGS = \
|
|||||||
-no-undefined
|
-no-undefined
|
||||||
libunivalue_la_CXXFLAGS = -I$(top_srcdir)/include
|
libunivalue_la_CXXFLAGS = -I$(top_srcdir)/include
|
||||||
|
|
||||||
TESTS = test/unitester
|
TESTS = test/object test/unitester test/no_nul
|
||||||
|
|
||||||
GENBIN = gen/gen$(BUILD_EXEEXT)
|
GENBIN = gen/gen$(BUILD_EXEEXT)
|
||||||
GEN_SRCS = gen/gen.cpp
|
GEN_SRCS = gen/gen.cpp
|
||||||
@ -33,7 +34,7 @@ gen: lib/univalue_escapes.h $(GENBIN)
|
|||||||
@echo Updating $<
|
@echo Updating $<
|
||||||
$(AM_V_at)$(GENBIN) > lib/univalue_escapes.h
|
$(AM_V_at)$(GENBIN) > lib/univalue_escapes.h
|
||||||
|
|
||||||
noinst_PROGRAMS = $(TESTS)
|
noinst_PROGRAMS = $(TESTS) test/test_json
|
||||||
|
|
||||||
TEST_DATA_DIR=test
|
TEST_DATA_DIR=test
|
||||||
|
|
||||||
@ -42,6 +43,21 @@ test_unitester_LDADD = libunivalue.la
|
|||||||
test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(TEST_DATA_DIR)\"
|
test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(TEST_DATA_DIR)\"
|
||||||
test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
|
test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
|
||||||
|
|
||||||
|
test_test_json_SOURCES = test/test_json.cpp
|
||||||
|
test_test_json_LDADD = libunivalue.la
|
||||||
|
test_test_json_CXXFLAGS = -I$(top_srcdir)/include
|
||||||
|
test_test_json_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
|
||||||
|
|
||||||
|
test_no_nul_SOURCES = test/no_nul.cpp
|
||||||
|
test_no_nul_LDADD = libunivalue.la
|
||||||
|
test_no_nul_CXXFLAGS = -I$(top_srcdir)/include
|
||||||
|
test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
|
||||||
|
|
||||||
|
test_object_SOURCES = test/object.cpp
|
||||||
|
test_object_LDADD = libunivalue.la
|
||||||
|
test_object_CXXFLAGS = -I$(top_srcdir)/include
|
||||||
|
test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
|
||||||
|
|
||||||
TEST_FILES = \
|
TEST_FILES = \
|
||||||
$(TEST_DATA_DIR)/fail10.json \
|
$(TEST_DATA_DIR)/fail10.json \
|
||||||
$(TEST_DATA_DIR)/fail11.json \
|
$(TEST_DATA_DIR)/fail11.json \
|
||||||
@ -77,6 +93,8 @@ TEST_FILES = \
|
|||||||
$(TEST_DATA_DIR)/fail39.json \
|
$(TEST_DATA_DIR)/fail39.json \
|
||||||
$(TEST_DATA_DIR)/fail40.json \
|
$(TEST_DATA_DIR)/fail40.json \
|
||||||
$(TEST_DATA_DIR)/fail41.json \
|
$(TEST_DATA_DIR)/fail41.json \
|
||||||
|
$(TEST_DATA_DIR)/fail42.json \
|
||||||
|
$(TEST_DATA_DIR)/fail44.json \
|
||||||
$(TEST_DATA_DIR)/fail3.json \
|
$(TEST_DATA_DIR)/fail3.json \
|
||||||
$(TEST_DATA_DIR)/fail4.json \
|
$(TEST_DATA_DIR)/fail4.json \
|
||||||
$(TEST_DATA_DIR)/fail5.json \
|
$(TEST_DATA_DIR)/fail5.json \
|
||||||
@ -88,6 +106,11 @@ TEST_FILES = \
|
|||||||
$(TEST_DATA_DIR)/pass2.json \
|
$(TEST_DATA_DIR)/pass2.json \
|
||||||
$(TEST_DATA_DIR)/pass3.json \
|
$(TEST_DATA_DIR)/pass3.json \
|
||||||
$(TEST_DATA_DIR)/round1.json \
|
$(TEST_DATA_DIR)/round1.json \
|
||||||
$(TEST_DATA_DIR)/round2.json
|
$(TEST_DATA_DIR)/round2.json \
|
||||||
|
$(TEST_DATA_DIR)/round3.json \
|
||||||
|
$(TEST_DATA_DIR)/round4.json \
|
||||||
|
$(TEST_DATA_DIR)/round5.json \
|
||||||
|
$(TEST_DATA_DIR)/round6.json \
|
||||||
|
$(TEST_DATA_DIR)/round7.json
|
||||||
|
|
||||||
EXTRA_DIST=$(TEST_FILES) $(GEN_SRCS)
|
EXTRA_DIST=$(TEST_FILES) $(GEN_SRCS)
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
|
|
||||||
UniValue
|
|
||||||
|
|
||||||
A universal value object, with JSON encoding (output) and decoding (input).
|
|
||||||
|
|
||||||
Built as a single dynamic RAII C++ object class, and no templates.
|
|
||||||
|
|
32
src/univalue/README.md
Normal file
32
src/univalue/README.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
# UniValue
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
A universal value class, with JSON encoding and decoding.
|
||||||
|
|
||||||
|
UniValue is an abstract data type that may be a null, boolean, string,
|
||||||
|
number, array container, or a key/value dictionary container, nested to
|
||||||
|
an arbitrary depth.
|
||||||
|
|
||||||
|
This class is aligned with the JSON standard, [RFC
|
||||||
|
7159](https://tools.ietf.org/html/rfc7159.html).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
This project is a standard GNU
|
||||||
|
[autotools](https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html)
|
||||||
|
project. Build and install instructions are available in the `INSTALL`
|
||||||
|
file provided with GNU autotools.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ ./autogen.sh
|
||||||
|
$ ./configure
|
||||||
|
$ make
|
||||||
|
```
|
||||||
|
|
||||||
|
## Design
|
||||||
|
|
||||||
|
UniValue provides a single dynamic RAII C++ object class,
|
||||||
|
and minimizes template use (contra json_spirit).
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
m4_define([libunivalue_major_version], [1])
|
m4_define([libunivalue_major_version], [1])
|
||||||
m4_define([libunivalue_minor_version], [1])
|
m4_define([libunivalue_minor_version], [1])
|
||||||
m4_define([libunivalue_micro_version], [2])
|
m4_define([libunivalue_micro_version], [3])
|
||||||
m4_define([libunivalue_interface_age], [2])
|
m4_define([libunivalue_interface_age], [3])
|
||||||
# If you need a modifier for the version number.
|
# If you need a modifier for the version number.
|
||||||
# Normally empty, but can be used to make "fixup" releases.
|
# Normally empty, but can be used to make "fixup" releases.
|
||||||
m4_define([libunivalue_extraversion], [])
|
m4_define([libunivalue_extraversion], [])
|
||||||
@ -14,7 +14,7 @@ m4_define([libunivalue_age], [m4_eval(libunivalue_binary_age - libunivalue_inter
|
|||||||
m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()])
|
m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()])
|
||||||
|
|
||||||
|
|
||||||
AC_INIT([univalue], [1.0.2],
|
AC_INIT([univalue], [1.0.3],
|
||||||
[http://github.com/jgarzik/univalue/])
|
[http://github.com/jgarzik/univalue/])
|
||||||
|
|
||||||
dnl make the compilation flags quiet unless V=1 is used
|
dnl make the compilation flags quiet unless V=1 is used
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#define __UNIVALUE_H__
|
#define __UNIVALUE_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -69,10 +70,11 @@ public:
|
|||||||
size_t size() const { return values.size(); }
|
size_t size() const { return values.size(); }
|
||||||
|
|
||||||
bool getBool() const { return isTrue(); }
|
bool getBool() const { return isTrue(); }
|
||||||
bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes);
|
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[](const std::string& key) const;
|
||||||
const UniValue& operator[](unsigned int index) const;
|
const UniValue& operator[](size_t index) const;
|
||||||
bool exists(const std::string& key) const { return (findKey(key) >= 0); }
|
bool exists(const std::string& key) const { size_t i; return findKey(key, i); }
|
||||||
|
|
||||||
bool isNull() const { return (typ == VNULL); }
|
bool isNull() const { return (typ == VNULL); }
|
||||||
bool isTrue() const { return (typ == VBOOL) && (val == "1"); }
|
bool isTrue() const { return (typ == VBOOL) && (val == "1"); }
|
||||||
@ -92,8 +94,25 @@ public:
|
|||||||
std::string s(val_);
|
std::string s(val_);
|
||||||
return push_back(s);
|
return push_back(s);
|
||||||
}
|
}
|
||||||
|
bool push_back(uint64_t val_) {
|
||||||
|
UniValue tmpVal(val_);
|
||||||
|
return push_back(tmpVal);
|
||||||
|
}
|
||||||
|
bool push_back(int64_t val_) {
|
||||||
|
UniValue tmpVal(val_);
|
||||||
|
return push_back(tmpVal);
|
||||||
|
}
|
||||||
|
bool push_back(int val_) {
|
||||||
|
UniValue tmpVal(val_);
|
||||||
|
return push_back(tmpVal);
|
||||||
|
}
|
||||||
|
bool push_back(double val_) {
|
||||||
|
UniValue tmpVal(val_);
|
||||||
|
return push_back(tmpVal);
|
||||||
|
}
|
||||||
bool push_backV(const std::vector<UniValue>& vec);
|
bool push_backV(const std::vector<UniValue>& vec);
|
||||||
|
|
||||||
|
void __pushKV(const std::string& key, const UniValue& val);
|
||||||
bool pushKV(const std::string& key, const UniValue& val);
|
bool pushKV(const std::string& key, const UniValue& val);
|
||||||
bool pushKV(const std::string& key, const std::string& val_) {
|
bool pushKV(const std::string& key, const std::string& val_) {
|
||||||
UniValue tmpVal(VSTR, val_);
|
UniValue tmpVal(VSTR, val_);
|
||||||
@ -124,9 +143,10 @@ public:
|
|||||||
std::string write(unsigned int prettyIndent = 0,
|
std::string write(unsigned int prettyIndent = 0,
|
||||||
unsigned int indentLevel = 0) const;
|
unsigned int indentLevel = 0) const;
|
||||||
|
|
||||||
bool read(const char *raw);
|
bool read(const char *raw, size_t len);
|
||||||
|
bool read(const char *raw) { return read(raw, strlen(raw)); }
|
||||||
bool read(const std::string& rawStr) {
|
bool read(const std::string& rawStr) {
|
||||||
return read(rawStr.c_str());
|
return read(rawStr.data(), rawStr.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -135,7 +155,7 @@ private:
|
|||||||
std::vector<std::string> keys;
|
std::vector<std::string> keys;
|
||||||
std::vector<UniValue> values;
|
std::vector<UniValue> values;
|
||||||
|
|
||||||
int findKey(const std::string& key) const;
|
bool findKey(const std::string& key, size_t& retIdx) const;
|
||||||
void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
|
void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
|
||||||
void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
|
void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
|
||||||
|
|
||||||
@ -240,7 +260,7 @@ enum jtokentype {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern enum jtokentype getJsonToken(std::string& tokenVal,
|
extern enum jtokentype getJsonToken(std::string& tokenVal,
|
||||||
unsigned int& consumed, const char *raw);
|
unsigned int& consumed, const char *raw, const char *end);
|
||||||
extern const char *uvTypeName(UniValue::VType t);
|
extern const char *uvTypeName(UniValue::VType t);
|
||||||
|
|
||||||
static inline bool jsonTokenIsValue(enum jtokentype jtt)
|
static inline bool jsonTokenIsValue(enum jtokentype jtt)
|
||||||
|
@ -4,75 +4,12 @@
|
|||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <limits>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "univalue.h"
|
#include "univalue.h"
|
||||||
|
|
||||||
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
|
|
||||||
return false;
|
|
||||||
if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ParseInt32(const std::string& str, int32_t *out)
|
|
||||||
{
|
|
||||||
if (!ParsePrechecks(str))
|
|
||||||
return false;
|
|
||||||
char *endp = NULL;
|
|
||||||
errno = 0; // strtol will not set errno if valid
|
|
||||||
long int n = strtol(str.c_str(), &endp, 10);
|
|
||||||
if(out) *out = (int32_t)n;
|
|
||||||
// Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
|
|
||||||
// we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
|
|
||||||
// platforms the size of these types may be different.
|
|
||||||
return endp && *endp == 0 && !errno &&
|
|
||||||
n >= std::numeric_limits<int32_t>::min() &&
|
|
||||||
n <= std::numeric_limits<int32_t>::max();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ParseInt64(const std::string& str, int64_t *out)
|
|
||||||
{
|
|
||||||
if (!ParsePrechecks(str))
|
|
||||||
return false;
|
|
||||||
char *endp = NULL;
|
|
||||||
errno = 0; // strtoll will not set errno if valid
|
|
||||||
long long int n = strtoll(str.c_str(), &endp, 10);
|
|
||||||
if(out) *out = (int64_t)n;
|
|
||||||
// Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow
|
|
||||||
// we still have to check that the returned value is within the range of an *int64_t*.
|
|
||||||
return endp && *endp == 0 && !errno &&
|
|
||||||
n >= std::numeric_limits<int64_t>::min() &&
|
|
||||||
n <= std::numeric_limits<int64_t>::max();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
return text.eof() && !text.fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
const UniValue NullUniValue;
|
const UniValue NullUniValue;
|
||||||
@ -104,7 +41,7 @@ static bool validNumStr(const string& s)
|
|||||||
{
|
{
|
||||||
string tokenVal;
|
string tokenVal;
|
||||||
unsigned int consumed;
|
unsigned int consumed;
|
||||||
enum jtokentype tt = getJsonToken(tokenVal, consumed, s.c_str());
|
enum jtokentype tt = getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size());
|
||||||
return (tt == JTOK_NUMBER);
|
return (tt == JTOK_NUMBER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,13 +126,22 @@ bool UniValue::push_backV(const std::vector<UniValue>& vec)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UniValue::__pushKV(const std::string& key, const UniValue& val_)
|
||||||
|
{
|
||||||
|
keys.push_back(key);
|
||||||
|
values.push_back(val_);
|
||||||
|
}
|
||||||
|
|
||||||
bool UniValue::pushKV(const std::string& key, const UniValue& val_)
|
bool UniValue::pushKV(const std::string& key, const UniValue& val_)
|
||||||
{
|
{
|
||||||
if (typ != VOBJ)
|
if (typ != VOBJ)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
keys.push_back(key);
|
size_t idx;
|
||||||
values.push_back(val_);
|
if (findKey(key, idx))
|
||||||
|
values[idx] = val_;
|
||||||
|
else
|
||||||
|
__pushKV(key, val_);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,30 +150,43 @@ bool UniValue::pushKVs(const UniValue& obj)
|
|||||||
if (typ != VOBJ || obj.typ != VOBJ)
|
if (typ != VOBJ || obj.typ != VOBJ)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < obj.keys.size(); i++) {
|
for (size_t i = 0; i < obj.keys.size(); i++)
|
||||||
keys.push_back(obj.keys[i]);
|
__pushKV(obj.keys[i], obj.values.at(i));
|
||||||
values.push_back(obj.values.at(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int UniValue::findKey(const std::string& key) const
|
void UniValue::getObjMap(std::map<std::string,UniValue>& kv) const
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < keys.size(); i++) {
|
if (typ != VOBJ)
|
||||||
if (keys[i] == key)
|
return;
|
||||||
return (int) i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
kv.clear();
|
||||||
|
for (size_t i = 0; i < keys.size(); i++)
|
||||||
|
kv[keys[i]] = values[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t)
|
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
|
||||||
|
{
|
||||||
|
if (typ != VOBJ)
|
||||||
|
return false;
|
||||||
|
|
||||||
for (std::map<std::string,UniValue::VType>::const_iterator it = t.begin();
|
for (std::map<std::string,UniValue::VType>::const_iterator it = t.begin();
|
||||||
it != t.end(); ++it) {
|
it != t.end(); ++it) {
|
||||||
int idx = findKey(it->first);
|
size_t idx = 0;
|
||||||
if (idx < 0)
|
if (!findKey(it->first, idx))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (values.at(idx).getType() != it->second)
|
if (values.at(idx).getType() != it->second)
|
||||||
@ -242,14 +201,14 @@ const UniValue& UniValue::operator[](const std::string& key) const
|
|||||||
if (typ != VOBJ)
|
if (typ != VOBJ)
|
||||||
return NullUniValue;
|
return NullUniValue;
|
||||||
|
|
||||||
int index = findKey(key);
|
size_t index = 0;
|
||||||
if (index < 0)
|
if (!findKey(key, index))
|
||||||
return NullUniValue;
|
return NullUniValue;
|
||||||
|
|
||||||
return values.at(index);
|
return values.at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
const UniValue& UniValue::operator[](unsigned int index) const
|
const UniValue& UniValue::operator[](size_t index) const
|
||||||
{
|
{
|
||||||
if (typ != VOBJ && typ != VARR)
|
if (typ != VOBJ && typ != VARR)
|
||||||
return NullUniValue;
|
return NullUniValue;
|
||||||
@ -283,75 +242,3 @@ const UniValue& find_value(const UniValue& obj, const std::string& name)
|
|||||||
return NullUniValue;
|
return NullUniValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string>& UniValue::getKeys() const
|
|
||||||
{
|
|
||||||
if (typ != VOBJ)
|
|
||||||
throw std::runtime_error("JSON value is not an object as expected");
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UniValue::get_bool() const
|
|
||||||
{
|
|
||||||
if (typ != VBOOL)
|
|
||||||
throw std::runtime_error("JSON value is not a boolean as expected");
|
|
||||||
return getBool();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& UniValue::get_str() const
|
|
||||||
{
|
|
||||||
if (typ != VSTR)
|
|
||||||
throw std::runtime_error("JSON value is not a string as expected");
|
|
||||||
return getValStr();
|
|
||||||
}
|
|
||||||
|
|
||||||
int UniValue::get_int() const
|
|
||||||
{
|
|
||||||
if (typ != VNUM)
|
|
||||||
throw std::runtime_error("JSON value is not an integer as expected");
|
|
||||||
int32_t retval;
|
|
||||||
if (!ParseInt32(getValStr(), &retval))
|
|
||||||
throw std::runtime_error("JSON integer out of range");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t UniValue::get_int64() const
|
|
||||||
{
|
|
||||||
if (typ != VNUM)
|
|
||||||
throw std::runtime_error("JSON value is not an integer as expected");
|
|
||||||
int64_t retval;
|
|
||||||
if (!ParseInt64(getValStr(), &retval))
|
|
||||||
throw std::runtime_error("JSON integer out of range");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
double UniValue::get_real() const
|
|
||||||
{
|
|
||||||
if (typ != VNUM)
|
|
||||||
throw std::runtime_error("JSON value is not a number as expected");
|
|
||||||
double retval;
|
|
||||||
if (!ParseDouble(getValStr(), &retval))
|
|
||||||
throw std::runtime_error("JSON double out of range");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
const UniValue& UniValue::get_obj() const
|
|
||||||
{
|
|
||||||
if (typ != VOBJ)
|
|
||||||
throw std::runtime_error("JSON value is not an object as expected");
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const UniValue& UniValue::get_array() const
|
|
||||||
{
|
|
||||||
if (typ != VARR)
|
|
||||||
throw std::runtime_error("JSON value is not an array as expected");
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
147
src/univalue/lib/univalue_get.cpp
Normal file
147
src/univalue/lib/univalue_get.cpp
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
// Copyright 2014 BitPay Inc.
|
||||||
|
// Copyright 2015 Bitcoin Core Developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
#include <limits>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "univalue.h"
|
||||||
|
|
||||||
|
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
|
||||||
|
return false;
|
||||||
|
if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParseInt32(const std::string& str, int32_t *out)
|
||||||
|
{
|
||||||
|
if (!ParsePrechecks(str))
|
||||||
|
return false;
|
||||||
|
char *endp = NULL;
|
||||||
|
errno = 0; // strtol will not set errno if valid
|
||||||
|
long int n = strtol(str.c_str(), &endp, 10);
|
||||||
|
if(out) *out = (int32_t)n;
|
||||||
|
// Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
|
||||||
|
// we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
|
||||||
|
// platforms the size of these types may be different.
|
||||||
|
return endp && *endp == 0 && !errno &&
|
||||||
|
n >= std::numeric_limits<int32_t>::min() &&
|
||||||
|
n <= std::numeric_limits<int32_t>::max();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParseInt64(const std::string& str, int64_t *out)
|
||||||
|
{
|
||||||
|
if (!ParsePrechecks(str))
|
||||||
|
return false;
|
||||||
|
char *endp = NULL;
|
||||||
|
errno = 0; // strtoll will not set errno if valid
|
||||||
|
long long int n = strtoll(str.c_str(), &endp, 10);
|
||||||
|
if(out) *out = (int64_t)n;
|
||||||
|
// Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow
|
||||||
|
// we still have to check that the returned value is within the range of an *int64_t*.
|
||||||
|
return endp && *endp == 0 && !errno &&
|
||||||
|
n >= std::numeric_limits<int64_t>::min() &&
|
||||||
|
n <= std::numeric_limits<int64_t>::max();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
return text.eof() && !text.fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string>& UniValue::getKeys() const
|
||||||
|
{
|
||||||
|
if (typ != VOBJ)
|
||||||
|
throw std::runtime_error("JSON value is not an object as expected");
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UniValue::get_bool() const
|
||||||
|
{
|
||||||
|
if (typ != VBOOL)
|
||||||
|
throw std::runtime_error("JSON value is not a boolean as expected");
|
||||||
|
return getBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& UniValue::get_str() const
|
||||||
|
{
|
||||||
|
if (typ != VSTR)
|
||||||
|
throw std::runtime_error("JSON value is not a string as expected");
|
||||||
|
return getValStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
int UniValue::get_int() const
|
||||||
|
{
|
||||||
|
if (typ != VNUM)
|
||||||
|
throw std::runtime_error("JSON value is not an integer as expected");
|
||||||
|
int32_t retval;
|
||||||
|
if (!ParseInt32(getValStr(), &retval))
|
||||||
|
throw std::runtime_error("JSON integer out of range");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t UniValue::get_int64() const
|
||||||
|
{
|
||||||
|
if (typ != VNUM)
|
||||||
|
throw std::runtime_error("JSON value is not an integer as expected");
|
||||||
|
int64_t retval;
|
||||||
|
if (!ParseInt64(getValStr(), &retval))
|
||||||
|
throw std::runtime_error("JSON integer out of range");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
double UniValue::get_real() const
|
||||||
|
{
|
||||||
|
if (typ != VNUM)
|
||||||
|
throw std::runtime_error("JSON value is not a number as expected");
|
||||||
|
double retval;
|
||||||
|
if (!ParseDouble(getValStr(), &retval))
|
||||||
|
throw std::runtime_error("JSON double out of range");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UniValue& UniValue::get_obj() const
|
||||||
|
{
|
||||||
|
if (typ != VOBJ)
|
||||||
|
throw std::runtime_error("JSON value is not an object as expected");
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UniValue& UniValue::get_array() const
|
||||||
|
{
|
||||||
|
if (typ != VARR)
|
||||||
|
throw std::runtime_error("JSON value is not an array as expected");
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
@ -43,21 +43,21 @@ static const char *hatoui(const char *first, const char *last,
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
|
enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
|
||||||
const char *raw)
|
const char *raw, const char *end)
|
||||||
{
|
{
|
||||||
tokenVal.clear();
|
tokenVal.clear();
|
||||||
consumed = 0;
|
consumed = 0;
|
||||||
|
|
||||||
const char *rawStart = raw;
|
const char *rawStart = raw;
|
||||||
|
|
||||||
while ((*raw) && (json_isspace(*raw))) // skip whitespace
|
while (raw < end && (json_isspace(*raw))) // skip whitespace
|
||||||
raw++;
|
raw++;
|
||||||
|
|
||||||
switch (*raw) {
|
if (raw >= end)
|
||||||
|
|
||||||
case 0:
|
|
||||||
return JTOK_NONE;
|
return JTOK_NONE;
|
||||||
|
|
||||||
|
switch (*raw) {
|
||||||
|
|
||||||
case '{':
|
case '{':
|
||||||
raw++;
|
raw++;
|
||||||
consumed = (raw - rawStart);
|
consumed = (raw - rawStart);
|
||||||
@ -127,40 +127,40 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
|
|||||||
numStr += *raw; // copy first char
|
numStr += *raw; // copy first char
|
||||||
raw++;
|
raw++;
|
||||||
|
|
||||||
if ((*first == '-') && (!json_isdigit(*raw)))
|
if ((*first == '-') && (raw < end) && (!json_isdigit(*raw)))
|
||||||
return JTOK_ERR;
|
return JTOK_ERR;
|
||||||
|
|
||||||
while ((*raw) && json_isdigit(*raw)) { // copy digits
|
while (raw < end && json_isdigit(*raw)) { // copy digits
|
||||||
numStr += *raw;
|
numStr += *raw;
|
||||||
raw++;
|
raw++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// part 2: frac
|
// part 2: frac
|
||||||
if (*raw == '.') {
|
if (raw < end && *raw == '.') {
|
||||||
numStr += *raw; // copy .
|
numStr += *raw; // copy .
|
||||||
raw++;
|
raw++;
|
||||||
|
|
||||||
if (!json_isdigit(*raw))
|
if (raw >= end || !json_isdigit(*raw))
|
||||||
return JTOK_ERR;
|
return JTOK_ERR;
|
||||||
while ((*raw) && json_isdigit(*raw)) { // copy digits
|
while (raw < end && json_isdigit(*raw)) { // copy digits
|
||||||
numStr += *raw;
|
numStr += *raw;
|
||||||
raw++;
|
raw++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// part 3: exp
|
// part 3: exp
|
||||||
if (*raw == 'e' || *raw == 'E') {
|
if (raw < end && (*raw == 'e' || *raw == 'E')) {
|
||||||
numStr += *raw; // copy E
|
numStr += *raw; // copy E
|
||||||
raw++;
|
raw++;
|
||||||
|
|
||||||
if (*raw == '-' || *raw == '+') { // copy +/-
|
if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/-
|
||||||
numStr += *raw;
|
numStr += *raw;
|
||||||
raw++;
|
raw++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!json_isdigit(*raw))
|
if (raw >= end || !json_isdigit(*raw))
|
||||||
return JTOK_ERR;
|
return JTOK_ERR;
|
||||||
while ((*raw) && json_isdigit(*raw)) { // copy digits
|
while (raw < end && json_isdigit(*raw)) { // copy digits
|
||||||
numStr += *raw;
|
numStr += *raw;
|
||||||
raw++;
|
raw++;
|
||||||
}
|
}
|
||||||
@ -177,13 +177,16 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
|
|||||||
string valStr;
|
string valStr;
|
||||||
JSONUTF8StringFilter writer(valStr);
|
JSONUTF8StringFilter writer(valStr);
|
||||||
|
|
||||||
while (*raw) {
|
while (true) {
|
||||||
if ((unsigned char)*raw < 0x20)
|
if (raw >= end || (unsigned char)*raw < 0x20)
|
||||||
return JTOK_ERR;
|
return JTOK_ERR;
|
||||||
|
|
||||||
else if (*raw == '\\') {
|
else if (*raw == '\\') {
|
||||||
raw++; // skip backslash
|
raw++; // skip backslash
|
||||||
|
|
||||||
|
if (raw >= end)
|
||||||
|
return JTOK_ERR;
|
||||||
|
|
||||||
switch (*raw) {
|
switch (*raw) {
|
||||||
case '"': writer.push_back('\"'); break;
|
case '"': writer.push_back('\"'); break;
|
||||||
case '\\': writer.push_back('\\'); break;
|
case '\\': writer.push_back('\\'); break;
|
||||||
@ -196,7 +199,8 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
|
|||||||
|
|
||||||
case 'u': {
|
case 'u': {
|
||||||
unsigned int codepoint;
|
unsigned int codepoint;
|
||||||
if (hatoui(raw + 1, raw + 1 + 4, codepoint) !=
|
if (raw + 1 + 4 >= end ||
|
||||||
|
hatoui(raw + 1, raw + 1 + 4, codepoint) !=
|
||||||
raw + 1 + 4)
|
raw + 1 + 4)
|
||||||
return JTOK_ERR;
|
return JTOK_ERR;
|
||||||
writer.push_back_u(codepoint);
|
writer.push_back_u(codepoint);
|
||||||
@ -246,7 +250,7 @@ enum expect_bits {
|
|||||||
#define setExpect(bit) (expectMask |= EXP_##bit)
|
#define setExpect(bit) (expectMask |= EXP_##bit)
|
||||||
#define clearExpect(bit) (expectMask &= ~EXP_##bit)
|
#define clearExpect(bit) (expectMask &= ~EXP_##bit)
|
||||||
|
|
||||||
bool UniValue::read(const char *raw)
|
bool UniValue::read(const char *raw, size_t size)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
@ -257,10 +261,11 @@ bool UniValue::read(const char *raw)
|
|||||||
unsigned int consumed;
|
unsigned int consumed;
|
||||||
enum jtokentype tok = JTOK_NONE;
|
enum jtokentype tok = JTOK_NONE;
|
||||||
enum jtokentype last_tok = JTOK_NONE;
|
enum jtokentype last_tok = JTOK_NONE;
|
||||||
|
const char* end = raw + size;
|
||||||
do {
|
do {
|
||||||
last_tok = tok;
|
last_tok = tok;
|
||||||
|
|
||||||
tok = getJsonToken(tokenVal, consumed, raw);
|
tok = getJsonToken(tokenVal, consumed, raw, end);
|
||||||
if (tok == JTOK_NONE || tok == JTOK_ERR)
|
if (tok == JTOK_NONE || tok == JTOK_ERR)
|
||||||
return false;
|
return false;
|
||||||
raw += consumed;
|
raw += consumed;
|
||||||
@ -371,9 +376,6 @@ bool UniValue::read(const char *raw)
|
|||||||
case JTOK_KW_NULL:
|
case JTOK_KW_NULL:
|
||||||
case JTOK_KW_TRUE:
|
case JTOK_KW_TRUE:
|
||||||
case JTOK_KW_FALSE: {
|
case JTOK_KW_FALSE: {
|
||||||
if (!stack.size())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
UniValue tmpVal;
|
UniValue tmpVal;
|
||||||
switch (tok) {
|
switch (tok) {
|
||||||
case JTOK_KW_NULL:
|
case JTOK_KW_NULL:
|
||||||
@ -388,6 +390,11 @@ bool UniValue::read(const char *raw)
|
|||||||
default: /* impossible */ break;
|
default: /* impossible */ break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!stack.size()) {
|
||||||
|
*this = tmpVal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
UniValue *top = stack.back();
|
UniValue *top = stack.back();
|
||||||
top->values.push_back(tmpVal);
|
top->values.push_back(tmpVal);
|
||||||
|
|
||||||
@ -396,10 +403,12 @@ bool UniValue::read(const char *raw)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case JTOK_NUMBER: {
|
case JTOK_NUMBER: {
|
||||||
if (!stack.size())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
UniValue tmpVal(VNUM, tokenVal);
|
UniValue tmpVal(VNUM, tokenVal);
|
||||||
|
if (!stack.size()) {
|
||||||
|
*this = tmpVal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
UniValue *top = stack.back();
|
UniValue *top = stack.back();
|
||||||
top->values.push_back(tmpVal);
|
top->values.push_back(tmpVal);
|
||||||
|
|
||||||
@ -408,17 +417,18 @@ bool UniValue::read(const char *raw)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case JTOK_STRING: {
|
case JTOK_STRING: {
|
||||||
if (!stack.size())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
UniValue *top = stack.back();
|
|
||||||
|
|
||||||
if (expect(OBJ_NAME)) {
|
if (expect(OBJ_NAME)) {
|
||||||
|
UniValue *top = stack.back();
|
||||||
top->keys.push_back(tokenVal);
|
top->keys.push_back(tokenVal);
|
||||||
clearExpect(OBJ_NAME);
|
clearExpect(OBJ_NAME);
|
||||||
setExpect(COLON);
|
setExpect(COLON);
|
||||||
} else {
|
} else {
|
||||||
UniValue tmpVal(VSTR, tokenVal);
|
UniValue tmpVal(VSTR, tokenVal);
|
||||||
|
if (!stack.size()) {
|
||||||
|
*this = tmpVal;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
UniValue *top = stack.back();
|
||||||
top->values.push_back(tmpVal);
|
top->values.push_back(tmpVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,7 +442,7 @@ bool UniValue::read(const char *raw)
|
|||||||
} while (!stack.empty ());
|
} while (!stack.empty ());
|
||||||
|
|
||||||
/* Check that nothing follows the initial construct (parsed above). */
|
/* Check that nothing follows the initial construct (parsed above). */
|
||||||
tok = getJsonToken(tokenVal, consumed, raw);
|
tok = getJsonToken(tokenVal, consumed, raw, end);
|
||||||
if (tok != JTOK_NONE)
|
if (tok != JTOK_NONE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -42,20 +42,20 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Write codepoint directly, possibly collating surrogate pairs
|
// Write codepoint directly, possibly collating surrogate pairs
|
||||||
void push_back_u(unsigned int codepoint)
|
void push_back_u(unsigned int codepoint_)
|
||||||
{
|
{
|
||||||
// Only accept full codepoints in open state
|
// Only accept full codepoints in open state
|
||||||
if (state)
|
if (state)
|
||||||
is_valid = false;
|
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
|
if (surpair) // Two subsequent surrogate pair openers - fail
|
||||||
is_valid = false;
|
is_valid = false;
|
||||||
else
|
else
|
||||||
surpair = codepoint;
|
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
|
if (surpair) { // Open surrogate pair, expect second half
|
||||||
// Compute code point from UTF-16 surrogate pair
|
// 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;
|
surpair = 0;
|
||||||
} else // First half of surrogate pair not followed by second
|
} else // First half of surrogate pair not followed by second
|
||||||
is_valid = false;
|
is_valid = false;
|
||||||
@ -63,7 +63,7 @@ public:
|
|||||||
if (surpair) // First half of surrogate pair not followed by second
|
if (surpair) // First half of surrogate pair not followed by second
|
||||||
is_valid = false;
|
is_valid = false;
|
||||||
else
|
else
|
||||||
append_codepoint(codepoint);
|
append_codepoint(codepoint_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check that we're in a state where the string can be ended
|
// Check that we're in a state where the string can be ended
|
||||||
@ -91,22 +91,22 @@ private:
|
|||||||
// Two subsequent \u.... may have to be replaced with one actual codepoint.
|
// Two subsequent \u.... may have to be replaced with one actual codepoint.
|
||||||
unsigned int surpair; // First of UTF-16 surrogate pair
|
unsigned int surpair; // First of UTF-16 surrogate pair
|
||||||
|
|
||||||
void append_codepoint(unsigned int codepoint)
|
void append_codepoint(unsigned int codepoint_)
|
||||||
{
|
{
|
||||||
if (codepoint <= 0x7f)
|
if (codepoint_ <= 0x7f)
|
||||||
str.push_back((char)codepoint);
|
str.push_back((char)codepoint_);
|
||||||
else if (codepoint <= 0x7FF) {
|
else if (codepoint_ <= 0x7FF) {
|
||||||
str.push_back((char)(0xC0 | (codepoint >> 6)));
|
str.push_back((char)(0xC0 | (codepoint_ >> 6)));
|
||||||
str.push_back((char)(0x80 | (codepoint & 0x3F)));
|
str.push_back((char)(0x80 | (codepoint_ & 0x3F)));
|
||||||
} else if (codepoint <= 0xFFFF) {
|
} else if (codepoint_ <= 0xFFFF) {
|
||||||
str.push_back((char)(0xE0 | (codepoint >> 12)));
|
str.push_back((char)(0xE0 | (codepoint_ >> 12)));
|
||||||
str.push_back((char)(0x80 | ((codepoint >> 6) & 0x3F)));
|
str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F)));
|
||||||
str.push_back((char)(0x80 | (codepoint & 0x3F)));
|
str.push_back((char)(0x80 | (codepoint_ & 0x3F)));
|
||||||
} else if (codepoint <= 0x1FFFFF) {
|
} else if (codepoint_ <= 0x1FFFFF) {
|
||||||
str.push_back((char)(0xF0 | (codepoint >> 18)));
|
str.push_back((char)(0xF0 | (codepoint_ >> 18)));
|
||||||
str.push_back((char)(0x80 | ((codepoint >> 12) & 0x3F)));
|
str.push_back((char)(0x80 | ((codepoint_ >> 12) & 0x3F)));
|
||||||
str.push_back((char)(0x80 | ((codepoint >> 6) & 0x3F)));
|
str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F)));
|
||||||
str.push_back((char)(0x80 | (codepoint & 0x3F)));
|
str.push_back((char)(0x80 | (codepoint_ & 0x3F)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -79,8 +79,6 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s
|
|||||||
s += values[i].write(prettyIndent, indentLevel + 1);
|
s += values[i].write(prettyIndent, indentLevel + 1);
|
||||||
if (i != (values.size() - 1)) {
|
if (i != (values.size() - 1)) {
|
||||||
s += ",";
|
s += ",";
|
||||||
if (prettyIndent)
|
|
||||||
s += " ";
|
|
||||||
}
|
}
|
||||||
if (prettyIndent)
|
if (prettyIndent)
|
||||||
s += "\n";
|
s += "\n";
|
||||||
|
4
src/univalue/test/.gitignore
vendored
4
src/univalue/test/.gitignore
vendored
@ -1,4 +1,8 @@
|
|||||||
|
|
||||||
|
object
|
||||||
unitester
|
unitester
|
||||||
|
test_json
|
||||||
|
no_nul
|
||||||
|
|
||||||
*.trs
|
*.trs
|
||||||
*.log
|
*.log
|
||||||
|
@ -1 +1 @@
|
|||||||
"A JSON payload should be an object or array, not a string."
|
"This is a string that never ends, yes it goes on and on, my friends.
|
||||||
|
BIN
src/univalue/test/fail42.json
Normal file
BIN
src/univalue/test/fail42.json
Normal file
Binary file not shown.
1
src/univalue/test/fail44.json
Normal file
1
src/univalue/test/fail44.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
"This file ends without a newline or close-quote.
|
8
src/univalue/test/no_nul.cpp
Normal file
8
src/univalue/test/no_nul.cpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include "univalue.h"
|
||||||
|
|
||||||
|
int main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char buf[] = "___[1,2,3]___";
|
||||||
|
UniValue val;
|
||||||
|
return val.read(buf + 3, 7) ? 0 : 1;
|
||||||
|
}
|
395
src/univalue/test/object.cpp
Normal file
395
src/univalue/test/object.cpp
Normal file
@ -0,0 +1,395 @@
|
|||||||
|
// 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 http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <cassert>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <univalue.h>
|
||||||
|
|
||||||
|
#define BOOST_FIXTURE_TEST_SUITE(a, b)
|
||||||
|
#define BOOST_AUTO_TEST_CASE(funcName) void funcName()
|
||||||
|
#define BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
#define BOOST_CHECK(expr) assert(expr)
|
||||||
|
#define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2))
|
||||||
|
#define BOOST_CHECK_THROW(stmt, excMatch) { \
|
||||||
|
try { \
|
||||||
|
(stmt); \
|
||||||
|
} catch (excMatch & e) { \
|
||||||
|
} catch (...) { \
|
||||||
|
assert(0); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#define BOOST_CHECK_NO_THROW(stmt) { \
|
||||||
|
try { \
|
||||||
|
(stmt); \
|
||||||
|
} catch (...) { \
|
||||||
|
assert(0); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(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;
|
||||||
|
BOOST_CHECK(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");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(univalue_typecheck)
|
||||||
|
{
|
||||||
|
UniValue v1;
|
||||||
|
BOOST_CHECK(v1.setNumStr("1"));
|
||||||
|
BOOST_CHECK(v1.isNum());
|
||||||
|
BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error);
|
||||||
|
|
||||||
|
UniValue v2;
|
||||||
|
BOOST_CHECK(v2.setBool(true));
|
||||||
|
BOOST_CHECK_EQUAL(v2.get_bool(), true);
|
||||||
|
BOOST_CHECK_THROW(v2.get_int(), std::runtime_error);
|
||||||
|
|
||||||
|
UniValue v3;
|
||||||
|
BOOST_CHECK(v3.setNumStr("32482348723847471234"));
|
||||||
|
BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error);
|
||||||
|
BOOST_CHECK(v3.setNumStr("1000"));
|
||||||
|
BOOST_CHECK_EQUAL(v3.get_int64(), 1000);
|
||||||
|
|
||||||
|
UniValue v4;
|
||||||
|
BOOST_CHECK(v4.setNumStr("2147483648"));
|
||||||
|
BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648);
|
||||||
|
BOOST_CHECK_THROW(v4.get_int(), std::runtime_error);
|
||||||
|
BOOST_CHECK(v4.setNumStr("1000"));
|
||||||
|
BOOST_CHECK_EQUAL(v4.get_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].get_int(), std::runtime_error);
|
||||||
|
BOOST_CHECK_EQUAL(vals[0].get_bool(), true);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(vals[1].get_int(), 10);
|
||||||
|
BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(univalue_set)
|
||||||
|
{
|
||||||
|
UniValue v(UniValue::VSTR, "foo");
|
||||||
|
v.clear();
|
||||||
|
BOOST_CHECK(v.isNull());
|
||||||
|
BOOST_CHECK_EQUAL(v.getValStr(), "");
|
||||||
|
|
||||||
|
BOOST_CHECK(v.setObject());
|
||||||
|
BOOST_CHECK(v.isObject());
|
||||||
|
BOOST_CHECK_EQUAL(v.size(), 0);
|
||||||
|
BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);
|
||||||
|
BOOST_CHECK(v.empty());
|
||||||
|
|
||||||
|
BOOST_CHECK(v.setArray());
|
||||||
|
BOOST_CHECK(v.isArray());
|
||||||
|
BOOST_CHECK_EQUAL(v.size(), 0);
|
||||||
|
|
||||||
|
BOOST_CHECK(v.setStr("zum"));
|
||||||
|
BOOST_CHECK(v.isStr());
|
||||||
|
BOOST_CHECK_EQUAL(v.getValStr(), "zum");
|
||||||
|
|
||||||
|
BOOST_CHECK(v.setFloat(-1.01));
|
||||||
|
BOOST_CHECK(v.isNum());
|
||||||
|
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
|
||||||
|
|
||||||
|
BOOST_CHECK(v.setInt((int)1023));
|
||||||
|
BOOST_CHECK(v.isNum());
|
||||||
|
BOOST_CHECK_EQUAL(v.getValStr(), "1023");
|
||||||
|
|
||||||
|
BOOST_CHECK(v.setInt((int64_t)-1023LL));
|
||||||
|
BOOST_CHECK(v.isNum());
|
||||||
|
BOOST_CHECK_EQUAL(v.getValStr(), "-1023");
|
||||||
|
|
||||||
|
BOOST_CHECK(v.setInt((uint64_t)1023ULL));
|
||||||
|
BOOST_CHECK(v.isNum());
|
||||||
|
BOOST_CHECK_EQUAL(v.getValStr(), "1023");
|
||||||
|
|
||||||
|
BOOST_CHECK(v.setNumStr("-688"));
|
||||||
|
BOOST_CHECK(v.isNum());
|
||||||
|
BOOST_CHECK_EQUAL(v.getValStr(), "-688");
|
||||||
|
|
||||||
|
BOOST_CHECK(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.getBool(), false);
|
||||||
|
|
||||||
|
BOOST_CHECK(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.getBool(), true);
|
||||||
|
|
||||||
|
BOOST_CHECK(!v.setNumStr("zombocom"));
|
||||||
|
|
||||||
|
BOOST_CHECK(v.setNull());
|
||||||
|
BOOST_CHECK(v.isNull());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(univalue_array)
|
||||||
|
{
|
||||||
|
UniValue arr(UniValue::VARR);
|
||||||
|
|
||||||
|
UniValue v((int64_t)1023LL);
|
||||||
|
BOOST_CHECK(arr.push_back(v));
|
||||||
|
|
||||||
|
std::string vStr("zippy");
|
||||||
|
BOOST_CHECK(arr.push_back(vStr));
|
||||||
|
|
||||||
|
const char *s = "pippy";
|
||||||
|
BOOST_CHECK(arr.push_back(s));
|
||||||
|
|
||||||
|
std::vector<UniValue> vec;
|
||||||
|
v.setStr("boing");
|
||||||
|
vec.push_back(v);
|
||||||
|
|
||||||
|
v.setStr("going");
|
||||||
|
vec.push_back(v);
|
||||||
|
|
||||||
|
BOOST_CHECK(arr.push_backV(vec));
|
||||||
|
|
||||||
|
BOOST_CHECK(arr.push_back((uint64_t) 400ULL));
|
||||||
|
BOOST_CHECK(arr.push_back((int64_t) -400LL));
|
||||||
|
BOOST_CHECK(arr.push_back((int) -401));
|
||||||
|
BOOST_CHECK(arr.push_back(-40.1));
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(arr.empty(), false);
|
||||||
|
BOOST_CHECK_EQUAL(arr.size(), 9);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023");
|
||||||
|
BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy");
|
||||||
|
BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy");
|
||||||
|
BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing");
|
||||||
|
BOOST_CHECK_EQUAL(arr[4].getValStr(), "going");
|
||||||
|
BOOST_CHECK_EQUAL(arr[5].getValStr(), "400");
|
||||||
|
BOOST_CHECK_EQUAL(arr[6].getValStr(), "-400");
|
||||||
|
BOOST_CHECK_EQUAL(arr[7].getValStr(), "-401");
|
||||||
|
BOOST_CHECK_EQUAL(arr[8].getValStr(), "-40.1");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(arr[999].getValStr(), "");
|
||||||
|
|
||||||
|
arr.clear();
|
||||||
|
BOOST_CHECK(arr.empty());
|
||||||
|
BOOST_CHECK_EQUAL(arr.size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(univalue_object)
|
||||||
|
{
|
||||||
|
UniValue obj(UniValue::VOBJ);
|
||||||
|
std::string strKey, strVal;
|
||||||
|
UniValue v;
|
||||||
|
|
||||||
|
strKey = "age";
|
||||||
|
v.setInt(100);
|
||||||
|
BOOST_CHECK(obj.pushKV(strKey, v));
|
||||||
|
|
||||||
|
strKey = "first";
|
||||||
|
strVal = "John";
|
||||||
|
BOOST_CHECK(obj.pushKV(strKey, strVal));
|
||||||
|
|
||||||
|
strKey = "last";
|
||||||
|
const char *cVal = "Smith";
|
||||||
|
BOOST_CHECK(obj.pushKV(strKey, cVal));
|
||||||
|
|
||||||
|
strKey = "distance";
|
||||||
|
BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25));
|
||||||
|
|
||||||
|
strKey = "time";
|
||||||
|
BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600));
|
||||||
|
|
||||||
|
strKey = "calories";
|
||||||
|
BOOST_CHECK(obj.pushKV(strKey, (int) 12));
|
||||||
|
|
||||||
|
strKey = "temperature";
|
||||||
|
BOOST_CHECK(obj.pushKV(strKey, (double) 90.012));
|
||||||
|
|
||||||
|
UniValue obj2(UniValue::VOBJ);
|
||||||
|
BOOST_CHECK(obj2.pushKV("cat1", 9000));
|
||||||
|
BOOST_CHECK(obj2.pushKV("cat2", 12345));
|
||||||
|
|
||||||
|
BOOST_CHECK(obj.pushKVs(obj2));
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(obj.empty(), false);
|
||||||
|
BOOST_CHECK_EQUAL(obj.size(), 9);
|
||||||
|
|
||||||
|
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["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("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["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);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(obj.setObject(), true);
|
||||||
|
UniValue uv;
|
||||||
|
uv.setInt(42);
|
||||||
|
obj.__pushKV("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;
|
||||||
|
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\"}}]";
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(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());
|
||||||
|
|
||||||
|
/* 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"));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
|
int main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
univalue_constructor();
|
||||||
|
univalue_typecheck();
|
||||||
|
univalue_set();
|
||||||
|
univalue_array();
|
||||||
|
univalue_object();
|
||||||
|
univalue_readwrite();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
1
src/univalue/test/round3.json
Normal file
1
src/univalue/test/round3.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
"abcdefghijklmnopqrstuvwxyz"
|
1
src/univalue/test/round4.json
Normal file
1
src/univalue/test/round4.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
7
|
1
src/univalue/test/round5.json
Normal file
1
src/univalue/test/round5.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
true
|
1
src/univalue/test/round6.json
Normal file
1
src/univalue/test/round6.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
false
|
1
src/univalue/test/round7.json
Normal file
1
src/univalue/test/round7.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
null
|
24
src/univalue/test/test_json.cpp
Normal file
24
src/univalue/test/test_json.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 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 <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include "univalue.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -113,6 +113,8 @@ static const char *filenames[] = {
|
|||||||
"fail39.json", // invalid unicode: only second half of surrogate pair
|
"fail39.json", // invalid unicode: only second half of surrogate pair
|
||||||
"fail40.json", // invalid unicode: broken UTF-8
|
"fail40.json", // invalid unicode: broken UTF-8
|
||||||
"fail41.json", // invalid unicode: unfinished UTF-8
|
"fail41.json", // invalid unicode: unfinished UTF-8
|
||||||
|
"fail42.json", // valid json with garbage following a nul byte
|
||||||
|
"fail44.json", // unterminated string
|
||||||
"fail3.json",
|
"fail3.json",
|
||||||
"fail4.json", // extra comma
|
"fail4.json", // extra comma
|
||||||
"fail5.json",
|
"fail5.json",
|
||||||
@ -125,6 +127,11 @@ static const char *filenames[] = {
|
|||||||
"pass3.json",
|
"pass3.json",
|
||||||
"round1.json", // round-trip test
|
"round1.json", // round-trip test
|
||||||
"round2.json", // unicode
|
"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
|
// Test \u handling
|
||||||
|
Loading…
Reference in New Issue
Block a user