Squashed 'src/univalue/' changes from 16a1f7f6e..a44caf65f
a44caf65f Merge bitcoin-core/univalue-subtree#28: Import fixes for sanitizer reported issues 135254331 Import fixes for sanitizer reported issues d5fb86940 refactor: use c++11 range based for loop in checkObject ff9c37930 refactor: Use nullptr (c++11) instead of NULL 08a99754d build: use ax_cxx_compile_stdcxx.m4 to check for C++11 support 66d3713ce Merge bitcoin-core/univalue#29: ci: travis -> cirrus 808d48729 ci: travis -> cirrus c390ac375 Merge bitcoin-core/univalue#19: Split sources for easier buildsystem integration 4a5b0a1c6 build: Move source entries out to sources.mk 6c7d94b33 build: cleanup wonky gen usage a222637c6 Merge #23: Merge changes from jgarzik/univalue@1ae6a23 98fadc090 Merge #24: Push bool into array correctly 5f03f1f39 Push bool into array correctly f77d0f718 Merge commit '1ae6a231a0169938eb3972c1d48dd17cba5947e1' into HEAD 98261b1e7 Merge #22: Clamp JSON object depth to PHP limit 54c401541 Clamp JSON object depth to PHP limit 5a58a4667 Merge #21: Remove hand-coded UniValue destructor. b4cdfc4f4 Remove hand-coded UniValue destructor. 1ae6a231a Merge pull request #57 from MarcoFalke/test_fix 92bdd11f0 univalue_write: remove unneeded sstream.h include ffb621c13 Merge pull request #56 from drodil/remove_sstream_header f33acf9fe Merge commit '7890db9~' into HEAD 7fba60b5a Merge #17: [docs] Update readme 4577454e7 Merge #13: Fix typo 66e0adec4 Remove unnecessary sstream header from univalue.h ac7e73cda [docs] Update readme 7890db99d Merge #11: Remove deprecated std pair wrappers 88967f658 Version 1.0.4 40e34852a Merge #14: Cleaned up namespace imports to reduce symbol collisions 1dc113dbe Merge pull request #50 from luke-jr/pushKV_bool 72392fb22 [tests] test pushKV for boolean values c23132bcf Pushing boolean value to univalue correctly 4a4964729 Fix typo 85052a481 Remove deprecated std::pair wrappers 81faab26a Merge pull request #48 from fwolfst/47-UPDATE_MIT_LINK_TO_HTTPS b17634ef2 Update URLs to MIT license. 51d3ab34b Merge #10: Add pushKV(key, boolean) function (replaces #5) 129bad96d [tests] test pushKV for boolean values b3c44c947 Pushing boolean value to univalue correctly 07947ff2d Merge #9: [tests] Fix BOOST_CHECK_THROW macro ec849d9a2 [tests] Fix BOOST_CHECK_THROW macro 88ab64f6b Merge pull request #46 from jasonbcox/master 35ed96da3 Merge pull request #44 from MarcoFalke/Mf1709-univalue-cherrypick-explicit 420c22629 Merge pull request #45 from MarcoFalke/Mf1710-univalue-revert-test d208f986d Cleaned up namespace imports to reduce symbol collisions 31bc9f5a4 Merge #8: Remove unused Homebrew workaround fa042093d Remove HomeBrew workaround a523e08ae Merge #7: Declare single-argument (non-converting) constructors "explicit" a9e53b38b Merge #4: Pull upstream fe805ea74 Declare single-argument (non-converting) constructors "explicit" 8a2d6f1e3 Merge pull request #41 from jgarzik/get-obj-map ba341a20d Add getObjMap() helper method. Also, constify checkObject(). ceb119413 Handle .pushKV() and .checkObject() edge cases. 107db9829 Add ::push_back(double) method for feature parity. d41530031 Move one-line implementation of UniValue::read() to header. 52e85b35b Move exception-throwing get_* methods into separate implementation module. dac529675 README.md: update code quotes 3e31dcffb README.md: close code quote d09b8429d Update README.md f1b86edb4 Convert README to markdown style. 1dfe464ef Import UniValue class unit tests from bitcoin project. 0d3e74dd1 operator[] takes size_t index parameter (versus unsigned int) 640158fa2 Private findKey() method becomes size_t clean, and returns bool on failure. 709913585 Merge pull request #36 from ryanofsky/pr/end-str a31231b51 Version 1.0.3 4fd5444d1 Reject unterminated strings 81eba332b Merge pull request #26 from isle2983/pushBackHelpers 36405413e Merge PR #32 from branch 'nul-not-special' of git://github.com/ryanofsky/univalue into merge 89bb07322 Merge pull request #31 from ryanofsky/raw-literals 511008c36 Merge pull request #30 from ryanofsky/test-driver 77974f3a9 Merge pull request #34 from paveljanik/20161116_Wshadow_codepoint a38fcd355 Do not shadow member variable codepoint. fd32d1ab8 Don't require nul-terminated string inputs 0bb1439d0 Support parsing raw literals in UniValue 28876d045 Merge pull request #29 from btcdrak/exportspace 839ccd71f Add test driver for JSONTestSuite 26ef3fff1 Remove trailing whitespace from JSON export cfa0384d6 Convenience wrappers for push_back-ing integer types git-subtree-dir: src/univalue git-subtree-split: a44caf65fe55b9dd8ddb08f04c0f70409efd53b3
This commit is contained in:
parent
2ca7faab42
commit
d29583af8f
|
@ -0,0 +1,44 @@
|
||||||
|
env:
|
||||||
|
MAKEJOBS: "-j4"
|
||||||
|
RUN_TESTS: "true"
|
||||||
|
BASE_OUTDIR: "$CIRRUS_WORKING_DIR/out_dir_base"
|
||||||
|
DEBIAN_FRONTEND: "noninteractive"
|
||||||
|
|
||||||
|
task:
|
||||||
|
container:
|
||||||
|
image: ubuntu:focal
|
||||||
|
cpu: 1
|
||||||
|
memory: 1G
|
||||||
|
greedy: true # https://medium.com/cirruslabs/introducing-greedy-container-instances-29aad06dc2b4
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
- name: "gcc"
|
||||||
|
env:
|
||||||
|
CC: "gcc"
|
||||||
|
CXX: "g++"
|
||||||
|
APT_PKGS: "gcc"
|
||||||
|
- name: "clang"
|
||||||
|
env:
|
||||||
|
CC: "clang"
|
||||||
|
CXX: "clang++"
|
||||||
|
APT_PKGS: "clang"
|
||||||
|
- name: "mingw"
|
||||||
|
env:
|
||||||
|
CC: ""
|
||||||
|
CXX: ""
|
||||||
|
UNIVALUE_CONFIG: "--host=x86_64-w64-mingw32"
|
||||||
|
APT_PKGS: "g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 binutils-mingw-w64-x86-64"
|
||||||
|
RUN_TESTS: "false"
|
||||||
|
|
||||||
|
install_script:
|
||||||
|
- apt update
|
||||||
|
- apt install -y pkg-config build-essential libtool autotools-dev automake bsdmainutils
|
||||||
|
- apt install -y $APT_PKGS
|
||||||
|
autogen_script:
|
||||||
|
- ./autogen.sh
|
||||||
|
configure_script:
|
||||||
|
- ./configure --cache-file=config.cache --bindir=$BASE_OUTDIR/bin --libdir=$BASE_OUTDIR/lib $UNIVALUE_CONFIG
|
||||||
|
make_script:
|
||||||
|
- make $MAKEJOBS V=1
|
||||||
|
test_script:
|
||||||
|
- if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi
|
52
.travis.yml
52
.travis.yml
|
@ -1,52 +0,0 @@
|
||||||
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
|
|
91
Makefile.am
91
Makefile.am
|
@ -1,26 +1,24 @@
|
||||||
|
include sources.mk
|
||||||
ACLOCAL_AMFLAGS = -I build-aux/m4
|
ACLOCAL_AMFLAGS = -I build-aux/m4
|
||||||
.PHONY: gen
|
.PHONY: gen FORCE
|
||||||
.INTERMEDIATE: $(GENBIN)
|
.INTERMEDIATE: $(GENBIN)
|
||||||
|
|
||||||
include_HEADERS = include/univalue.h
|
include_HEADERS = $(UNIVALUE_DIST_HEADERS_INT)
|
||||||
noinst_HEADERS = lib/univalue_escapes.h lib/univalue_utffilter.h
|
noinst_HEADERS = $(UNIVALUE_LIB_HEADERS_INT)
|
||||||
|
|
||||||
lib_LTLIBRARIES = libunivalue.la
|
lib_LTLIBRARIES = libunivalue.la
|
||||||
|
|
||||||
pkgconfigdir = $(libdir)/pkgconfig
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
pkgconfig_DATA = pc/libunivalue.pc
|
pkgconfig_DATA = pc/libunivalue.pc
|
||||||
|
|
||||||
libunivalue_la_SOURCES = \
|
libunivalue_la_SOURCES = $(UNIVALUE_LIB_SOURCES_INT)
|
||||||
lib/univalue.cpp \
|
|
||||||
lib/univalue_read.cpp \
|
|
||||||
lib/univalue_write.cpp
|
|
||||||
|
|
||||||
libunivalue_la_LDFLAGS = \
|
libunivalue_la_LDFLAGS = \
|
||||||
-version-info $(LIBUNIVALUE_CURRENT):$(LIBUNIVALUE_REVISION):$(LIBUNIVALUE_AGE) \
|
-version-info $(LIBUNIVALUE_CURRENT):$(LIBUNIVALUE_REVISION):$(LIBUNIVALUE_AGE) \
|
||||||
-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
|
||||||
|
@ -29,65 +27,32 @@ $(GENBIN): $(GEN_SRCS)
|
||||||
@echo Building $@
|
@echo Building $@
|
||||||
$(AM_V_at)c++ -I$(top_srcdir)/include -o $@ $<
|
$(AM_V_at)c++ -I$(top_srcdir)/include -o $@ $<
|
||||||
|
|
||||||
gen: lib/univalue_escapes.h $(GENBIN)
|
gen: $(GENBIN) FORCE
|
||||||
@echo Updating $<
|
@echo Updating lib/univalue_escapes.h
|
||||||
$(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_unitester_SOURCES = $(UNIVALUE_TEST_UNITESTER_INT)
|
||||||
|
|
||||||
test_unitester_SOURCES = test/unitester.cpp
|
|
||||||
test_unitester_LDADD = libunivalue.la
|
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)/$(UNIVALUE_TEST_DATA_DIR_INT)\"
|
||||||
test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
|
test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
|
||||||
|
|
||||||
TEST_FILES = \
|
test_test_json_SOURCES = $(UNIVALUE_TEST_JSON_INT)
|
||||||
$(TEST_DATA_DIR)/fail10.json \
|
test_test_json_LDADD = libunivalue.la
|
||||||
$(TEST_DATA_DIR)/fail11.json \
|
test_test_json_CXXFLAGS = -I$(top_srcdir)/include
|
||||||
$(TEST_DATA_DIR)/fail12.json \
|
test_test_json_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
|
||||||
$(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)/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
|
|
||||||
|
|
||||||
EXTRA_DIST=$(TEST_FILES) $(GEN_SRCS)
|
test_no_nul_SOURCES = $(UNIVALUE_TEST_NO_NUL_INT)
|
||||||
|
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 = $(UNIVALUE_TEST_OBJECT_INT)
|
||||||
|
test_object_LDADD = libunivalue.la
|
||||||
|
test_object_CXXFLAGS = -I$(top_srcdir)/include
|
||||||
|
test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
|
||||||
|
|
||||||
|
TEST_FILES = $(UNIVALUE_TEST_FILES_INT)
|
||||||
|
|
||||||
|
EXTRA_DIST=$(UNIVALUE_TEST_FILES_INT) $(GEN_SRCS)
|
||||||
|
|
7
README
7
README
|
@ -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.
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
# 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).
|
||||||
|
|
||||||
|
## Library usage
|
||||||
|
|
||||||
|
This is a fork of univalue used by Bitcoin Core. It is not maintained for usage
|
||||||
|
by other projects. Notably, the API may break in non-backward-compatible ways.
|
||||||
|
|
||||||
|
Other projects looking for a maintained library should use the upstream
|
||||||
|
univalue at https://github.com/jgarzik/univalue.
|
|
@ -0,0 +1,962 @@
|
||||||
|
# ===========================================================================
|
||||||
|
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
|
||||||
|
# ===========================================================================
|
||||||
|
#
|
||||||
|
# SYNOPSIS
|
||||||
|
#
|
||||||
|
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
|
||||||
|
#
|
||||||
|
# DESCRIPTION
|
||||||
|
#
|
||||||
|
# Check for baseline language coverage in the compiler for the specified
|
||||||
|
# version of the C++ standard. If necessary, add switches to CXX and
|
||||||
|
# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
|
||||||
|
# or '14' (for the C++14 standard).
|
||||||
|
#
|
||||||
|
# The second argument, if specified, indicates whether you insist on an
|
||||||
|
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
|
||||||
|
# -std=c++11). If neither is specified, you get whatever works, with
|
||||||
|
# preference for no added switch, and then for an extended mode.
|
||||||
|
#
|
||||||
|
# The third argument, if specified 'mandatory' or if left unspecified,
|
||||||
|
# indicates that baseline support for the specified C++ standard is
|
||||||
|
# required and that the macro should error out if no mode with that
|
||||||
|
# support is found. If specified 'optional', then configuration proceeds
|
||||||
|
# regardless, after defining HAVE_CXX${VERSION} if and only if a
|
||||||
|
# supporting mode is found.
|
||||||
|
#
|
||||||
|
# LICENSE
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
|
||||||
|
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
|
||||||
|
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
|
||||||
|
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
|
||||||
|
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
|
||||||
|
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
|
||||||
|
# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
|
||||||
|
# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
|
||||||
|
# Copyright (c) 2020 Jason Merrill <jason@redhat.com>
|
||||||
|
#
|
||||||
|
# Copying and distribution of this file, with or without modification, are
|
||||||
|
# permitted in any medium without royalty provided the copyright notice
|
||||||
|
# and this notice are preserved. This file is offered as-is, without any
|
||||||
|
# warranty.
|
||||||
|
|
||||||
|
#serial 12
|
||||||
|
|
||||||
|
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
|
||||||
|
dnl (serial version number 13).
|
||||||
|
|
||||||
|
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
|
||||||
|
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
|
||||||
|
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
|
||||||
|
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
|
||||||
|
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
|
||||||
|
m4_if([$2], [], [],
|
||||||
|
[$2], [ext], [],
|
||||||
|
[$2], [noext], [],
|
||||||
|
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
|
||||||
|
m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
|
||||||
|
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
|
||||||
|
[$3], [optional], [ax_cxx_compile_cxx$1_required=false],
|
||||||
|
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
|
||||||
|
AC_LANG_PUSH([C++])dnl
|
||||||
|
ac_success=no
|
||||||
|
|
||||||
|
m4_if([$2], [], [dnl
|
||||||
|
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
|
||||||
|
ax_cv_cxx_compile_cxx$1,
|
||||||
|
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||||
|
[ax_cv_cxx_compile_cxx$1=yes],
|
||||||
|
[ax_cv_cxx_compile_cxx$1=no])])
|
||||||
|
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
|
||||||
|
ac_success=yes
|
||||||
|
fi])
|
||||||
|
|
||||||
|
m4_if([$2], [noext], [], [dnl
|
||||||
|
if test x$ac_success = xno; then
|
||||||
|
for alternative in ${ax_cxx_compile_alternatives}; do
|
||||||
|
switch="-std=gnu++${alternative}"
|
||||||
|
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
|
||||||
|
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
|
||||||
|
$cachevar,
|
||||||
|
[ac_save_CXX="$CXX"
|
||||||
|
CXX="$CXX $switch"
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||||
|
[eval $cachevar=yes],
|
||||||
|
[eval $cachevar=no])
|
||||||
|
CXX="$ac_save_CXX"])
|
||||||
|
if eval test x\$$cachevar = xyes; then
|
||||||
|
CXX="$CXX $switch"
|
||||||
|
if test -n "$CXXCPP" ; then
|
||||||
|
CXXCPP="$CXXCPP $switch"
|
||||||
|
fi
|
||||||
|
ac_success=yes
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi])
|
||||||
|
|
||||||
|
m4_if([$2], [ext], [], [dnl
|
||||||
|
if test x$ac_success = xno; then
|
||||||
|
dnl HP's aCC needs +std=c++11 according to:
|
||||||
|
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
|
||||||
|
dnl Cray's crayCC needs "-h std=c++11"
|
||||||
|
for alternative in ${ax_cxx_compile_alternatives}; do
|
||||||
|
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
|
||||||
|
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
|
||||||
|
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
|
||||||
|
$cachevar,
|
||||||
|
[ac_save_CXX="$CXX"
|
||||||
|
CXX="$CXX $switch"
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||||
|
[eval $cachevar=yes],
|
||||||
|
[eval $cachevar=no])
|
||||||
|
CXX="$ac_save_CXX"])
|
||||||
|
if eval test x\$$cachevar = xyes; then
|
||||||
|
CXX="$CXX $switch"
|
||||||
|
if test -n "$CXXCPP" ; then
|
||||||
|
CXXCPP="$CXXCPP $switch"
|
||||||
|
fi
|
||||||
|
ac_success=yes
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test x$ac_success = xyes; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi])
|
||||||
|
AC_LANG_POP([C++])
|
||||||
|
if test x$ax_cxx_compile_cxx$1_required = xtrue; then
|
||||||
|
if test x$ac_success = xno; then
|
||||||
|
AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if test x$ac_success = xno; then
|
||||||
|
HAVE_CXX$1=0
|
||||||
|
AC_MSG_NOTICE([No compiler with C++$1 support was found])
|
||||||
|
else
|
||||||
|
HAVE_CXX$1=1
|
||||||
|
AC_DEFINE(HAVE_CXX$1,1,
|
||||||
|
[define if the compiler supports basic C++$1 syntax])
|
||||||
|
fi
|
||||||
|
AC_SUBST(HAVE_CXX$1)
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
dnl Test body for checking C++11 support
|
||||||
|
|
||||||
|
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
|
||||||
|
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
dnl Test body for checking C++14 support
|
||||||
|
|
||||||
|
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
|
||||||
|
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||||
|
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||||
|
)
|
||||||
|
|
||||||
|
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
|
||||||
|
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||||
|
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||||
|
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
|
||||||
|
)
|
||||||
|
|
||||||
|
dnl Tests for new features in C++11
|
||||||
|
|
||||||
|
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
|
||||||
|
|
||||||
|
// If the compiler admits that it is not ready for C++11, why torture it?
|
||||||
|
// Hopefully, this will speed up the test.
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
|
||||||
|
#error "This is not a C++ compiler"
|
||||||
|
|
||||||
|
#elif __cplusplus < 201103L
|
||||||
|
|
||||||
|
#error "This is not a C++11 compiler"
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
namespace cxx11
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace test_static_assert
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct check
|
||||||
|
{
|
||||||
|
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_final_override
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Base
|
||||||
|
{
|
||||||
|
virtual ~Base() {}
|
||||||
|
virtual void f() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Derived : public Base
|
||||||
|
{
|
||||||
|
virtual ~Derived() override {}
|
||||||
|
virtual void f() override {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_double_right_angle_brackets
|
||||||
|
{
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
struct check {};
|
||||||
|
|
||||||
|
typedef check<void> single_type;
|
||||||
|
typedef check<check<void>> double_type;
|
||||||
|
typedef check<check<check<void>>> triple_type;
|
||||||
|
typedef check<check<check<check<void>>>> quadruple_type;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_decltype
|
||||||
|
{
|
||||||
|
|
||||||
|
int
|
||||||
|
f()
|
||||||
|
{
|
||||||
|
int a = 1;
|
||||||
|
decltype(a) b = 2;
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_type_deduction
|
||||||
|
{
|
||||||
|
|
||||||
|
template < typename T1, typename T2 >
|
||||||
|
struct is_same
|
||||||
|
{
|
||||||
|
static const bool value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
struct is_same<T, T>
|
||||||
|
{
|
||||||
|
static const bool value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename T1, typename T2 >
|
||||||
|
auto
|
||||||
|
add(T1 a1, T2 a2) -> decltype(a1 + a2)
|
||||||
|
{
|
||||||
|
return a1 + a2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
test(const int c, volatile int v)
|
||||||
|
{
|
||||||
|
static_assert(is_same<int, decltype(0)>::value == true, "");
|
||||||
|
static_assert(is_same<int, decltype(c)>::value == false, "");
|
||||||
|
static_assert(is_same<int, decltype(v)>::value == false, "");
|
||||||
|
auto ac = c;
|
||||||
|
auto av = v;
|
||||||
|
auto sumi = ac + av + 'x';
|
||||||
|
auto sumf = ac + av + 1.0;
|
||||||
|
static_assert(is_same<int, decltype(ac)>::value == true, "");
|
||||||
|
static_assert(is_same<int, decltype(av)>::value == true, "");
|
||||||
|
static_assert(is_same<int, decltype(sumi)>::value == true, "");
|
||||||
|
static_assert(is_same<int, decltype(sumf)>::value == false, "");
|
||||||
|
static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
|
||||||
|
return (sumf > 0.0) ? sumi : add(c, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_noexcept
|
||||||
|
{
|
||||||
|
|
||||||
|
int f() { return 0; }
|
||||||
|
int g() noexcept { return 0; }
|
||||||
|
|
||||||
|
static_assert(noexcept(f()) == false, "");
|
||||||
|
static_assert(noexcept(g()) == true, "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_constexpr
|
||||||
|
{
|
||||||
|
|
||||||
|
template < typename CharT >
|
||||||
|
unsigned long constexpr
|
||||||
|
strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
|
||||||
|
{
|
||||||
|
return *s ? strlen_c_r(s + 1, acc + 1) : acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename CharT >
|
||||||
|
unsigned long constexpr
|
||||||
|
strlen_c(const CharT *const s) noexcept
|
||||||
|
{
|
||||||
|
return strlen_c_r(s, 0UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(strlen_c("") == 0UL, "");
|
||||||
|
static_assert(strlen_c("1") == 1UL, "");
|
||||||
|
static_assert(strlen_c("example") == 7UL, "");
|
||||||
|
static_assert(strlen_c("another\0example") == 7UL, "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_rvalue_references
|
||||||
|
{
|
||||||
|
|
||||||
|
template < int N >
|
||||||
|
struct answer
|
||||||
|
{
|
||||||
|
static constexpr int value = N;
|
||||||
|
};
|
||||||
|
|
||||||
|
answer<1> f(int&) { return answer<1>(); }
|
||||||
|
answer<2> f(const int&) { return answer<2>(); }
|
||||||
|
answer<3> f(int&&) { return answer<3>(); }
|
||||||
|
|
||||||
|
void
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
const int c = 0;
|
||||||
|
static_assert(decltype(f(i))::value == 1, "");
|
||||||
|
static_assert(decltype(f(c))::value == 2, "");
|
||||||
|
static_assert(decltype(f(0))::value == 3, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_uniform_initialization
|
||||||
|
{
|
||||||
|
|
||||||
|
struct test
|
||||||
|
{
|
||||||
|
static const int zero {};
|
||||||
|
static const int one {1};
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(test::zero == 0, "");
|
||||||
|
static_assert(test::one == 1, "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_lambdas
|
||||||
|
{
|
||||||
|
|
||||||
|
void
|
||||||
|
test1()
|
||||||
|
{
|
||||||
|
auto lambda1 = [](){};
|
||||||
|
auto lambda2 = lambda1;
|
||||||
|
lambda1();
|
||||||
|
lambda2();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
test2()
|
||||||
|
{
|
||||||
|
auto a = [](int i, int j){ return i + j; }(1, 2);
|
||||||
|
auto b = []() -> int { return '0'; }();
|
||||||
|
auto c = [=](){ return a + b; }();
|
||||||
|
auto d = [&](){ return c; }();
|
||||||
|
auto e = [a, &b](int x) mutable {
|
||||||
|
const auto identity = [](int y){ return y; };
|
||||||
|
for (auto i = 0; i < a; ++i)
|
||||||
|
a += b--;
|
||||||
|
return x + identity(a + b);
|
||||||
|
}(0);
|
||||||
|
return a + b + c + d + e;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
test3()
|
||||||
|
{
|
||||||
|
const auto nullary = [](){ return 0; };
|
||||||
|
const auto unary = [](int x){ return x; };
|
||||||
|
using nullary_t = decltype(nullary);
|
||||||
|
using unary_t = decltype(unary);
|
||||||
|
const auto higher1st = [](nullary_t f){ return f(); };
|
||||||
|
const auto higher2nd = [unary](nullary_t f1){
|
||||||
|
return [unary, f1](unary_t f2){ return f2(unary(f1())); };
|
||||||
|
};
|
||||||
|
return higher1st(nullary) + higher2nd(nullary)(unary);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_variadic_templates
|
||||||
|
{
|
||||||
|
|
||||||
|
template <int...>
|
||||||
|
struct sum;
|
||||||
|
|
||||||
|
template <int N0, int... N1toN>
|
||||||
|
struct sum<N0, N1toN...>
|
||||||
|
{
|
||||||
|
static constexpr auto value = N0 + sum<N1toN...>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct sum<>
|
||||||
|
{
|
||||||
|
static constexpr auto value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sum<>::value == 0, "");
|
||||||
|
static_assert(sum<1>::value == 1, "");
|
||||||
|
static_assert(sum<23>::value == 23, "");
|
||||||
|
static_assert(sum<1, 2>::value == 3, "");
|
||||||
|
static_assert(sum<5, 5, 11>::value == 21, "");
|
||||||
|
static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
|
||||||
|
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
|
||||||
|
// because of this.
|
||||||
|
namespace test_template_alias_sfinae
|
||||||
|
{
|
||||||
|
|
||||||
|
struct foo {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using member = typename T::member_type;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void func(...) {}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void func(member<T>*) {}
|
||||||
|
|
||||||
|
void test();
|
||||||
|
|
||||||
|
void test() { func<foo>(0); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cxx11
|
||||||
|
|
||||||
|
#endif // __cplusplus >= 201103L
|
||||||
|
|
||||||
|
]])
|
||||||
|
|
||||||
|
|
||||||
|
dnl Tests for new features in C++14
|
||||||
|
|
||||||
|
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
|
||||||
|
|
||||||
|
// If the compiler admits that it is not ready for C++14, why torture it?
|
||||||
|
// Hopefully, this will speed up the test.
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
|
||||||
|
#error "This is not a C++ compiler"
|
||||||
|
|
||||||
|
#elif __cplusplus < 201402L
|
||||||
|
|
||||||
|
#error "This is not a C++14 compiler"
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
namespace cxx14
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace test_polymorphic_lambdas
|
||||||
|
{
|
||||||
|
|
||||||
|
int
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
const auto lambda = [](auto&&... args){
|
||||||
|
const auto istiny = [](auto x){
|
||||||
|
return (sizeof(x) == 1UL) ? 1 : 0;
|
||||||
|
};
|
||||||
|
const int aretiny[] = { istiny(args)... };
|
||||||
|
return aretiny[0];
|
||||||
|
};
|
||||||
|
return lambda(1, 1L, 1.0f, '1');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_binary_literals
|
||||||
|
{
|
||||||
|
|
||||||
|
constexpr auto ivii = 0b0000000000101010;
|
||||||
|
static_assert(ivii == 42, "wrong value");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_generalized_constexpr
|
||||||
|
{
|
||||||
|
|
||||||
|
template < typename CharT >
|
||||||
|
constexpr unsigned long
|
||||||
|
strlen_c(const CharT *const s) noexcept
|
||||||
|
{
|
||||||
|
auto length = 0UL;
|
||||||
|
for (auto p = s; *p; ++p)
|
||||||
|
++length;
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(strlen_c("") == 0UL, "");
|
||||||
|
static_assert(strlen_c("x") == 1UL, "");
|
||||||
|
static_assert(strlen_c("test") == 4UL, "");
|
||||||
|
static_assert(strlen_c("another\0test") == 7UL, "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_lambda_init_capture
|
||||||
|
{
|
||||||
|
|
||||||
|
int
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
auto x = 0;
|
||||||
|
const auto lambda1 = [a = x](int b){ return a + b; };
|
||||||
|
const auto lambda2 = [a = lambda1(x)](){ return a; };
|
||||||
|
return lambda2();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_digit_separators
|
||||||
|
{
|
||||||
|
|
||||||
|
constexpr auto ten_million = 100'000'000;
|
||||||
|
static_assert(ten_million == 100000000, "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_return_type_deduction
|
||||||
|
{
|
||||||
|
|
||||||
|
auto f(int& x) { return x; }
|
||||||
|
decltype(auto) g(int& x) { return x; }
|
||||||
|
|
||||||
|
template < typename T1, typename T2 >
|
||||||
|
struct is_same
|
||||||
|
{
|
||||||
|
static constexpr auto value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
struct is_same<T, T>
|
||||||
|
{
|
||||||
|
static constexpr auto value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
test()
|
||||||
|
{
|
||||||
|
auto x = 0;
|
||||||
|
static_assert(is_same<int, decltype(f(x))>::value, "");
|
||||||
|
static_assert(is_same<int&, decltype(g(x))>::value, "");
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cxx14
|
||||||
|
|
||||||
|
#endif // __cplusplus >= 201402L
|
||||||
|
|
||||||
|
]])
|
||||||
|
|
||||||
|
|
||||||
|
dnl Tests for new features in C++17
|
||||||
|
|
||||||
|
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
|
||||||
|
|
||||||
|
// If the compiler admits that it is not ready for C++17, why torture it?
|
||||||
|
// Hopefully, this will speed up the test.
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
|
||||||
|
#error "This is not a C++ compiler"
|
||||||
|
|
||||||
|
#elif __cplusplus < 201703L
|
||||||
|
|
||||||
|
#error "This is not a C++17 compiler"
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <utility>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace cxx17
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace test_constexpr_lambdas
|
||||||
|
{
|
||||||
|
|
||||||
|
constexpr int foo = [](){return 42;}();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test::nested_namespace::definitions
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_fold_expression
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
int multiply(Args... args)
|
||||||
|
{
|
||||||
|
return (args * ... * 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
bool all(Args... args)
|
||||||
|
{
|
||||||
|
return (args && ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_extended_static_assert
|
||||||
|
{
|
||||||
|
|
||||||
|
static_assert (true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_auto_brace_init_list
|
||||||
|
{
|
||||||
|
|
||||||
|
auto foo = {5};
|
||||||
|
auto bar {5};
|
||||||
|
|
||||||
|
static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
|
||||||
|
static_assert(std::is_same<int, decltype(bar)>::value);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_typename_in_template_template_parameter
|
||||||
|
{
|
||||||
|
|
||||||
|
template<template<typename> typename X> struct D;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_fallthrough_nodiscard_maybe_unused_attributes
|
||||||
|
{
|
||||||
|
|
||||||
|
int f1()
|
||||||
|
{
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] int f2()
|
||||||
|
{
|
||||||
|
[[maybe_unused]] auto unused = f1();
|
||||||
|
|
||||||
|
switch (f1())
|
||||||
|
{
|
||||||
|
case 17:
|
||||||
|
f1();
|
||||||
|
[[fallthrough]];
|
||||||
|
case 42:
|
||||||
|
f1();
|
||||||
|
}
|
||||||
|
return f1();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_extended_aggregate_initialization
|
||||||
|
{
|
||||||
|
|
||||||
|
struct base1
|
||||||
|
{
|
||||||
|
int b1, b2 = 42;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct base2
|
||||||
|
{
|
||||||
|
base2() {
|
||||||
|
b3 = 42;
|
||||||
|
}
|
||||||
|
int b3;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct derived : base1, base2
|
||||||
|
{
|
||||||
|
int d;
|
||||||
|
};
|
||||||
|
|
||||||
|
derived d1 {{1, 2}, {}, 4}; // full initialization
|
||||||
|
derived d2 {{}, {}, 4}; // value-initialized bases
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_general_range_based_for_loop
|
||||||
|
{
|
||||||
|
|
||||||
|
struct iter
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
int& operator* ()
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int& operator* () const
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter& operator++()
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sentinel
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator== (const iter& i, const sentinel& s)
|
||||||
|
{
|
||||||
|
return i.i == s.i;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!= (const iter& i, const sentinel& s)
|
||||||
|
{
|
||||||
|
return !(i == s);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct range
|
||||||
|
{
|
||||||
|
iter begin() const
|
||||||
|
{
|
||||||
|
return {0};
|
||||||
|
}
|
||||||
|
|
||||||
|
sentinel end() const
|
||||||
|
{
|
||||||
|
return {5};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void f()
|
||||||
|
{
|
||||||
|
range r {};
|
||||||
|
|
||||||
|
for (auto i : r)
|
||||||
|
{
|
||||||
|
[[maybe_unused]] auto v = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_lambda_capture_asterisk_this_by_value
|
||||||
|
{
|
||||||
|
|
||||||
|
struct t
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int foo()
|
||||||
|
{
|
||||||
|
return [*this]()
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_enum_class_construction
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class byte : unsigned char
|
||||||
|
{};
|
||||||
|
|
||||||
|
byte foo {42};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_constexpr_if
|
||||||
|
{
|
||||||
|
|
||||||
|
template <bool cond>
|
||||||
|
int f ()
|
||||||
|
{
|
||||||
|
if constexpr(cond)
|
||||||
|
{
|
||||||
|
return 13;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_selection_statement_with_initializer
|
||||||
|
{
|
||||||
|
|
||||||
|
int f()
|
||||||
|
{
|
||||||
|
return 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
int f2()
|
||||||
|
{
|
||||||
|
if (auto i = f(); i > 0)
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (auto i = f(); i + 4)
|
||||||
|
{
|
||||||
|
case 17:
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_template_argument_deduction_for_class_templates
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
struct pair
|
||||||
|
{
|
||||||
|
pair (T1 p1, T2 p2)
|
||||||
|
: m1 {p1},
|
||||||
|
m2 {p2}
|
||||||
|
{}
|
||||||
|
|
||||||
|
T1 m1;
|
||||||
|
T2 m2;
|
||||||
|
};
|
||||||
|
|
||||||
|
void f()
|
||||||
|
{
|
||||||
|
[[maybe_unused]] auto p = pair{13, 42u};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_non_type_auto_template_parameters
|
||||||
|
{
|
||||||
|
|
||||||
|
template <auto n>
|
||||||
|
struct B
|
||||||
|
{};
|
||||||
|
|
||||||
|
B<5> b1;
|
||||||
|
B<'a'> b2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_structured_bindings
|
||||||
|
{
|
||||||
|
|
||||||
|
int arr[2] = { 1, 2 };
|
||||||
|
std::pair<int, int> pr = { 1, 2 };
|
||||||
|
|
||||||
|
auto f1() -> int(&)[2]
|
||||||
|
{
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto f2() -> std::pair<int, int>&
|
||||||
|
{
|
||||||
|
return pr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S
|
||||||
|
{
|
||||||
|
int x1 : 2;
|
||||||
|
volatile double y1;
|
||||||
|
};
|
||||||
|
|
||||||
|
S f3()
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto [ x1, y1 ] = f1();
|
||||||
|
auto& [ xr1, yr1 ] = f1();
|
||||||
|
auto [ x2, y2 ] = f2();
|
||||||
|
auto& [ xr2, yr2 ] = f2();
|
||||||
|
const auto [ x3, y3 ] = f3();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_exception_spec_type_system
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Good {};
|
||||||
|
struct Bad {};
|
||||||
|
|
||||||
|
void g1() noexcept;
|
||||||
|
void g2();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Bad
|
||||||
|
f(T*, T*);
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
Good
|
||||||
|
f(T1*, T2*);
|
||||||
|
|
||||||
|
static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test_inline_variables
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class T> void f(T)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<class T> inline T g(T)
|
||||||
|
{
|
||||||
|
return T{};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void f<>(int)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<> int g<>(int)
|
||||||
|
{
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cxx17
|
||||||
|
|
||||||
|
#endif // __cplusplus < 201703L
|
||||||
|
|
||||||
|
]])
|
|
@ -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], [4])
|
||||||
m4_define([libunivalue_interface_age], [2])
|
m4_define([libunivalue_interface_age], [4])
|
||||||
# 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.4],
|
||||||
[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
|
||||||
|
@ -45,6 +45,9 @@ AC_SUBST(LIBUNIVALUE_AGE)
|
||||||
LT_INIT
|
LT_INIT
|
||||||
LT_LANG([C++])
|
LT_LANG([C++])
|
||||||
|
|
||||||
|
dnl Require C++11 compiler (no GNU extensions)
|
||||||
|
AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory], [nodefault])
|
||||||
|
|
||||||
case $host in
|
case $host in
|
||||||
*mingw*)
|
*mingw*)
|
||||||
LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static"
|
LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Copyright 2014 BitPay Inc.
|
// Copyright 2014 BitPay Inc.
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or https://opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
//
|
//
|
||||||
// To re-create univalue_escapes.h:
|
// To re-create univalue_escapes.h:
|
||||||
|
@ -12,8 +12,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "univalue.h"
|
#include "univalue.h"
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
static bool initEscapes;
|
static bool initEscapes;
|
||||||
static std::string escapes[256];
|
static std::string escapes[256];
|
||||||
|
|
||||||
|
@ -47,7 +45,7 @@ static void outputEscape()
|
||||||
|
|
||||||
for (unsigned int i = 0; i < 256; i++) {
|
for (unsigned int i = 0; i < 256; i++) {
|
||||||
if (escapes[i].empty()) {
|
if (escapes[i].empty()) {
|
||||||
printf("\tNULL,\n");
|
printf("\tnullptr,\n");
|
||||||
} else {
|
} else {
|
||||||
printf("\t\"");
|
printf("\t\"");
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
// Copyright 2014 BitPay Inc.
|
// Copyright 2014 BitPay Inc.
|
||||||
// Copyright 2015 Bitcoin Core Developers
|
// Copyright 2015 Bitcoin Core Developers
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or https://opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#ifndef __UNIVALUE_H__
|
#ifndef __UNIVALUE_H__
|
||||||
#define __UNIVALUE_H__
|
#define __UNIVALUE_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <sstream> // .get_int64()
|
|
||||||
#include <utility> // std::pair
|
|
||||||
|
|
||||||
class UniValue {
|
class UniValue {
|
||||||
public:
|
public:
|
||||||
enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
|
enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
|
||||||
|
@ -47,7 +45,6 @@ public:
|
||||||
std::string s(val_);
|
std::string s(val_);
|
||||||
setStr(s);
|
setStr(s);
|
||||||
}
|
}
|
||||||
~UniValue() {}
|
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
@ -69,10 +66,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 +90,29 @@ 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(bool 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_);
|
||||||
|
@ -111,6 +130,10 @@ public:
|
||||||
UniValue tmpVal(val_);
|
UniValue tmpVal(val_);
|
||||||
return pushKV(key, tmpVal);
|
return pushKV(key, tmpVal);
|
||||||
}
|
}
|
||||||
|
bool pushKV(const std::string& key, bool val_) {
|
||||||
|
UniValue tmpVal(val_);
|
||||||
|
return pushKV(key, tmpVal);
|
||||||
|
}
|
||||||
bool pushKV(const std::string& key, int val_) {
|
bool pushKV(const std::string& key, int val_) {
|
||||||
UniValue tmpVal((int64_t)val_);
|
UniValue tmpVal((int64_t)val_);
|
||||||
return pushKV(key, tmpVal);
|
return pushKV(key, tmpVal);
|
||||||
|
@ -124,9 +147,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 +159,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;
|
||||||
|
|
||||||
|
@ -153,76 +177,9 @@ public:
|
||||||
const UniValue& get_array() const;
|
const UniValue& get_array() const;
|
||||||
|
|
||||||
enum VType type() const { return getType(); }
|
enum VType type() const { return getType(); }
|
||||||
bool push_back(std::pair<std::string,UniValue> pear) {
|
|
||||||
return pushKV(pear.first, pear.second);
|
|
||||||
}
|
|
||||||
friend const UniValue& find_value( const UniValue& obj, const std::string& name);
|
friend const UniValue& find_value( const UniValue& obj, const std::string& name);
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
|
||||||
// The following were added for compatibility with json_spirit.
|
|
||||||
// Most duplicate other methods, and should be removed.
|
|
||||||
//
|
|
||||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, const char *cVal)
|
|
||||||
{
|
|
||||||
std::string key(cKey);
|
|
||||||
UniValue uVal(cVal);
|
|
||||||
return std::make_pair(key, uVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, std::string strVal)
|
|
||||||
{
|
|
||||||
std::string key(cKey);
|
|
||||||
UniValue uVal(strVal);
|
|
||||||
return std::make_pair(key, uVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, uint64_t u64Val)
|
|
||||||
{
|
|
||||||
std::string key(cKey);
|
|
||||||
UniValue uVal(u64Val);
|
|
||||||
return std::make_pair(key, uVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, int64_t i64Val)
|
|
||||||
{
|
|
||||||
std::string key(cKey);
|
|
||||||
UniValue uVal(i64Val);
|
|
||||||
return std::make_pair(key, uVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, bool iVal)
|
|
||||||
{
|
|
||||||
std::string key(cKey);
|
|
||||||
UniValue uVal(iVal);
|
|
||||||
return std::make_pair(key, uVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, int iVal)
|
|
||||||
{
|
|
||||||
std::string key(cKey);
|
|
||||||
UniValue uVal(iVal);
|
|
||||||
return std::make_pair(key, uVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, double dVal)
|
|
||||||
{
|
|
||||||
std::string key(cKey);
|
|
||||||
UniValue uVal(dVal);
|
|
||||||
return std::make_pair(key, uVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::pair<std::string,UniValue> Pair(const char *cKey, const UniValue& uVal)
|
|
||||||
{
|
|
||||||
std::string key(cKey);
|
|
||||||
return std::make_pair(key, uVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::pair<std::string,UniValue> Pair(std::string key, const UniValue& uVal)
|
|
||||||
{
|
|
||||||
return std::make_pair(key, uVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum jtokentype {
|
enum jtokentype {
|
||||||
JTOK_ERR = -1,
|
JTOK_ERR = -1,
|
||||||
JTOK_NONE = 0, // eof
|
JTOK_NONE = 0, // eof
|
||||||
|
@ -240,7 +197,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)
|
||||||
|
|
225
lib/univalue.cpp
225
lib/univalue.cpp
|
@ -1,80 +1,15 @@
|
||||||
// Copyright 2014 BitPay Inc.
|
// Copyright 2014 BitPay Inc.
|
||||||
// Copyright 2015 Bitcoin Core Developers
|
// Copyright 2015 Bitcoin Core Developers
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or https://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;
|
|
||||||
|
|
||||||
const UniValue NullUniValue;
|
const UniValue NullUniValue;
|
||||||
|
|
||||||
void UniValue::clear()
|
void UniValue::clear()
|
||||||
|
@ -100,15 +35,15 @@ bool UniValue::setBool(bool val_)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool validNumStr(const string& s)
|
static bool validNumStr(const std::string& s)
|
||||||
{
|
{
|
||||||
string tokenVal;
|
std::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);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UniValue::setNumStr(const string& val_)
|
bool UniValue::setNumStr(const std::string& val_)
|
||||||
{
|
{
|
||||||
if (!validNumStr(val_))
|
if (!validNumStr(val_))
|
||||||
return false;
|
return false;
|
||||||
|
@ -121,7 +56,7 @@ bool UniValue::setNumStr(const string& val_)
|
||||||
|
|
||||||
bool UniValue::setInt(uint64_t val_)
|
bool UniValue::setInt(uint64_t val_)
|
||||||
{
|
{
|
||||||
ostringstream oss;
|
std::ostringstream oss;
|
||||||
|
|
||||||
oss << val_;
|
oss << val_;
|
||||||
|
|
||||||
|
@ -130,7 +65,7 @@ bool UniValue::setInt(uint64_t val_)
|
||||||
|
|
||||||
bool UniValue::setInt(int64_t val_)
|
bool UniValue::setInt(int64_t val_)
|
||||||
{
|
{
|
||||||
ostringstream oss;
|
std::ostringstream oss;
|
||||||
|
|
||||||
oss << val_;
|
oss << val_;
|
||||||
|
|
||||||
|
@ -139,7 +74,7 @@ bool UniValue::setInt(int64_t val_)
|
||||||
|
|
||||||
bool UniValue::setFloat(double val_)
|
bool UniValue::setFloat(double val_)
|
||||||
{
|
{
|
||||||
ostringstream oss;
|
std::ostringstream oss;
|
||||||
|
|
||||||
oss << std::setprecision(16) << val_;
|
oss << std::setprecision(16) << val_;
|
||||||
|
|
||||||
|
@ -148,7 +83,7 @@ bool UniValue::setFloat(double val_)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UniValue::setStr(const string& val_)
|
bool UniValue::setStr(const std::string& val_)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
typ = VSTR;
|
typ = VSTR;
|
||||||
|
@ -189,13 +124,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,34 +148,49 @@ 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 (std::map<std::string,UniValue::VType>::const_iterator it = t.begin();
|
for (size_t i = 0; i < keys.size(); i++) {
|
||||||
it != t.end(); ++it) {
|
if (keys[i] == key) {
|
||||||
int idx = findKey(it->first);
|
retIdx = i;
|
||||||
if (idx < 0)
|
return true;
|
||||||
return false;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (values.at(idx).getType() != it->second)
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t) const
|
||||||
|
{
|
||||||
|
if (typ != VOBJ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& object: t) {
|
||||||
|
size_t idx = 0;
|
||||||
|
if (!findKey(object.first, idx)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.at(idx).getType() != object.second) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -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;
|
||||||
|
@ -271,7 +230,7 @@ const char *uvTypeName(UniValue::VType t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// not reached
|
// not reached
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UniValue& find_value(const UniValue& obj, const std::string& name)
|
const UniValue& find_value(const UniValue& obj, const std::string& name)
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -34,229 +34,229 @@ static const char *escapes[256] = {
|
||||||
"\\u001d",
|
"\\u001d",
|
||||||
"\\u001e",
|
"\\u001e",
|
||||||
"\\u001f",
|
"\\u001f",
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
"\\\"",
|
"\\\"",
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
"\\\\",
|
"\\\\",
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
"\\u007f",
|
"\\u007f",
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
NULL,
|
nullptr,
|
||||||
};
|
};
|
||||||
#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H
|
#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
// Copyright 2014 BitPay Inc.
|
||||||
|
// Copyright 2015 Bitcoin Core Developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or https://opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
#include <limits>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#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 = nullptr;
|
||||||
|
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 an 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 = nullptr;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Copyright 2014 BitPay Inc.
|
// Copyright 2014 BitPay Inc.
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or https://opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -8,7 +8,13 @@
|
||||||
#include "univalue.h"
|
#include "univalue.h"
|
||||||
#include "univalue_utffilter.h"
|
#include "univalue_utffilter.h"
|
||||||
|
|
||||||
using namespace std;
|
/*
|
||||||
|
* According to stackexchange, the original json test suite wanted
|
||||||
|
* to limit depth to 22. Widely-deployed PHP bails at depth 512,
|
||||||
|
* so we will follow PHP's lead, which should be more than sufficient
|
||||||
|
* (further stackexchange comments indicate depth > 32 rarely occurs).
|
||||||
|
*/
|
||||||
|
static const size_t MAX_JSON_DEPTH = 512;
|
||||||
|
|
||||||
static bool json_isdigit(int ch)
|
static bool json_isdigit(int ch)
|
||||||
{
|
{
|
||||||
|
@ -42,22 +48,22 @@ static const char *hatoui(const char *first, const char *last,
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
|
enum jtokentype getJsonToken(std::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);
|
||||||
|
@ -114,7 +120,7 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
|
||||||
case '8':
|
case '8':
|
||||||
case '9': {
|
case '9': {
|
||||||
// part 1: int
|
// part 1: int
|
||||||
string numStr;
|
std::string numStr;
|
||||||
|
|
||||||
const char *first = raw;
|
const char *first = raw;
|
||||||
|
|
||||||
|
@ -127,40 +133,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++;
|
||||||
}
|
}
|
||||||
|
@ -174,16 +180,19 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
|
||||||
case '"': {
|
case '"': {
|
||||||
raw++; // skip "
|
raw++; // skip "
|
||||||
|
|
||||||
string valStr;
|
std::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 +205,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);
|
||||||
|
@ -217,7 +227,7 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
writer.push_back(*raw);
|
writer.push_back(static_cast<unsigned char>(*raw));
|
||||||
raw++;
|
raw++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,7 +244,7 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum expect_bits {
|
enum expect_bits : unsigned {
|
||||||
EXP_OBJ_NAME = (1U << 0),
|
EXP_OBJ_NAME = (1U << 0),
|
||||||
EXP_COLON = (1U << 1),
|
EXP_COLON = (1U << 1),
|
||||||
EXP_ARR_VALUE = (1U << 2),
|
EXP_ARR_VALUE = (1U << 2),
|
||||||
|
@ -246,21 +256,22 @@ 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();
|
||||||
|
|
||||||
uint32_t expectMask = 0;
|
uint32_t expectMask = 0;
|
||||||
vector<UniValue*> stack;
|
std::vector<UniValue*> stack;
|
||||||
|
|
||||||
string tokenVal;
|
std::string tokenVal;
|
||||||
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;
|
||||||
|
@ -320,6 +331,9 @@ bool UniValue::read(const char *raw)
|
||||||
stack.push_back(newTop);
|
stack.push_back(newTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stack.size() > MAX_JSON_DEPTH)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (utyp == VOBJ)
|
if (utyp == VOBJ)
|
||||||
setExpect(OBJ_NAME);
|
setExpect(OBJ_NAME);
|
||||||
else
|
else
|
||||||
|
@ -371,9 +385,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 +399,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 +412,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 +426,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 +451,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;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Copyright 2016 Wladimir J. van der Laan
|
// Copyright 2016 Wladimir J. van der Laan
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or https://opensource.org/licenses/mit-license.php.
|
||||||
#ifndef UNIVALUE_UTFFILTER_H
|
#ifndef UNIVALUE_UTFFILTER_H
|
||||||
#define UNIVALUE_UTFFILTER_H
|
#define UNIVALUE_UTFFILTER_H
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
class JSONUTF8StringFilter
|
class JSONUTF8StringFilter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
JSONUTF8StringFilter(std::string &s):
|
explicit JSONUTF8StringFilter(std::string &s):
|
||||||
str(s), is_valid(true), codepoint(0), state(0), surpair(0)
|
str(s), is_valid(true), codepoint(0), state(0), surpair(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -46,19 +46,19 @@ 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_)
|
||||||
{
|
{
|
||||||
if (state) // Only accept full codepoints in open state
|
if (state) // Only accept full codepoints in open 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 // Second half doesn't follow a first half - fail
|
} else // Second half doesn't follow a first half - fail
|
||||||
is_valid = false;
|
is_valid = false;
|
||||||
|
@ -66,7 +66,7 @@ public:
|
||||||
if (surpair) // First half of surrogate pair not followed by second - fail
|
if (surpair) // First half of surrogate pair not followed by second - fail
|
||||||
is_valid = false;
|
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
|
||||||
|
@ -96,22 +96,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 half of open UTF-16 surrogate pair, or 0
|
unsigned int surpair; // First half of open UTF-16 surrogate pair, or 0
|
||||||
|
|
||||||
void append_codepoint(unsigned int codepoint)
|
void append_codepoint(unsigned int codepoint_)
|
||||||
{
|
{
|
||||||
if (codepoint <= 0x7f)
|
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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,37 +1,34 @@
|
||||||
// Copyright 2014 BitPay Inc.
|
// Copyright 2014 BitPay Inc.
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or https://opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "univalue.h"
|
#include "univalue.h"
|
||||||
#include "univalue_escapes.h"
|
#include "univalue_escapes.h"
|
||||||
|
|
||||||
using namespace std;
|
static std::string json_escape(const std::string& inS)
|
||||||
|
|
||||||
static string json_escape(const string& inS)
|
|
||||||
{
|
{
|
||||||
string outS;
|
std::string outS;
|
||||||
outS.reserve(inS.size() * 2);
|
outS.reserve(inS.size() * 2);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < inS.size(); i++) {
|
for (unsigned int i = 0; i < inS.size(); i++) {
|
||||||
unsigned char ch = inS[i];
|
unsigned char ch = static_cast<unsigned char>(inS[i]);
|
||||||
const char *escStr = escapes[ch];
|
const char *escStr = escapes[ch];
|
||||||
|
|
||||||
if (escStr)
|
if (escStr)
|
||||||
outS += escStr;
|
outS += escStr;
|
||||||
else
|
else
|
||||||
outS += ch;
|
outS += static_cast<char>(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
return outS;
|
return outS;
|
||||||
}
|
}
|
||||||
|
|
||||||
string UniValue::write(unsigned int prettyIndent,
|
std::string UniValue::write(unsigned int prettyIndent,
|
||||||
unsigned int indentLevel) const
|
unsigned int indentLevel) const
|
||||||
{
|
{
|
||||||
string s;
|
std::string s;
|
||||||
s.reserve(1024);
|
s.reserve(1024);
|
||||||
|
|
||||||
unsigned int modIndent = indentLevel;
|
unsigned int modIndent = indentLevel;
|
||||||
|
@ -62,12 +59,12 @@ string UniValue::write(unsigned int prettyIndent,
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, string& s)
|
static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, std::string& s)
|
||||||
{
|
{
|
||||||
s.append(prettyIndent * indentLevel, ' ');
|
s.append(prettyIndent * indentLevel, ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, string& s) const
|
void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const
|
||||||
{
|
{
|
||||||
s += "[";
|
s += "[";
|
||||||
if (prettyIndent)
|
if (prettyIndent)
|
||||||
|
@ -79,8 +76,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";
|
||||||
|
@ -91,7 +86,7 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s
|
||||||
s += "]";
|
s += "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, string& s) const
|
void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const
|
||||||
{
|
{
|
||||||
s += "{";
|
s += "{";
|
||||||
if (prettyIndent)
|
if (prettyIndent)
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
# - All variables are namespaced with UNIVALUE_ to avoid colliding with
|
||||||
|
# downstream makefiles.
|
||||||
|
# - All Variables ending in _HEADERS or _SOURCES confuse automake, so the
|
||||||
|
# _INT postfix is applied.
|
||||||
|
# - Convenience variables, for example a UNIVALUE_TEST_DIR should not be used
|
||||||
|
# as they interfere with automatic dependency generation
|
||||||
|
# - The %reldir% is the relative path from the Makefile.am. This allows
|
||||||
|
# downstreams to use these variables without having to manually account for
|
||||||
|
# the path change.
|
||||||
|
|
||||||
|
UNIVALUE_INCLUDE_DIR_INT = %reldir%/include
|
||||||
|
|
||||||
|
UNIVALUE_DIST_HEADERS_INT =
|
||||||
|
UNIVALUE_DIST_HEADERS_INT += %reldir%/include/univalue.h
|
||||||
|
|
||||||
|
UNIVALUE_LIB_HEADERS_INT =
|
||||||
|
UNIVALUE_LIB_HEADERS_INT += %reldir%/lib/univalue_utffilter.h
|
||||||
|
UNIVALUE_LIB_HEADERS_INT += %reldir%/lib/univalue_escapes.h
|
||||||
|
|
||||||
|
UNIVALUE_LIB_SOURCES_INT =
|
||||||
|
UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue.cpp
|
||||||
|
UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_get.cpp
|
||||||
|
UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_read.cpp
|
||||||
|
UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_write.cpp
|
||||||
|
|
||||||
|
UNIVALUE_TEST_DATA_DIR_INT = %reldir%/test
|
||||||
|
|
||||||
|
UNIVALUE_TEST_UNITESTER_INT =
|
||||||
|
UNIVALUE_TEST_UNITESTER_INT += %reldir%/test/unitester.cpp
|
||||||
|
|
||||||
|
UNIVALUE_TEST_JSON_INT =
|
||||||
|
UNIVALUE_TEST_JSON_INT += %reldir%/test/test_json.cpp
|
||||||
|
|
||||||
|
UNIVALUE_TEST_NO_NUL_INT =
|
||||||
|
UNIVALUE_TEST_NO_NUL_INT += %reldir%/test/no_nul.cpp
|
||||||
|
|
||||||
|
UNIVALUE_TEST_OBJECT_INT =
|
||||||
|
UNIVALUE_TEST_OBJECT_INT += %reldir%/test/object.cpp
|
||||||
|
|
||||||
|
UNIVALUE_TEST_FILES_INT =
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail1.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail2.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail3.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail4.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail5.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail6.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail7.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail8.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail9.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail10.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail11.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail12.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail13.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail14.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail15.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail16.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail17.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail18.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail19.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail20.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail21.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail22.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail23.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail24.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail25.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail26.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail27.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail28.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail29.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail30.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail31.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail32.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail33.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail34.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail35.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail36.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail37.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail38.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail39.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail40.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail41.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail42.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail44.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/fail45.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/pass1.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/pass2.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/pass3.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/pass4.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/round1.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/round2.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/round3.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/round4.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/round5.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/round6.json
|
||||||
|
UNIVALUE_TEST_FILES_INT += %reldir%/test/round7.json
|
|
@ -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.
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
"This file ends without a newline or close-quote.
|
|
@ -0,0 +1 @@
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
|
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1,420 @@
|
||||||
|
// Copyright (c) 2014 BitPay Inc.
|
||||||
|
// Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or https://opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <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); \
|
||||||
|
assert(0 && "No exception caught"); \
|
||||||
|
} catch (excMatch & e) { \
|
||||||
|
} catch (...) { \
|
||||||
|
assert(0 && "Wrong exception caught"); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#define BOOST_CHECK_NO_THROW(stmt) { \
|
||||||
|
try { \
|
||||||
|
(stmt); \
|
||||||
|
} catch (...) { \
|
||||||
|
assert(0); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
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(arr.push_back(true));
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(arr.empty(), false);
|
||||||
|
BOOST_CHECK_EQUAL(arr.size(), 10);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023");
|
||||||
|
BOOST_CHECK_EQUAL(arr[0].getType(), UniValue::VNUM);
|
||||||
|
BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy");
|
||||||
|
BOOST_CHECK_EQUAL(arr[1].getType(), UniValue::VSTR);
|
||||||
|
BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy");
|
||||||
|
BOOST_CHECK_EQUAL(arr[2].getType(), UniValue::VSTR);
|
||||||
|
BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing");
|
||||||
|
BOOST_CHECK_EQUAL(arr[3].getType(), UniValue::VSTR);
|
||||||
|
BOOST_CHECK_EQUAL(arr[4].getValStr(), "going");
|
||||||
|
BOOST_CHECK_EQUAL(arr[4].getType(), UniValue::VSTR);
|
||||||
|
BOOST_CHECK_EQUAL(arr[5].getValStr(), "400");
|
||||||
|
BOOST_CHECK_EQUAL(arr[5].getType(), UniValue::VNUM);
|
||||||
|
BOOST_CHECK_EQUAL(arr[6].getValStr(), "-400");
|
||||||
|
BOOST_CHECK_EQUAL(arr[6].getType(), UniValue::VNUM);
|
||||||
|
BOOST_CHECK_EQUAL(arr[7].getValStr(), "-401");
|
||||||
|
BOOST_CHECK_EQUAL(arr[7].getType(), UniValue::VNUM);
|
||||||
|
BOOST_CHECK_EQUAL(arr[8].getValStr(), "-40.1");
|
||||||
|
BOOST_CHECK_EQUAL(arr[8].getType(), UniValue::VNUM);
|
||||||
|
BOOST_CHECK_EQUAL(arr[9].getValStr(), "1");
|
||||||
|
BOOST_CHECK_EQUAL(arr[9].getType(), UniValue::VBOOL);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(arr[999].getValStr(), "");
|
||||||
|
|
||||||
|
arr.clear();
|
||||||
|
BOOST_CHECK(arr.empty());
|
||||||
|
BOOST_CHECK_EQUAL(arr.size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
strKey = "moon";
|
||||||
|
BOOST_CHECK(obj.pushKV(strKey, true));
|
||||||
|
|
||||||
|
strKey = "spoon";
|
||||||
|
BOOST_CHECK(obj.pushKV(strKey, false));
|
||||||
|
|
||||||
|
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(), 11);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100");
|
||||||
|
BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John");
|
||||||
|
BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith");
|
||||||
|
BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25");
|
||||||
|
BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600");
|
||||||
|
BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12");
|
||||||
|
BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012");
|
||||||
|
BOOST_CHECK_EQUAL(obj["moon"].getValStr(), "1");
|
||||||
|
BOOST_CHECK_EQUAL(obj["spoon"].getValStr(), "");
|
||||||
|
BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000");
|
||||||
|
BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345");
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), "");
|
||||||
|
|
||||||
|
BOOST_CHECK(obj.exists("age"));
|
||||||
|
BOOST_CHECK(obj.exists("first"));
|
||||||
|
BOOST_CHECK(obj.exists("last"));
|
||||||
|
BOOST_CHECK(obj.exists("distance"));
|
||||||
|
BOOST_CHECK(obj.exists("time"));
|
||||||
|
BOOST_CHECK(obj.exists("calories"));
|
||||||
|
BOOST_CHECK(obj.exists("temperature"));
|
||||||
|
BOOST_CHECK(obj.exists("moon"));
|
||||||
|
BOOST_CHECK(obj.exists("spoon"));
|
||||||
|
BOOST_CHECK(obj.exists("cat1"));
|
||||||
|
BOOST_CHECK(obj.exists("cat2"));
|
||||||
|
|
||||||
|
BOOST_CHECK(!obj.exists("nyuknyuknyuk"));
|
||||||
|
|
||||||
|
std::map<std::string, UniValue::VType> objTypes;
|
||||||
|
objTypes["age"] = UniValue::VNUM;
|
||||||
|
objTypes["first"] = UniValue::VSTR;
|
||||||
|
objTypes["last"] = UniValue::VSTR;
|
||||||
|
objTypes["distance"] = UniValue::VNUM;
|
||||||
|
objTypes["time"] = UniValue::VNUM;
|
||||||
|
objTypes["calories"] = UniValue::VNUM;
|
||||||
|
objTypes["temperature"] = UniValue::VNUM;
|
||||||
|
objTypes["moon"] = UniValue::VBOOL;
|
||||||
|
objTypes["spoon"] = UniValue::VBOOL;
|
||||||
|
objTypes["cat1"] = UniValue::VNUM;
|
||||||
|
objTypes["cat2"] = UniValue::VNUM;
|
||||||
|
BOOST_CHECK(obj.checkObject(objTypes));
|
||||||
|
|
||||||
|
objTypes["cat2"] = UniValue::VSTR;
|
||||||
|
BOOST_CHECK(!obj.checkObject(objTypes));
|
||||||
|
|
||||||
|
obj.clear();
|
||||||
|
BOOST_CHECK(obj.empty());
|
||||||
|
BOOST_CHECK_EQUAL(obj.size(), 0);
|
||||||
|
BOOST_CHECK_EQUAL(obj.getType(), UniValue::VNULL);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
|
|
@ -0,0 +1 @@
|
||||||
|
"abcdefghijklmnopqrstuvwxyz"
|
|
@ -0,0 +1 @@
|
||||||
|
7
|
|
@ -0,0 +1 @@
|
||||||
|
true
|
|
@ -0,0 +1 @@
|
||||||
|
false
|
|
@ -0,0 +1 @@
|
||||||
|
null
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
// Copyright 2014 BitPay Inc.
|
// Copyright 2014 BitPay Inc.
|
||||||
// Distributed under the MIT/X11 software license, see the accompanying
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or https://opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -17,8 +17,7 @@
|
||||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace std;
|
std::string srcdir(JSON_TEST_SRC);
|
||||||
string srcdir(JSON_TEST_SRC);
|
|
||||||
static bool test_failed = false;
|
static bool test_failed = false;
|
||||||
|
|
||||||
#define d_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", filename.c_str()); } }
|
#define d_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", filename.c_str()); } }
|
||||||
|
@ -30,9 +29,9 @@ static std::string rtrim(std::string s)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void runtest(string filename, const string& jdata)
|
static void runtest(std::string filename, const std::string& jdata)
|
||||||
{
|
{
|
||||||
string prefix = filename.substr(0, 4);
|
std::string prefix = filename.substr(0, 4);
|
||||||
|
|
||||||
bool wantPass = (prefix == "pass") || (prefix == "roun");
|
bool wantPass = (prefix == "pass") || (prefix == "roun");
|
||||||
bool wantFail = (prefix == "fail");
|
bool wantFail = (prefix == "fail");
|
||||||
|
@ -56,19 +55,19 @@ static void runtest(string filename, const string& jdata)
|
||||||
|
|
||||||
static void runtest_file(const char *filename_)
|
static void runtest_file(const char *filename_)
|
||||||
{
|
{
|
||||||
string basename(filename_);
|
std::string basename(filename_);
|
||||||
string filename = srcdir + "/" + basename;
|
std::string filename = srcdir + "/" + basename;
|
||||||
FILE *f = fopen(filename.c_str(), "r");
|
FILE *f = fopen(filename.c_str(), "r");
|
||||||
assert(f != NULL);
|
assert(f != nullptr);
|
||||||
|
|
||||||
string jdata;
|
std::string jdata;
|
||||||
|
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
while (!feof(f)) {
|
while (!feof(f)) {
|
||||||
int bread = fread(buf, 1, sizeof(buf), f);
|
int bread = fread(buf, 1, sizeof(buf), f);
|
||||||
assert(!ferror(f));
|
assert(!ferror(f));
|
||||||
|
|
||||||
string s(buf, bread);
|
std::string s(buf, bread);
|
||||||
jdata += s;
|
jdata += s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,6 +112,9 @@ 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
|
||||||
|
"fail45.json", // nested beyond max depth
|
||||||
"fail3.json",
|
"fail3.json",
|
||||||
"fail4.json", // extra comma
|
"fail4.json", // extra comma
|
||||||
"fail5.json",
|
"fail5.json",
|
||||||
|
@ -123,8 +125,14 @@ static const char *filenames[] = {
|
||||||
"pass1.json",
|
"pass1.json",
|
||||||
"pass2.json",
|
"pass2.json",
|
||||||
"pass3.json",
|
"pass3.json",
|
||||||
|
"pass4.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