├── .cirrus.yml ├── .gitignore ├── COPYING ├── Makefile.am ├── README.md ├── autogen.sh ├── build-aux └── m4 │ ├── .gitignore │ └── ax_cxx_compile_stdcxx.m4 ├── configure.ac ├── gen └── gen.cpp ├── include └── univalue.h ├── lib ├── .gitignore ├── univalue.cpp ├── univalue_escapes.h ├── univalue_get.cpp ├── univalue_read.cpp ├── univalue_utffilter.h └── univalue_write.cpp ├── pc ├── libunivalue-uninstalled.pc.in └── libunivalue.pc.in ├── sources.mk └── test ├── .gitignore ├── fail1.json ├── fail10.json ├── fail11.json ├── fail12.json ├── fail13.json ├── fail14.json ├── fail15.json ├── fail16.json ├── fail17.json ├── fail18.json ├── fail19.json ├── fail2.json ├── fail20.json ├── fail21.json ├── fail22.json ├── fail23.json ├── fail24.json ├── fail25.json ├── fail26.json ├── fail27.json ├── fail28.json ├── fail29.json ├── fail3.json ├── fail30.json ├── fail31.json ├── fail32.json ├── fail33.json ├── fail34.json ├── fail35.json ├── fail36.json ├── fail37.json ├── fail38.json ├── fail39.json ├── fail4.json ├── fail40.json ├── fail41.json ├── fail42.json ├── fail44.json ├── fail45.json ├── fail5.json ├── fail6.json ├── fail7.json ├── fail8.json ├── fail9.json ├── no_nul.cpp ├── object.cpp ├── pass1.json ├── pass2.json ├── pass3.json ├── pass4.json ├── round1.json ├── round2.json ├── round3.json ├── round4.json ├── round5.json ├── round6.json ├── round7.json ├── test_json.cpp └── unitester.cpp /.cirrus.yml: -------------------------------------------------------------------------------- 1 | env: 2 | MAKEJOBS: "-j4" 3 | RUN_TESTS: "true" 4 | BASE_OUTDIR: "$CIRRUS_WORKING_DIR/out_dir_base" 5 | DEBIAN_FRONTEND: "noninteractive" 6 | 7 | task: 8 | container: 9 | image: ubuntu:focal 10 | cpu: 1 11 | memory: 1G 12 | greedy: true # https://medium.com/cirruslabs/introducing-greedy-container-instances-29aad06dc2b4 13 | 14 | matrix: 15 | - name: "gcc" 16 | env: 17 | CC: "gcc" 18 | CXX: "g++" 19 | APT_PKGS: "gcc" 20 | - name: "clang" 21 | env: 22 | CC: "clang" 23 | CXX: "clang++" 24 | APT_PKGS: "clang" 25 | - name: "mingw" 26 | env: 27 | CC: "" 28 | CXX: "" 29 | UNIVALUE_CONFIG: "--host=x86_64-w64-mingw32" 30 | APT_PKGS: "g++-mingw-w64-x86-64 gcc-mingw-w64-x86-64 binutils-mingw-w64-x86-64" 31 | RUN_TESTS: "false" 32 | 33 | install_script: 34 | - apt update 35 | - apt install -y pkg-config build-essential libtool autotools-dev automake bsdmainutils 36 | - apt install -y $APT_PKGS 37 | autogen_script: 38 | - ./autogen.sh 39 | configure_script: 40 | - ./configure --cache-file=config.cache --bindir=$BASE_OUTDIR/bin --libdir=$BASE_OUTDIR/lib $UNIVALUE_CONFIG 41 | make_script: 42 | - make $MAKEJOBS V=1 43 | test_script: 44 | - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .deps/ 2 | INSTALL 3 | Makefile 4 | Makefile.in 5 | aclocal.m4 6 | autom4te.cache/ 7 | compile 8 | config.log 9 | config.status 10 | config.guess 11 | config.sub 12 | configure 13 | depcomp 14 | install-sh 15 | missing 16 | stamp-h1 17 | univalue-config.h* 18 | test-driver 19 | libtool 20 | ltmain.sh 21 | test-suite.log 22 | 23 | *.a 24 | *.la 25 | *.lo 26 | *.logs 27 | *.o 28 | *.pc 29 | *.trs 30 | 31 | .dirstamp 32 | .libs 33 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to deal 4 | in the Software without restriction, including without limitation the rights 5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | THE SOFTWARE. 19 | 20 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | include sources.mk 2 | ACLOCAL_AMFLAGS = -I build-aux/m4 3 | .PHONY: gen FORCE 4 | .INTERMEDIATE: $(GENBIN) 5 | 6 | include_HEADERS = $(UNIVALUE_DIST_HEADERS_INT) 7 | noinst_HEADERS = $(UNIVALUE_LIB_HEADERS_INT) 8 | 9 | lib_LTLIBRARIES = libunivalue.la 10 | 11 | pkgconfigdir = $(libdir)/pkgconfig 12 | pkgconfig_DATA = pc/libunivalue.pc 13 | 14 | libunivalue_la_SOURCES = $(UNIVALUE_LIB_SOURCES_INT) 15 | 16 | libunivalue_la_LDFLAGS = \ 17 | -version-info $(LIBUNIVALUE_CURRENT):$(LIBUNIVALUE_REVISION):$(LIBUNIVALUE_AGE) \ 18 | -no-undefined 19 | libunivalue_la_CXXFLAGS = -I$(top_srcdir)/include 20 | 21 | TESTS = test/object test/unitester test/no_nul 22 | 23 | GENBIN = gen/gen$(BUILD_EXEEXT) 24 | GEN_SRCS = gen/gen.cpp 25 | 26 | $(GENBIN): $(GEN_SRCS) 27 | @echo Building $@ 28 | $(AM_V_at)c++ -I$(top_srcdir)/include -o $@ $< 29 | 30 | gen: $(GENBIN) FORCE 31 | @echo Updating lib/univalue_escapes.h 32 | $(AM_V_at)$(GENBIN) > lib/univalue_escapes.h 33 | 34 | noinst_PROGRAMS = $(TESTS) test/test_json 35 | 36 | test_unitester_SOURCES = $(UNIVALUE_TEST_UNITESTER_INT) 37 | test_unitester_LDADD = libunivalue.la 38 | test_unitester_CXXFLAGS = -I$(top_srcdir)/include -DJSON_TEST_SRC=\"$(srcdir)/$(UNIVALUE_TEST_DATA_DIR_INT)\" 39 | test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) 40 | 41 | test_test_json_SOURCES = $(UNIVALUE_TEST_JSON_INT) 42 | test_test_json_LDADD = libunivalue.la 43 | test_test_json_CXXFLAGS = -I$(top_srcdir)/include 44 | test_test_json_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) 45 | 46 | test_no_nul_SOURCES = $(UNIVALUE_TEST_NO_NUL_INT) 47 | test_no_nul_LDADD = libunivalue.la 48 | test_no_nul_CXXFLAGS = -I$(top_srcdir)/include 49 | test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) 50 | 51 | test_object_SOURCES = $(UNIVALUE_TEST_OBJECT_INT) 52 | test_object_LDADD = libunivalue.la 53 | test_object_CXXFLAGS = -I$(top_srcdir)/include 54 | test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) 55 | 56 | TEST_FILES = $(UNIVALUE_TEST_FILES_INT) 57 | 58 | EXTRA_DIST=$(UNIVALUE_TEST_FILES_INT) $(GEN_SRCS) 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # UniValue 3 | 4 | ## Summary 5 | 6 | A universal value class, with JSON encoding and decoding. 7 | 8 | UniValue is an abstract data type that may be a null, boolean, string, 9 | number, array container, or a key/value dictionary container, nested to 10 | an arbitrary depth. 11 | 12 | This class is aligned with the JSON standard, [RFC 13 | 7159](https://tools.ietf.org/html/rfc7159.html). 14 | 15 | ## Library usage 16 | 17 | This is a fork of univalue used by Bitcoin Core. It is not maintained for usage 18 | by other projects. Notably, the API is broken in non-backward-compatible ways. 19 | 20 | Other projects looking for a maintained library should use the upstream 21 | univalue at https://github.com/jgarzik/univalue. 22 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | srcdir="$(dirname $0)" 4 | cd "$srcdir" 5 | if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then 6 | LIBTOOLIZE="${GLIBTOOLIZE}" 7 | export LIBTOOLIZE 8 | fi 9 | autoreconf --install --force 10 | -------------------------------------------------------------------------------- /build-aux/m4/.gitignore: -------------------------------------------------------------------------------- 1 | /*.m4 2 | -------------------------------------------------------------------------------- /build-aux/m4/ax_cxx_compile_stdcxx.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check for baseline language coverage in the compiler for the specified 12 | # version of the C++ standard. If necessary, add switches to CXX and 13 | # CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) 14 | # or '14' (for the C++14 standard). 15 | # 16 | # The second argument, if specified, indicates whether you insist on an 17 | # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. 18 | # -std=c++11). If neither is specified, you get whatever works, with 19 | # preference for no added switch, and then for an extended mode. 20 | # 21 | # The third argument, if specified 'mandatory' or if left unspecified, 22 | # indicates that baseline support for the specified C++ standard is 23 | # required and that the macro should error out if no mode with that 24 | # support is found. If specified 'optional', then configuration proceeds 25 | # regardless, after defining HAVE_CXX${VERSION} if and only if a 26 | # supporting mode is found. 27 | # 28 | # LICENSE 29 | # 30 | # Copyright (c) 2008 Benjamin Kosnik 31 | # Copyright (c) 2012 Zack Weinberg 32 | # Copyright (c) 2013 Roy Stogner 33 | # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov 34 | # Copyright (c) 2015 Paul Norman 35 | # Copyright (c) 2015 Moritz Klammler 36 | # Copyright (c) 2016, 2018 Krzesimir Nowak 37 | # Copyright (c) 2019 Enji Cooper 38 | # Copyright (c) 2020 Jason Merrill 39 | # 40 | # Copying and distribution of this file, with or without modification, are 41 | # permitted in any medium without royalty provided the copyright notice 42 | # and this notice are preserved. This file is offered as-is, without any 43 | # warranty. 44 | 45 | #serial 12 46 | 47 | dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro 48 | dnl (serial version number 13). 49 | 50 | AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl 51 | m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], 52 | [$1], [14], [ax_cxx_compile_alternatives="14 1y"], 53 | [$1], [17], [ax_cxx_compile_alternatives="17 1z"], 54 | [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl 55 | m4_if([$2], [], [], 56 | [$2], [ext], [], 57 | [$2], [noext], [], 58 | [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl 59 | m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], 60 | [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], 61 | [$3], [optional], [ax_cxx_compile_cxx$1_required=false], 62 | [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) 63 | AC_LANG_PUSH([C++])dnl 64 | ac_success=no 65 | 66 | m4_if([$2], [], [dnl 67 | AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, 68 | ax_cv_cxx_compile_cxx$1, 69 | [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], 70 | [ax_cv_cxx_compile_cxx$1=yes], 71 | [ax_cv_cxx_compile_cxx$1=no])]) 72 | if test x$ax_cv_cxx_compile_cxx$1 = xyes; then 73 | ac_success=yes 74 | fi]) 75 | 76 | m4_if([$2], [noext], [], [dnl 77 | if test x$ac_success = xno; then 78 | for alternative in ${ax_cxx_compile_alternatives}; do 79 | switch="-std=gnu++${alternative}" 80 | cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) 81 | AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, 82 | $cachevar, 83 | [ac_save_CXX="$CXX" 84 | CXX="$CXX $switch" 85 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], 86 | [eval $cachevar=yes], 87 | [eval $cachevar=no]) 88 | CXX="$ac_save_CXX"]) 89 | if eval test x\$$cachevar = xyes; then 90 | CXX="$CXX $switch" 91 | if test -n "$CXXCPP" ; then 92 | CXXCPP="$CXXCPP $switch" 93 | fi 94 | ac_success=yes 95 | break 96 | fi 97 | done 98 | fi]) 99 | 100 | m4_if([$2], [ext], [], [dnl 101 | if test x$ac_success = xno; then 102 | dnl HP's aCC needs +std=c++11 according to: 103 | dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf 104 | dnl Cray's crayCC needs "-h std=c++11" 105 | for alternative in ${ax_cxx_compile_alternatives}; do 106 | for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do 107 | cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) 108 | AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, 109 | $cachevar, 110 | [ac_save_CXX="$CXX" 111 | CXX="$CXX $switch" 112 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], 113 | [eval $cachevar=yes], 114 | [eval $cachevar=no]) 115 | CXX="$ac_save_CXX"]) 116 | if eval test x\$$cachevar = xyes; then 117 | CXX="$CXX $switch" 118 | if test -n "$CXXCPP" ; then 119 | CXXCPP="$CXXCPP $switch" 120 | fi 121 | ac_success=yes 122 | break 123 | fi 124 | done 125 | if test x$ac_success = xyes; then 126 | break 127 | fi 128 | done 129 | fi]) 130 | AC_LANG_POP([C++]) 131 | if test x$ax_cxx_compile_cxx$1_required = xtrue; then 132 | if test x$ac_success = xno; then 133 | AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) 134 | fi 135 | fi 136 | if test x$ac_success = xno; then 137 | HAVE_CXX$1=0 138 | AC_MSG_NOTICE([No compiler with C++$1 support was found]) 139 | else 140 | HAVE_CXX$1=1 141 | AC_DEFINE(HAVE_CXX$1,1, 142 | [define if the compiler supports basic C++$1 syntax]) 143 | fi 144 | AC_SUBST(HAVE_CXX$1) 145 | ]) 146 | 147 | 148 | dnl Test body for checking C++11 support 149 | 150 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], 151 | _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 152 | ) 153 | 154 | 155 | dnl Test body for checking C++14 support 156 | 157 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], 158 | _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 159 | _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 160 | ) 161 | 162 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], 163 | _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 164 | _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 165 | _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 166 | ) 167 | 168 | dnl Tests for new features in C++11 169 | 170 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ 171 | 172 | // If the compiler admits that it is not ready for C++11, why torture it? 173 | // Hopefully, this will speed up the test. 174 | 175 | #ifndef __cplusplus 176 | 177 | #error "This is not a C++ compiler" 178 | 179 | #elif __cplusplus < 201103L 180 | 181 | #error "This is not a C++11 compiler" 182 | 183 | #else 184 | 185 | namespace cxx11 186 | { 187 | 188 | namespace test_static_assert 189 | { 190 | 191 | template 192 | struct check 193 | { 194 | static_assert(sizeof(int) <= sizeof(T), "not big enough"); 195 | }; 196 | 197 | } 198 | 199 | namespace test_final_override 200 | { 201 | 202 | struct Base 203 | { 204 | virtual ~Base() {} 205 | virtual void f() {} 206 | }; 207 | 208 | struct Derived : public Base 209 | { 210 | virtual ~Derived() override {} 211 | virtual void f() override {} 212 | }; 213 | 214 | } 215 | 216 | namespace test_double_right_angle_brackets 217 | { 218 | 219 | template < typename T > 220 | struct check {}; 221 | 222 | typedef check single_type; 223 | typedef check> double_type; 224 | typedef check>> triple_type; 225 | typedef check>>> quadruple_type; 226 | 227 | } 228 | 229 | namespace test_decltype 230 | { 231 | 232 | int 233 | f() 234 | { 235 | int a = 1; 236 | decltype(a) b = 2; 237 | return a + b; 238 | } 239 | 240 | } 241 | 242 | namespace test_type_deduction 243 | { 244 | 245 | template < typename T1, typename T2 > 246 | struct is_same 247 | { 248 | static const bool value = false; 249 | }; 250 | 251 | template < typename T > 252 | struct is_same 253 | { 254 | static const bool value = true; 255 | }; 256 | 257 | template < typename T1, typename T2 > 258 | auto 259 | add(T1 a1, T2 a2) -> decltype(a1 + a2) 260 | { 261 | return a1 + a2; 262 | } 263 | 264 | int 265 | test(const int c, volatile int v) 266 | { 267 | static_assert(is_same::value == true, ""); 268 | static_assert(is_same::value == false, ""); 269 | static_assert(is_same::value == false, ""); 270 | auto ac = c; 271 | auto av = v; 272 | auto sumi = ac + av + 'x'; 273 | auto sumf = ac + av + 1.0; 274 | static_assert(is_same::value == true, ""); 275 | static_assert(is_same::value == true, ""); 276 | static_assert(is_same::value == true, ""); 277 | static_assert(is_same::value == false, ""); 278 | static_assert(is_same::value == true, ""); 279 | return (sumf > 0.0) ? sumi : add(c, v); 280 | } 281 | 282 | } 283 | 284 | namespace test_noexcept 285 | { 286 | 287 | int f() { return 0; } 288 | int g() noexcept { return 0; } 289 | 290 | static_assert(noexcept(f()) == false, ""); 291 | static_assert(noexcept(g()) == true, ""); 292 | 293 | } 294 | 295 | namespace test_constexpr 296 | { 297 | 298 | template < typename CharT > 299 | unsigned long constexpr 300 | strlen_c_r(const CharT *const s, const unsigned long acc) noexcept 301 | { 302 | return *s ? strlen_c_r(s + 1, acc + 1) : acc; 303 | } 304 | 305 | template < typename CharT > 306 | unsigned long constexpr 307 | strlen_c(const CharT *const s) noexcept 308 | { 309 | return strlen_c_r(s, 0UL); 310 | } 311 | 312 | static_assert(strlen_c("") == 0UL, ""); 313 | static_assert(strlen_c("1") == 1UL, ""); 314 | static_assert(strlen_c("example") == 7UL, ""); 315 | static_assert(strlen_c("another\0example") == 7UL, ""); 316 | 317 | } 318 | 319 | namespace test_rvalue_references 320 | { 321 | 322 | template < int N > 323 | struct answer 324 | { 325 | static constexpr int value = N; 326 | }; 327 | 328 | answer<1> f(int&) { return answer<1>(); } 329 | answer<2> f(const int&) { return answer<2>(); } 330 | answer<3> f(int&&) { return answer<3>(); } 331 | 332 | void 333 | test() 334 | { 335 | int i = 0; 336 | const int c = 0; 337 | static_assert(decltype(f(i))::value == 1, ""); 338 | static_assert(decltype(f(c))::value == 2, ""); 339 | static_assert(decltype(f(0))::value == 3, ""); 340 | } 341 | 342 | } 343 | 344 | namespace test_uniform_initialization 345 | { 346 | 347 | struct test 348 | { 349 | static const int zero {}; 350 | static const int one {1}; 351 | }; 352 | 353 | static_assert(test::zero == 0, ""); 354 | static_assert(test::one == 1, ""); 355 | 356 | } 357 | 358 | namespace test_lambdas 359 | { 360 | 361 | void 362 | test1() 363 | { 364 | auto lambda1 = [](){}; 365 | auto lambda2 = lambda1; 366 | lambda1(); 367 | lambda2(); 368 | } 369 | 370 | int 371 | test2() 372 | { 373 | auto a = [](int i, int j){ return i + j; }(1, 2); 374 | auto b = []() -> int { return '0'; }(); 375 | auto c = [=](){ return a + b; }(); 376 | auto d = [&](){ return c; }(); 377 | auto e = [a, &b](int x) mutable { 378 | const auto identity = [](int y){ return y; }; 379 | for (auto i = 0; i < a; ++i) 380 | a += b--; 381 | return x + identity(a + b); 382 | }(0); 383 | return a + b + c + d + e; 384 | } 385 | 386 | int 387 | test3() 388 | { 389 | const auto nullary = [](){ return 0; }; 390 | const auto unary = [](int x){ return x; }; 391 | using nullary_t = decltype(nullary); 392 | using unary_t = decltype(unary); 393 | const auto higher1st = [](nullary_t f){ return f(); }; 394 | const auto higher2nd = [unary](nullary_t f1){ 395 | return [unary, f1](unary_t f2){ return f2(unary(f1())); }; 396 | }; 397 | return higher1st(nullary) + higher2nd(nullary)(unary); 398 | } 399 | 400 | } 401 | 402 | namespace test_variadic_templates 403 | { 404 | 405 | template 406 | struct sum; 407 | 408 | template 409 | struct sum 410 | { 411 | static constexpr auto value = N0 + sum::value; 412 | }; 413 | 414 | template <> 415 | struct sum<> 416 | { 417 | static constexpr auto value = 0; 418 | }; 419 | 420 | static_assert(sum<>::value == 0, ""); 421 | static_assert(sum<1>::value == 1, ""); 422 | static_assert(sum<23>::value == 23, ""); 423 | static_assert(sum<1, 2>::value == 3, ""); 424 | static_assert(sum<5, 5, 11>::value == 21, ""); 425 | static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); 426 | 427 | } 428 | 429 | // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae 430 | // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function 431 | // because of this. 432 | namespace test_template_alias_sfinae 433 | { 434 | 435 | struct foo {}; 436 | 437 | template 438 | using member = typename T::member_type; 439 | 440 | template 441 | void func(...) {} 442 | 443 | template 444 | void func(member*) {} 445 | 446 | void test(); 447 | 448 | void test() { func(0); } 449 | 450 | } 451 | 452 | } // namespace cxx11 453 | 454 | #endif // __cplusplus >= 201103L 455 | 456 | ]]) 457 | 458 | 459 | dnl Tests for new features in C++14 460 | 461 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ 462 | 463 | // If the compiler admits that it is not ready for C++14, why torture it? 464 | // Hopefully, this will speed up the test. 465 | 466 | #ifndef __cplusplus 467 | 468 | #error "This is not a C++ compiler" 469 | 470 | #elif __cplusplus < 201402L 471 | 472 | #error "This is not a C++14 compiler" 473 | 474 | #else 475 | 476 | namespace cxx14 477 | { 478 | 479 | namespace test_polymorphic_lambdas 480 | { 481 | 482 | int 483 | test() 484 | { 485 | const auto lambda = [](auto&&... args){ 486 | const auto istiny = [](auto x){ 487 | return (sizeof(x) == 1UL) ? 1 : 0; 488 | }; 489 | const int aretiny[] = { istiny(args)... }; 490 | return aretiny[0]; 491 | }; 492 | return lambda(1, 1L, 1.0f, '1'); 493 | } 494 | 495 | } 496 | 497 | namespace test_binary_literals 498 | { 499 | 500 | constexpr auto ivii = 0b0000000000101010; 501 | static_assert(ivii == 42, "wrong value"); 502 | 503 | } 504 | 505 | namespace test_generalized_constexpr 506 | { 507 | 508 | template < typename CharT > 509 | constexpr unsigned long 510 | strlen_c(const CharT *const s) noexcept 511 | { 512 | auto length = 0UL; 513 | for (auto p = s; *p; ++p) 514 | ++length; 515 | return length; 516 | } 517 | 518 | static_assert(strlen_c("") == 0UL, ""); 519 | static_assert(strlen_c("x") == 1UL, ""); 520 | static_assert(strlen_c("test") == 4UL, ""); 521 | static_assert(strlen_c("another\0test") == 7UL, ""); 522 | 523 | } 524 | 525 | namespace test_lambda_init_capture 526 | { 527 | 528 | int 529 | test() 530 | { 531 | auto x = 0; 532 | const auto lambda1 = [a = x](int b){ return a + b; }; 533 | const auto lambda2 = [a = lambda1(x)](){ return a; }; 534 | return lambda2(); 535 | } 536 | 537 | } 538 | 539 | namespace test_digit_separators 540 | { 541 | 542 | constexpr auto ten_million = 100'000'000; 543 | static_assert(ten_million == 100000000, ""); 544 | 545 | } 546 | 547 | namespace test_return_type_deduction 548 | { 549 | 550 | auto f(int& x) { return x; } 551 | decltype(auto) g(int& x) { return x; } 552 | 553 | template < typename T1, typename T2 > 554 | struct is_same 555 | { 556 | static constexpr auto value = false; 557 | }; 558 | 559 | template < typename T > 560 | struct is_same 561 | { 562 | static constexpr auto value = true; 563 | }; 564 | 565 | int 566 | test() 567 | { 568 | auto x = 0; 569 | static_assert(is_same::value, ""); 570 | static_assert(is_same::value, ""); 571 | return x; 572 | } 573 | 574 | } 575 | 576 | } // namespace cxx14 577 | 578 | #endif // __cplusplus >= 201402L 579 | 580 | ]]) 581 | 582 | 583 | dnl Tests for new features in C++17 584 | 585 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ 586 | 587 | // If the compiler admits that it is not ready for C++17, why torture it? 588 | // Hopefully, this will speed up the test. 589 | 590 | #ifndef __cplusplus 591 | 592 | #error "This is not a C++ compiler" 593 | 594 | #elif __cplusplus < 201703L 595 | 596 | #error "This is not a C++17 compiler" 597 | 598 | #else 599 | 600 | #include 601 | #include 602 | #include 603 | 604 | namespace cxx17 605 | { 606 | 607 | namespace test_constexpr_lambdas 608 | { 609 | 610 | constexpr int foo = [](){return 42;}(); 611 | 612 | } 613 | 614 | namespace test::nested_namespace::definitions 615 | { 616 | 617 | } 618 | 619 | namespace test_fold_expression 620 | { 621 | 622 | template 623 | int multiply(Args... args) 624 | { 625 | return (args * ... * 1); 626 | } 627 | 628 | template 629 | bool all(Args... args) 630 | { 631 | return (args && ...); 632 | } 633 | 634 | } 635 | 636 | namespace test_extended_static_assert 637 | { 638 | 639 | static_assert (true); 640 | 641 | } 642 | 643 | namespace test_auto_brace_init_list 644 | { 645 | 646 | auto foo = {5}; 647 | auto bar {5}; 648 | 649 | static_assert(std::is_same, decltype(foo)>::value); 650 | static_assert(std::is_same::value); 651 | } 652 | 653 | namespace test_typename_in_template_template_parameter 654 | { 655 | 656 | template typename X> struct D; 657 | 658 | } 659 | 660 | namespace test_fallthrough_nodiscard_maybe_unused_attributes 661 | { 662 | 663 | int f1() 664 | { 665 | return 42; 666 | } 667 | 668 | [[nodiscard]] int f2() 669 | { 670 | [[maybe_unused]] auto unused = f1(); 671 | 672 | switch (f1()) 673 | { 674 | case 17: 675 | f1(); 676 | [[fallthrough]]; 677 | case 42: 678 | f1(); 679 | } 680 | return f1(); 681 | } 682 | 683 | } 684 | 685 | namespace test_extended_aggregate_initialization 686 | { 687 | 688 | struct base1 689 | { 690 | int b1, b2 = 42; 691 | }; 692 | 693 | struct base2 694 | { 695 | base2() { 696 | b3 = 42; 697 | } 698 | int b3; 699 | }; 700 | 701 | struct derived : base1, base2 702 | { 703 | int d; 704 | }; 705 | 706 | derived d1 {{1, 2}, {}, 4}; // full initialization 707 | derived d2 {{}, {}, 4}; // value-initialized bases 708 | 709 | } 710 | 711 | namespace test_general_range_based_for_loop 712 | { 713 | 714 | struct iter 715 | { 716 | int i; 717 | 718 | int& operator* () 719 | { 720 | return i; 721 | } 722 | 723 | const int& operator* () const 724 | { 725 | return i; 726 | } 727 | 728 | iter& operator++() 729 | { 730 | ++i; 731 | return *this; 732 | } 733 | }; 734 | 735 | struct sentinel 736 | { 737 | int i; 738 | }; 739 | 740 | bool operator== (const iter& i, const sentinel& s) 741 | { 742 | return i.i == s.i; 743 | } 744 | 745 | bool operator!= (const iter& i, const sentinel& s) 746 | { 747 | return !(i == s); 748 | } 749 | 750 | struct range 751 | { 752 | iter begin() const 753 | { 754 | return {0}; 755 | } 756 | 757 | sentinel end() const 758 | { 759 | return {5}; 760 | } 761 | }; 762 | 763 | void f() 764 | { 765 | range r {}; 766 | 767 | for (auto i : r) 768 | { 769 | [[maybe_unused]] auto v = i; 770 | } 771 | } 772 | 773 | } 774 | 775 | namespace test_lambda_capture_asterisk_this_by_value 776 | { 777 | 778 | struct t 779 | { 780 | int i; 781 | int foo() 782 | { 783 | return [*this]() 784 | { 785 | return i; 786 | }(); 787 | } 788 | }; 789 | 790 | } 791 | 792 | namespace test_enum_class_construction 793 | { 794 | 795 | enum class byte : unsigned char 796 | {}; 797 | 798 | byte foo {42}; 799 | 800 | } 801 | 802 | namespace test_constexpr_if 803 | { 804 | 805 | template 806 | int f () 807 | { 808 | if constexpr(cond) 809 | { 810 | return 13; 811 | } 812 | else 813 | { 814 | return 42; 815 | } 816 | } 817 | 818 | } 819 | 820 | namespace test_selection_statement_with_initializer 821 | { 822 | 823 | int f() 824 | { 825 | return 13; 826 | } 827 | 828 | int f2() 829 | { 830 | if (auto i = f(); i > 0) 831 | { 832 | return 3; 833 | } 834 | 835 | switch (auto i = f(); i + 4) 836 | { 837 | case 17: 838 | return 2; 839 | 840 | default: 841 | return 1; 842 | } 843 | } 844 | 845 | } 846 | 847 | namespace test_template_argument_deduction_for_class_templates 848 | { 849 | 850 | template 851 | struct pair 852 | { 853 | pair (T1 p1, T2 p2) 854 | : m1 {p1}, 855 | m2 {p2} 856 | {} 857 | 858 | T1 m1; 859 | T2 m2; 860 | }; 861 | 862 | void f() 863 | { 864 | [[maybe_unused]] auto p = pair{13, 42u}; 865 | } 866 | 867 | } 868 | 869 | namespace test_non_type_auto_template_parameters 870 | { 871 | 872 | template 873 | struct B 874 | {}; 875 | 876 | B<5> b1; 877 | B<'a'> b2; 878 | 879 | } 880 | 881 | namespace test_structured_bindings 882 | { 883 | 884 | int arr[2] = { 1, 2 }; 885 | std::pair pr = { 1, 2 }; 886 | 887 | auto f1() -> int(&)[2] 888 | { 889 | return arr; 890 | } 891 | 892 | auto f2() -> std::pair& 893 | { 894 | return pr; 895 | } 896 | 897 | struct S 898 | { 899 | int x1 : 2; 900 | volatile double y1; 901 | }; 902 | 903 | S f3() 904 | { 905 | return {}; 906 | } 907 | 908 | auto [ x1, y1 ] = f1(); 909 | auto& [ xr1, yr1 ] = f1(); 910 | auto [ x2, y2 ] = f2(); 911 | auto& [ xr2, yr2 ] = f2(); 912 | const auto [ x3, y3 ] = f3(); 913 | 914 | } 915 | 916 | namespace test_exception_spec_type_system 917 | { 918 | 919 | struct Good {}; 920 | struct Bad {}; 921 | 922 | void g1() noexcept; 923 | void g2(); 924 | 925 | template 926 | Bad 927 | f(T*, T*); 928 | 929 | template 930 | Good 931 | f(T1*, T2*); 932 | 933 | static_assert (std::is_same_v); 934 | 935 | } 936 | 937 | namespace test_inline_variables 938 | { 939 | 940 | template void f(T) 941 | {} 942 | 943 | template inline T g(T) 944 | { 945 | return T{}; 946 | } 947 | 948 | template<> inline void f<>(int) 949 | {} 950 | 951 | template<> int g<>(int) 952 | { 953 | return 5; 954 | } 955 | 956 | } 957 | 958 | } // namespace cxx17 959 | 960 | #endif // __cplusplus < 201703L 961 | 962 | ]]) 963 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | m4_define([libunivalue_major_version], [1]) 2 | m4_define([libunivalue_minor_version], [1]) 3 | m4_define([libunivalue_micro_version], [4]) 4 | m4_define([libunivalue_interface_age], [4]) 5 | # If you need a modifier for the version number. 6 | # Normally empty, but can be used to make "fixup" releases. 7 | m4_define([libunivalue_extraversion], []) 8 | 9 | dnl libtool versioning from libunivalue 10 | m4_define([libunivalue_current], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version - libunivalue_interface_age)]) 11 | m4_define([libunivalue_binary_age], [m4_eval(100 * libunivalue_minor_version + libunivalue_micro_version)]) 12 | m4_define([libunivalue_revision], [libunivalue_interface_age]) 13 | m4_define([libunivalue_age], [m4_eval(libunivalue_binary_age - libunivalue_interface_age)]) 14 | m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()]) 15 | 16 | 17 | AC_INIT([univalue], [1.0.4], 18 | [http://github.com/jgarzik/univalue/]) 19 | 20 | dnl make the compilation flags quiet unless V=1 is used 21 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 22 | 23 | AC_PREREQ(2.60) 24 | AC_CONFIG_SRCDIR([lib/univalue.cpp]) 25 | AC_CONFIG_AUX_DIR([build-aux]) 26 | AC_CONFIG_MACRO_DIR([build-aux/m4]) 27 | AC_CONFIG_HEADERS([univalue-config.h]) 28 | AM_INIT_AUTOMAKE([subdir-objects foreign]) 29 | 30 | LIBUNIVALUE_MAJOR_VERSION=libunivalue_major_version 31 | LIBUNIVALUE_MINOR_VERSION=libunivalue_minor_version 32 | LIBUNIVALUE_MICRO_VERSION=libunivalue_micro_version 33 | LIBUNIVALUE_INTERFACE_AGE=libunivalue_interface_age 34 | 35 | # ABI version 36 | # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html 37 | LIBUNIVALUE_CURRENT=libunivalue_current 38 | LIBUNIVALUE_REVISION=libunivalue_revision 39 | LIBUNIVALUE_AGE=libunivalue_age 40 | 41 | AC_SUBST(LIBUNIVALUE_CURRENT) 42 | AC_SUBST(LIBUNIVALUE_REVISION) 43 | AC_SUBST(LIBUNIVALUE_AGE) 44 | 45 | LT_INIT 46 | LT_LANG([C++]) 47 | 48 | dnl Require C++17 compiler (no GNU extensions) 49 | AX_CXX_COMPILE_STDCXX([17], [noext], [mandatory], [nodefault]) 50 | 51 | case $host in 52 | *mingw*) 53 | LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static" 54 | ;; 55 | esac 56 | 57 | BUILD_EXEEXT= 58 | case $build in 59 | *mingw*) 60 | BUILD_EXEEXT=".exe" 61 | ;; 62 | esac 63 | 64 | AC_CONFIG_FILES([ 65 | Makefile 66 | pc/libunivalue.pc 67 | pc/libunivalue-uninstalled.pc]) 68 | 69 | AC_SUBST(LIBTOOL_APP_LDFLAGS) 70 | AC_SUBST(BUILD_EXEEXT) 71 | AC_OUTPUT 72 | 73 | -------------------------------------------------------------------------------- /gen/gen.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2014 BitPay Inc. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or https://opensource.org/licenses/mit-license.php. 4 | 5 | // 6 | // To re-create univalue_escapes.h: 7 | // $ g++ -o gen gen.cpp 8 | // $ ./gen > univalue_escapes.h 9 | // 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | static bool initEscapes; 18 | static std::string escapes[256]; 19 | 20 | static void initJsonEscape() 21 | { 22 | // Escape all lower control characters (some get overridden with smaller sequences below) 23 | for (int ch=0x00; ch<0x20; ++ch) { 24 | char tmpbuf[20]; 25 | snprintf(tmpbuf, sizeof(tmpbuf), "\\u%04x", ch); 26 | escapes[ch] = std::string(tmpbuf); 27 | } 28 | 29 | escapes[(int)'"'] = "\\\""; 30 | escapes[(int)'\\'] = "\\\\"; 31 | escapes[(int)'\b'] = "\\b"; 32 | escapes[(int)'\f'] = "\\f"; 33 | escapes[(int)'\n'] = "\\n"; 34 | escapes[(int)'\r'] = "\\r"; 35 | escapes[(int)'\t'] = "\\t"; 36 | escapes[(int)'\x7f'] = "\\u007f"; // U+007F DELETE 37 | 38 | initEscapes = true; 39 | } 40 | 41 | static void outputEscape() 42 | { 43 | printf( "// Automatically generated file. Do not modify.\n" 44 | "#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" 45 | "#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" 46 | "static const char *escapes[256] = {\n"); 47 | 48 | for (unsigned int i = 0; i < 256; i++) { 49 | if (escapes[i].empty()) { 50 | printf("\tnullptr,\n"); 51 | } else { 52 | printf("\t\""); 53 | 54 | unsigned int si; 55 | for (si = 0; si < escapes[i].size(); si++) { 56 | char ch = escapes[i][si]; 57 | switch (ch) { 58 | case '"': 59 | printf("\\\""); 60 | break; 61 | case '\\': 62 | printf("\\\\"); 63 | break; 64 | default: 65 | printf("%c", escapes[i][si]); 66 | break; 67 | } 68 | } 69 | 70 | printf("\",\n"); 71 | } 72 | } 73 | 74 | printf( "};\n" 75 | "#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n"); 76 | } 77 | 78 | int main (int argc, char *argv[]) 79 | { 80 | initJsonEscape(); 81 | outputEscape(); 82 | return 0; 83 | } 84 | 85 | -------------------------------------------------------------------------------- /include/univalue.h: -------------------------------------------------------------------------------- 1 | // Copyright 2014 BitPay Inc. 2 | // Copyright 2015 Bitcoin Core Developers 3 | // Distributed under the MIT software license, see the accompanying 4 | // file COPYING or https://opensource.org/licenses/mit-license.php. 5 | 6 | #ifndef __UNIVALUE_H__ 7 | #define __UNIVALUE_H__ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | class UniValue { 19 | public: 20 | enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, }; 21 | 22 | UniValue() { typ = VNULL; } 23 | UniValue(UniValue::VType initialType, const std::string& initialStr = "") { 24 | typ = initialType; 25 | val = initialStr; 26 | } 27 | UniValue(uint64_t val_) { 28 | setInt(val_); 29 | } 30 | UniValue(int64_t val_) { 31 | setInt(val_); 32 | } 33 | UniValue(bool val_) { 34 | setBool(val_); 35 | } 36 | UniValue(int val_) { 37 | setInt(val_); 38 | } 39 | UniValue(double val_) { 40 | setFloat(val_); 41 | } 42 | UniValue(const std::string& val_) { 43 | setStr(val_); 44 | } 45 | UniValue(const char *val_) { 46 | std::string s(val_); 47 | setStr(s); 48 | } 49 | 50 | void clear(); 51 | 52 | bool setNull(); 53 | bool setBool(bool val); 54 | bool setNumStr(const std::string& val); 55 | bool setInt(uint64_t val); 56 | bool setInt(int64_t val); 57 | bool setInt(int val_) { return setInt((int64_t)val_); } 58 | bool setFloat(double val); 59 | bool setStr(const std::string& val); 60 | bool setArray(); 61 | bool setObject(); 62 | 63 | enum VType getType() const { return typ; } 64 | const std::string& getValStr() const { return val; } 65 | bool empty() const { return (values.size() == 0); } 66 | 67 | size_t size() const { return values.size(); } 68 | 69 | bool getBool() const { return isTrue(); } 70 | void getObjMap(std::map& kv) const; 71 | bool checkObject(const std::map& memberTypes) const; 72 | const UniValue& operator[](const std::string& key) const; 73 | const UniValue& operator[](size_t index) const; 74 | bool exists(const std::string& key) const { size_t i; return findKey(key, i); } 75 | 76 | bool isNull() const { return (typ == VNULL); } 77 | bool isTrue() const { return (typ == VBOOL) && (val == "1"); } 78 | bool isFalse() const { return (typ == VBOOL) && (val != "1"); } 79 | bool isBool() const { return (typ == VBOOL); } 80 | bool isStr() const { return (typ == VSTR); } 81 | bool isNum() const { return (typ == VNUM); } 82 | bool isArray() const { return (typ == VARR); } 83 | bool isObject() const { return (typ == VOBJ); } 84 | 85 | bool push_back(const UniValue& val); 86 | bool push_backV(const std::vector& vec); 87 | 88 | void __pushKV(const std::string& key, const UniValue& val); 89 | bool pushKV(const std::string& key, const UniValue& val); 90 | bool pushKVs(const UniValue& obj); 91 | 92 | std::string write(unsigned int prettyIndent = 0, 93 | unsigned int indentLevel = 0) const; 94 | 95 | bool read(const char *raw, size_t len); 96 | bool read(const char *raw) { return read(raw, strlen(raw)); } 97 | bool read(const std::string& rawStr) { 98 | return read(rawStr.data(), rawStr.size()); 99 | } 100 | 101 | private: 102 | UniValue::VType typ; 103 | std::string val; // numbers are stored as C++ strings 104 | std::vector keys; 105 | std::vector values; 106 | 107 | bool findKey(const std::string& key, size_t& retIdx) const; 108 | void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; 109 | void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; 110 | 111 | public: 112 | // Strict type-specific getters, these throw std::runtime_error if the 113 | // value is of unexpected type 114 | const std::vector& getKeys() const; 115 | const std::vector& getValues() const; 116 | template 117 | auto getInt() const 118 | { 119 | static_assert(std::is_integral::value); 120 | if (typ != VNUM) { 121 | throw std::runtime_error("JSON value is not an integer as expected"); 122 | } 123 | Int result; 124 | const auto [first_nonmatching, error_condition] = std::from_chars(val.data(), val.data() + val.size(), result); 125 | if (first_nonmatching != val.data() + val.size() || error_condition != std::errc{}) { 126 | throw std::runtime_error("JSON integer out of range"); 127 | } 128 | return result; 129 | } 130 | bool get_bool() const; 131 | const std::string& get_str() const; 132 | double get_real() const; 133 | const UniValue& get_obj() const; 134 | const UniValue& get_array() const; 135 | 136 | enum VType type() const { return getType(); } 137 | friend const UniValue& find_value( const UniValue& obj, const std::string& name); 138 | }; 139 | 140 | enum jtokentype { 141 | JTOK_ERR = -1, 142 | JTOK_NONE = 0, // eof 143 | JTOK_OBJ_OPEN, 144 | JTOK_OBJ_CLOSE, 145 | JTOK_ARR_OPEN, 146 | JTOK_ARR_CLOSE, 147 | JTOK_COLON, 148 | JTOK_COMMA, 149 | JTOK_KW_NULL, 150 | JTOK_KW_TRUE, 151 | JTOK_KW_FALSE, 152 | JTOK_NUMBER, 153 | JTOK_STRING, 154 | }; 155 | 156 | extern enum jtokentype getJsonToken(std::string& tokenVal, 157 | unsigned int& consumed, const char *raw, const char *end); 158 | extern const char *uvTypeName(UniValue::VType t); 159 | 160 | static inline bool jsonTokenIsValue(enum jtokentype jtt) 161 | { 162 | switch (jtt) { 163 | case JTOK_KW_NULL: 164 | case JTOK_KW_TRUE: 165 | case JTOK_KW_FALSE: 166 | case JTOK_NUMBER: 167 | case JTOK_STRING: 168 | return true; 169 | 170 | default: 171 | return false; 172 | } 173 | 174 | // not reached 175 | } 176 | 177 | static inline bool json_isspace(int ch) 178 | { 179 | switch (ch) { 180 | case 0x20: 181 | case 0x09: 182 | case 0x0a: 183 | case 0x0d: 184 | return true; 185 | 186 | default: 187 | return false; 188 | } 189 | 190 | // not reached 191 | } 192 | 193 | extern const UniValue NullUniValue; 194 | 195 | const UniValue& find_value( const UniValue& obj, const std::string& name); 196 | 197 | #endif // __UNIVALUE_H__ 198 | -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | gen 2 | .libs 3 | -------------------------------------------------------------------------------- /lib/univalue.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2014 BitPay Inc. 2 | // Copyright 2015 Bitcoin Core Developers 3 | // Distributed under the MIT software license, see the accompanying 4 | // file COPYING or https://opensource.org/licenses/mit-license.php. 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | const UniValue NullUniValue; 17 | 18 | void UniValue::clear() 19 | { 20 | typ = VNULL; 21 | val.clear(); 22 | keys.clear(); 23 | values.clear(); 24 | } 25 | 26 | bool UniValue::setNull() 27 | { 28 | clear(); 29 | return true; 30 | } 31 | 32 | bool UniValue::setBool(bool val_) 33 | { 34 | clear(); 35 | typ = VBOOL; 36 | if (val_) 37 | val = "1"; 38 | return true; 39 | } 40 | 41 | static bool validNumStr(const std::string& s) 42 | { 43 | std::string tokenVal; 44 | unsigned int consumed; 45 | enum jtokentype tt = getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size()); 46 | return (tt == JTOK_NUMBER); 47 | } 48 | 49 | bool UniValue::setNumStr(const std::string& val_) 50 | { 51 | if (!validNumStr(val_)) 52 | return false; 53 | 54 | clear(); 55 | typ = VNUM; 56 | val = val_; 57 | return true; 58 | } 59 | 60 | bool UniValue::setInt(uint64_t val_) 61 | { 62 | std::ostringstream oss; 63 | 64 | oss << val_; 65 | 66 | return setNumStr(oss.str()); 67 | } 68 | 69 | bool UniValue::setInt(int64_t val_) 70 | { 71 | std::ostringstream oss; 72 | 73 | oss << val_; 74 | 75 | return setNumStr(oss.str()); 76 | } 77 | 78 | bool UniValue::setFloat(double val_) 79 | { 80 | std::ostringstream oss; 81 | 82 | oss << std::setprecision(16) << val_; 83 | 84 | bool ret = setNumStr(oss.str()); 85 | typ = VNUM; 86 | return ret; 87 | } 88 | 89 | bool UniValue::setStr(const std::string& val_) 90 | { 91 | clear(); 92 | typ = VSTR; 93 | val = val_; 94 | return true; 95 | } 96 | 97 | bool UniValue::setArray() 98 | { 99 | clear(); 100 | typ = VARR; 101 | return true; 102 | } 103 | 104 | bool UniValue::setObject() 105 | { 106 | clear(); 107 | typ = VOBJ; 108 | return true; 109 | } 110 | 111 | bool UniValue::push_back(const UniValue& val_) 112 | { 113 | if (typ != VARR) 114 | return false; 115 | 116 | values.push_back(val_); 117 | return true; 118 | } 119 | 120 | bool UniValue::push_backV(const std::vector& vec) 121 | { 122 | if (typ != VARR) 123 | return false; 124 | 125 | values.insert(values.end(), vec.begin(), vec.end()); 126 | 127 | return true; 128 | } 129 | 130 | void UniValue::__pushKV(const std::string& key, const UniValue& val_) 131 | { 132 | keys.push_back(key); 133 | values.push_back(val_); 134 | } 135 | 136 | bool UniValue::pushKV(const std::string& key, const UniValue& val_) 137 | { 138 | if (typ != VOBJ) 139 | return false; 140 | 141 | size_t idx; 142 | if (findKey(key, idx)) 143 | values[idx] = val_; 144 | else 145 | __pushKV(key, val_); 146 | return true; 147 | } 148 | 149 | bool UniValue::pushKVs(const UniValue& obj) 150 | { 151 | if (typ != VOBJ || obj.typ != VOBJ) 152 | return false; 153 | 154 | for (size_t i = 0; i < obj.keys.size(); i++) 155 | __pushKV(obj.keys[i], obj.values.at(i)); 156 | 157 | return true; 158 | } 159 | 160 | void UniValue::getObjMap(std::map& kv) const 161 | { 162 | if (typ != VOBJ) 163 | return; 164 | 165 | kv.clear(); 166 | for (size_t i = 0; i < keys.size(); i++) 167 | kv[keys[i]] = values[i]; 168 | } 169 | 170 | bool UniValue::findKey(const std::string& key, size_t& retIdx) const 171 | { 172 | for (size_t i = 0; i < keys.size(); i++) { 173 | if (keys[i] == key) { 174 | retIdx = i; 175 | return true; 176 | } 177 | } 178 | 179 | return false; 180 | } 181 | 182 | bool UniValue::checkObject(const std::map& t) const 183 | { 184 | if (typ != VOBJ) { 185 | return false; 186 | } 187 | 188 | for (const auto& object: t) { 189 | size_t idx = 0; 190 | if (!findKey(object.first, idx)) { 191 | return false; 192 | } 193 | 194 | if (values.at(idx).getType() != object.second) { 195 | return false; 196 | } 197 | } 198 | 199 | return true; 200 | } 201 | 202 | const UniValue& UniValue::operator[](const std::string& key) const 203 | { 204 | if (typ != VOBJ) 205 | return NullUniValue; 206 | 207 | size_t index = 0; 208 | if (!findKey(key, index)) 209 | return NullUniValue; 210 | 211 | return values.at(index); 212 | } 213 | 214 | const UniValue& UniValue::operator[](size_t index) const 215 | { 216 | if (typ != VOBJ && typ != VARR) 217 | return NullUniValue; 218 | if (index >= values.size()) 219 | return NullUniValue; 220 | 221 | return values.at(index); 222 | } 223 | 224 | const char *uvTypeName(UniValue::VType t) 225 | { 226 | switch (t) { 227 | case UniValue::VNULL: return "null"; 228 | case UniValue::VBOOL: return "bool"; 229 | case UniValue::VOBJ: return "object"; 230 | case UniValue::VARR: return "array"; 231 | case UniValue::VSTR: return "string"; 232 | case UniValue::VNUM: return "number"; 233 | } 234 | 235 | // not reached 236 | return nullptr; 237 | } 238 | 239 | const UniValue& find_value(const UniValue& obj, const std::string& name) 240 | { 241 | for (unsigned int i = 0; i < obj.keys.size(); i++) 242 | if (obj.keys[i] == name) 243 | return obj.values.at(i); 244 | 245 | return NullUniValue; 246 | } 247 | 248 | -------------------------------------------------------------------------------- /lib/univalue_escapes.h: -------------------------------------------------------------------------------- 1 | // Automatically generated file. Do not modify. 2 | #ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H 3 | #define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H 4 | static const char *escapes[256] = { 5 | "\\u0000", 6 | "\\u0001", 7 | "\\u0002", 8 | "\\u0003", 9 | "\\u0004", 10 | "\\u0005", 11 | "\\u0006", 12 | "\\u0007", 13 | "\\b", 14 | "\\t", 15 | "\\n", 16 | "\\u000b", 17 | "\\f", 18 | "\\r", 19 | "\\u000e", 20 | "\\u000f", 21 | "\\u0010", 22 | "\\u0011", 23 | "\\u0012", 24 | "\\u0013", 25 | "\\u0014", 26 | "\\u0015", 27 | "\\u0016", 28 | "\\u0017", 29 | "\\u0018", 30 | "\\u0019", 31 | "\\u001a", 32 | "\\u001b", 33 | "\\u001c", 34 | "\\u001d", 35 | "\\u001e", 36 | "\\u001f", 37 | nullptr, 38 | nullptr, 39 | "\\\"", 40 | nullptr, 41 | nullptr, 42 | nullptr, 43 | nullptr, 44 | nullptr, 45 | nullptr, 46 | nullptr, 47 | nullptr, 48 | nullptr, 49 | nullptr, 50 | nullptr, 51 | nullptr, 52 | nullptr, 53 | nullptr, 54 | nullptr, 55 | nullptr, 56 | nullptr, 57 | nullptr, 58 | nullptr, 59 | nullptr, 60 | nullptr, 61 | nullptr, 62 | nullptr, 63 | nullptr, 64 | nullptr, 65 | nullptr, 66 | nullptr, 67 | nullptr, 68 | nullptr, 69 | nullptr, 70 | nullptr, 71 | nullptr, 72 | nullptr, 73 | nullptr, 74 | nullptr, 75 | nullptr, 76 | nullptr, 77 | nullptr, 78 | nullptr, 79 | nullptr, 80 | nullptr, 81 | nullptr, 82 | nullptr, 83 | nullptr, 84 | nullptr, 85 | nullptr, 86 | nullptr, 87 | nullptr, 88 | nullptr, 89 | nullptr, 90 | nullptr, 91 | nullptr, 92 | nullptr, 93 | nullptr, 94 | nullptr, 95 | nullptr, 96 | nullptr, 97 | "\\\\", 98 | nullptr, 99 | nullptr, 100 | nullptr, 101 | nullptr, 102 | nullptr, 103 | nullptr, 104 | nullptr, 105 | nullptr, 106 | nullptr, 107 | nullptr, 108 | nullptr, 109 | nullptr, 110 | nullptr, 111 | nullptr, 112 | nullptr, 113 | nullptr, 114 | nullptr, 115 | nullptr, 116 | nullptr, 117 | nullptr, 118 | nullptr, 119 | nullptr, 120 | nullptr, 121 | nullptr, 122 | nullptr, 123 | nullptr, 124 | nullptr, 125 | nullptr, 126 | nullptr, 127 | nullptr, 128 | nullptr, 129 | nullptr, 130 | nullptr, 131 | nullptr, 132 | "\\u007f", 133 | nullptr, 134 | nullptr, 135 | nullptr, 136 | nullptr, 137 | nullptr, 138 | nullptr, 139 | nullptr, 140 | nullptr, 141 | nullptr, 142 | nullptr, 143 | nullptr, 144 | nullptr, 145 | nullptr, 146 | nullptr, 147 | nullptr, 148 | nullptr, 149 | nullptr, 150 | nullptr, 151 | nullptr, 152 | nullptr, 153 | nullptr, 154 | nullptr, 155 | nullptr, 156 | nullptr, 157 | nullptr, 158 | nullptr, 159 | nullptr, 160 | nullptr, 161 | nullptr, 162 | nullptr, 163 | nullptr, 164 | nullptr, 165 | nullptr, 166 | nullptr, 167 | nullptr, 168 | nullptr, 169 | nullptr, 170 | nullptr, 171 | nullptr, 172 | nullptr, 173 | nullptr, 174 | nullptr, 175 | nullptr, 176 | nullptr, 177 | nullptr, 178 | nullptr, 179 | nullptr, 180 | nullptr, 181 | nullptr, 182 | nullptr, 183 | nullptr, 184 | nullptr, 185 | nullptr, 186 | nullptr, 187 | nullptr, 188 | nullptr, 189 | nullptr, 190 | nullptr, 191 | nullptr, 192 | nullptr, 193 | nullptr, 194 | nullptr, 195 | nullptr, 196 | nullptr, 197 | nullptr, 198 | nullptr, 199 | nullptr, 200 | nullptr, 201 | nullptr, 202 | nullptr, 203 | nullptr, 204 | nullptr, 205 | nullptr, 206 | nullptr, 207 | nullptr, 208 | nullptr, 209 | nullptr, 210 | nullptr, 211 | nullptr, 212 | nullptr, 213 | nullptr, 214 | nullptr, 215 | nullptr, 216 | nullptr, 217 | nullptr, 218 | nullptr, 219 | nullptr, 220 | nullptr, 221 | nullptr, 222 | nullptr, 223 | nullptr, 224 | nullptr, 225 | nullptr, 226 | nullptr, 227 | nullptr, 228 | nullptr, 229 | nullptr, 230 | nullptr, 231 | nullptr, 232 | nullptr, 233 | nullptr, 234 | nullptr, 235 | nullptr, 236 | nullptr, 237 | nullptr, 238 | nullptr, 239 | nullptr, 240 | nullptr, 241 | nullptr, 242 | nullptr, 243 | nullptr, 244 | nullptr, 245 | nullptr, 246 | nullptr, 247 | nullptr, 248 | nullptr, 249 | nullptr, 250 | nullptr, 251 | nullptr, 252 | nullptr, 253 | nullptr, 254 | nullptr, 255 | nullptr, 256 | nullptr, 257 | nullptr, 258 | nullptr, 259 | nullptr, 260 | nullptr, 261 | }; 262 | #endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H 263 | -------------------------------------------------------------------------------- /lib/univalue_get.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2014 BitPay Inc. 2 | // Copyright 2015 Bitcoin Core Developers 3 | // Distributed under the MIT software license, see the accompanying 4 | // file COPYING or https://opensource.org/licenses/mit-license.php. 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace 20 | { 21 | static bool ParsePrechecks(const std::string& str) 22 | { 23 | if (str.empty()) // No empty string allowed 24 | return false; 25 | if (str.size() >= 1 && (json_isspace(str[0]) || json_isspace(str[str.size()-1]))) // No padding allowed 26 | return false; 27 | if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed 28 | return false; 29 | return true; 30 | } 31 | 32 | bool ParseDouble(const std::string& str, double *out) 33 | { 34 | if (!ParsePrechecks(str)) 35 | return false; 36 | if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed 37 | return false; 38 | std::istringstream text(str); 39 | text.imbue(std::locale::classic()); 40 | double result; 41 | text >> result; 42 | if(out) *out = result; 43 | return text.eof() && !text.fail(); 44 | } 45 | } 46 | 47 | const std::vector& UniValue::getKeys() const 48 | { 49 | if (typ != VOBJ) 50 | throw std::runtime_error("JSON value is not an object as expected"); 51 | return keys; 52 | } 53 | 54 | const std::vector& UniValue::getValues() const 55 | { 56 | if (typ != VOBJ && typ != VARR) 57 | throw std::runtime_error("JSON value is not an object or array as expected"); 58 | return values; 59 | } 60 | 61 | bool UniValue::get_bool() const 62 | { 63 | if (typ != VBOOL) 64 | throw std::runtime_error("JSON value is not a boolean as expected"); 65 | return getBool(); 66 | } 67 | 68 | const std::string& UniValue::get_str() const 69 | { 70 | if (typ != VSTR) 71 | throw std::runtime_error("JSON value is not a string as expected"); 72 | return getValStr(); 73 | } 74 | 75 | double UniValue::get_real() const 76 | { 77 | if (typ != VNUM) 78 | throw std::runtime_error("JSON value is not a number as expected"); 79 | double retval; 80 | if (!ParseDouble(getValStr(), &retval)) 81 | throw std::runtime_error("JSON double out of range"); 82 | return retval; 83 | } 84 | 85 | const UniValue& UniValue::get_obj() const 86 | { 87 | if (typ != VOBJ) 88 | throw std::runtime_error("JSON value is not an object as expected"); 89 | return *this; 90 | } 91 | 92 | const UniValue& UniValue::get_array() const 93 | { 94 | if (typ != VARR) 95 | throw std::runtime_error("JSON value is not an array as expected"); 96 | return *this; 97 | } 98 | 99 | -------------------------------------------------------------------------------- /lib/univalue_read.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2014 BitPay Inc. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or https://opensource.org/licenses/mit-license.php. 4 | 5 | #include 6 | #include "univalue_utffilter.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /* 15 | * According to stackexchange, the original json test suite wanted 16 | * to limit depth to 22. Widely-deployed PHP bails at depth 512, 17 | * so we will follow PHP's lead, which should be more than sufficient 18 | * (further stackexchange comments indicate depth > 32 rarely occurs). 19 | */ 20 | static constexpr size_t MAX_JSON_DEPTH = 512; 21 | 22 | static bool json_isdigit(int ch) 23 | { 24 | return ((ch >= '0') && (ch <= '9')); 25 | } 26 | 27 | // convert hexadecimal string to unsigned integer 28 | static const char *hatoui(const char *first, const char *last, 29 | unsigned int& out) 30 | { 31 | unsigned int result = 0; 32 | for (; first != last; ++first) 33 | { 34 | int digit; 35 | if (json_isdigit(*first)) 36 | digit = *first - '0'; 37 | 38 | else if (*first >= 'a' && *first <= 'f') 39 | digit = *first - 'a' + 10; 40 | 41 | else if (*first >= 'A' && *first <= 'F') 42 | digit = *first - 'A' + 10; 43 | 44 | else 45 | break; 46 | 47 | result = 16 * result + digit; 48 | } 49 | out = result; 50 | 51 | return first; 52 | } 53 | 54 | enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed, 55 | const char *raw, const char *end) 56 | { 57 | tokenVal.clear(); 58 | consumed = 0; 59 | 60 | const char *rawStart = raw; 61 | 62 | while (raw < end && (json_isspace(*raw))) // skip whitespace 63 | raw++; 64 | 65 | if (raw >= end) 66 | return JTOK_NONE; 67 | 68 | switch (*raw) { 69 | 70 | case '{': 71 | raw++; 72 | consumed = (raw - rawStart); 73 | return JTOK_OBJ_OPEN; 74 | case '}': 75 | raw++; 76 | consumed = (raw - rawStart); 77 | return JTOK_OBJ_CLOSE; 78 | case '[': 79 | raw++; 80 | consumed = (raw - rawStart); 81 | return JTOK_ARR_OPEN; 82 | case ']': 83 | raw++; 84 | consumed = (raw - rawStart); 85 | return JTOK_ARR_CLOSE; 86 | 87 | case ':': 88 | raw++; 89 | consumed = (raw - rawStart); 90 | return JTOK_COLON; 91 | case ',': 92 | raw++; 93 | consumed = (raw - rawStart); 94 | return JTOK_COMMA; 95 | 96 | case 'n': 97 | case 't': 98 | case 'f': 99 | if (!strncmp(raw, "null", 4)) { 100 | raw += 4; 101 | consumed = (raw - rawStart); 102 | return JTOK_KW_NULL; 103 | } else if (!strncmp(raw, "true", 4)) { 104 | raw += 4; 105 | consumed = (raw - rawStart); 106 | return JTOK_KW_TRUE; 107 | } else if (!strncmp(raw, "false", 5)) { 108 | raw += 5; 109 | consumed = (raw - rawStart); 110 | return JTOK_KW_FALSE; 111 | } else 112 | return JTOK_ERR; 113 | 114 | case '-': 115 | case '0': 116 | case '1': 117 | case '2': 118 | case '3': 119 | case '4': 120 | case '5': 121 | case '6': 122 | case '7': 123 | case '8': 124 | case '9': { 125 | // part 1: int 126 | std::string numStr; 127 | 128 | const char *first = raw; 129 | 130 | const char *firstDigit = first; 131 | if (!json_isdigit(*firstDigit)) 132 | firstDigit++; 133 | if ((*firstDigit == '0') && json_isdigit(firstDigit[1])) 134 | return JTOK_ERR; 135 | 136 | numStr += *raw; // copy first char 137 | raw++; 138 | 139 | if ((*first == '-') && (raw < end) && (!json_isdigit(*raw))) 140 | return JTOK_ERR; 141 | 142 | while (raw < end && json_isdigit(*raw)) { // copy digits 143 | numStr += *raw; 144 | raw++; 145 | } 146 | 147 | // part 2: frac 148 | if (raw < end && *raw == '.') { 149 | numStr += *raw; // copy . 150 | raw++; 151 | 152 | if (raw >= end || !json_isdigit(*raw)) 153 | return JTOK_ERR; 154 | while (raw < end && json_isdigit(*raw)) { // copy digits 155 | numStr += *raw; 156 | raw++; 157 | } 158 | } 159 | 160 | // part 3: exp 161 | if (raw < end && (*raw == 'e' || *raw == 'E')) { 162 | numStr += *raw; // copy E 163 | raw++; 164 | 165 | if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/- 166 | numStr += *raw; 167 | raw++; 168 | } 169 | 170 | if (raw >= end || !json_isdigit(*raw)) 171 | return JTOK_ERR; 172 | while (raw < end && json_isdigit(*raw)) { // copy digits 173 | numStr += *raw; 174 | raw++; 175 | } 176 | } 177 | 178 | tokenVal = numStr; 179 | consumed = (raw - rawStart); 180 | return JTOK_NUMBER; 181 | } 182 | 183 | case '"': { 184 | raw++; // skip " 185 | 186 | std::string valStr; 187 | JSONUTF8StringFilter writer(valStr); 188 | 189 | while (true) { 190 | if (raw >= end || (unsigned char)*raw < 0x20) 191 | return JTOK_ERR; 192 | 193 | else if (*raw == '\\') { 194 | raw++; // skip backslash 195 | 196 | if (raw >= end) 197 | return JTOK_ERR; 198 | 199 | switch (*raw) { 200 | case '"': writer.push_back('\"'); break; 201 | case '\\': writer.push_back('\\'); break; 202 | case '/': writer.push_back('/'); break; 203 | case 'b': writer.push_back('\b'); break; 204 | case 'f': writer.push_back('\f'); break; 205 | case 'n': writer.push_back('\n'); break; 206 | case 'r': writer.push_back('\r'); break; 207 | case 't': writer.push_back('\t'); break; 208 | 209 | case 'u': { 210 | unsigned int codepoint; 211 | if (raw + 1 + 4 >= end || 212 | hatoui(raw + 1, raw + 1 + 4, codepoint) != 213 | raw + 1 + 4) 214 | return JTOK_ERR; 215 | writer.push_back_u(codepoint); 216 | raw += 4; 217 | break; 218 | } 219 | default: 220 | return JTOK_ERR; 221 | 222 | } 223 | 224 | raw++; // skip esc'd char 225 | } 226 | 227 | else if (*raw == '"') { 228 | raw++; // skip " 229 | break; // stop scanning 230 | } 231 | 232 | else { 233 | writer.push_back(static_cast(*raw)); 234 | raw++; 235 | } 236 | } 237 | 238 | if (!writer.finalize()) 239 | return JTOK_ERR; 240 | tokenVal = valStr; 241 | consumed = (raw - rawStart); 242 | return JTOK_STRING; 243 | } 244 | 245 | default: 246 | return JTOK_ERR; 247 | } 248 | } 249 | 250 | enum expect_bits : unsigned { 251 | EXP_OBJ_NAME = (1U << 0), 252 | EXP_COLON = (1U << 1), 253 | EXP_ARR_VALUE = (1U << 2), 254 | EXP_VALUE = (1U << 3), 255 | EXP_NOT_VALUE = (1U << 4), 256 | }; 257 | 258 | #define expect(bit) (expectMask & (EXP_##bit)) 259 | #define setExpect(bit) (expectMask |= EXP_##bit) 260 | #define clearExpect(bit) (expectMask &= ~EXP_##bit) 261 | 262 | bool UniValue::read(const char *raw, size_t size) 263 | { 264 | clear(); 265 | 266 | uint32_t expectMask = 0; 267 | std::vector stack; 268 | 269 | std::string tokenVal; 270 | unsigned int consumed; 271 | enum jtokentype tok = JTOK_NONE; 272 | enum jtokentype last_tok = JTOK_NONE; 273 | const char* end = raw + size; 274 | do { 275 | last_tok = tok; 276 | 277 | tok = getJsonToken(tokenVal, consumed, raw, end); 278 | if (tok == JTOK_NONE || tok == JTOK_ERR) 279 | return false; 280 | raw += consumed; 281 | 282 | bool isValueOpen = jsonTokenIsValue(tok) || 283 | tok == JTOK_OBJ_OPEN || tok == JTOK_ARR_OPEN; 284 | 285 | if (expect(VALUE)) { 286 | if (!isValueOpen) 287 | return false; 288 | clearExpect(VALUE); 289 | 290 | } else if (expect(ARR_VALUE)) { 291 | bool isArrValue = isValueOpen || (tok == JTOK_ARR_CLOSE); 292 | if (!isArrValue) 293 | return false; 294 | 295 | clearExpect(ARR_VALUE); 296 | 297 | } else if (expect(OBJ_NAME)) { 298 | bool isObjName = (tok == JTOK_OBJ_CLOSE || tok == JTOK_STRING); 299 | if (!isObjName) 300 | return false; 301 | 302 | } else if (expect(COLON)) { 303 | if (tok != JTOK_COLON) 304 | return false; 305 | clearExpect(COLON); 306 | 307 | } else if (!expect(COLON) && (tok == JTOK_COLON)) { 308 | return false; 309 | } 310 | 311 | if (expect(NOT_VALUE)) { 312 | if (isValueOpen) 313 | return false; 314 | clearExpect(NOT_VALUE); 315 | } 316 | 317 | switch (tok) { 318 | 319 | case JTOK_OBJ_OPEN: 320 | case JTOK_ARR_OPEN: { 321 | VType utyp = (tok == JTOK_OBJ_OPEN ? VOBJ : VARR); 322 | if (!stack.size()) { 323 | if (utyp == VOBJ) 324 | setObject(); 325 | else 326 | setArray(); 327 | stack.push_back(this); 328 | } else { 329 | UniValue tmpVal(utyp); 330 | UniValue *top = stack.back(); 331 | top->values.push_back(tmpVal); 332 | 333 | UniValue *newTop = &(top->values.back()); 334 | stack.push_back(newTop); 335 | } 336 | 337 | if (stack.size() > MAX_JSON_DEPTH) 338 | return false; 339 | 340 | if (utyp == VOBJ) 341 | setExpect(OBJ_NAME); 342 | else 343 | setExpect(ARR_VALUE); 344 | break; 345 | } 346 | 347 | case JTOK_OBJ_CLOSE: 348 | case JTOK_ARR_CLOSE: { 349 | if (!stack.size() || (last_tok == JTOK_COMMA)) 350 | return false; 351 | 352 | VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR); 353 | UniValue *top = stack.back(); 354 | if (utyp != top->getType()) 355 | return false; 356 | 357 | stack.pop_back(); 358 | clearExpect(OBJ_NAME); 359 | setExpect(NOT_VALUE); 360 | break; 361 | } 362 | 363 | case JTOK_COLON: { 364 | if (!stack.size()) 365 | return false; 366 | 367 | UniValue *top = stack.back(); 368 | if (top->getType() != VOBJ) 369 | return false; 370 | 371 | setExpect(VALUE); 372 | break; 373 | } 374 | 375 | case JTOK_COMMA: { 376 | if (!stack.size() || 377 | (last_tok == JTOK_COMMA) || (last_tok == JTOK_ARR_OPEN)) 378 | return false; 379 | 380 | UniValue *top = stack.back(); 381 | if (top->getType() == VOBJ) 382 | setExpect(OBJ_NAME); 383 | else 384 | setExpect(ARR_VALUE); 385 | break; 386 | } 387 | 388 | case JTOK_KW_NULL: 389 | case JTOK_KW_TRUE: 390 | case JTOK_KW_FALSE: { 391 | UniValue tmpVal; 392 | switch (tok) { 393 | case JTOK_KW_NULL: 394 | // do nothing more 395 | break; 396 | case JTOK_KW_TRUE: 397 | tmpVal.setBool(true); 398 | break; 399 | case JTOK_KW_FALSE: 400 | tmpVal.setBool(false); 401 | break; 402 | default: /* impossible */ break; 403 | } 404 | 405 | if (!stack.size()) { 406 | *this = tmpVal; 407 | break; 408 | } 409 | 410 | UniValue *top = stack.back(); 411 | top->values.push_back(tmpVal); 412 | 413 | setExpect(NOT_VALUE); 414 | break; 415 | } 416 | 417 | case JTOK_NUMBER: { 418 | UniValue tmpVal(VNUM, tokenVal); 419 | if (!stack.size()) { 420 | *this = tmpVal; 421 | break; 422 | } 423 | 424 | UniValue *top = stack.back(); 425 | top->values.push_back(tmpVal); 426 | 427 | setExpect(NOT_VALUE); 428 | break; 429 | } 430 | 431 | case JTOK_STRING: { 432 | if (expect(OBJ_NAME)) { 433 | UniValue *top = stack.back(); 434 | top->keys.push_back(tokenVal); 435 | clearExpect(OBJ_NAME); 436 | setExpect(COLON); 437 | } else { 438 | UniValue tmpVal(VSTR, tokenVal); 439 | if (!stack.size()) { 440 | *this = tmpVal; 441 | break; 442 | } 443 | UniValue *top = stack.back(); 444 | top->values.push_back(tmpVal); 445 | } 446 | 447 | setExpect(NOT_VALUE); 448 | break; 449 | } 450 | 451 | default: 452 | return false; 453 | } 454 | } while (!stack.empty ()); 455 | 456 | /* Check that nothing follows the initial construct (parsed above). */ 457 | tok = getJsonToken(tokenVal, consumed, raw, end); 458 | if (tok != JTOK_NONE) 459 | return false; 460 | 461 | return true; 462 | } 463 | 464 | -------------------------------------------------------------------------------- /lib/univalue_utffilter.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Wladimir J. van der Laan 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or https://opensource.org/licenses/mit-license.php. 4 | #ifndef UNIVALUE_UTFFILTER_H 5 | #define UNIVALUE_UTFFILTER_H 6 | 7 | #include 8 | 9 | /** 10 | * Filter that generates and validates UTF-8, as well as collates UTF-16 11 | * surrogate pairs as specified in RFC4627. 12 | */ 13 | class JSONUTF8StringFilter 14 | { 15 | public: 16 | explicit JSONUTF8StringFilter(std::string &s): 17 | str(s), is_valid(true), codepoint(0), state(0), surpair(0) 18 | { 19 | } 20 | // Write single 8-bit char (may be part of UTF-8 sequence) 21 | void push_back(unsigned char ch) 22 | { 23 | if (state == 0) { 24 | if (ch < 0x80) // 7-bit ASCII, fast direct pass-through 25 | str.push_back(ch); 26 | else if (ch < 0xc0) // Mid-sequence character, invalid in this state 27 | is_valid = false; 28 | else if (ch < 0xe0) { // Start of 2-byte sequence 29 | codepoint = (ch & 0x1f) << 6; 30 | state = 6; 31 | } else if (ch < 0xf0) { // Start of 3-byte sequence 32 | codepoint = (ch & 0x0f) << 12; 33 | state = 12; 34 | } else if (ch < 0xf8) { // Start of 4-byte sequence 35 | codepoint = (ch & 0x07) << 18; 36 | state = 18; 37 | } else // Reserved, invalid 38 | is_valid = false; 39 | } else { 40 | if ((ch & 0xc0) != 0x80) // Not a continuation, invalid 41 | is_valid = false; 42 | state -= 6; 43 | codepoint |= (ch & 0x3f) << state; 44 | if (state == 0) 45 | push_back_u(codepoint); 46 | } 47 | } 48 | // Write codepoint directly, possibly collating surrogate pairs 49 | void push_back_u(unsigned int codepoint_) 50 | { 51 | if (state) // Only accept full codepoints in open state 52 | is_valid = false; 53 | if (codepoint_ >= 0xD800 && codepoint_ < 0xDC00) { // First half of surrogate pair 54 | if (surpair) // Two subsequent surrogate pair openers - fail 55 | is_valid = false; 56 | else 57 | surpair = codepoint_; 58 | } else if (codepoint_ >= 0xDC00 && codepoint_ < 0xE000) { // Second half of surrogate pair 59 | if (surpair) { // Open surrogate pair, expect second half 60 | // Compute code point from UTF-16 surrogate pair 61 | append_codepoint(0x10000 | ((surpair - 0xD800)<<10) | (codepoint_ - 0xDC00)); 62 | surpair = 0; 63 | } else // Second half doesn't follow a first half - fail 64 | is_valid = false; 65 | } else { 66 | if (surpair) // First half of surrogate pair not followed by second - fail 67 | is_valid = false; 68 | else 69 | append_codepoint(codepoint_); 70 | } 71 | } 72 | // Check that we're in a state where the string can be ended 73 | // No open sequences, no open surrogate pairs, etc 74 | bool finalize() 75 | { 76 | if (state || surpair) 77 | is_valid = false; 78 | return is_valid; 79 | } 80 | private: 81 | std::string &str; 82 | bool is_valid; 83 | // Current UTF-8 decoding state 84 | unsigned int codepoint; 85 | int state; // Top bit to be filled in for next UTF-8 byte, or 0 86 | 87 | // Keep track of the following state to handle the following section of 88 | // RFC4627: 89 | // 90 | // To escape an extended character that is not in the Basic Multilingual 91 | // Plane, the character is represented as a twelve-character sequence, 92 | // encoding the UTF-16 surrogate pair. So, for example, a string 93 | // containing only the G clef character (U+1D11E) may be represented as 94 | // "\uD834\uDD1E". 95 | // 96 | // Two subsequent \u.... may have to be replaced with one actual codepoint. 97 | unsigned int surpair; // First half of open UTF-16 surrogate pair, or 0 98 | 99 | void append_codepoint(unsigned int codepoint_) 100 | { 101 | if (codepoint_ <= 0x7f) 102 | str.push_back((char)codepoint_); 103 | else if (codepoint_ <= 0x7FF) { 104 | str.push_back((char)(0xC0 | (codepoint_ >> 6))); 105 | str.push_back((char)(0x80 | (codepoint_ & 0x3F))); 106 | } else if (codepoint_ <= 0xFFFF) { 107 | str.push_back((char)(0xE0 | (codepoint_ >> 12))); 108 | str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); 109 | str.push_back((char)(0x80 | (codepoint_ & 0x3F))); 110 | } else if (codepoint_ <= 0x1FFFFF) { 111 | str.push_back((char)(0xF0 | (codepoint_ >> 18))); 112 | str.push_back((char)(0x80 | ((codepoint_ >> 12) & 0x3F))); 113 | str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); 114 | str.push_back((char)(0x80 | (codepoint_ & 0x3F))); 115 | } 116 | } 117 | }; 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /lib/univalue_write.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2014 BitPay Inc. 2 | // Distributed under the MIT software license, see the accompanying 3 | // file COPYING or https://opensource.org/licenses/mit-license.php. 4 | 5 | #include 6 | #include "univalue_escapes.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | static std::string json_escape(const std::string& inS) 13 | { 14 | std::string outS; 15 | outS.reserve(inS.size() * 2); 16 | 17 | for (unsigned int i = 0; i < inS.size(); i++) { 18 | unsigned char ch = static_cast(inS[i]); 19 | const char *escStr = escapes[ch]; 20 | 21 | if (escStr) 22 | outS += escStr; 23 | else 24 | outS += static_cast(ch); 25 | } 26 | 27 | return outS; 28 | } 29 | 30 | std::string UniValue::write(unsigned int prettyIndent, 31 | unsigned int indentLevel) const 32 | { 33 | std::string s; 34 | s.reserve(1024); 35 | 36 | unsigned int modIndent = indentLevel; 37 | if (modIndent == 0) 38 | modIndent = 1; 39 | 40 | switch (typ) { 41 | case VNULL: 42 | s += "null"; 43 | break; 44 | case VOBJ: 45 | writeObject(prettyIndent, modIndent, s); 46 | break; 47 | case VARR: 48 | writeArray(prettyIndent, modIndent, s); 49 | break; 50 | case VSTR: 51 | s += "\"" + json_escape(val) + "\""; 52 | break; 53 | case VNUM: 54 | s += val; 55 | break; 56 | case VBOOL: 57 | s += (val == "1" ? "true" : "false"); 58 | break; 59 | } 60 | 61 | return s; 62 | } 63 | 64 | static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) 65 | { 66 | s.append(prettyIndent * indentLevel, ' '); 67 | } 68 | 69 | void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const 70 | { 71 | s += "["; 72 | if (prettyIndent) 73 | s += "\n"; 74 | 75 | for (unsigned int i = 0; i < values.size(); i++) { 76 | if (prettyIndent) 77 | indentStr(prettyIndent, indentLevel, s); 78 | s += values[i].write(prettyIndent, indentLevel + 1); 79 | if (i != (values.size() - 1)) { 80 | s += ","; 81 | } 82 | if (prettyIndent) 83 | s += "\n"; 84 | } 85 | 86 | if (prettyIndent) 87 | indentStr(prettyIndent, indentLevel - 1, s); 88 | s += "]"; 89 | } 90 | 91 | void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const 92 | { 93 | s += "{"; 94 | if (prettyIndent) 95 | s += "\n"; 96 | 97 | for (unsigned int i = 0; i < keys.size(); i++) { 98 | if (prettyIndent) 99 | indentStr(prettyIndent, indentLevel, s); 100 | s += "\"" + json_escape(keys[i]) + "\":"; 101 | if (prettyIndent) 102 | s += " "; 103 | s += values.at(i).write(prettyIndent, indentLevel + 1); 104 | if (i != (values.size() - 1)) 105 | s += ","; 106 | if (prettyIndent) 107 | s += "\n"; 108 | } 109 | 110 | if (prettyIndent) 111 | indentStr(prettyIndent, indentLevel - 1, s); 112 | s += "}"; 113 | } 114 | 115 | -------------------------------------------------------------------------------- /pc/libunivalue-uninstalled.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libunivalue 7 | Description: libunivalue, C++ universal value object and JSON library 8 | Version: @VERSION@ 9 | Libs: ${pc_top_builddir}/${pcfiledir}/libunivalue.la 10 | -------------------------------------------------------------------------------- /pc/libunivalue.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libunivalue 7 | Description: libunivalue, C++ universal value object and JSON library 8 | Version: @VERSION@ 9 | Libs: -L${libdir} -lunivalue 10 | Cflags: -I${includedir} 11 | -------------------------------------------------------------------------------- /sources.mk: -------------------------------------------------------------------------------- 1 | # - All variables are namespaced with UNIVALUE_ to avoid colliding with 2 | # downstream makefiles. 3 | # - All Variables ending in _HEADERS or _SOURCES confuse automake, so the 4 | # _INT postfix is applied. 5 | # - Convenience variables, for example a UNIVALUE_TEST_DIR should not be used 6 | # as they interfere with automatic dependency generation 7 | # - The %reldir% is the relative path from the Makefile.am. This allows 8 | # downstreams to use these variables without having to manually account for 9 | # the path change. 10 | 11 | UNIVALUE_INCLUDE_DIR_INT = %reldir%/include 12 | 13 | UNIVALUE_DIST_HEADERS_INT = 14 | UNIVALUE_DIST_HEADERS_INT += %reldir%/include/univalue.h 15 | 16 | UNIVALUE_LIB_HEADERS_INT = 17 | UNIVALUE_LIB_HEADERS_INT += %reldir%/lib/univalue_utffilter.h 18 | UNIVALUE_LIB_HEADERS_INT += %reldir%/lib/univalue_escapes.h 19 | 20 | UNIVALUE_LIB_SOURCES_INT = 21 | UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue.cpp 22 | UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_get.cpp 23 | UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_read.cpp 24 | UNIVALUE_LIB_SOURCES_INT += %reldir%/lib/univalue_write.cpp 25 | 26 | UNIVALUE_TEST_DATA_DIR_INT = %reldir%/test 27 | 28 | UNIVALUE_TEST_UNITESTER_INT = 29 | UNIVALUE_TEST_UNITESTER_INT += %reldir%/test/unitester.cpp 30 | 31 | UNIVALUE_TEST_JSON_INT = 32 | UNIVALUE_TEST_JSON_INT += %reldir%/test/test_json.cpp 33 | 34 | UNIVALUE_TEST_NO_NUL_INT = 35 | UNIVALUE_TEST_NO_NUL_INT += %reldir%/test/no_nul.cpp 36 | 37 | UNIVALUE_TEST_OBJECT_INT = 38 | UNIVALUE_TEST_OBJECT_INT += %reldir%/test/object.cpp 39 | 40 | UNIVALUE_TEST_FILES_INT = 41 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail1.json 42 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail2.json 43 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail3.json 44 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail4.json 45 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail5.json 46 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail6.json 47 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail7.json 48 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail8.json 49 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail9.json 50 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail10.json 51 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail11.json 52 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail12.json 53 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail13.json 54 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail14.json 55 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail15.json 56 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail16.json 57 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail17.json 58 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail18.json 59 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail19.json 60 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail20.json 61 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail21.json 62 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail22.json 63 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail23.json 64 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail24.json 65 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail25.json 66 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail26.json 67 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail27.json 68 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail28.json 69 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail29.json 70 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail30.json 71 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail31.json 72 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail32.json 73 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail33.json 74 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail34.json 75 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail35.json 76 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail36.json 77 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail37.json 78 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail38.json 79 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail39.json 80 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail40.json 81 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail41.json 82 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail42.json 83 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail44.json 84 | UNIVALUE_TEST_FILES_INT += %reldir%/test/fail45.json 85 | UNIVALUE_TEST_FILES_INT += %reldir%/test/pass1.json 86 | UNIVALUE_TEST_FILES_INT += %reldir%/test/pass2.json 87 | UNIVALUE_TEST_FILES_INT += %reldir%/test/pass3.json 88 | UNIVALUE_TEST_FILES_INT += %reldir%/test/pass4.json 89 | UNIVALUE_TEST_FILES_INT += %reldir%/test/round1.json 90 | UNIVALUE_TEST_FILES_INT += %reldir%/test/round2.json 91 | UNIVALUE_TEST_FILES_INT += %reldir%/test/round3.json 92 | UNIVALUE_TEST_FILES_INT += %reldir%/test/round4.json 93 | UNIVALUE_TEST_FILES_INT += %reldir%/test/round5.json 94 | UNIVALUE_TEST_FILES_INT += %reldir%/test/round6.json 95 | UNIVALUE_TEST_FILES_INT += %reldir%/test/round7.json 96 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | object 3 | unitester 4 | test_json 5 | no_nul 6 | 7 | *.trs 8 | *.log 9 | -------------------------------------------------------------------------------- /test/fail1.json: -------------------------------------------------------------------------------- 1 | "This is a string that never ends, yes it goes on and on, my friends. 2 | -------------------------------------------------------------------------------- /test/fail10.json: -------------------------------------------------------------------------------- 1 | {"Extra value after close": true} "misplaced quoted value" -------------------------------------------------------------------------------- /test/fail11.json: -------------------------------------------------------------------------------- 1 | {"Illegal expression": 1 + 2} -------------------------------------------------------------------------------- /test/fail12.json: -------------------------------------------------------------------------------- 1 | {"Illegal invocation": alert()} -------------------------------------------------------------------------------- /test/fail13.json: -------------------------------------------------------------------------------- 1 | {"Numbers cannot have leading zeroes": 013} -------------------------------------------------------------------------------- /test/fail14.json: -------------------------------------------------------------------------------- 1 | {"Numbers cannot be hex": 0x14} -------------------------------------------------------------------------------- /test/fail15.json: -------------------------------------------------------------------------------- 1 | ["Illegal backslash escape: \x15"] -------------------------------------------------------------------------------- /test/fail16.json: -------------------------------------------------------------------------------- 1 | [\naked] -------------------------------------------------------------------------------- /test/fail17.json: -------------------------------------------------------------------------------- 1 | ["Illegal backslash escape: \017"] -------------------------------------------------------------------------------- /test/fail18.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /test/fail19.json: -------------------------------------------------------------------------------- 1 | {"Missing colon" null} -------------------------------------------------------------------------------- /test/fail2.json: -------------------------------------------------------------------------------- 1 | ["Unclosed array" -------------------------------------------------------------------------------- /test/fail20.json: -------------------------------------------------------------------------------- 1 | {"Double colon":: null} -------------------------------------------------------------------------------- /test/fail21.json: -------------------------------------------------------------------------------- 1 | {"Comma instead of colon", null} -------------------------------------------------------------------------------- /test/fail22.json: -------------------------------------------------------------------------------- 1 | ["Colon instead of comma": false] -------------------------------------------------------------------------------- /test/fail23.json: -------------------------------------------------------------------------------- 1 | ["Bad value", truth] -------------------------------------------------------------------------------- /test/fail24.json: -------------------------------------------------------------------------------- 1 | ['single quote'] -------------------------------------------------------------------------------- /test/fail25.json: -------------------------------------------------------------------------------- 1 | [" tab character in string "] -------------------------------------------------------------------------------- /test/fail26.json: -------------------------------------------------------------------------------- 1 | ["tab\ character\ in\ string\ "] -------------------------------------------------------------------------------- /test/fail27.json: -------------------------------------------------------------------------------- 1 | ["line 2 | break"] -------------------------------------------------------------------------------- /test/fail28.json: -------------------------------------------------------------------------------- 1 | ["line\ 2 | break"] -------------------------------------------------------------------------------- /test/fail29.json: -------------------------------------------------------------------------------- 1 | [0e] -------------------------------------------------------------------------------- /test/fail3.json: -------------------------------------------------------------------------------- 1 | {unquoted_key: "keys must be quoted"} -------------------------------------------------------------------------------- /test/fail30.json: -------------------------------------------------------------------------------- 1 | [0e+] -------------------------------------------------------------------------------- /test/fail31.json: -------------------------------------------------------------------------------- 1 | [0e+-1] -------------------------------------------------------------------------------- /test/fail32.json: -------------------------------------------------------------------------------- 1 | {"Comma instead if closing brace": true, -------------------------------------------------------------------------------- /test/fail33.json: -------------------------------------------------------------------------------- 1 | ["mismatch"} -------------------------------------------------------------------------------- /test/fail34.json: -------------------------------------------------------------------------------- 1 | {} garbage -------------------------------------------------------------------------------- /test/fail35.json: -------------------------------------------------------------------------------- 1 | [ true true true [] [] [] ] 2 | -------------------------------------------------------------------------------- /test/fail36.json: -------------------------------------------------------------------------------- 1 | {"a":} 2 | -------------------------------------------------------------------------------- /test/fail37.json: -------------------------------------------------------------------------------- 1 | {"a":1 "b":2} 2 | -------------------------------------------------------------------------------- /test/fail38.json: -------------------------------------------------------------------------------- 1 | ["\ud834"] 2 | -------------------------------------------------------------------------------- /test/fail39.json: -------------------------------------------------------------------------------- 1 | ["\udd61"] 2 | -------------------------------------------------------------------------------- /test/fail4.json: -------------------------------------------------------------------------------- 1 | ["extra comma",] -------------------------------------------------------------------------------- /test/fail40.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitcoin-core/univalue-subtree/de4f73ddca40487179e9ed08c6f6aa745d6cbba3/test/fail40.json -------------------------------------------------------------------------------- /test/fail41.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitcoin-core/univalue-subtree/de4f73ddca40487179e9ed08c6f6aa745d6cbba3/test/fail41.json -------------------------------------------------------------------------------- /test/fail42.json: -------------------------------------------------------------------------------- 1 | ["before nul byte"]"after nul byte" 2 | -------------------------------------------------------------------------------- /test/fail44.json: -------------------------------------------------------------------------------- 1 | "This file ends without a newline or close-quote. -------------------------------------------------------------------------------- /test/fail45.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] 2 | -------------------------------------------------------------------------------- /test/fail5.json: -------------------------------------------------------------------------------- 1 | ["double extra comma",,] -------------------------------------------------------------------------------- /test/fail6.json: -------------------------------------------------------------------------------- 1 | [ , "<-- missing value"] -------------------------------------------------------------------------------- /test/fail7.json: -------------------------------------------------------------------------------- 1 | ["Comma after the close"], -------------------------------------------------------------------------------- /test/fail8.json: -------------------------------------------------------------------------------- 1 | ["Extra close"]] -------------------------------------------------------------------------------- /test/fail9.json: -------------------------------------------------------------------------------- 1 | {"Extra comma": true,} -------------------------------------------------------------------------------- /test/no_nul.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main (int argc, char *argv[]) 4 | { 5 | char buf[] = "___[1,2,3]___"; 6 | UniValue val; 7 | return val.read(buf + 3, 7) ? 0 : 1; 8 | } 9 | -------------------------------------------------------------------------------- /test/object.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 BitPay Inc. 2 | // Copyright (c) 2014-2016 The Bitcoin Core developers 3 | // Distributed under the MIT software license, see the accompanying 4 | // file COPYING or https://opensource.org/licenses/mit-license.php. 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define BOOST_FIXTURE_TEST_SUITE(a, b) 17 | #define BOOST_AUTO_TEST_CASE(funcName) void funcName() 18 | #define BOOST_AUTO_TEST_SUITE_END() 19 | #define BOOST_CHECK(expr) assert(expr) 20 | #define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2)) 21 | #define BOOST_CHECK_THROW(stmt, excMatch) { \ 22 | try { \ 23 | (stmt); \ 24 | assert(0 && "No exception caught"); \ 25 | } catch (excMatch & e) { \ 26 | } catch (...) { \ 27 | assert(0 && "Wrong exception caught"); \ 28 | } \ 29 | } 30 | #define BOOST_CHECK_NO_THROW(stmt) { \ 31 | try { \ 32 | (stmt); \ 33 | } catch (...) { \ 34 | assert(0); \ 35 | } \ 36 | } 37 | 38 | BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup) 39 | 40 | BOOST_AUTO_TEST_CASE(univalue_constructor) 41 | { 42 | UniValue v1; 43 | BOOST_CHECK(v1.isNull()); 44 | 45 | UniValue v2(UniValue::VSTR); 46 | BOOST_CHECK(v2.isStr()); 47 | 48 | UniValue v3(UniValue::VSTR, "foo"); 49 | BOOST_CHECK(v3.isStr()); 50 | BOOST_CHECK_EQUAL(v3.getValStr(), "foo"); 51 | 52 | UniValue numTest; 53 | BOOST_CHECK(numTest.setNumStr("82")); 54 | BOOST_CHECK(numTest.isNum()); 55 | BOOST_CHECK_EQUAL(numTest.getValStr(), "82"); 56 | 57 | uint64_t vu64 = 82; 58 | UniValue v4(vu64); 59 | BOOST_CHECK(v4.isNum()); 60 | BOOST_CHECK_EQUAL(v4.getValStr(), "82"); 61 | 62 | int64_t vi64 = -82; 63 | UniValue v5(vi64); 64 | BOOST_CHECK(v5.isNum()); 65 | BOOST_CHECK_EQUAL(v5.getValStr(), "-82"); 66 | 67 | int vi = -688; 68 | UniValue v6(vi); 69 | BOOST_CHECK(v6.isNum()); 70 | BOOST_CHECK_EQUAL(v6.getValStr(), "-688"); 71 | 72 | double vd = -7.21; 73 | UniValue v7(vd); 74 | BOOST_CHECK(v7.isNum()); 75 | BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21"); 76 | 77 | std::string vs("yawn"); 78 | UniValue v8(vs); 79 | BOOST_CHECK(v8.isStr()); 80 | BOOST_CHECK_EQUAL(v8.getValStr(), "yawn"); 81 | 82 | const char *vcs = "zappa"; 83 | UniValue v9(vcs); 84 | BOOST_CHECK(v9.isStr()); 85 | BOOST_CHECK_EQUAL(v9.getValStr(), "zappa"); 86 | } 87 | 88 | BOOST_AUTO_TEST_CASE(univalue_typecheck) 89 | { 90 | UniValue v1; 91 | BOOST_CHECK(v1.setNumStr("1")); 92 | BOOST_CHECK(v1.isNum()); 93 | BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error); 94 | 95 | { 96 | UniValue v_negative; 97 | BOOST_CHECK(v_negative.setNumStr("-1")); 98 | BOOST_CHECK_THROW(v_negative.getInt(), std::runtime_error); 99 | BOOST_CHECK_EQUAL(v_negative.getInt(), -1); 100 | } 101 | 102 | UniValue v2; 103 | BOOST_CHECK(v2.setBool(true)); 104 | BOOST_CHECK_EQUAL(v2.get_bool(), true); 105 | BOOST_CHECK_THROW(v2.getInt(), std::runtime_error); 106 | 107 | UniValue v3; 108 | BOOST_CHECK(v3.setNumStr("32482348723847471234")); 109 | BOOST_CHECK_THROW(v3.getInt(), std::runtime_error); 110 | BOOST_CHECK(v3.setNumStr("1000")); 111 | BOOST_CHECK_EQUAL(v3.getInt(), 1000); 112 | 113 | UniValue v4; 114 | BOOST_CHECK(v4.setNumStr("2147483648")); 115 | BOOST_CHECK_EQUAL(v4.getInt(), 2147483648); 116 | BOOST_CHECK_THROW(v4.getInt(), std::runtime_error); 117 | BOOST_CHECK(v4.setNumStr("1000")); 118 | BOOST_CHECK_EQUAL(v4.getInt(), 1000); 119 | BOOST_CHECK_THROW(v4.get_str(), std::runtime_error); 120 | BOOST_CHECK_EQUAL(v4.get_real(), 1000); 121 | BOOST_CHECK_THROW(v4.get_array(), std::runtime_error); 122 | BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error); 123 | BOOST_CHECK_THROW(v4.getValues(), std::runtime_error); 124 | BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error); 125 | 126 | UniValue v5; 127 | BOOST_CHECK(v5.read("[true, 10]")); 128 | BOOST_CHECK_NO_THROW(v5.get_array()); 129 | std::vector vals = v5.getValues(); 130 | BOOST_CHECK_THROW(vals[0].getInt(), std::runtime_error); 131 | BOOST_CHECK_EQUAL(vals[0].get_bool(), true); 132 | 133 | BOOST_CHECK_EQUAL(vals[1].getInt(), 10); 134 | BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error); 135 | } 136 | 137 | BOOST_AUTO_TEST_CASE(univalue_set) 138 | { 139 | UniValue v(UniValue::VSTR, "foo"); 140 | v.clear(); 141 | BOOST_CHECK(v.isNull()); 142 | BOOST_CHECK_EQUAL(v.getValStr(), ""); 143 | 144 | BOOST_CHECK(v.setObject()); 145 | BOOST_CHECK(v.isObject()); 146 | BOOST_CHECK_EQUAL(v.size(), 0); 147 | BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ); 148 | BOOST_CHECK(v.empty()); 149 | 150 | BOOST_CHECK(v.setArray()); 151 | BOOST_CHECK(v.isArray()); 152 | BOOST_CHECK_EQUAL(v.size(), 0); 153 | 154 | BOOST_CHECK(v.setStr("zum")); 155 | BOOST_CHECK(v.isStr()); 156 | BOOST_CHECK_EQUAL(v.getValStr(), "zum"); 157 | 158 | BOOST_CHECK(v.setFloat(-1.01)); 159 | BOOST_CHECK(v.isNum()); 160 | BOOST_CHECK_EQUAL(v.getValStr(), "-1.01"); 161 | 162 | BOOST_CHECK(v.setInt((int)1023)); 163 | BOOST_CHECK(v.isNum()); 164 | BOOST_CHECK_EQUAL(v.getValStr(), "1023"); 165 | 166 | BOOST_CHECK(v.setInt((int64_t)-1023LL)); 167 | BOOST_CHECK(v.isNum()); 168 | BOOST_CHECK_EQUAL(v.getValStr(), "-1023"); 169 | 170 | BOOST_CHECK(v.setInt((uint64_t)1023ULL)); 171 | BOOST_CHECK(v.isNum()); 172 | BOOST_CHECK_EQUAL(v.getValStr(), "1023"); 173 | 174 | BOOST_CHECK(v.setNumStr("-688")); 175 | BOOST_CHECK(v.isNum()); 176 | BOOST_CHECK_EQUAL(v.getValStr(), "-688"); 177 | 178 | BOOST_CHECK(v.setBool(false)); 179 | BOOST_CHECK_EQUAL(v.isBool(), true); 180 | BOOST_CHECK_EQUAL(v.isTrue(), false); 181 | BOOST_CHECK_EQUAL(v.isFalse(), true); 182 | BOOST_CHECK_EQUAL(v.getBool(), false); 183 | 184 | BOOST_CHECK(v.setBool(true)); 185 | BOOST_CHECK_EQUAL(v.isBool(), true); 186 | BOOST_CHECK_EQUAL(v.isTrue(), true); 187 | BOOST_CHECK_EQUAL(v.isFalse(), false); 188 | BOOST_CHECK_EQUAL(v.getBool(), true); 189 | 190 | BOOST_CHECK(!v.setNumStr("zombocom")); 191 | 192 | BOOST_CHECK(v.setNull()); 193 | BOOST_CHECK(v.isNull()); 194 | } 195 | 196 | BOOST_AUTO_TEST_CASE(univalue_array) 197 | { 198 | UniValue arr(UniValue::VARR); 199 | 200 | UniValue v((int64_t)1023LL); 201 | BOOST_CHECK(arr.push_back(v)); 202 | 203 | std::string vStr("zippy"); 204 | BOOST_CHECK(arr.push_back(vStr)); 205 | 206 | const char *s = "pippy"; 207 | BOOST_CHECK(arr.push_back(s)); 208 | 209 | std::vector vec; 210 | v.setStr("boing"); 211 | vec.push_back(v); 212 | 213 | v.setStr("going"); 214 | vec.push_back(v); 215 | 216 | BOOST_CHECK(arr.push_backV(vec)); 217 | 218 | BOOST_CHECK(arr.push_back((uint64_t) 400ULL)); 219 | BOOST_CHECK(arr.push_back((int64_t) -400LL)); 220 | BOOST_CHECK(arr.push_back((int) -401)); 221 | BOOST_CHECK(arr.push_back(-40.1)); 222 | BOOST_CHECK(arr.push_back(true)); 223 | 224 | BOOST_CHECK_EQUAL(arr.empty(), false); 225 | BOOST_CHECK_EQUAL(arr.size(), 10); 226 | 227 | BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023"); 228 | BOOST_CHECK_EQUAL(arr[0].getType(), UniValue::VNUM); 229 | BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy"); 230 | BOOST_CHECK_EQUAL(arr[1].getType(), UniValue::VSTR); 231 | BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy"); 232 | BOOST_CHECK_EQUAL(arr[2].getType(), UniValue::VSTR); 233 | BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing"); 234 | BOOST_CHECK_EQUAL(arr[3].getType(), UniValue::VSTR); 235 | BOOST_CHECK_EQUAL(arr[4].getValStr(), "going"); 236 | BOOST_CHECK_EQUAL(arr[4].getType(), UniValue::VSTR); 237 | BOOST_CHECK_EQUAL(arr[5].getValStr(), "400"); 238 | BOOST_CHECK_EQUAL(arr[5].getType(), UniValue::VNUM); 239 | BOOST_CHECK_EQUAL(arr[6].getValStr(), "-400"); 240 | BOOST_CHECK_EQUAL(arr[6].getType(), UniValue::VNUM); 241 | BOOST_CHECK_EQUAL(arr[7].getValStr(), "-401"); 242 | BOOST_CHECK_EQUAL(arr[7].getType(), UniValue::VNUM); 243 | BOOST_CHECK_EQUAL(arr[8].getValStr(), "-40.1"); 244 | BOOST_CHECK_EQUAL(arr[8].getType(), UniValue::VNUM); 245 | BOOST_CHECK_EQUAL(arr[9].getValStr(), "1"); 246 | BOOST_CHECK_EQUAL(arr[9].getType(), UniValue::VBOOL); 247 | 248 | BOOST_CHECK_EQUAL(arr[999].getValStr(), ""); 249 | 250 | arr.clear(); 251 | BOOST_CHECK(arr.empty()); 252 | BOOST_CHECK_EQUAL(arr.size(), 0); 253 | } 254 | 255 | BOOST_AUTO_TEST_CASE(univalue_object) 256 | { 257 | UniValue obj(UniValue::VOBJ); 258 | std::string strKey, strVal; 259 | UniValue v; 260 | 261 | strKey = "age"; 262 | v.setInt(100); 263 | BOOST_CHECK(obj.pushKV(strKey, v)); 264 | 265 | strKey = "first"; 266 | strVal = "John"; 267 | BOOST_CHECK(obj.pushKV(strKey, strVal)); 268 | 269 | strKey = "last"; 270 | const char *cVal = "Smith"; 271 | BOOST_CHECK(obj.pushKV(strKey, cVal)); 272 | 273 | strKey = "distance"; 274 | BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25)); 275 | 276 | strKey = "time"; 277 | BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600)); 278 | 279 | strKey = "calories"; 280 | BOOST_CHECK(obj.pushKV(strKey, (int) 12)); 281 | 282 | strKey = "temperature"; 283 | BOOST_CHECK(obj.pushKV(strKey, (double) 90.012)); 284 | 285 | strKey = "moon"; 286 | BOOST_CHECK(obj.pushKV(strKey, true)); 287 | 288 | strKey = "spoon"; 289 | BOOST_CHECK(obj.pushKV(strKey, false)); 290 | 291 | UniValue obj2(UniValue::VOBJ); 292 | BOOST_CHECK(obj2.pushKV("cat1", 9000)); 293 | BOOST_CHECK(obj2.pushKV("cat2", 12345)); 294 | 295 | BOOST_CHECK(obj.pushKVs(obj2)); 296 | 297 | BOOST_CHECK_EQUAL(obj.empty(), false); 298 | BOOST_CHECK_EQUAL(obj.size(), 11); 299 | 300 | BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100"); 301 | BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John"); 302 | BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith"); 303 | BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25"); 304 | BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600"); 305 | BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12"); 306 | BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012"); 307 | BOOST_CHECK_EQUAL(obj["moon"].getValStr(), "1"); 308 | BOOST_CHECK_EQUAL(obj["spoon"].getValStr(), ""); 309 | BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000"); 310 | BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345"); 311 | 312 | BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), ""); 313 | 314 | BOOST_CHECK(obj.exists("age")); 315 | BOOST_CHECK(obj.exists("first")); 316 | BOOST_CHECK(obj.exists("last")); 317 | BOOST_CHECK(obj.exists("distance")); 318 | BOOST_CHECK(obj.exists("time")); 319 | BOOST_CHECK(obj.exists("calories")); 320 | BOOST_CHECK(obj.exists("temperature")); 321 | BOOST_CHECK(obj.exists("moon")); 322 | BOOST_CHECK(obj.exists("spoon")); 323 | BOOST_CHECK(obj.exists("cat1")); 324 | BOOST_CHECK(obj.exists("cat2")); 325 | 326 | BOOST_CHECK(!obj.exists("nyuknyuknyuk")); 327 | 328 | std::map objTypes; 329 | objTypes["age"] = UniValue::VNUM; 330 | objTypes["first"] = UniValue::VSTR; 331 | objTypes["last"] = UniValue::VSTR; 332 | objTypes["distance"] = UniValue::VNUM; 333 | objTypes["time"] = UniValue::VNUM; 334 | objTypes["calories"] = UniValue::VNUM; 335 | objTypes["temperature"] = UniValue::VNUM; 336 | objTypes["moon"] = UniValue::VBOOL; 337 | objTypes["spoon"] = UniValue::VBOOL; 338 | objTypes["cat1"] = UniValue::VNUM; 339 | objTypes["cat2"] = UniValue::VNUM; 340 | BOOST_CHECK(obj.checkObject(objTypes)); 341 | 342 | objTypes["cat2"] = UniValue::VSTR; 343 | BOOST_CHECK(!obj.checkObject(objTypes)); 344 | 345 | obj.clear(); 346 | BOOST_CHECK(obj.empty()); 347 | BOOST_CHECK_EQUAL(obj.size(), 0); 348 | BOOST_CHECK_EQUAL(obj.getType(), UniValue::VNULL); 349 | 350 | BOOST_CHECK_EQUAL(obj.setObject(), true); 351 | UniValue uv; 352 | uv.setInt(42); 353 | obj.__pushKV("age", uv); 354 | BOOST_CHECK_EQUAL(obj.size(), 1); 355 | BOOST_CHECK_EQUAL(obj["age"].getValStr(), "42"); 356 | 357 | uv.setInt(43); 358 | obj.pushKV("age", uv); 359 | BOOST_CHECK_EQUAL(obj.size(), 1); 360 | BOOST_CHECK_EQUAL(obj["age"].getValStr(), "43"); 361 | 362 | obj.pushKV("name", "foo bar"); 363 | 364 | std::map kv; 365 | obj.getObjMap(kv); 366 | BOOST_CHECK_EQUAL(kv["age"].getValStr(), "43"); 367 | BOOST_CHECK_EQUAL(kv["name"].getValStr(), "foo bar"); 368 | 369 | } 370 | 371 | static const char *json1 = 372 | "[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]"; 373 | 374 | BOOST_AUTO_TEST_CASE(univalue_readwrite) 375 | { 376 | UniValue v; 377 | BOOST_CHECK(v.read(json1)); 378 | 379 | std::string strJson1(json1); 380 | BOOST_CHECK(v.read(strJson1)); 381 | 382 | BOOST_CHECK(v.isArray()); 383 | BOOST_CHECK_EQUAL(v.size(), 2); 384 | 385 | BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000"); 386 | 387 | UniValue obj = v[1]; 388 | BOOST_CHECK(obj.isObject()); 389 | BOOST_CHECK_EQUAL(obj.size(), 3); 390 | 391 | BOOST_CHECK(obj["key1"].isStr()); 392 | std::string correctValue("str"); 393 | correctValue.push_back('\0'); 394 | BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue); 395 | BOOST_CHECK(obj["key2"].isNum()); 396 | BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800"); 397 | BOOST_CHECK(obj["key3"].isObject()); 398 | 399 | BOOST_CHECK_EQUAL(strJson1, v.write()); 400 | 401 | /* Check for (correctly reporting) a parsing error if the initial 402 | JSON construct is followed by more stuff. Note that whitespace 403 | is, of course, exempt. */ 404 | 405 | BOOST_CHECK(v.read(" {}\n ")); 406 | BOOST_CHECK(v.isObject()); 407 | BOOST_CHECK(v.read(" []\n ")); 408 | BOOST_CHECK(v.isArray()); 409 | 410 | BOOST_CHECK(!v.read("@{}")); 411 | BOOST_CHECK(!v.read("{} garbage")); 412 | BOOST_CHECK(!v.read("[]{}")); 413 | BOOST_CHECK(!v.read("{}[]")); 414 | BOOST_CHECK(!v.read("{} 42")); 415 | } 416 | 417 | BOOST_AUTO_TEST_SUITE_END() 418 | 419 | int main (int argc, char *argv[]) 420 | { 421 | univalue_constructor(); 422 | univalue_typecheck(); 423 | univalue_set(); 424 | univalue_array(); 425 | univalue_object(); 426 | univalue_readwrite(); 427 | return 0; 428 | } 429 | 430 | -------------------------------------------------------------------------------- /test/pass1.json: -------------------------------------------------------------------------------- 1 | [ 2 | "JSON Test Pattern pass1", 3 | {"object with 1 member":["array with 1 element"]}, 4 | {}, 5 | [], 6 | -42, 7 | true, 8 | false, 9 | null, 10 | { 11 | "integer": 1234567890, 12 | "real": -9876.543210, 13 | "e": 0.123456789e-12, 14 | "E": 1.234567890E+34, 15 | "": 23456789012E66, 16 | "zero": 0, 17 | "one": 1, 18 | "space": " ", 19 | "quote": "\"", 20 | "backslash": "\\", 21 | "controls": "\b\f\n\r\t", 22 | "slash": "/ & \/", 23 | "alpha": "abcdefghijklmnopqrstuvwyz", 24 | "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", 25 | "digit": "0123456789", 26 | "0123456789": "digit", 27 | "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", 28 | "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", 29 | "true": true, 30 | "false": false, 31 | "null": null, 32 | "array":[ ], 33 | "object":{ }, 34 | "address": "50 St. James Street", 35 | "url": "http://www.JSON.org/", 36 | "comment": "// /* */": " ", 38 | " s p a c e d " :[1,2 , 3 39 | 40 | , 41 | 42 | 4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], 43 | "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", 44 | "quotes": "" \u0022 %22 0x22 034 "", 45 | "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" 46 | : "A key can be any string" 47 | }, 48 | 0.5 ,98.6 49 | , 50 | 99.44 51 | , 52 | 53 | 1066, 54 | 1e1, 55 | 0.1e1, 56 | 1e-1, 57 | 1e00,2e+00,2e-00 58 | ,"rosebud"] -------------------------------------------------------------------------------- /test/pass2.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] -------------------------------------------------------------------------------- /test/pass3.json: -------------------------------------------------------------------------------- 1 | { 2 | "JSON Test Pattern pass3": { 3 | "The outermost value": "must be an object or array.", 4 | "In this test": "It is an object." 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/pass4.json: -------------------------------------------------------------------------------- 1 | [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] 2 | -------------------------------------------------------------------------------- /test/round1.json: -------------------------------------------------------------------------------- 1 | ["\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f"] 2 | -------------------------------------------------------------------------------- /test/round2.json: -------------------------------------------------------------------------------- 1 | ["a§■𐎒𝅘𝅥𝅯"] 2 | -------------------------------------------------------------------------------- /test/round3.json: -------------------------------------------------------------------------------- 1 | "abcdefghijklmnopqrstuvwxyz" 2 | -------------------------------------------------------------------------------- /test/round4.json: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /test/round5.json: -------------------------------------------------------------------------------- 1 | true 2 | -------------------------------------------------------------------------------- /test/round6.json: -------------------------------------------------------------------------------- 1 | false 2 | -------------------------------------------------------------------------------- /test/round7.json: -------------------------------------------------------------------------------- 1 | null 2 | -------------------------------------------------------------------------------- /test/test_json.cpp: -------------------------------------------------------------------------------- 1 | // Test program that can be called by the JSON test suite at 2 | // https://github.com/nst/JSONTestSuite. 3 | // 4 | // It reads JSON input from stdin and exits with code 0 if it can be parsed 5 | // successfully. It also pretty prints the parsed JSON value to stdout. 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | int main (int argc, char *argv[]) 16 | { 17 | UniValue val; 18 | if (val.read(string(istreambuf_iterator(cin), 19 | istreambuf_iterator()))) { 20 | cout << val.write(1 /* prettyIndent */, 4 /* indentLevel */) << endl; 21 | return 0; 22 | } else { 23 | cerr << "JSON Parse Error." << endl; 24 | return 1; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/unitester.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2014 BitPay Inc. 2 | // Distributed under the MIT/X11 software license, see the accompanying 3 | // file COPYING or https://opensource.org/licenses/mit-license.php. 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #ifndef JSON_TEST_SRC 12 | #error JSON_TEST_SRC must point to test source directory 13 | #endif 14 | 15 | #ifndef ARRAY_SIZE 16 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 17 | #endif 18 | 19 | std::string srcdir(JSON_TEST_SRC); 20 | static bool test_failed = false; 21 | 22 | #define d_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", filename.c_str()); } } 23 | #define f_assert(expr) { if (!(expr)) { test_failed = true; fprintf(stderr, "%s failed\n", __func__); } } 24 | 25 | static std::string rtrim(std::string s) 26 | { 27 | s.erase(s.find_last_not_of(" \n\r\t")+1); 28 | return s; 29 | } 30 | 31 | static void runtest(std::string filename, const std::string& jdata) 32 | { 33 | std::string prefix = filename.substr(0, 4); 34 | 35 | bool wantPass = (prefix == "pass") || (prefix == "roun"); 36 | bool wantFail = (prefix == "fail"); 37 | bool wantRoundTrip = (prefix == "roun"); 38 | assert(wantPass || wantFail); 39 | 40 | UniValue val; 41 | bool testResult = val.read(jdata); 42 | 43 | if (wantPass) { 44 | d_assert(testResult == true); 45 | } else { 46 | d_assert(testResult == false); 47 | } 48 | 49 | if (wantRoundTrip) { 50 | std::string odata = val.write(0, 0); 51 | assert(odata == rtrim(jdata)); 52 | } 53 | } 54 | 55 | static void runtest_file(const char *filename_) 56 | { 57 | std::string basename(filename_); 58 | std::string filename = srcdir + "/" + basename; 59 | FILE *f = fopen(filename.c_str(), "r"); 60 | assert(f != nullptr); 61 | 62 | std::string jdata; 63 | 64 | char buf[4096]; 65 | while (!feof(f)) { 66 | int bread = fread(buf, 1, sizeof(buf), f); 67 | assert(!ferror(f)); 68 | 69 | std::string s(buf, bread); 70 | jdata += s; 71 | } 72 | 73 | assert(!ferror(f)); 74 | fclose(f); 75 | 76 | runtest(basename, jdata); 77 | } 78 | 79 | static const char *filenames[] = { 80 | "fail10.json", 81 | "fail11.json", 82 | "fail12.json", 83 | "fail13.json", 84 | "fail14.json", 85 | "fail15.json", 86 | "fail16.json", 87 | "fail17.json", 88 | //"fail18.json", // investigate 89 | "fail19.json", 90 | "fail1.json", 91 | "fail20.json", 92 | "fail21.json", 93 | "fail22.json", 94 | "fail23.json", 95 | "fail24.json", 96 | "fail25.json", 97 | "fail26.json", 98 | "fail27.json", 99 | "fail28.json", 100 | "fail29.json", 101 | "fail2.json", 102 | "fail30.json", 103 | "fail31.json", 104 | "fail32.json", 105 | "fail33.json", 106 | "fail34.json", 107 | "fail35.json", 108 | "fail36.json", 109 | "fail37.json", 110 | "fail38.json", // invalid unicode: only first half of surrogate pair 111 | "fail39.json", // invalid unicode: only second half of surrogate pair 112 | "fail40.json", // invalid unicode: broken UTF-8 113 | "fail41.json", // invalid unicode: unfinished UTF-8 114 | "fail42.json", // valid json with garbage following a nul byte 115 | "fail44.json", // unterminated string 116 | "fail45.json", // nested beyond max depth 117 | "fail3.json", 118 | "fail4.json", // extra comma 119 | "fail5.json", 120 | "fail6.json", 121 | "fail7.json", 122 | "fail8.json", 123 | "fail9.json", // extra comma 124 | "pass1.json", 125 | "pass2.json", 126 | "pass3.json", 127 | "pass4.json", 128 | "round1.json", // round-trip test 129 | "round2.json", // unicode 130 | "round3.json", // bare string 131 | "round4.json", // bare number 132 | "round5.json", // bare true 133 | "round6.json", // bare false 134 | "round7.json", // bare null 135 | }; 136 | 137 | // Test \u handling 138 | void unescape_unicode_test() 139 | { 140 | UniValue val; 141 | bool testResult; 142 | // Escaped ASCII (quote) 143 | testResult = val.read("[\"\\u0022\"]"); 144 | f_assert(testResult); 145 | f_assert(val[0].get_str() == "\""); 146 | // Escaped Basic Plane character, two-byte UTF-8 147 | testResult = val.read("[\"\\u0191\"]"); 148 | f_assert(testResult); 149 | f_assert(val[0].get_str() == "\xc6\x91"); 150 | // Escaped Basic Plane character, three-byte UTF-8 151 | testResult = val.read("[\"\\u2191\"]"); 152 | f_assert(testResult); 153 | f_assert(val[0].get_str() == "\xe2\x86\x91"); 154 | // Escaped Supplementary Plane character U+1d161 155 | testResult = val.read("[\"\\ud834\\udd61\"]"); 156 | f_assert(testResult); 157 | f_assert(val[0].get_str() == "\xf0\x9d\x85\xa1"); 158 | } 159 | 160 | int main (int argc, char *argv[]) 161 | { 162 | for (unsigned int fidx = 0; fidx < ARRAY_SIZE(filenames); fidx++) { 163 | runtest_file(filenames[fidx]); 164 | } 165 | 166 | unescape_unicode_test(); 167 | 168 | return test_failed ? 1 : 0; 169 | } 170 | 171 | --------------------------------------------------------------------------------