Auto merge of #2082 - str4d:univalue-subtree, r=bitcartel

Add UniValue as subtree

Cherry-picked from the following upstream PRs:

- bitcoin/bitcoin#6637
- bitcoin/bitcoin#6239
- bitcoin/bitcoin#6379
- bitcoin/bitcoin#6456
- bitcoin/bitcoin#6788
This commit is contained in:
zkbot 2017-02-10 07:46:58 +00:00
commit eaaa5f625f
118 changed files with 1488 additions and 326 deletions

View File

@ -1003,7 +1003,7 @@ unset PKG_CONFIG_LIBDIR
PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP"
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no"
AC_CONFIG_SUBDIRS([src/secp256k1])
AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue])
AC_OUTPUT

View File

@ -242,14 +242,14 @@ class WalletProtectCoinbaseTest (BitcoinTestFramework):
self.nodes[0].z_sendmany(myzaddr, recipients, 1, -1)
except JSONRPCException,e:
errorString = e.error['message']
assert_equal("Invalid amount" in errorString, True)
assert_equal("Amount out of range" in errorString, True)
# Send will fail because fee is larger than MAX_MONEY
try:
self.nodes[0].z_sendmany(myzaddr, recipients, 1, Decimal('21000000.00000001'))
except JSONRPCException,e:
errorString = e.error['message']
assert_equal("Invalid amount" in errorString, True)
assert_equal("Amount out of range" in errorString, True)
# Send will fail because fee is larger than sum of outputs
try:

View File

@ -1,4 +1,4 @@
DIST_SUBDIRS = secp256k1
DIST_SUBDIRS = secp256k1 univalue
AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS)
@ -21,6 +21,7 @@ BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
BITCOIN_INCLUDES += -I$(srcdir)/univalue/include
LIBBITCOIN_SERVER=libbitcoin_server.a
LIBBITCOIN_WALLET=libbitcoin_wallet.a
@ -28,13 +29,16 @@ LIBBITCOIN_COMMON=libbitcoin_common.a
LIBBITCOIN_CLI=libbitcoin_cli.a
LIBBITCOIN_UTIL=libbitcoin_util.a
LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a
LIBBITCOIN_UNIVALUE=univalue/libbitcoin_univalue.a
LIBBITCOINQT=qt/libbitcoinqt.a
LIBSECP256K1=secp256k1/libsecp256k1.la
LIBUNIVALUE=univalue/libunivalue.la
LIBZCASH=libzcash.a
$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*)
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F)
$(LIBUNIVALUE): $(wildcard univalue/lib/*)
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue/
# Make is not made aware of per-object dependencies to avoid limiting building parallelization
# But to build the less dependent modules first, we manually select their order here:
@ -42,7 +46,6 @@ EXTRA_LIBRARIES = \
crypto/libbitcoin_crypto.a \
libbitcoin_util.a \
libbitcoin_common.a \
univalue/libbitcoin_univalue.a \
libbitcoin_server.a \
libbitcoin_cli.a \
libzcash.a
@ -287,14 +290,6 @@ crypto_libbitcoin_crypto_a_SOURCES += \
${EQUIHASH_TROMP_SOURCES}
endif
# univalue JSON library
univalue_libbitcoin_univalue_a_SOURCES = \
univalue/univalue.cpp \
univalue/univalue.h \
univalue/univalue_escapes.h \
univalue/univalue_read.cpp \
univalue/univalue_write.cpp
# common: shared between bitcoind, and bitcoin-qt and non-server tools
libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES)
libbitcoin_common_a_SOURCES = \
@ -374,7 +369,7 @@ endif
zcashd_LDADD = \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_UNIVALUE) \
$(LIBUNIVALUE) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZCASH) \
@ -411,7 +406,7 @@ endif
zcash_cli_LDADD = \
$(LIBBITCOIN_CLI) \
$(LIBBITCOIN_UNIVALUE) \
$(LIBUNIVALUE) \
$(LIBBITCOIN_UTIL) \
$(BOOST_LIBS) \
$(SSL_LIBS) \
@ -432,7 +427,7 @@ endif
# FIXME: Is libzcash needed for zcash_tx?
zcash_tx_LDADD = \
$(LIBBITCOIN_UNIVALUE) \
$(LIBUNIVALUE) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_UTIL) \
$(LIBSECP256K1) \

View File

@ -40,9 +40,9 @@ zcash_gtest_SOURCES += \
wallet/gtest/test_wallet.cpp
endif
zcash_gtest_CPPFLAGS = -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC
zcash_gtest_CPPFLAGS = -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES)
zcash_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
zcash_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1)
if ENABLE_ZMQ
zcash_gtest_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)

View File

@ -364,7 +364,7 @@ endif
if ENABLE_ZMQ
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(LIBZCASH_LIBS)
qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_bitcoin_qt_LIBTOOLFLAGS = --tag CXX

View File

@ -33,7 +33,7 @@ endif
if ENABLE_ZMQ
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \
$(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
$(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) $(LIBZCASH_LIBS)
qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)

View File

@ -98,7 +98,7 @@ endif
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
test_test_bitcoin_CPPFLAGS = -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS)
test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1)
if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
@ -131,6 +131,7 @@ check-local:
@echo "Running test/bitcoin-util-test.py..."
$(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/bitcoin-util-test.py
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check
%.json.h: %.json
@$(MKDIR_P) $(@D)

View File

@ -15,7 +15,7 @@
#include <utility>
#include <future>
#include "univalue/univalue.h"
#include <univalue.h>
using namespace std;

View File

@ -12,7 +12,7 @@
#include <boost/filesystem/operations.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
using namespace std;

View File

@ -11,7 +11,7 @@
#include "primitives/transaction.h"
#include "script/script.h"
#include "script/sign.h"
#include "univalue/univalue.h"
#include <univalue.h>
#include "util.h"
#include "utilmoneystr.h"
#include "utilstrencodings.h"

View File

@ -9,7 +9,7 @@
#include "script/script.h"
#include "serialize.h"
#include "streams.h"
#include "univalue/univalue.h"
#include <univalue.h>
#include "util.h"
#include "utilstrencodings.h"
#include "version.h"

View File

@ -10,7 +10,7 @@
#include "script/standard.h"
#include "serialize.h"
#include "streams.h"
#include "univalue/univalue.h"
#include <univalue.h>
#include "util.h"
#include "utilmoneystr.h"
#include "utilstrencodings.h"

View File

@ -5,7 +5,7 @@
#include "serialize.h"
#include "streams.h"
#include "univalue/univalue.h"
#include <univalue.h>
UniValue
read_json(const std::string& jsondata);

View File

@ -1,5 +1,5 @@
#include <gtest/gtest.h>
#include "univalue/univalue.h"
#include <univalue.h>
#include "chain.h"
#include "chainparams.h"

View File

@ -18,7 +18,7 @@
#include <openssl/crypto.h>
#include "univalue/univalue.h"
#include <univalue.h>
#ifdef ENABLE_WALLET
#include <db_cxx.h>

View File

@ -16,7 +16,7 @@
#include <boost/algorithm/string.hpp>
#include <boost/dynamic_bitset.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
using namespace std;

View File

@ -13,7 +13,7 @@
#include <stdint.h>
#include "univalue/univalue.h"
#include <univalue.h>
using namespace std;

View File

@ -11,7 +11,7 @@
#include <set>
#include <stdint.h>
#include "univalue/univalue.h"
#include <univalue.h>
using namespace std;

View File

@ -6,7 +6,7 @@
#ifndef BITCOIN_RPCCLIENT_H
#define BITCOIN_RPCCLIENT_H
#include "univalue/univalue.h"
#include <univalue.h>
UniValue RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams);
/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)

View File

@ -28,7 +28,7 @@
#include <boost/assign/list_of.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
using namespace std;

View File

@ -20,7 +20,8 @@
#include <stdint.h>
#include <boost/assign/list_of.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
#include "zcash/Address.hpp"

View File

@ -16,7 +16,7 @@
#include <boost/foreach.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
using namespace std;

View File

@ -26,7 +26,7 @@
#include <boost/iostreams/stream.hpp>
#include <boost/shared_ptr.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
using namespace std;

View File

@ -16,7 +16,7 @@
#include <boost/asio/ssl.hpp>
#include <boost/filesystem.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
//! HTTP status codes
enum HTTPStatusCode

View File

@ -26,7 +26,7 @@
#include <boost/assign/list_of.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
using namespace std;

View File

@ -31,7 +31,7 @@
#include <boost/signals2/signal.hpp>
#include <boost/thread.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
using namespace boost::asio;
using namespace RPCServer;
@ -121,25 +121,26 @@ void RPCTypeCheckObj(const UniValue& o,
}
}
static inline int64_t roundint64(double d)
{
return (int64_t)(d > 0 ? d + 0.5 : d - 0.5);
}
CAmount AmountFromValue(const UniValue& value)
{
double dAmount = value.get_real();
if (dAmount <= 0.0 || dAmount > 21000000.0)
if (!value.isNum())
throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number");
CAmount amount;
if (!ParseFixedPoint(value.getValStr(), 8, &amount))
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
CAmount nAmount = roundint64(dAmount * COIN);
if (!MoneyRange(nAmount))
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
return nAmount;
if (!MoneyRange(amount))
throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
return amount;
}
UniValue ValueFromAmount(const CAmount& amount)
{
return (double)amount / (double)COIN;
bool sign = amount < 0;
int64_t n_abs = (sign ? -amount : amount);
int64_t quotient = n_abs / COIN;
int64_t remainder = n_abs % COIN;
return UniValue(UniValue::VNUM,
strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
}
uint256 ParseHashV(const UniValue& v, string strName)

View File

@ -18,7 +18,7 @@
#include <boost/function.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
class AsyncRPCQueue;
class CRPCCommand;

View File

@ -18,7 +18,7 @@
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
extern UniValue read_json(const std::string& jsondata);

View File

@ -13,7 +13,7 @@
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
using namespace std;
@ -126,6 +126,29 @@ BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000");
BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990");
BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999");
BOOST_CHECK_EQUAL(ValueFromAmount(0).write(), "0.00000000");
BOOST_CHECK_EQUAL(ValueFromAmount((COIN/10000)*123456789).write(), "12345.67890000");
BOOST_CHECK_EQUAL(ValueFromAmount(-COIN).write(), "-1.00000000");
BOOST_CHECK_EQUAL(ValueFromAmount(-COIN/10).write(), "-0.10000000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000000).write(), "100000000.00000000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000000).write(), "10000000.00000000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000000).write(), "1000000.00000000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000).write(), "100000.00000000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000).write(), "10000.00000000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000).write(), "1000.00000000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100).write(), "100.00000000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10).write(), "10.00000000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN).write(), "1.00000000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10).write(), "0.10000000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100).write(), "0.01000000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000).write(), "0.00100000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000).write(), "0.00010000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000).write(), "0.00001000");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000000).write(), "0.00000100");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000000).write(), "0.00000010");
BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000000).write(), "0.00000001");
}
static UniValue ValueFromString(const std::string &str)
@ -137,6 +160,9 @@ static UniValue ValueFromString(const std::string &str)
BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
{
BOOST_CHECK_THROW(AmountFromValue(ValueFromString("-0.00000001")), UniValue);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0")), 0LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000000")), 0LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001")), 1LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.17622195")), 17622195LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.5")), 50000000LL);
@ -145,6 +171,24 @@ BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1.00000000")), 100000000LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.9999999")), 2099999999999990LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.99999999")), 2099999999999999LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1e-8")), COIN/100000000);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.1e-7")), COIN/100000000);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.01e-6")), COIN/100000000);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.0000000000000000000000000000000000000000000000000000000000000000000000000001e+68")), COIN/100000000);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("10000000000000000000000000000000000000000000000000000000000000000e-64")), COIN);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000e64")), COIN);
BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e-9")), UniValue); //should fail
BOOST_CHECK_THROW(AmountFromValue(ValueFromString("0.000000019")), UniValue); //should fail
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001000000")), 1LL); //should pass, cut trailing 0
BOOST_CHECK_THROW(AmountFromValue(ValueFromString("19e-9")), UniValue); //should fail
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.19e-6")), 19); //should pass, leading 0 is present
BOOST_CHECK_THROW(AmountFromValue(ValueFromString("92233720368.54775808")), UniValue); //overflow error
BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e+11")), UniValue); //overflow error
BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e11")), UniValue); //overflow error signless
BOOST_CHECK_THROW(AmountFromValue(ValueFromString("93e+9")), UniValue); //overflow error
}
BOOST_AUTO_TEST_CASE(json_parse_errors)
@ -154,6 +198,9 @@ BOOST_AUTO_TEST_CASE(json_parse_errors)
// Valid, with leading or trailing whitespace
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(" 1.0").get_real(), 1.0);
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0 ").get_real(), 1.0);
BOOST_CHECK_THROW(AmountFromValue(ParseNonRFCJSONValue(".19e-6")), std::runtime_error); //should fail, missing leading 0, therefore invalid JSON
BOOST_CHECK_EQUAL(AmountFromValue(ParseNonRFCJSONValue("0.00000000000000000000000000000000000001e+30 ")), 1);
// Invalid, initial garbage
BOOST_CHECK_THROW(ParseNonRFCJSONValue("[1.0"), std::runtime_error);
BOOST_CHECK_THROW(ParseNonRFCJSONValue("a1.0"), std::runtime_error);

View File

@ -31,7 +31,7 @@
#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
using namespace std;

View File

@ -27,7 +27,7 @@
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
using namespace std;

View File

@ -18,7 +18,7 @@
#include <boost/test/unit_test.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
extern UniValue read_json(const std::string& jsondata);

View File

@ -27,7 +27,7 @@
#include <boost/test/unit_test.hpp>
#include <boost/assign/list_of.hpp>
#include "univalue/univalue.h"
#include <univalue.h>
#include "zcash/Note.hpp"
#include "zcash/Address.hpp"

View File

@ -6,7 +6,7 @@
#include <vector>
#include <string>
#include <map>
#include "univalue/univalue.h"
#include <univalue.h>
#include "test/test_bitcoin.h"
#include <boost/test/unit_test.hpp>
@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(univalue_constructor)
double vd = -7.21;
UniValue v7(vd);
BOOST_CHECK(v7.isReal());
BOOST_CHECK(v7.isNum());
BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");
string vs("yawn");
@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(univalue_set)
BOOST_CHECK_EQUAL(v.getValStr(), "zum");
BOOST_CHECK(v.setFloat(-1.01));
BOOST_CHECK(v.isReal());
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
BOOST_CHECK(v.setInt((int)1023));
@ -272,7 +272,7 @@ BOOST_AUTO_TEST_CASE(univalue_object)
objTypes["distance"] = UniValue::VNUM;
objTypes["time"] = UniValue::VNUM;
objTypes["calories"] = UniValue::VNUM;
objTypes["temperature"] = UniValue::VREAL;
objTypes["temperature"] = UniValue::VNUM;
objTypes["cat1"] = UniValue::VNUM;
objTypes["cat2"] = UniValue::VNUM;
BOOST_CHECK(obj.checkObject(objTypes));

View File

@ -146,29 +146,27 @@ BOOST_AUTO_TEST_CASE(util_GetArg)
BOOST_AUTO_TEST_CASE(util_FormatMoney)
{
BOOST_CHECK_EQUAL(FormatMoney(0, false), "0.00");
BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789, false), "12345.6789");
BOOST_CHECK_EQUAL(FormatMoney(COIN, true), "+1.00");
BOOST_CHECK_EQUAL(FormatMoney(-COIN, false), "-1.00");
BOOST_CHECK_EQUAL(FormatMoney(-COIN, true), "-1.00");
BOOST_CHECK_EQUAL(FormatMoney(0), "0.00");
BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789), "12345.6789");
BOOST_CHECK_EQUAL(FormatMoney(-COIN), "-1.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000, false), "100000000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000, false), "10000000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000, false), "1000000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*100000, false), "100000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*10000, false), "10000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*1000, false), "1000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*100, false), "100.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*10, false), "10.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN, false), "1.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN/10, false), "0.10");
BOOST_CHECK_EQUAL(FormatMoney(COIN/100, false), "0.01");
BOOST_CHECK_EQUAL(FormatMoney(COIN/1000, false), "0.001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/10000, false), "0.0001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/100000, false), "0.00001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000, false), "0.000001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000, false), "0.0000001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000, false), "0.00000001");
BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000), "100000000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000), "10000000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000), "1000000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*100000), "100000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*10000), "10000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*1000), "1000.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*100), "100.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN*10), "10.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN), "1.00");
BOOST_CHECK_EQUAL(FormatMoney(COIN/10), "0.10");
BOOST_CHECK_EQUAL(FormatMoney(COIN/100), "0.01");
BOOST_CHECK_EQUAL(FormatMoney(COIN/1000), "0.001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/10000), "0.0001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/100000), "0.00001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000), "0.000001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000), "0.0000001");
BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000), "0.00000001");
}
BOOST_AUTO_TEST_CASE(util_ParseMoney)
@ -428,4 +426,70 @@ BOOST_AUTO_TEST_CASE(test_FormatSubVersion)
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2), std::string("/Test:0.9.99-beta1(comment1; comment2)/"));
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99950, comments2), std::string("/Test:0.9.99(comment1; comment2)/"));
}
BOOST_AUTO_TEST_CASE(test_ParseFixedPoint)
{
int64_t amount = 0;
BOOST_CHECK(ParseFixedPoint("0", 8, &amount));
BOOST_CHECK_EQUAL(amount, 0LL);
BOOST_CHECK(ParseFixedPoint("1", 8, &amount));
BOOST_CHECK_EQUAL(amount, 100000000LL);
BOOST_CHECK(ParseFixedPoint("0.0", 8, &amount));
BOOST_CHECK_EQUAL(amount, 0LL);
BOOST_CHECK(ParseFixedPoint("-0.1", 8, &amount));
BOOST_CHECK_EQUAL(amount, -10000000LL);
BOOST_CHECK(ParseFixedPoint("1.1", 8, &amount));
BOOST_CHECK_EQUAL(amount, 110000000LL);
BOOST_CHECK(ParseFixedPoint("1.10000000000000000", 8, &amount));
BOOST_CHECK_EQUAL(amount, 110000000LL);
BOOST_CHECK(ParseFixedPoint("1.1e1", 8, &amount));
BOOST_CHECK_EQUAL(amount, 1100000000LL);
BOOST_CHECK(ParseFixedPoint("1.1e-1", 8, &amount));
BOOST_CHECK_EQUAL(amount, 11000000LL);
BOOST_CHECK(ParseFixedPoint("1000", 8, &amount));
BOOST_CHECK_EQUAL(amount, 100000000000LL);
BOOST_CHECK(ParseFixedPoint("-1000", 8, &amount));
BOOST_CHECK_EQUAL(amount, -100000000000LL);
BOOST_CHECK(ParseFixedPoint("0.00000001", 8, &amount));
BOOST_CHECK_EQUAL(amount, 1LL);
BOOST_CHECK(ParseFixedPoint("0.0000000100000000", 8, &amount));
BOOST_CHECK_EQUAL(amount, 1LL);
BOOST_CHECK(ParseFixedPoint("-0.00000001", 8, &amount));
BOOST_CHECK_EQUAL(amount, -1LL);
BOOST_CHECK(ParseFixedPoint("1000000000.00000001", 8, &amount));
BOOST_CHECK_EQUAL(amount, 100000000000000001LL);
BOOST_CHECK(ParseFixedPoint("9999999999.99999999", 8, &amount));
BOOST_CHECK_EQUAL(amount, 999999999999999999LL);
BOOST_CHECK(ParseFixedPoint("-9999999999.99999999", 8, &amount));
BOOST_CHECK_EQUAL(amount, -999999999999999999LL);
BOOST_CHECK(!ParseFixedPoint("", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("a-1000", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-a1000", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-1000a", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-01000", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("00.1", 8, &amount));
BOOST_CHECK(!ParseFixedPoint(".1", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("--0.1", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("0.000000001", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-0.000000001", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("0.00000001000000001", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-10000000000.00000000", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("10000000000.00000000", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-10000000000.00000001", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("10000000000.00000001", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-10000000000.00000009", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("10000000000.00000009", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-99999999999.99999999", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("99999909999.09999999", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("92233720368.54775807", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("92233720368.54775808", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-92233720368.54775808", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("-92233720368.54775809", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("1.1e", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("1.1e-", 8, &amount));
BOOST_CHECK(!ParseFixedPoint("1.", 8, &amount));
}
BOOST_AUTO_TEST_SUITE_END()

32
src/univalue/.gitignore vendored Normal file
View File

@ -0,0 +1,32 @@
.deps/
INSTALL
Makefile
Makefile.in
aclocal.m4
autom4te.cache/
compile
config.log
config.status
config.guess
config.sub
configure
depcomp
install-sh
missing
stamp-h1
univalue-config.h*
test-driver
libtool
ltmain.sh
test-suite.log
*.a
*.la
*.lo
*.logs
*.o
*.pc
*.trs
.dirstamp
.libs

52
src/univalue/.travis.yml Normal file
View File

@ -0,0 +1,52 @@
language: cpp
compiler:
- clang
- gcc
os:
- linux
- osx
sudo: false
env:
global:
- MAKEJOBS=-j3
- RUN_TESTS=true
- BASE_OUTDIR=$TRAVIS_BUILD_DIR/out
cache:
apt: true
addons:
apt:
packages:
- pkg-config
before_script:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew uninstall libtool; brew install libtool; fi
- if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi
- test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh
script:
- if [ -n "$UNIVALUE_CONFIG" ]; then unset CC; unset CXX; fi
- OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST
- UNIVALUE_CONFIG_ALL="--prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib"
- ./configure --cache-file=config.cache $UNIVALUE_CONFIG_ALL $UNIVALUE_CONFIG || ( cat config.log && false)
- make -s $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL ; false )
- export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib
- if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi
matrix:
fast_finish: true
include:
- os: linux
compiler: gcc
env: UNIVALUE_CONFIG=--host=x86_64-w64-mingw32 RUN_TESTS=false
addons:
apt:
packages:
- g++-mingw-w64-x86-64
- gcc-mingw-w64-x86-64
- binutils-mingw-w64-x86-64

19
src/univalue/COPYING Normal file
View File

@ -0,0 +1,19 @@
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

109
src/univalue/Makefile.am Normal file
View File

@ -0,0 +1,109 @@
ACLOCAL_AMFLAGS = -I build-aux/m4
.PHONY: gen
.INTERMEDIATE: $(GENBIN)
include_HEADERS = include/univalue.h
noinst_HEADERS = lib/univalue_escapes.h lib/univalue_utffilter.h
lib_LTLIBRARIES = libunivalue.la
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = pc/libunivalue.pc
libunivalue_la_SOURCES = \
lib/univalue.cpp \
lib/univalue_read.cpp \
lib/univalue_write.cpp
libunivalue_la_LDFLAGS = \
-version-info $(LIBUNIVALUE_CURRENT):$(LIBUNIVALUE_REVISION):$(LIBUNIVALUE_AGE) \
-no-undefined
libunivalue_la_CXXFLAGS = -I$(top_srcdir)/include
TESTS = test/unitester test/no_nul
GENBIN = gen/gen$(BUILD_EXEEXT)
GEN_SRCS = gen/gen.cpp
$(GENBIN): $(GEN_SRCS)
@echo Building $@
$(AM_V_at)c++ -I$(top_srcdir)/include -o $@ $<
gen: lib/univalue_escapes.h $(GENBIN)
@echo Updating $<
$(AM_V_at)$(GENBIN) > lib/univalue_escapes.h
noinst_PROGRAMS = $(TESTS) test/test_json
TEST_DATA_DIR=test
test_unitester_SOURCES = test/unitester.cpp
test_unitester_LDADD = libunivalue.la
test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(TEST_DATA_DIR)\"
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_FILES = \
$(TEST_DATA_DIR)/fail10.json \
$(TEST_DATA_DIR)/fail11.json \
$(TEST_DATA_DIR)/fail12.json \
$(TEST_DATA_DIR)/fail13.json \
$(TEST_DATA_DIR)/fail14.json \
$(TEST_DATA_DIR)/fail15.json \
$(TEST_DATA_DIR)/fail16.json \
$(TEST_DATA_DIR)/fail17.json \
$(TEST_DATA_DIR)/fail18.json \
$(TEST_DATA_DIR)/fail19.json \
$(TEST_DATA_DIR)/fail1.json \
$(TEST_DATA_DIR)/fail20.json \
$(TEST_DATA_DIR)/fail21.json \
$(TEST_DATA_DIR)/fail22.json \
$(TEST_DATA_DIR)/fail23.json \
$(TEST_DATA_DIR)/fail24.json \
$(TEST_DATA_DIR)/fail25.json \
$(TEST_DATA_DIR)/fail26.json \
$(TEST_DATA_DIR)/fail27.json \
$(TEST_DATA_DIR)/fail28.json \
$(TEST_DATA_DIR)/fail29.json \
$(TEST_DATA_DIR)/fail2.json \
$(TEST_DATA_DIR)/fail30.json \
$(TEST_DATA_DIR)/fail31.json \
$(TEST_DATA_DIR)/fail32.json \
$(TEST_DATA_DIR)/fail33.json \
$(TEST_DATA_DIR)/fail34.json \
$(TEST_DATA_DIR)/fail35.json \
$(TEST_DATA_DIR)/fail36.json \
$(TEST_DATA_DIR)/fail37.json \
$(TEST_DATA_DIR)/fail38.json \
$(TEST_DATA_DIR)/fail39.json \
$(TEST_DATA_DIR)/fail40.json \
$(TEST_DATA_DIR)/fail41.json \
$(TEST_DATA_DIR)/fail42.json \
$(TEST_DATA_DIR)/fail3.json \
$(TEST_DATA_DIR)/fail4.json \
$(TEST_DATA_DIR)/fail5.json \
$(TEST_DATA_DIR)/fail6.json \
$(TEST_DATA_DIR)/fail7.json \
$(TEST_DATA_DIR)/fail8.json \
$(TEST_DATA_DIR)/fail9.json \
$(TEST_DATA_DIR)/pass1.json \
$(TEST_DATA_DIR)/pass2.json \
$(TEST_DATA_DIR)/pass3.json \
$(TEST_DATA_DIR)/round1.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)

7
src/univalue/README Normal file
View File

@ -0,0 +1,7 @@
UniValue
A universal value object, with JSON encoding (output) and decoding (input).
Built as a single dynamic RAII C++ object class, and no templates.

10
src/univalue/TODO Normal file
View File

@ -0,0 +1,10 @@
Rearrange tree for easier 'git subtree' style use
Move towards C++11 etc.
Namespace support - must come up with useful shorthand, avoiding
long Univalue::Univalue::Univalue usages forced upon library users.
Improve test suite

9
src/univalue/autogen.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
set -e
srcdir="$(dirname $0)"
cd "$srcdir"
if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then
LIBTOOLIZE="${GLIBTOOLIZE}"
export LIBTOOLIZE
fi
autoreconf --install --force

1
src/univalue/build-aux/m4/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/*.m4

69
src/univalue/configure.ac Normal file
View File

@ -0,0 +1,69 @@
m4_define([libunivalue_major_version], [1])
m4_define([libunivalue_minor_version], [1])
m4_define([libunivalue_micro_version], [3])
m4_define([libunivalue_interface_age], [3])
# If you need a modifier for the version number.
# Normally empty, but can be used to make "fixup" releases.
m4_define([libunivalue_extraversion], [])
dnl libtool versioning from libunivalue
m4_define([libunivalue_current], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version - libunivalue_interface_age)])
m4_define([libunivalue_binary_age], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version)])
m4_define([libunivalue_revision], [libunivalue_interface_age])
m4_define([libunivalue_age], [m4_eval(libunivalue_binary_age - libunivalue_interface_age)])
m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()])
AC_INIT([univalue], [1.0.3],
[http://github.com/jgarzik/univalue/])
dnl make the compilation flags quiet unless V=1 is used
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_PREREQ(2.60)
AC_CONFIG_SRCDIR([lib/univalue.cpp])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4])
AC_CONFIG_HEADERS([univalue-config.h])
AM_INIT_AUTOMAKE([subdir-objects foreign])
LIBUNIVALUE_MAJOR_VERSION=libunivalue_major_version
LIBUNIVALUE_MINOR_VERSION=libunivalue_minor_version
LIBUNIVALUE_MICRO_VERSION=libunivalue_micro_version
LIBUNIVALUE_INTERFACE_AGE=libunivalue_interface_age
# ABI version
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
LIBUNIVALUE_CURRENT=libunivalue_current
LIBUNIVALUE_REVISION=libunivalue_revision
LIBUNIVALUE_AGE=libunivalue_age
AC_SUBST(LIBUNIVALUE_CURRENT)
AC_SUBST(LIBUNIVALUE_REVISION)
AC_SUBST(LIBUNIVALUE_AGE)
LT_INIT
LT_LANG([C++])
case $host in
*mingw*)
LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static"
;;
esac
BUILD_EXEEXT=
case $build in
*mingw*)
BUILD_EXEEXT=".exe"
;;
esac
AC_CONFIG_FILES([
Makefile
pc/libunivalue.pc
pc/libunivalue-uninstalled.pc])
AC_SUBST(LIBTOOL_APP_LDFLAGS)
AC_SUBST(BUILD_EXEEXT)
AC_OUTPUT

View File

@ -8,7 +8,6 @@
// $ ./gen > univalue_escapes.h
//
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "univalue.h"
@ -16,18 +15,25 @@
using namespace std;
static bool initEscapes;
static const char *escapes[256];
static std::string escapes[256];
static void initJsonEscape()
{
// Escape all lower control characters (some get overridden with smaller sequences below)
for (int ch=0x00; ch<0x20; ++ch) {
char tmpbuf[20];
snprintf(tmpbuf, sizeof(tmpbuf), "\\u%04x", ch);
escapes[ch] = std::string(tmpbuf);
}
escapes[(int)'"'] = "\\\"";
escapes[(int)'\\'] = "\\\\";
escapes[(int)'/'] = "\\/";
escapes[(int)'\b'] = "\\b";
escapes[(int)'\f'] = "\\f";
escapes[(int)'\n'] = "\\n";
escapes[(int)'\r'] = "\\r";
escapes[(int)'\t'] = "\\t";
escapes[(int)'\x7f'] = "\\u007f"; // U+007F DELETE
initEscapes = true;
}
@ -40,13 +46,13 @@ static void outputEscape()
"static const char *escapes[256] = {\n");
for (unsigned int i = 0; i < 256; i++) {
if (!escapes[i]) {
if (escapes[i].empty()) {
printf("\tNULL,\n");
} else {
printf("\t\"");
unsigned int si;
for (si = 0; si < strlen(escapes[i]); si++) {
for (si = 0; si < escapes[i].size(); si++) {
char ch = escapes[i][si];
switch (ch) {
case '"':

View File

@ -1,11 +1,13 @@
// 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.
#ifndef BITCOIN_UNIVALUE_UNIVALUE_H
#define BITCOIN_UNIVALUE_UNIVALUE_H
#ifndef __UNIVALUE_H__
#define __UNIVALUE_H__
#include <stdint.h>
#include <string>
#include <vector>
#include <map>
@ -16,7 +18,7 @@
class UniValue {
public:
enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VREAL, VBOOL, };
enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
UniValue() { typ = VNULL; }
UniValue(UniValue::VType initialType, const std::string& initialStr = "") {
@ -54,14 +56,14 @@ public:
bool setNumStr(const std::string& val);
bool setInt(uint64_t val);
bool setInt(int64_t val);
bool setInt(int val) { return setInt((int64_t)val); }
bool setInt(int val_) { return setInt((int64_t)val_); }
bool setFloat(double val);
bool setStr(const std::string& val);
bool setArray();
bool setObject();
enum VType getType() const { return typ; }
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(); }
@ -69,8 +71,8 @@ public:
bool getBool() const { return isTrue(); }
bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes);
const UniValue& operator[](const std::string& key) const;
const UniValue& operator[](unsigned int index) const;
bool exists(const std::string& key) const { return (findKey(key) >= 0); }
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"); }
@ -78,7 +80,6 @@ public:
bool isBool() const { return (typ == VBOOL); }
bool isStr() const { return (typ == VSTR); }
bool isNum() const { return (typ == VNUM); }
bool isReal() const { return (typ == VREAL); }
bool isArray() const { return (typ == VARR); }
bool isObject() const { return (typ == VOBJ); }
@ -91,31 +92,43 @@ public:
std::string s(val_);
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_backV(const std::vector<UniValue>& vec);
bool pushKV(const std::string& key, const UniValue& val);
bool pushKV(const std::string& key, const std::string& val) {
UniValue tmpVal(VSTR, val);
bool pushKV(const std::string& key, const std::string& val_) {
UniValue tmpVal(VSTR, val_);
return pushKV(key, tmpVal);
}
bool pushKV(const std::string& key, const char *val_) {
std::string val(val_);
return pushKV(key, val);
std::string _val(val_);
return pushKV(key, _val);
}
bool pushKV(const std::string& key, int64_t val) {
UniValue tmpVal(val);
bool pushKV(const std::string& key, int64_t val_) {
UniValue tmpVal(val_);
return pushKV(key, tmpVal);
}
bool pushKV(const std::string& key, uint64_t val) {
UniValue tmpVal(val);
bool pushKV(const std::string& key, uint64_t val_) {
UniValue tmpVal(val_);
return pushKV(key, tmpVal);
}
bool pushKV(const std::string& key, int val) {
UniValue tmpVal((int64_t)val);
bool pushKV(const std::string& key, int val_) {
UniValue tmpVal((int64_t)val_);
return pushKV(key, tmpVal);
}
bool pushKV(const std::string& key, double val) {
UniValue tmpVal(val);
bool pushKV(const std::string& key, double val_) {
UniValue tmpVal(val_);
return pushKV(key, tmpVal);
}
bool pushKVs(const UniValue& obj);
@ -123,9 +136,10 @@ public:
std::string write(unsigned int prettyIndent = 0,
unsigned int indentLevel = 0) const;
bool read(const char *raw, size_t len);
bool read(const char *raw);
bool read(const std::string& rawStr) {
return read(rawStr.c_str());
return read(rawStr.data(), rawStr.size());
}
private:
@ -134,17 +148,17 @@ private:
std::vector<std::string> keys;
std::vector<UniValue> values;
int findKey(const std::string& key) const;
bool findKey(const std::string& key, size_t& ret) 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;
public:
// Strict type-specific getters, these throw std::runtime_error if the
// value is of unexpected type
std::vector<std::string> getKeys() const;
std::vector<UniValue> getValues() const;
const std::vector<std::string>& getKeys() const;
const std::vector<UniValue>& getValues() const;
bool get_bool() const;
std::string get_str() const;
const std::string& get_str() const;
int get_int() const;
int64_t get_int64() const;
double get_real() const;
@ -239,12 +253,44 @@ enum jtokentype {
};
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);
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;
}
// not reached
}
static inline bool json_isspace(int ch)
{
switch (ch) {
case 0x20:
case 0x09:
case 0x0a:
case 0x0d:
return true;
default:
return false;
}
// not reached
}
extern const UniValue NullUniValue;
const UniValue& find_value( const UniValue& obj, const std::string& name);
#endif // BITCOIN_UNIVALUE_UNIVALUE_H
#endif // __UNIVALUE_H__

2
src/univalue/lib/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
gen
.libs

View File

@ -1,16 +1,77 @@
// 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 <ctype.h>
#include <errno.h>
#include <iomanip>
#include <limits>
#include <sstream>
#include <stdexcept> // std::runtime_error
#include <stdexcept>
#include <stdlib.h>
#include <string.h>
#include "univalue.h"
#include "utilstrencodings.h" // ParseXX
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;
@ -43,7 +104,7 @@ static bool validNumStr(const string& s)
{
string tokenVal;
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);
}
@ -58,35 +119,32 @@ bool UniValue::setNumStr(const string& val_)
return true;
}
bool UniValue::setInt(uint64_t val)
bool UniValue::setInt(uint64_t val_)
{
string s;
ostringstream oss;
oss << val;
oss << val_;
return setNumStr(oss.str());
}
bool UniValue::setInt(int64_t val)
bool UniValue::setInt(int64_t val_)
{
string s;
ostringstream oss;
oss << val;
oss << val_;
return setNumStr(oss.str());
}
bool UniValue::setFloat(double val)
bool UniValue::setFloat(double val_)
{
string s;
ostringstream oss;
oss << std::setprecision(16) << val;
oss << std::setprecision(16) << val_;
bool ret = setNumStr(oss.str());
typ = VREAL;
typ = VNUM;
return ret;
}
@ -112,12 +170,12 @@ bool UniValue::setObject()
return true;
}
bool UniValue::push_back(const UniValue& val)
bool UniValue::push_back(const UniValue& val_)
{
if (typ != VARR)
return false;
values.push_back(val);
values.push_back(val_);
return true;
}
@ -131,13 +189,13 @@ bool UniValue::push_backV(const std::vector<UniValue>& vec)
return true;
}
bool UniValue::pushKV(const std::string& key, const UniValue& val)
bool UniValue::pushKV(const std::string& key, const UniValue& val_)
{
if (typ != VOBJ)
return false;
keys.push_back(key);
values.push_back(val);
values.push_back(val_);
return true;
}
@ -148,31 +206,33 @@ bool UniValue::pushKVs(const UniValue& obj)
for (unsigned int i = 0; i < obj.keys.size(); i++) {
keys.push_back(obj.keys[i]);
values.push_back(obj.values[i]);
values.push_back(obj.values.at(i));
}
return true;
}
int UniValue::findKey(const std::string& key) const
bool UniValue::findKey(const std::string& key, size_t& ret) const
{
for (unsigned int i = 0; i < keys.size(); i++) {
if (keys[i] == key)
return (int) i;
for (size_t i = 0; i < keys.size(); i++) {
if (keys[i] == key) {
ret = i;
return true;
}
}
return -1;
return false;
}
bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t)
{
for (std::map<std::string,UniValue::VType>::const_iterator it = t.begin();
it != t.end(); it++) {
int idx = findKey(it->first);
if (idx < 0)
it != t.end(); ++it) {
size_t idx;
if (!findKey(it->first, idx))
return false;
if (values[idx].getType() != it->second)
if (values.at(idx).getType() != it->second)
return false;
}
@ -184,21 +244,21 @@ const UniValue& UniValue::operator[](const std::string& key) const
if (typ != VOBJ)
return NullUniValue;
int index = findKey(key);
if (index < 0)
size_t index;
if (!findKey(key, index))
return NullUniValue;
return values[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)
return NullUniValue;
if (index >= values.size())
return NullUniValue;
return values[index];
return values.at(index);
}
const char *uvTypeName(UniValue::VType t)
@ -210,34 +270,29 @@ const char *uvTypeName(UniValue::VType t)
case UniValue::VARR: return "array";
case UniValue::VSTR: return "string";
case UniValue::VNUM: return "number";
case UniValue::VREAL: return "number";
}
// not reached
return NULL;
}
const UniValue& find_value( const UniValue& obj, const std::string& name)
const UniValue& find_value(const UniValue& obj, const std::string& name)
{
for (unsigned int i = 0; i < obj.keys.size(); i++)
{
if( obj.keys[i] == name )
{
return obj.values[i];
}
}
if (obj.keys[i] == name)
return obj.values.at(i);
return NullUniValue;
}
std::vector<std::string> UniValue::getKeys() const
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;
}
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");
@ -251,7 +306,7 @@ bool UniValue::get_bool() const
return getBool();
}
std::string UniValue::get_str() const
const std::string& UniValue::get_str() const
{
if (typ != VSTR)
throw std::runtime_error("JSON value is not a string as expected");
@ -280,7 +335,7 @@ int64_t UniValue::get_int64() const
double UniValue::get_real() const
{
if (typ != VREAL && typ != VNUM)
if (typ != VNUM)
throw std::runtime_error("JSON value is not a number as expected");
double retval;
if (!ParseDouble(getValStr(), &retval))

View File

@ -2,38 +2,38 @@
#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H
#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H
static const char *escapes[256] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"\\u0000",
"\\u0001",
"\\u0002",
"\\u0003",
"\\u0004",
"\\u0005",
"\\u0006",
"\\u0007",
"\\b",
"\\t",
"\\n",
NULL,
"\\u000b",
"\\f",
"\\r",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"\\u000e",
"\\u000f",
"\\u0010",
"\\u0011",
"\\u0012",
"\\u0013",
"\\u0014",
"\\u0015",
"\\u0016",
"\\u0017",
"\\u0018",
"\\u0019",
"\\u001a",
"\\u001b",
"\\u001c",
"\\u001d",
"\\u001e",
"\\u001f",
NULL,
NULL,
"\\\"",
@ -49,7 +49,7 @@ static const char *escapes[256] = {
NULL,
NULL,
NULL,
"\\/",
NULL,
NULL,
NULL,
NULL,
@ -129,7 +129,7 @@ static const char *escapes[256] = {
NULL,
NULL,
NULL,
NULL,
"\\u007f",
NULL,
NULL,
NULL,

View File

@ -6,9 +6,15 @@
#include <vector>
#include <stdio.h>
#include "univalue.h"
#include "univalue_utffilter.h"
using namespace std;
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)
@ -17,7 +23,7 @@ static const char *hatoui(const char *first, const char *last,
for (; first != last; ++first)
{
int digit;
if (isdigit(*first))
if (json_isdigit(*first))
digit = *first - '0';
else if (*first >= 'a' && *first <= 'f')
@ -37,21 +43,21 @@ static const char *hatoui(const char *first, const char *last,
}
enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
const char *raw)
const char *raw, const char *end)
{
tokenVal.clear();
consumed = 0;
const char *rawStart = raw;
while ((*raw) && (isspace(*raw))) // skip whitespace
while (raw < end && (json_isspace(*raw))) // skip whitespace
raw++;
switch (*raw) {
case 0:
if (raw >= end)
return JTOK_NONE;
switch (*raw) {
case '{':
raw++;
consumed = (raw - rawStart);
@ -113,48 +119,48 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
const char *first = raw;
const char *firstDigit = first;
if (!isdigit(*firstDigit))
if (!json_isdigit(*firstDigit))
firstDigit++;
if ((*firstDigit == '0') && isdigit(firstDigit[1]))
if ((*firstDigit == '0') && json_isdigit(firstDigit[1]))
return JTOK_ERR;
numStr += *raw; // copy first char
raw++;
if ((*first == '-') && (!isdigit(*raw)))
if ((*first == '-') && (raw < end) && (!json_isdigit(*raw)))
return JTOK_ERR;
while ((*raw) && isdigit(*raw)) { // copy digits
while (raw < end && json_isdigit(*raw)) { // copy digits
numStr += *raw;
raw++;
}
// part 2: frac
if (*raw == '.') {
if (raw < end && *raw == '.') {
numStr += *raw; // copy .
raw++;
if (!isdigit(*raw))
if (raw >= end || !json_isdigit(*raw))
return JTOK_ERR;
while ((*raw) && isdigit(*raw)) { // copy digits
while (raw < end && json_isdigit(*raw)) { // copy digits
numStr += *raw;
raw++;
}
}
// part 3: exp
if (*raw == 'e' || *raw == 'E') {
if (raw < end && (*raw == 'e' || *raw == 'E')) {
numStr += *raw; // copy E
raw++;
if (*raw == '-' || *raw == '+') { // copy +/-
if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/-
numStr += *raw;
raw++;
}
if (!isdigit(*raw))
if (raw >= end || !json_isdigit(*raw))
return JTOK_ERR;
while ((*raw) && isdigit(*raw)) { // copy digits
while (raw < end && json_isdigit(*raw)) { // copy digits
numStr += *raw;
raw++;
}
@ -169,44 +175,35 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
raw++; // skip "
string valStr;
JSONUTF8StringFilter writer(valStr);
while (*raw) {
if (*raw < 0x20)
while (raw < end) {
if ((unsigned char)*raw < 0x20)
return JTOK_ERR;
else if (*raw == '\\') {
raw++; // skip backslash
if (raw >= end)
return JTOK_ERR;
switch (*raw) {
case '"': valStr += "\""; break;
case '\\': valStr += "\\"; break;
case '/': valStr += "/"; break;
case 'b': valStr += "\b"; break;
case 'f': valStr += "\f"; break;
case 'n': valStr += "\n"; break;
case 'r': valStr += "\r"; break;
case 't': valStr += "\t"; break;
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': {
char buf[4] = {0,0,0,0};
char *last = &buf[0];
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)
return JTOK_ERR;
if (codepoint <= 0x7f)
*last = (char)codepoint;
else if (codepoint <= 0x7FF) {
*last++ = (char)(0xC0 | (codepoint >> 6));
*last = (char)(0x80 | (codepoint & 0x3F));
} else if (codepoint <= 0xFFFF) {
*last++ = (char)(0xE0 | (codepoint >> 12));
*last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
*last = (char)(0x80 | (codepoint & 0x3F));
}
valStr += buf;
writer.push_back_u(codepoint);
raw += 4;
break;
}
@ -224,11 +221,13 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
}
else {
valStr += *raw;
writer.push_back(*raw);
raw++;
}
}
if (!writer.finalize())
return JTOK_ERR;
tokenVal = valStr;
consumed = (raw - rawStart);
return JTOK_STRING;
@ -239,26 +238,73 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
}
}
bool UniValue::read(const char *raw)
enum expect_bits {
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(const char *raw, size_t size)
{
clear();
bool expectName = false;
bool expectColon = false;
uint32_t expectMask = 0;
vector<UniValue*> stack;
string tokenVal;
unsigned int consumed;
enum jtokentype tok = JTOK_NONE;
enum jtokentype last_tok = JTOK_NONE;
while (1) {
const char* end = raw + size;
do {
last_tok = tok;
string tokenVal;
unsigned int consumed;
tok = getJsonToken(tokenVal, consumed, raw);
tok = getJsonToken(tokenVal, consumed, raw, end);
if (tok == JTOK_NONE || tok == JTOK_ERR)
break;
return false;
raw += consumed;
bool isValueOpen = jsonTokenIsValue(tok) ||
tok == JTOK_OBJ_OPEN || tok == JTOK_ARR_OPEN;
if (expect(VALUE)) {
if (!isValueOpen)
return false;
clearExpect(VALUE);
} else if (expect(ARR_VALUE)) {
bool isArrValue = isValueOpen || (tok == JTOK_ARR_CLOSE);
if (!isArrValue)
return false;
clearExpect(ARR_VALUE);
} else if (expect(OBJ_NAME)) {
bool isObjName = (tok == JTOK_OBJ_CLOSE || tok == JTOK_STRING);
if (!isObjName)
return false;
} else if (expect(COLON)) {
if (tok != JTOK_COLON)
return false;
clearExpect(COLON);
} else if (!expect(COLON) && (tok == JTOK_COLON)) {
return false;
}
if (expect(NOT_VALUE)) {
if (isValueOpen)
return false;
clearExpect(NOT_VALUE);
}
switch (tok) {
case JTOK_OBJ_OPEN:
@ -280,13 +326,15 @@ bool UniValue::read(const char *raw)
}
if (utyp == VOBJ)
expectName = true;
setExpect(OBJ_NAME);
else
setExpect(ARR_VALUE);
break;
}
case JTOK_OBJ_CLOSE:
case JTOK_ARR_CLOSE: {
if (!stack.size() || expectColon || (last_tok == JTOK_COMMA))
if (!stack.size() || (last_tok == JTOK_COMMA))
return false;
VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR);
@ -295,39 +343,39 @@ bool UniValue::read(const char *raw)
return false;
stack.pop_back();
expectName = false;
clearExpect(OBJ_NAME);
setExpect(NOT_VALUE);
break;
}
case JTOK_COLON: {
if (!stack.size() || expectName || !expectColon)
if (!stack.size())
return false;
UniValue *top = stack.back();
if (top->getType() != VOBJ)
return false;
expectColon = false;
setExpect(VALUE);
break;
}
case JTOK_COMMA: {
if (!stack.size() || expectName || expectColon ||
if (!stack.size() ||
(last_tok == JTOK_COMMA) || (last_tok == JTOK_ARR_OPEN))
return false;
UniValue *top = stack.back();
if (top->getType() == VOBJ)
expectName = true;
setExpect(OBJ_NAME);
else
setExpect(ARR_VALUE);
break;
}
case JTOK_KW_NULL:
case JTOK_KW_TRUE:
case JTOK_KW_FALSE: {
if (!stack.size() || expectName || expectColon)
return false;
UniValue tmpVal;
switch (tok) {
case JTOK_KW_NULL:
@ -342,49 +390,65 @@ bool UniValue::read(const char *raw)
default: /* impossible */ break;
}
if (!stack.size()) {
*this = tmpVal;
break;
}
UniValue *top = stack.back();
top->values.push_back(tmpVal);
setExpect(NOT_VALUE);
break;
}
case JTOK_NUMBER: {
if (!stack.size() || expectName || expectColon)
return false;
UniValue tmpVal(VNUM, tokenVal);
if (!stack.size()) {
*this = tmpVal;
break;
}
UniValue *top = stack.back();
top->values.push_back(tmpVal);
setExpect(NOT_VALUE);
break;
}
case JTOK_STRING: {
if (!stack.size())
return false;
UniValue *top = stack.back();
if (expectName) {
if (expect(OBJ_NAME)) {
UniValue *top = stack.back();
top->keys.push_back(tokenVal);
expectName = false;
expectColon = true;
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:
return false;
}
}
} while (!stack.empty ());
if (stack.size() != 0)
/* Check that nothing follows the initial construct (parsed above). */
tok = getJsonToken(tokenVal, consumed, raw, end);
if (tok != JTOK_NONE)
return false;
return true;
}
bool UniValue::read(const char *raw) {
return read(raw, strlen(raw));
}

View File

@ -0,0 +1,119 @@
// Copyright 2016 Wladimir J. van der Laan
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef UNIVALUE_UTFFILTER_H
#define 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
{
public:
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)
{
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);
}
}
// Write codepoint directly, possibly collating surrogate pairs
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 (surpair) // Two subsequent surrogate pair openers - fail
is_valid = false;
else
surpair = codepoint_;
} 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));
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
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;
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_)
{
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

View File

@ -2,15 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <ctype.h>
#include <iomanip>
#include <sstream>
#include <stdio.h>
#include "univalue.h"
#include "univalue_escapes.h"
// TODO: Using UTF8
using namespace std;
static string json_escape(const string& inS)
@ -24,15 +21,8 @@ static string json_escape(const string& inS)
if (escStr)
outS += escStr;
else if (isprint(ch))
else
outS += ch;
else {
char tmpesc[16];
sprintf(tmpesc, "\\u%04x", ch);
outS += tmpesc;
}
}
return outS;
@ -61,13 +51,6 @@ string UniValue::write(unsigned int prettyIndent,
case VSTR:
s += "\"" + json_escape(val) + "\"";
break;
case VREAL:
{
std::stringstream ss;
ss << std::showpoint << std::fixed << std::setprecision(8) << get_real();
s += ss.str();
}
break;
case VNUM:
s += val;
break;
@ -96,8 +79,6 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s
s += values[i].write(prettyIndent, indentLevel + 1);
if (i != (values.size() - 1)) {
s += ",";
if (prettyIndent)
s += " ";
}
if (prettyIndent)
s += "\n";
@ -120,7 +101,7 @@ void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel,
s += "\"" + json_escape(keys[i]) + "\":";
if (prettyIndent)
s += " ";
s += values[i].write(prettyIndent, indentLevel + 1);
s += values.at(i).write(prettyIndent, indentLevel + 1);
if (i != (values.size() - 1))
s += ",";
if (prettyIndent)

View File

@ -0,0 +1,9 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libunivalue
Description: libunivalue, C++ universal value object and JSON library
Version: @VERSION@
Libs: ${pc_top_builddir}/${pcfiledir}/libunivalue.la

View File

@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libunivalue
Description: libunivalue, C++ universal value object and JSON library
Version: @VERSION@
Libs: -L${libdir} -lunivalue
Cflags: -I${includedir}

6
src/univalue/test/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
unitester
test_json
no_nul
*.trs
*.log

View File

@ -0,0 +1 @@
"This is a string that never ends, yes it goes on and on, my friends.

View File

@ -0,0 +1 @@
{"Extra value after close": true} "misplaced quoted value"

View File

@ -0,0 +1 @@
{"Illegal expression": 1 + 2}

View File

@ -0,0 +1 @@
{"Illegal invocation": alert()}

View File

@ -0,0 +1 @@
{"Numbers cannot have leading zeroes": 013}

View File

@ -0,0 +1 @@
{"Numbers cannot be hex": 0x14}

View File

@ -0,0 +1 @@
["Illegal backslash escape: \x15"]

View File

@ -0,0 +1 @@
[\naked]

View File

@ -0,0 +1 @@
["Illegal backslash escape: \017"]

View File

@ -0,0 +1 @@
[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]

View File

@ -0,0 +1 @@
{"Missing colon" null}

View File

@ -0,0 +1 @@
["Unclosed array"

View File

@ -0,0 +1 @@
{"Double colon":: null}

View File

@ -0,0 +1 @@
{"Comma instead of colon", null}

View File

@ -0,0 +1 @@
["Colon instead of comma": false]

View File

@ -0,0 +1 @@
["Bad value", truth]

View File

@ -0,0 +1 @@
['single quote']

View File

@ -0,0 +1 @@
[" tab character in string "]

View File

@ -0,0 +1 @@
["tab\ character\ in\ string\ "]

View File

@ -0,0 +1,2 @@
["line
break"]

View File

@ -0,0 +1,2 @@
["line\
break"]

View File

@ -0,0 +1 @@
[0e]

View File

@ -0,0 +1 @@
{unquoted_key: "keys must be quoted"}

View File

@ -0,0 +1 @@
[0e+]

View File

@ -0,0 +1 @@
[0e+-1]

View File

@ -0,0 +1 @@
{"Comma instead if closing brace": true,

View File

@ -0,0 +1 @@
["mismatch"}

View File

@ -0,0 +1 @@
{} garbage

View File

@ -0,0 +1 @@
[ true true true [] [] [] ]

View File

@ -0,0 +1 @@
{"a":}

View File

@ -0,0 +1 @@
{"a":1 "b":2}

View File

@ -0,0 +1 @@
["\ud834"]

View File

@ -0,0 +1 @@
["\udd61"]

View File

@ -0,0 +1 @@
["extra comma",]

View File

@ -0,0 +1 @@
["揣。"]

View File

@ -0,0 +1 @@
["<22><><EFBFBD>"]

Binary file not shown.

View File

@ -0,0 +1 @@
["double extra comma",,]

View File

@ -0,0 +1 @@
[ , "<-- missing value"]

View File

@ -0,0 +1 @@
["Comma after the close"],

View File

@ -0,0 +1 @@
["Extra close"]]

View File

@ -0,0 +1 @@
{"Extra comma": true,}

View 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;
}

View File

@ -0,0 +1,58 @@
[
"JSON Test Pattern pass1",
{"object with 1 member":["array with 1 element"]},
{},
[],
-42,
true,
false,
null,
{
"integer": 1234567890,
"real": -9876.543210,
"e": 0.123456789e-12,
"E": 1.234567890E+34,
"": 23456789012E66,
"zero": 0,
"one": 1,
"space": " ",
"quote": "\"",
"backslash": "\\",
"controls": "\b\f\n\r\t",
"slash": "/ & \/",
"alpha": "abcdefghijklmnopqrstuvwyz",
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
"digit": "0123456789",
"0123456789": "digit",
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
"true": true,
"false": false,
"null": null,
"array":[ ],
"object":{ },
"address": "50 St. James Street",
"url": "http://www.JSON.org/",
"comment": "// /* <!-- --",
"# -- --> */": " ",
" s p a c e d " :[1,2 , 3
,
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
"quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
: "A key can be any string"
},
0.5 ,98.6
,
99.44
,
1066,
1e1,
0.1e1,
1e-1,
1e00,2e+00,2e-00
,"rosebud"]

View File

@ -0,0 +1 @@
[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]

Some files were not shown because too many files have changed in this diff Show More