summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--3rdparty/rapidjson/.gitignore4
-rw-r--r--3rdparty/rapidjson/.travis.yml120
-rw-r--r--3rdparty/rapidjson/CHANGELOG.md14
-rw-r--r--3rdparty/rapidjson/CMakeLists.txt128
-rw-r--r--3rdparty/rapidjson/RapidJSON.pc.in2
-rw-r--r--3rdparty/rapidjson/RapidJSONConfig.cmake.in28
-rw-r--r--3rdparty/rapidjson/appveyor.yml81
-rw-r--r--3rdparty/rapidjson/contrib/natvis/LICENSE45
-rw-r--r--3rdparty/rapidjson/contrib/natvis/README.md7
-rw-r--r--3rdparty/rapidjson/contrib/natvis/rapidjson.natvis38
-rw-r--r--3rdparty/rapidjson/doc/CMakeLists.txt4
-rw-r--r--3rdparty/rapidjson/doc/Doxyfile.in2
-rw-r--r--3rdparty/rapidjson/doc/Doxyfile.zh-cn.in4
-rw-r--r--3rdparty/rapidjson/doc/diagram/move2.dot8
-rw-r--r--3rdparty/rapidjson/doc/diagram/move3.dot8
-rw-r--r--3rdparty/rapidjson/doc/dom.md5
-rw-r--r--3rdparty/rapidjson/doc/dom.zh-cn.md5
-rw-r--r--3rdparty/rapidjson/doc/encoding.md2
-rw-r--r--3rdparty/rapidjson/doc/encoding.zh-cn.md2
-rw-r--r--3rdparty/rapidjson/doc/faq.md30
-rw-r--r--3rdparty/rapidjson/doc/faq.zh-cn.md24
-rw-r--r--3rdparty/rapidjson/doc/features.md12
-rw-r--r--3rdparty/rapidjson/doc/features.zh-cn.md2
-rw-r--r--3rdparty/rapidjson/doc/internals.md15
-rw-r--r--3rdparty/rapidjson/doc/internals.zh-cn.md363
-rw-r--r--3rdparty/rapidjson/doc/misc/header.html2
-rw-r--r--3rdparty/rapidjson/doc/npm.md2
-rw-r--r--3rdparty/rapidjson/doc/performance.md6
-rw-r--r--3rdparty/rapidjson/doc/performance.zh-cn.md4
-rw-r--r--3rdparty/rapidjson/doc/pointer.md2
-rw-r--r--3rdparty/rapidjson/doc/pointer.zh-cn.md2
-rw-r--r--3rdparty/rapidjson/doc/sax.md53
-rw-r--r--3rdparty/rapidjson/doc/sax.zh-cn.md6
-rw-r--r--3rdparty/rapidjson/doc/schema.md306
-rw-r--r--3rdparty/rapidjson/doc/schema.zh-cn.md28
-rw-r--r--3rdparty/rapidjson/doc/stream.md19
-rw-r--r--3rdparty/rapidjson/doc/stream.zh-cn.md5
-rw-r--r--3rdparty/rapidjson/doc/tutorial.md84
-rw-r--r--3rdparty/rapidjson/doc/tutorial.zh-cn.md33
-rw-r--r--3rdparty/rapidjson/example/CMakeLists.txt10
-rw-r--r--3rdparty/rapidjson/example/archiver/archiver.cpp292
-rw-r--r--3rdparty/rapidjson/example/archiver/archiver.h145
-rw-r--r--3rdparty/rapidjson/example/archiver/archivertest.cpp287
-rw-r--r--3rdparty/rapidjson/example/jsonx/jsonx.cpp2
-rw-r--r--3rdparty/rapidjson/example/lookaheadparser/lookaheadparser.cpp350
-rw-r--r--3rdparty/rapidjson/example/parsebyparts/parsebyparts.cpp9
-rw-r--r--3rdparty/rapidjson/example/schemavalidator/schemavalidator.cpp127
-rw-r--r--3rdparty/rapidjson/example/simplepullreader/simplepullreader.cpp53
-rw-r--r--3rdparty/rapidjson/example/sortkeys/sortkeys.cpp62
-rw-r--r--3rdparty/rapidjson/example/traverseaspointer.cpp39
-rw-r--r--3rdparty/rapidjson/example/tutorial/tutorial.cpp2
-rw-r--r--3rdparty/rapidjson/include/rapidjson/allocators.h534
-rw-r--r--3rdparty/rapidjson/include/rapidjson/cursorstreamwrapper.h78
-rw-r--r--3rdparty/rapidjson/include/rapidjson/document.h788
-rw-r--r--3rdparty/rapidjson/include/rapidjson/encodedstream.h4
-rw-r--r--3rdparty/rapidjson/include/rapidjson/encodings.h88
-rw-r--r--3rdparty/rapidjson/include/rapidjson/error/en.h118
-rw-r--r--3rdparty/rapidjson/include/rapidjson/error/error.h146
-rw-r--r--3rdparty/rapidjson/include/rapidjson/filereadstream.h6
-rw-r--r--3rdparty/rapidjson/include/rapidjson/filewritestream.h6
-rw-r--r--3rdparty/rapidjson/include/rapidjson/fwd.h4
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/biginteger.h25
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/clzll.h71
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/diyfp.h59
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/dtoa.h18
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/ieee754.h6
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/itoa.h84
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/meta.h11
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/pow10.h2
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/regex.h246
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/stack.h12
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/strfunc.h30
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/strtod.h122
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/swap.h2
-rw-r--r--3rdparty/rapidjson/include/rapidjson/istreamwrapper.h89
-rw-r--r--3rdparty/rapidjson/include/rapidjson/memorybuffer.h2
-rw-r--r--3rdparty/rapidjson/include/rapidjson/memorystream.h2
-rw-r--r--3rdparty/rapidjson/include/rapidjson/ostreamwrapper.h2
-rw-r--r--3rdparty/rapidjson/include/rapidjson/pointer.h194
-rw-r--r--3rdparty/rapidjson/include/rapidjson/prettywriter.h64
-rw-r--r--3rdparty/rapidjson/include/rapidjson/rapidjson.h218
-rw-r--r--3rdparty/rapidjson/include/rapidjson/reader.h677
-rw-r--r--3rdparty/rapidjson/include/rapidjson/schema.h1996
-rw-r--r--3rdparty/rapidjson/include/rapidjson/stream.h54
-rw-r--r--3rdparty/rapidjson/include/rapidjson/stringbuffer.h6
-rw-r--r--3rdparty/rapidjson/include/rapidjson/uri.h481
-rw-r--r--3rdparty/rapidjson/include/rapidjson/writer.h166
-rw-r--r--3rdparty/rapidjson/library.json27
-rw-r--r--3rdparty/rapidjson/package.json6
-rw-r--r--3rdparty/rapidjson/rapidjson.autopkg10
-rw-r--r--3rdparty/rapidjson/readme.md114
-rw-r--r--3rdparty/rapidjson/readme.zh-cn.md62
-rw-r--r--3rdparty/rapidjson/test/perftest/CMakeLists.txt2
-rw-r--r--3rdparty/rapidjson/test/perftest/misctest.cpp6
-rw-r--r--3rdparty/rapidjson/test/perftest/perftest.cpp2
-rw-r--r--3rdparty/rapidjson/test/perftest/perftest.h14
-rw-r--r--3rdparty/rapidjson/test/perftest/platformtest.cpp4
-rw-r--r--3rdparty/rapidjson/test/perftest/rapidjsontest.cpp129
-rw-r--r--3rdparty/rapidjson/test/perftest/schematest.cpp7
-rw-r--r--3rdparty/rapidjson/test/unittest/CMakeLists.txt13
-rw-r--r--3rdparty/rapidjson/test/unittest/allocatorstest.cpp222
-rw-r--r--3rdparty/rapidjson/test/unittest/bigintegertest.cpp7
-rw-r--r--3rdparty/rapidjson/test/unittest/clzlltest.cpp34
-rw-r--r--3rdparty/rapidjson/test/unittest/cursorstreamwrappertest.cpp115
-rw-r--r--3rdparty/rapidjson/test/unittest/documenttest.cpp28
-rw-r--r--3rdparty/rapidjson/test/unittest/dtoatest.cpp3
-rw-r--r--3rdparty/rapidjson/test/unittest/encodedstreamtest.cpp4
-rw-r--r--3rdparty/rapidjson/test/unittest/encodingstest.cpp4
-rw-r--r--3rdparty/rapidjson/test/unittest/filestreamtest.cpp47
-rw-r--r--3rdparty/rapidjson/test/unittest/fwdtest.cpp27
-rw-r--r--3rdparty/rapidjson/test/unittest/istreamwrappertest.cpp24
-rw-r--r--3rdparty/rapidjson/test/unittest/itoatest.cpp24
-rw-r--r--3rdparty/rapidjson/test/unittest/jsoncheckertest.cpp56
-rw-r--r--3rdparty/rapidjson/test/unittest/namespacetest.cpp2
-rw-r--r--3rdparty/rapidjson/test/unittest/ostreamwrappertest.cpp7
-rw-r--r--3rdparty/rapidjson/test/unittest/platformtest.cpp40
-rw-r--r--3rdparty/rapidjson/test/unittest/pointertest.cpp256
-rw-r--r--3rdparty/rapidjson/test/unittest/prettywritertest.cpp172
-rw-r--r--3rdparty/rapidjson/test/unittest/readertest.cpp704
-rw-r--r--3rdparty/rapidjson/test/unittest/regextest.cpp625
-rw-r--r--3rdparty/rapidjson/test/unittest/schematest.cpp2582
-rw-r--r--3rdparty/rapidjson/test/unittest/simdtest.cpp20
-rw-r--r--3rdparty/rapidjson/test/unittest/strfunctest.cpp2
-rw-r--r--3rdparty/rapidjson/test/unittest/stringbuffertest.cpp30
-rw-r--r--3rdparty/rapidjson/test/unittest/strtodtest.cpp4
-rw-r--r--3rdparty/rapidjson/test/unittest/unittest.cpp2
-rw-r--r--3rdparty/rapidjson/test/unittest/unittest.h14
-rw-r--r--3rdparty/rapidjson/test/unittest/uritest.cpp725
-rw-r--r--3rdparty/rapidjson/test/unittest/valuetest.cpp139
-rw-r--r--3rdparty/rapidjson/test/unittest/writertest.cpp105
-rw-r--r--3rdparty/rapidjson/test/valgrind.supp26
-rwxr-xr-x[-rw-r--r--]3rdparty/rapidjson/travis-doxygen.sh24
132 files changed, 13451 insertions, 2313 deletions
diff --git a/3rdparty/rapidjson/.gitignore b/3rdparty/rapidjson/.gitignore
index e7e8fba9bb3..5932e82c21c 100644
--- a/3rdparty/rapidjson/.gitignore
+++ b/3rdparty/rapidjson/.gitignore
@@ -3,6 +3,7 @@
!/bin/encodings
!/bin/jsonchecker
!/bin/types
+!/bin/unittestschema
/build
/doc/html
/doc/doxygen_*.db
@@ -23,3 +24,6 @@ Doxyfile
Doxyfile.zh-cn
DartConfiguration.tcl
*.nupkg
+
+# Files created by OS
+*.DS_Store
diff --git a/3rdparty/rapidjson/.travis.yml b/3rdparty/rapidjson/.travis.yml
index f9319f2edb9..17d8f03d630 100644
--- a/3rdparty/rapidjson/.travis.yml
+++ b/3rdparty/rapidjson/.travis.yml
@@ -1,10 +1,18 @@
sudo: required
-dist: precise
+dist: xenial
language: cpp
cache:
- ccache
+addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - cmake
+ - valgrind
+ - clang-8
env:
global:
- USE_CCACHE=1
@@ -13,49 +21,96 @@ env:
- CCACHE_MAXSIZE=100M
- ARCH_FLAGS_x86='-m32' # #266: don't use SSE on 32-bit
- ARCH_FLAGS_x86_64='-msse4.2' # use SSE4.2 on 64-bit
- - GITHUB_REPO='miloyip/rapidjson'
+ - ARCH_FLAGS_aarch64='-march=armv8-a'
+ - GITHUB_REPO='Tencent/rapidjson'
- secure: "HrsaCb+N66EG1HR+LWH1u51SjaJyRwJEDzqJGYMB7LJ/bfqb9mWKF1fLvZGk46W5t7TVaXRDD5KHFx9DPWvKn4gRUVkwTHEy262ah5ORh8M6n/6VVVajeV/AYt2C0sswdkDBDO4Xq+xy5gdw3G8s1A4Inbm73pUh+6vx+7ltBbk="
-before_install:
- - sudo apt-add-repository -y ppa:ubuntu-toolchain-r/test
- - sudo apt-get update -qq
- - sudo apt-get install -y cmake valgrind g++-multilib libc6-dbg:i386
-
matrix:
include:
# gcc
- - env: CONF=release ARCH=x86 CXX11=ON
+ - env: CONF=release ARCH=x86 CXX11=ON CXX17=OFF MEMBERSMAP=OFF
+ compiler: gcc
+ arch: amd64
+ - env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF MEMBERSMAP=OFF
+ compiler: gcc
+ arch: amd64
+ - env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF MEMBERSMAP=ON
+ compiler: gcc
+ arch: amd64
+ - env: CONF=debug ARCH=x86 CXX11=OFF CXX17=OFF MEMBERSMAP=OFF
+ compiler: gcc
+ arch: amd64
+ - env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=OFF MEMBERSMAP=OFF
compiler: gcc
- - env: CONF=release ARCH=x86_64 CXX11=ON
+ arch: amd64
+ - env: CONF=debug ARCH=x86 CXX11=OFF CXX17=ON MEMBERSMAP=ON CXX_FLAGS='-D_GLIBCXX_DEBUG'
compiler: gcc
- - env: CONF=debug ARCH=x86 CXX11=OFF
+ arch: amd64
+ - env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=ON MEMBERSMAP=ON CXX_FLAGS='-D_GLIBCXX_DEBUG'
compiler: gcc
- - env: CONF=debug ARCH=x86_64 CXX11=OFF
+ arch: amd64
+ - env: CONF=release ARCH=aarch64 CXX11=ON CXX17=OFF MEMBERSMAP=OFF
compiler: gcc
+ arch: arm64
+ - env: CONF=release ARCH=aarch64 CXX11=OFF CXX17=OFF MEMBERSMAP=OFF
+ compiler: gcc
+ arch: arm64
+ - env: CONF=release ARCH=aarch64 CXX11=OFF CXX17=ON MEMBERSMAP=ON
+ compiler: gcc
+ arch: arm64
# clang
- - env: CONF=debug ARCH=x86 CXX11=ON CCACHE_CPP2=yes
+ - env: CONF=release ARCH=x86 CXX11=ON CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
+ compiler: clang
+ arch: amd64
+ - env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
+ compiler: clang
+ arch: amd64
+ - env: CONF=release ARCH=x86_64 CXX11=ON CXX17=OFF MEMBERSMAP=OFF CCACHE_CPP2=yes
+ compiler: clang
+ arch: amd64
+ - env: CONF=debug ARCH=x86 CXX11=OFF CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
compiler: clang
- - env: CONF=debug ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
+ arch: amd64
+ - env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
compiler: clang
- - env: CONF=debug ARCH=x86 CXX11=OFF CCACHE_CPP2=yes
+ arch: amd64
+ - env: CONF=debug ARCH=x86 CXX11=OFF CXX17=ON MEMBERSMAP=OFF CCACHE_CPP2=yes
compiler: clang
- - env: CONF=debug ARCH=x86_64 CXX11=OFF CCACHE_CPP2=yes
+ arch: amd64
+ - env: CONF=debug ARCH=x86_64 CXX11=OFF CXX17=ON MEMBERSMAP=OFF CCACHE_CPP2=yes
compiler: clang
- - env: CONF=release ARCH=x86 CXX11=ON CCACHE_CPP2=yes
+ arch: amd64
+ - env: CONF=debug ARCH=aarch64 CXX11=ON CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
compiler: clang
- - env: CONF=release ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
+ arch: arm64
+ - env: CONF=debug ARCH=aarch64 CXX11=OFF CXX17=OFF MEMBERSMAP=ON CCACHE_CPP2=yes
compiler: clang
+ arch: arm64
+ - env: CONF=debug ARCH=aarch64 CXX11=OFF CXX17=ON MEMBERSMAP=OFF CCACHE_CPP2=yes
+ compiler: clang
+ arch: arm64
# coverage report
- - env: CONF=debug ARCH=x86 CXX11=ON GCOV_FLAGS='--coverage'
+ - env: CONF=debug ARCH=x86 GCOV_FLAGS='--coverage' CXX_FLAGS='-O0' CXX11=OFF CXX17=OFF
+ compiler: gcc
+ arch: amd64
+ cache:
+ - ccache
+ - pip
+ after_success:
+ - pip install --user cpp-coveralls
+ - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h
+ - env: CONF=debug ARCH=x86_64 GCOV_FLAGS='--coverage' CXX_FLAGS='-O0' CXX11=ON CXX17=OFF MEMBERSMAP=ON
compiler: gcc
+ arch: amd64
cache:
- ccache
- pip
after_success:
- pip install --user cpp-coveralls
- coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h
- - env: CONF=debug ARCH=x86_64 GCOV_FLAGS='--coverage'
+ - env: CONF=debug ARCH=aarch64 GCOV_FLAGS='--coverage' CXX_FLAGS='-O0' CXX11=OFF CXX17=ON
compiler: gcc
+ arch: arm64
cache:
- ccache
- pip
@@ -72,13 +127,24 @@ matrix:
packages:
- doxygen
+before_install:
+ - if [ "x86_64" = "$(arch)" ]; then sudo apt-get install -y g++-multilib libc6-dbg:i386 --allow-unauthenticated; fi
+
before_script:
- - ccache -s
- # hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469),
- # exposed by merging PR#163 (using -march=native)
- # TODO: Since this bug is already fixed. Remove this when valgrind can be upgraded.
- - sed -i "s/-march=native//" CMakeLists.txt
- - mkdir build
+ # travis provides clang-7 for amd64 and clang-3.8 for arm64
+ # here use clang-8 to all architectures as clang-7 is not available for arm64
+ - if [ -f /usr/bin/clang++-8 ]; then
+ sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-8 1000;
+ sudo update-alternatives --config clang++;
+ export PATH=/usr/bin:$PATH;
+ fi
+ - if [ "$CXX" = "clang++" ]; then export CCACHE_CPP2=yes; fi
+ - ccache -s
+ # hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469),
+ # exposed by merging PR#163 (using -march=native)
+ # TODO: Since this bug is already fixed. Remove this when valgrind can be upgraded.
+ - sed -i "s/-march=native//" CMakeLists.txt
+ - mkdir build
script:
- if [ "$CXX" = "clang++" ]; then export CXXFLAGS="-stdlib=libc++ ${CXXFLAGS}"; fi
@@ -86,10 +152,12 @@ script:
eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ;
(cd build && cmake
-DRAPIDJSON_HAS_STDSTRING=ON
+ -DRAPIDJSON_USE_MEMBERSMAP=$MEMBERSMAP
-DRAPIDJSON_BUILD_CXX11=$CXX11
+ -DRAPIDJSON_BUILD_CXX17=$CXX17
-DCMAKE_VERBOSE_MAKEFILE=ON
-DCMAKE_BUILD_TYPE=$CONF
- -DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS"
+ -DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS $CXX_FLAGS"
-DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS
..)
- cd build
diff --git a/3rdparty/rapidjson/CHANGELOG.md b/3rdparty/rapidjson/CHANGELOG.md
index 0205e7b89fb..1c580bd1400 100644
--- a/3rdparty/rapidjson/CHANGELOG.md
+++ b/3rdparty/rapidjson/CHANGELOG.md
@@ -109,7 +109,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [1.0.0] - 2015-04-22
### Added
-* 100% [Coverall](https://coveralls.io/r/miloyip/rapidjson?branch=master) coverage.
+* 100% [Coverall](https://coveralls.io/r/Tencent/rapidjson?branch=master) coverage.
* Version macros (#311)
### Fixed
@@ -140,7 +140,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
* Redo all documentation (English, Simplified Chinese)
### Changed
-* Copyright ownership transfered to THL A29 Limited (a Tencent company).
+* Copyright ownership transferred to THL A29 Limited (a Tencent company).
* Migrating from Premake to CMAKE (#192)
* Resolve all warning reports
@@ -151,8 +151,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## 0.1 - 2011-11-18
-[Unreleased]: https://github.com/miloyip/rapidjson/compare/v1.1.0...HEAD
-[1.1.0]: https://github.com/miloyip/rapidjson/compare/v1.0.2...v1.1.0
-[1.0.2]: https://github.com/miloyip/rapidjson/compare/v1.0.1...v1.0.2
-[1.0.1]: https://github.com/miloyip/rapidjson/compare/v1.0.0...v1.0.1
-[1.0.0]: https://github.com/miloyip/rapidjson/compare/v1.0-beta...v1.0.0
+[Unreleased]: https://github.com/Tencent/rapidjson/compare/v1.1.0...HEAD
+[1.1.0]: https://github.com/Tencent/rapidjson/compare/v1.0.2...v1.1.0
+[1.0.2]: https://github.com/Tencent/rapidjson/compare/v1.0.1...v1.0.2
+[1.0.1]: https://github.com/Tencent/rapidjson/compare/v1.0.0...v1.0.1
+[1.0.0]: https://github.com/Tencent/rapidjson/compare/v1.0-beta...v1.0.0
diff --git a/3rdparty/rapidjson/CMakeLists.txt b/3rdparty/rapidjson/CMakeLists.txt
index ceda71b1b67..f8927b4900d 100644
--- a/3rdparty/rapidjson/CMakeLists.txt
+++ b/3rdparty/rapidjson/CMakeLists.txt
@@ -1,4 +1,4 @@
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12)
if(POLICY CMP0025)
# detect Apple's Clang
cmake_policy(SET CMP0025 NEW)
@@ -9,13 +9,18 @@ endif()
SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules)
-PROJECT(RapidJSON CXX)
-
set(LIB_MAJOR_VERSION "1")
set(LIB_MINOR_VERSION "1")
set(LIB_PATCH_VERSION "0")
set(LIB_VERSION_STRING "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_PATCH_VERSION}")
+if (CMAKE_VERSION VERSION_LESS 3.0)
+ PROJECT(RapidJSON CXX)
+else()
+ cmake_policy(SET CMP0048 NEW)
+ PROJECT(RapidJSON VERSION "${LIB_VERSION_STRING}" LANGUAGES CXX)
+endif()
+
# compile in release with debug info mode by default
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
@@ -30,16 +35,28 @@ option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." ON)
option(RAPIDJSON_BUILD_THIRDPARTY_GTEST
"Use gtest installation in `thirdparty/gtest` by default if available" OFF)
-option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11 (gcc/clang)" ON)
+option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11" ON)
+option(RAPIDJSON_BUILD_CXX17 "Build rapidjson with C++17" OFF)
+if(RAPIDJSON_BUILD_CXX11)
+ set(CMAKE_CXX_STANDARD 11)
+ set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
+endif()
option(RAPIDJSON_BUILD_ASAN "Build rapidjson with address sanitizer (gcc/clang)" OFF)
option(RAPIDJSON_BUILD_UBSAN "Build rapidjson with undefined behavior sanitizer (gcc/clang)" OFF)
+option(RAPIDJSON_ENABLE_INSTRUMENTATION_OPT "Build rapidjson with -march or -mcpu options" ON)
+
option(RAPIDJSON_HAS_STDSTRING "" OFF)
if(RAPIDJSON_HAS_STDSTRING)
add_definitions(-DRAPIDJSON_HAS_STDSTRING)
endif()
+option(RAPIDJSON_USE_MEMBERSMAP "" OFF)
+if(RAPIDJSON_USE_MEMBERSMAP)
+ add_definitions(-DRAPIDJSON_USE_MEMBERSMAP=1)
+endif()
+
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
@@ -49,14 +66,25 @@ if(CCACHE_FOUND)
endif()
endif(CCACHE_FOUND)
-if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror")
- if (RAPIDJSON_BUILD_CXX11)
+if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ if(RAPIDJSON_ENABLE_INSTRUMENTATION_OPT AND NOT CMAKE_CROSSCOMPILING)
+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "powerpc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
+ else()
+ #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER.
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
+ endif()
+ endif()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror")
+ set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wsign-conversion)
+ if (RAPIDJSON_BUILD_CXX11 AND CMAKE_VERSION VERSION_LESS 3.1)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7.0")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
+ elseif (RAPIDJSON_BUILD_CXX17 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
endif()
if (RAPIDJSON_BUILD_ASAN)
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8.0")
@@ -73,9 +101,20 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
endif()
endif()
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror -Wno-missing-field-initializers")
- if (RAPIDJSON_BUILD_CXX11)
+ if(NOT CMAKE_CROSSCOMPILING)
+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "powerpc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native")
+ else()
+ #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER.
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
+ endif()
+ endif()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror -Wno-missing-field-initializers")
+ set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wimplicit-fallthrough)
+ if (RAPIDJSON_BUILD_CXX11 AND CMAKE_VERSION VERSION_LESS 3.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ elseif (RAPIDJSON_BUILD_CXX17 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.0")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
endif()
if (RAPIDJSON_BUILD_ASAN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
@@ -87,9 +126,24 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
endif()
endif()
-elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
+ add_definitions(-DNOMINMAX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
+ # CMake >= 3.10 should handle the above CMAKE_CXX_STANDARD fine, otherwise use /std:c++XX with MSVC >= 19.10
+ if (RAPIDJSON_BUILD_CXX11 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.10")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++11")
+ elseif (RAPIDJSON_BUILD_CXX17 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.14")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17")
+ endif()
+ # Always compile with /WX
+ if(CMAKE_CXX_FLAGS MATCHES "/WX-")
+ string(REGEX REPLACE "/WX-" "/WX" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX")
+ endif()
+elseif (CMAKE_CXX_COMPILER_ID MATCHES "XL")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -qarch=auto")
endif()
#add extra search paths for libraries and includes
@@ -102,7 +156,7 @@ IF(UNIX OR CYGWIN)
ELSEIF(WIN32)
SET(_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/cmake")
ENDIF()
-SET(CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" CACHE PATH "The directory cmake fiels are installed in")
+SET(CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" CACHE PATH "The directory cmake files are installed in")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
@@ -157,17 +211,41 @@ install(DIRECTORY example/
# Provide config and version files to be used by other applications
# ===============================
-export(PACKAGE ${PROJECT_NAME})
-
-# cmake-modules
-CONFIGURE_FILE(${PROJECT_NAME}Config.cmake.in
- ${PROJECT_NAME}Config.cmake
- @ONLY)
-CONFIGURE_FILE(${PROJECT_NAME}ConfigVersion.cmake.in
- ${PROJECT_NAME}ConfigVersion.cmake
- @ONLY)
-INSTALL(FILES
- ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
- ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
- DESTINATION "${CMAKE_INSTALL_DIR}"
- COMPONENT dev)
+################################################################################
+# Export package for use from the build tree
+EXPORT( PACKAGE ${PROJECT_NAME} )
+
+# Create the RapidJSONConfig.cmake file for other cmake projects.
+# ... for the build tree
+SET( CONFIG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+SET( CONFIG_DIR ${CMAKE_CURRENT_BINARY_DIR})
+SET( ${PROJECT_NAME}_INCLUDE_DIR "\${${PROJECT_NAME}_SOURCE_DIR}/include" )
+
+CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY )
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake @ONLY)
+
+# ... for the install tree
+SET( CMAKECONFIG_INSTALL_DIR ${LIB_INSTALL_DIR}/cmake/${PROJECT_NAME} )
+FILE( RELATIVE_PATH REL_INCLUDE_DIR
+ "${CMAKECONFIG_INSTALL_DIR}"
+ "${CMAKE_INSTALL_PREFIX}/include" )
+
+SET( ${PROJECT_NAME}_INCLUDE_DIR "\${${PROJECT_NAME}_CMAKE_DIR}/${REL_INCLUDE_DIR}" )
+SET( CONFIG_SOURCE_DIR )
+SET( CONFIG_DIR )
+CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in
+ ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake @ONLY )
+
+INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake"
+ DESTINATION ${CMAKECONFIG_INSTALL_DIR} )
+
+# Install files
+IF(CMAKE_INSTALL_DIR)
+ INSTALL(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
+ DESTINATION "${CMAKE_INSTALL_DIR}"
+ COMPONENT dev)
+ENDIF()
diff --git a/3rdparty/rapidjson/RapidJSON.pc.in b/3rdparty/rapidjson/RapidJSON.pc.in
index 7467f9779b8..6afb079f81a 100644
--- a/3rdparty/rapidjson/RapidJSON.pc.in
+++ b/3rdparty/rapidjson/RapidJSON.pc.in
@@ -3,5 +3,5 @@ includedir=@INCLUDE_INSTALL_DIR@
Name: @PROJECT_NAME@
Description: A fast JSON parser/generator for C++ with both SAX/DOM style API
Version: @LIB_VERSION_STRING@
-URL: https://github.com/miloyip/rapidjson
+URL: https://github.com/Tencent/rapidjson
Cflags: -I${includedir}
diff --git a/3rdparty/rapidjson/RapidJSONConfig.cmake.in b/3rdparty/rapidjson/RapidJSONConfig.cmake.in
index 9fa12186ab6..c25d3125852 100644
--- a/3rdparty/rapidjson/RapidJSONConfig.cmake.in
+++ b/3rdparty/rapidjson/RapidJSONConfig.cmake.in
@@ -1,3 +1,25 @@
-get_filename_component(RAPIDJSON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
-set(RAPIDJSON_INCLUDE_DIRS "@INCLUDE_INSTALL_DIR@")
-message(STATUS "RapidJSON found. Headers: ${RAPIDJSON_INCLUDE_DIRS}")
+################################################################################
+# CMake minimum version required
+cmake_minimum_required(VERSION 3.0)
+
+################################################################################
+# RapidJSON source dir
+set( RapidJSON_SOURCE_DIR "@CONFIG_SOURCE_DIR@")
+
+################################################################################
+# RapidJSON build dir
+set( RapidJSON_DIR "@CONFIG_DIR@")
+
+################################################################################
+# Compute paths
+get_filename_component(RapidJSON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+set( RapidJSON_INCLUDE_DIR "@RapidJSON_INCLUDE_DIR@" )
+set( RapidJSON_INCLUDE_DIRS "@RapidJSON_INCLUDE_DIR@" )
+message(STATUS "RapidJSON found. Headers: ${RapidJSON_INCLUDE_DIRS}")
+
+if(NOT TARGET rapidjson)
+ add_library(rapidjson INTERFACE IMPORTED)
+ set_property(TARGET rapidjson PROPERTY
+ INTERFACE_INCLUDE_DIRECTORIES ${RapidJSON_INCLUDE_DIRS})
+endif()
diff --git a/3rdparty/rapidjson/appveyor.yml b/3rdparty/rapidjson/appveyor.yml
index dfedf9c297b..4044ba66409 100644
--- a/3rdparty/rapidjson/appveyor.yml
+++ b/3rdparty/rapidjson/appveyor.yml
@@ -1,4 +1,3 @@
-os: Visual Studio 2015 CTP
version: 1.1.0.{build}
configuration:
@@ -11,26 +10,88 @@ environment:
# VS_PLATFORM: win32
# - VS_VERSION: 9 2008
# VS_PLATFORM: x64
- - VS_VERSION: 10 2010
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
+ VS_VERSION: 10 2010
VS_PLATFORM: win32
- - VS_VERSION: 10 2010
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: OFF
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
+ VS_VERSION: 10 2010
VS_PLATFORM: x64
- - VS_VERSION: 11 2012
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: ON
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
+ VS_VERSION: 11 2012
VS_PLATFORM: win32
- - VS_VERSION: 11 2012
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: ON
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
+ VS_VERSION: 11 2012
VS_PLATFORM: x64
- - VS_VERSION: 12 2013
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: OFF
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
+ VS_VERSION: 12 2013
VS_PLATFORM: win32
- - VS_VERSION: 12 2013
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: OFF
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
+ VS_VERSION: 12 2013
VS_PLATFORM: x64
- - VS_VERSION: 14 2015
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: ON
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ VS_VERSION: 14 2015
VS_PLATFORM: win32
- - VS_VERSION: 14 2015
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: ON
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ VS_VERSION: 14 2015
VS_PLATFORM: x64
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: OFF
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ VS_VERSION: 15 2017
+ VS_PLATFORM: win32
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: OFF
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ VS_VERSION: 15 2017
+ VS_PLATFORM: x64
+ CXX11: OFF
+ CXX17: OFF
+ MEMBERSMAP: ON
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ VS_VERSION: 15 2017
+ VS_PLATFORM: x64
+ CXX11: ON
+ CXX17: OFF
+ MEMBERSMAP: OFF
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+ VS_VERSION: 15 2017
+ VS_PLATFORM: x64
+ CXX11: OFF
+ CXX17: ON
+ MEMBERSMAP: OFF
+ - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+ VS_VERSION: 16 2019
+ VS_PLATFORM: x64
+ CXX11: OFF
+ CXX17: ON
+ MEMBERSMAP: ON
before_build:
- git submodule update --init --recursive
-- cmake -H. -BBuild/VS -G "Visual Studio %VS_VERSION%" -DCMAKE_GENERATOR_PLATFORM=%VS_PLATFORM% -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=true -Wno-dev
+- cmake -H. -BBuild/VS -G "Visual Studio %VS_VERSION%" -DCMAKE_GENERATOR_PLATFORM=%VS_PLATFORM% -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=true -DRAPIDJSON_BUILD_CXX11=%CXX11% -DRAPIDJSON_BUILD_CXX17=%CXX17% -DRAPIDJSON_USE_MEMBERSMAP=%MEMBERSMAP% -Wno-dev
build:
project: Build\VS\RapidJSON.sln
diff --git a/3rdparty/rapidjson/contrib/natvis/LICENSE b/3rdparty/rapidjson/contrib/natvis/LICENSE
new file mode 100644
index 00000000000..f57da96cf90
--- /dev/null
+++ b/3rdparty/rapidjson/contrib/natvis/LICENSE
@@ -0,0 +1,45 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Bart Muzzin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+Derived from:
+
+The MIT License (MIT)
+
+Copyright (c) 2015 mojmir svoboda
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/3rdparty/rapidjson/contrib/natvis/README.md b/3rdparty/rapidjson/contrib/natvis/README.md
new file mode 100644
index 00000000000..9685c7f7c1c
--- /dev/null
+++ b/3rdparty/rapidjson/contrib/natvis/README.md
@@ -0,0 +1,7 @@
+# rapidjson.natvis
+
+This file can be used as a [Visual Studio Visualizer](https://docs.microsoft.com/en-gb/visualstudio/debugger/create-custom-views-of-native-objects) to aid in visualizing rapidjson structures within the Visual Studio debugger. Natvis visualizers are supported in Visual Studio 2012 and later. To install, copy the file into this directory:
+
+`%USERPROFILE%\Documents\Visual Studio 2012\Visualizers`
+
+Each version of Visual Studio has a similar directory, it must be copied into each directory to be used with that particular version. In Visual Studio 2015 and later, this can be done without restarting Visual Studio (a new debugging session must be started).
diff --git a/3rdparty/rapidjson/contrib/natvis/rapidjson.natvis b/3rdparty/rapidjson/contrib/natvis/rapidjson.natvis
new file mode 100644
index 00000000000..2a4316ee98c
--- /dev/null
+++ b/3rdparty/rapidjson/contrib/natvis/rapidjson.natvis
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
+ <!-- rapidjson::GenericValue - basic support -->
+ <Type Name="rapidjson::GenericValue&lt;*,*&gt;">
+ <DisplayString Condition="(data_.f.flags &amp; kTypeMask) == rapidjson::kNullType">null</DisplayString>
+ <DisplayString Condition="data_.f.flags == kTrueFlag">true</DisplayString>
+ <DisplayString Condition="data_.f.flags == kFalseFlag">false</DisplayString>
+ <DisplayString Condition="data_.f.flags == kShortStringFlag">{(const Ch*)data_.ss.str,na}</DisplayString>
+ <DisplayString Condition="(data_.f.flags &amp; kTypeMask) == rapidjson::kStringType">{(const Ch*)((size_t)data_.s.str &amp; 0x0000FFFFFFFFFFFF),[data_.s.length]na}</DisplayString>
+ <DisplayString Condition="(data_.f.flags &amp; kNumberIntFlag) == kNumberIntFlag">{data_.n.i.i}</DisplayString>
+ <DisplayString Condition="(data_.f.flags &amp; kNumberUintFlag) == kNumberUintFlag">{data_.n.u.u}</DisplayString>
+ <DisplayString Condition="(data_.f.flags &amp; kNumberInt64Flag) == kNumberInt64Flag">{data_.n.i64}</DisplayString>
+ <DisplayString Condition="(data_.f.flags &amp; kNumberUint64Flag) == kNumberUint64Flag">{data_.n.u64}</DisplayString>
+ <DisplayString Condition="(data_.f.flags &amp; kNumberDoubleFlag) == kNumberDoubleFlag">{data_.n.d}</DisplayString>
+ <DisplayString Condition="data_.f.flags == rapidjson::kObjectType">Object members={data_.o.size}</DisplayString>
+ <DisplayString Condition="data_.f.flags == rapidjson::kArrayType">Array members={data_.a.size}</DisplayString>
+ <Expand>
+ <Item Condition="data_.f.flags == rapidjson::kObjectType" Name="[size]">data_.o.size</Item>
+ <Item Condition="data_.f.flags == rapidjson::kObjectType" Name="[capacity]">data_.o.capacity</Item>
+ <ArrayItems Condition="data_.f.flags == rapidjson::kObjectType">
+ <Size>data_.o.size</Size>
+ <!-- NOTE: Rapidjson stores some extra data in the high bits of pointers, which is why the mask -->
+ <ValuePointer>(rapidjson::GenericMember&lt;$T1,$T2&gt;*)(((size_t)data_.o.members) &amp; 0x0000FFFFFFFFFFFF)</ValuePointer>
+ </ArrayItems>
+
+ <Item Condition="data_.f.flags == rapidjson::kArrayType" Name="[size]">data_.a.size</Item>
+ <Item Condition="data_.f.flags == rapidjson::kArrayType" Name="[capacity]">data_.a.capacity</Item>
+ <ArrayItems Condition="data_.f.flags == rapidjson::kArrayType">
+ <Size>data_.a.size</Size>
+ <!-- NOTE: Rapidjson stores some extra data in the high bits of pointers, which is why the mask -->
+ <ValuePointer>(rapidjson::GenericValue&lt;$T1,$T2&gt;*)(((size_t)data_.a.elements) &amp; 0x0000FFFFFFFFFFFF)</ValuePointer>
+ </ArrayItems>
+
+ </Expand>
+ </Type>
+
+</AutoVisualizer>
+
diff --git a/3rdparty/rapidjson/doc/CMakeLists.txt b/3rdparty/rapidjson/doc/CMakeLists.txt
index c1f165a37ad..c5345ba6976 100644
--- a/3rdparty/rapidjson/doc/CMakeLists.txt
+++ b/3rdparty/rapidjson/doc/CMakeLists.txt
@@ -10,11 +10,13 @@ ELSE()
CONFIGURE_FILE(Doxyfile.in Doxyfile @ONLY)
CONFIGURE_FILE(Doxyfile.zh-cn.in Doxyfile.zh-cn @ONLY)
+ file(GLOB DOXYFILES ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile*)
+
add_custom_command(OUTPUT html
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.zh-cn
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/html
- DEPENDS ${MARKDOWN_DOC} ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile*
+ DEPENDS ${MARKDOWN_DOC} ${SOURCES} ${DOXYFILES}
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../
)
diff --git a/3rdparty/rapidjson/doc/Doxyfile.in b/3rdparty/rapidjson/doc/Doxyfile.in
index ca14233960a..6e79f9371d6 100644
--- a/3rdparty/rapidjson/doc/Doxyfile.in
+++ b/3rdparty/rapidjson/doc/Doxyfile.in
@@ -1126,7 +1126,7 @@ HTML_STYLESHEET =
# defined cascading style sheet that is included after the standard style sheets
# created by doxygen. Using this option one can overrule certain style aspects.
# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefor more robust against future updates.
+# standard style sheet and is therefore more robust against future updates.
# Doxygen will copy the style sheet file to the output directory. For an example
# see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
diff --git a/3rdparty/rapidjson/doc/Doxyfile.zh-cn.in b/3rdparty/rapidjson/doc/Doxyfile.zh-cn.in
index 87dd8661b9b..6a08f72d66b 100644
--- a/3rdparty/rapidjson/doc/Doxyfile.zh-cn.in
+++ b/3rdparty/rapidjson/doc/Doxyfile.zh-cn.in
@@ -777,7 +777,7 @@ INPUT = readme.zh-cn.md \
doc/sax.zh-cn.md \
doc/schema.zh-cn.md \
doc/performance.zh-cn.md \
- doc/internals.md \
+ doc/internals.zh-cn.md \
doc/faq.zh-cn.md
# This tag can be used to specify the character encoding of the source files
@@ -1126,7 +1126,7 @@ HTML_STYLESHEET =
# defined cascading style sheet that is included after the standard style sheets
# created by doxygen. Using this option one can overrule certain style aspects.
# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefor more robust against future updates.
+# standard style sheet and is therefore more robust against future updates.
# Doxygen will copy the style sheet file to the output directory. For an example
# see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
diff --git a/3rdparty/rapidjson/doc/diagram/move2.dot b/3rdparty/rapidjson/doc/diagram/move2.dot
index 7037ea6cbb2..2319871b9ec 100644
--- a/3rdparty/rapidjson/doc/diagram/move2.dot
+++ b/3rdparty/rapidjson/doc/diagram/move2.dot
@@ -18,7 +18,7 @@ digraph {
node [shape=Mrecord, style=filled, colorscheme=spectral7]
- c1 [label="{contact:array|}", fillcolor=4]
+ c1 [label="{contacts:array|}", fillcolor=4]
c11 [label="{|}"]
c12 [label="{|}"]
c13 [shape="none", label="...", style="solid"]
@@ -41,13 +41,13 @@ digraph {
node [shape=Mrecord, style=filled, colorscheme=spectral7]
- c2 [label="{contact:array|}", fillcolor=4]
+ c2 [label="{contacts:array|}", fillcolor=4]
c3 [label="{array|}", fillcolor=4]
c21 [label="{|}"]
c22 [label="{|}"]
c23 [shape=none, label="...", style="solid"]
o2 [label="{o:object|}", fillcolor=3]
- cs [label="{string|\"contact\"}", fillcolor=5]
+ cs [label="{string|\"contacts\"}", fillcolor=5]
c31 [label="{|}"]
c32 [label="{|}"]
c33 [shape="none", label="...", style="solid"]
@@ -59,4 +59,4 @@ digraph {
c3 -> { c31; c32; c33 }
}
ghost -> o2 [style=invis]
-} \ No newline at end of file
+}
diff --git a/3rdparty/rapidjson/doc/diagram/move3.dot b/3rdparty/rapidjson/doc/diagram/move3.dot
index c197b99df59..57adb4f9d7d 100644
--- a/3rdparty/rapidjson/doc/diagram/move3.dot
+++ b/3rdparty/rapidjson/doc/diagram/move3.dot
@@ -19,7 +19,7 @@ digraph {
node [shape=Mrecord, style=filled, colorscheme=spectral7]
- c1 [label="{contact:array|}", fillcolor=4]
+ c1 [label="{contacts:array|}", fillcolor=4]
c11 [label="{|}"]
c12 [label="{|}"]
c13 [shape=none, label="...", style="solid"]
@@ -42,13 +42,13 @@ digraph {
node [shape=Mrecord, style=filled, colorscheme=spectral7]
- c2 [label="{contact:null|}", fillcolor=1]
+ c2 [label="{contacts:null|}", fillcolor=1]
c3 [label="{array|}", fillcolor=4]
c21 [label="{|}"]
c22 [label="{|}"]
c23 [shape="none", label="...", style="solid"]
o2 [label="{o:object|}", fillcolor=3]
- cs [label="{string|\"contact\"}", fillcolor=5]
+ cs [label="{string|\"contacts\"}", fillcolor=5]
c2 -> o2 [style="dashed", constraint=false, label="AddMember", style=invis]
edge [arrowhead=vee]
@@ -57,4 +57,4 @@ digraph {
cs -> c3 [arrowhead=none]
}
ghost -> o2 [style=invis]
-} \ No newline at end of file
+}
diff --git a/3rdparty/rapidjson/doc/dom.md b/3rdparty/rapidjson/doc/dom.md
index 6c541fe93c6..6992e77d1d8 100644
--- a/3rdparty/rapidjson/doc/dom.md
+++ b/3rdparty/rapidjson/doc/dom.md
@@ -119,6 +119,7 @@ Parse flags | Meaning
`kParseNumbersAsStringsFlag` | Parse numerical type values as strings.
`kParseTrailingCommasFlag` | Allow trailing commas at the end of objects and arrays (relaxed JSON syntax).
`kParseNanAndInfFlag` | Allow parsing `NaN`, `Inf`, `Infinity`, `-Inf` and `-Infinity` as `double` values (relaxed JSON syntax).
+`kParseEscapedApostropheFlag` | Allow escaped apostrophe `\'` in strings (relaxed JSON syntax).
By using a non-type template parameter, instead of a function parameter, C++ compiler can generate code which is optimized for specified combinations, improving speed, and reducing code size (if only using a single specialization). The downside is the flags needed to be determined in compile-time.
@@ -128,7 +129,7 @@ And the `InputStream` is type of input stream.
## Parse Error {#ParseError}
-When the parse processing succeeded, the `Document` contains the parse results. When there is an error, the original DOM is *unchanged*. And the error state of parsing can be obtained by `bool HasParseError()`, `ParseErrorCode GetParseError()` and `size_t GetParseOffset()`.
+When the parse processing succeeded, the `Document` contains the parse results. When there is an error, the original DOM is *unchanged*. And the error state of parsing can be obtained by `bool HasParseError()`, `ParseErrorCode GetParseError()` and `size_t GetErrorOffset()`.
Parse Error Code | Description
--------------------------------------------|---------------------------------------------------
@@ -241,7 +242,7 @@ Some techniques about using DOM API is discussed here.
## DOM as SAX Event Publisher
-In RapidJSON, stringifying a DOM with `Writer` may be look a little bit weired.
+In RapidJSON, stringifying a DOM with `Writer` may be look a little bit weird.
~~~~~~~~~~cpp
// ...
diff --git a/3rdparty/rapidjson/doc/dom.zh-cn.md b/3rdparty/rapidjson/doc/dom.zh-cn.md
index d93f6036b63..7a555dc1c62 100644
--- a/3rdparty/rapidjson/doc/dom.zh-cn.md
+++ b/3rdparty/rapidjson/doc/dom.zh-cn.md
@@ -1,6 +1,6 @@
# DOM
-文档对象模型(Document Object Model, DOM)是一ç§ç½äºŽå†…存中的 JSON 表示方å¼ï¼Œä»¥ä¾›æŸ¥è¯¢åŠæ“作。我们己于 [教程](doc/tutorial.zh-cn.md) 中介ç»äº† DOM 的基本用法,本节将讲述一些细节åŠé«˜çº§ç”¨æ³•。
+文档对象模型(Document Object Model, DOM)是一ç§ç½äºŽå†…存中的 JSON 表示方å¼ï¼Œä»¥ä¾›æŸ¥è¯¢åŠæ“作。我们已于 [教程](doc/tutorial.zh-cn.md) 中介ç»äº† DOM 的基本用法,本节将讲述一些细节åŠé«˜çº§ç”¨æ³•。
[TOC]
@@ -119,6 +119,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str);
`kParseNumbersAsStringsFlag` | æŠŠæ•°å­—ç±»åž‹è§£æžæˆå­—符串。
`kParseTrailingCommasFlag` | 容许在对象和数组结æŸå‰å«æœ‰é€—å·ï¼ˆæ”¾å®½çš„ JSON 语法)。
`kParseNanAndInfFlag` | 容许 `NaN`ã€`Inf`ã€`Infinity`ã€`-Inf` åŠ `-Infinity` 作为 `double` 值(放宽的 JSON 语法)。
+`kParseEscapedApostropheFlag` | 容许字符串中转义å•å¼•å· `\'` (放宽的 JSON 语法)。
由于使用了éžç±»åž‹æ¨¡æ¿å‚æ•°ï¼Œè€Œä¸æ˜¯å‡½æ•°å‚数,C++ 编译器能为个别组åˆç”Ÿæˆä»£ç ï¼Œä»¥æ”¹å–„性能åŠå‡å°‘代ç å°ºå¯¸ï¼ˆå½“åªç”¨å•ç§ç‰¹åŒ–)。缺点是需è¦åœ¨ç¼–译期决定标志。
@@ -128,7 +129,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str);
## è§£æžé”™è¯¯ {#ParseError}
-当解æžè¿‡ç¨‹é¡ºåˆ©å®Œæˆï¼Œ`Document` ä¾¿ä¼šå«æœ‰è§£æžç»“果。当过程出现错误,原æ¥çš„ DOM 会 * ç»´æŒä¸ä¾¿ *。å¯ä½¿ç”¨ `bool HasParseError()`ã€`ParseErrorCode GetParseError()` åŠ `size_t GetParseOffset()` 获å–è§£æžçš„错误状æ€ã€‚
+当解æžè¿‡ç¨‹é¡ºåˆ©å®Œæˆï¼Œ`Document` ä¾¿ä¼šå«æœ‰è§£æžç»“果。当过程出现错误,原æ¥çš„ DOM 会*ç»´æŒä¸å˜*。å¯ä½¿ç”¨ `bool HasParseError()`ã€`ParseErrorCode GetParseError()` åŠ `size_t GetErrorOffset()` 获å–è§£æžçš„错误状æ€ã€‚
è§£æžé”™è¯¯ä»£å· | æè¿°
--------------------------------------------|---------------------------------------------------
diff --git a/3rdparty/rapidjson/doc/encoding.md b/3rdparty/rapidjson/doc/encoding.md
index 8f8ff7f45aa..e663aeac972 100644
--- a/3rdparty/rapidjson/doc/encoding.md
+++ b/3rdparty/rapidjson/doc/encoding.md
@@ -10,7 +10,7 @@ The earlier [RFC4627](http://www.ietf.org/rfc/rfc4627.txt) stated that,
> (in §6) JSON may be represented using UTF-8, UTF-16, or UTF-32. When JSON is written in UTF-8, JSON is 8bit compatible. When JSON is written in UTF-16 or UTF-32, the binary content-transfer-encoding must be used.
-RapidJSON supports various encodings. It can also validate the encodings of JSON, and transconding JSON among encodings. All these features are implemented internally, without the need for external libraries (e.g. [ICU](http://site.icu-project.org/)).
+RapidJSON supports various encodings. It can also validate the encodings of JSON, and transcoding JSON among encodings. All these features are implemented internally, without the need for external libraries (e.g. [ICU](http://site.icu-project.org/)).
[TOC]
diff --git a/3rdparty/rapidjson/doc/encoding.zh-cn.md b/3rdparty/rapidjson/doc/encoding.zh-cn.md
index 6816923559c..808ba525f6c 100644
--- a/3rdparty/rapidjson/doc/encoding.zh-cn.md
+++ b/3rdparty/rapidjson/doc/encoding.zh-cn.md
@@ -14,7 +14,7 @@
> (in §6) JSON may be represented using UTF-8, UTF-16, or UTF-32. When JSON is written in UTF-8, JSON is 8bit compatible. When JSON is written in UTF-16 or UTF-32, the binary content-transfer-encoding must be used.
>
-> 翻译:JSON å¯ä½¿ç”¨ UTF-8ã€UTF-16 或 UTF-18 表示。当 JSON 以 UTF-8 写入,该 JSON 是 8 ä½å…¼å®¹çš„。当 JSON 以 UTF-16 或 UTF-32 写入,就必须使用二进制的内容传é€ç¼–ç ã€‚
+> 翻译:JSON å¯ä½¿ç”¨ UTF-8ã€UTF-16 或 UTF-32 表示。当 JSON 以 UTF-8 写入,该 JSON 是 8 ä½å…¼å®¹çš„。当 JSON 以 UTF-16 或 UTF-32 写入,就必须使用二进制的内容传é€ç¼–ç ã€‚
RapidJSON 支æŒå¤šç§ç¼–ç ã€‚它也能检查 JSON 的编ç ï¼Œä»¥åŠåœ¨ä¸åŒç¼–ç ä¸­è¿›è¡Œè½¬ç ã€‚所有这些功能都是在内部实现,无需使用外部的程åºåº“(如 [ICU](http://site.icu-project.org/))。
diff --git a/3rdparty/rapidjson/doc/faq.md b/3rdparty/rapidjson/doc/faq.md
index 1b0541c27a9..55fa2af8809 100644
--- a/3rdparty/rapidjson/doc/faq.md
+++ b/3rdparty/rapidjson/doc/faq.md
@@ -18,7 +18,7 @@
4. Is RapidJSON free?
- Yes, it is free under MIT license. It can be used in commercial applications. Please check the details in [license.txt](https://github.com/miloyip/rapidjson/blob/master/license.txt).
+ Yes, it is free under MIT license. It can be used in commercial applications. Please check the details in [license.txt](https://github.com/Tencent/rapidjson/blob/master/license.txt).
5. Is RapidJSON small? What are its dependencies?
@@ -44,7 +44,7 @@
10. How RapidJSON is tested?
- RapidJSON contains a unit test suite for automatic testing. [Travis](https://travis-ci.org/miloyip/rapidjson/)(for Linux) and [AppVeyor](https://ci.appveyor.com/project/miloyip/rapidjson/)(for Windows) will compile and run the unit test suite for all modifications. The test process also uses Valgrind (in Linux) to detect memory leaks.
+ RapidJSON contains a unit test suite for automatic testing. [Travis](https://travis-ci.org/Tencent/rapidjson/)(for Linux) and [AppVeyor](https://ci.appveyor.com/project/Tencent/rapidjson/)(for Windows) will compile and run the unit test suite for all modifications. The test process also uses Valgrind (in Linux) to detect memory leaks.
11. Is RapidJSON well documented?
@@ -64,13 +64,13 @@
JSON are commonly used in web applications for transferring structured data. It is also used as a file format for data persistence.
-2. Does RapidJSON conform to the JSON standard?
+3. Does RapidJSON conform to the JSON standard?
Yes. RapidJSON is fully compliance with [RFC7159](http://www.ietf.org/rfc/rfc7159.txt) and [ECMA-404](http://www.ecma-international.org/publications/standards/Ecma-404.htm). It can handle corner cases, such as supporting null character and surrogate pairs in JSON strings.
-3. Does RapidJSON support relaxed syntax?
+4. Does RapidJSON support relaxed syntax?
- Currently no. RapidJSON only support the strict standardized format. Support on related syntax is under discussion in this [issue](https://github.com/miloyip/rapidjson/issues/36).
+ Currently no. RapidJSON only support the strict standardized format. Support on related syntax is under discussion in this [issue](https://github.com/Tencent/rapidjson/issues/36).
## DOM and SAX
@@ -116,7 +116,7 @@
~~~~~~~~~~cpp
Value(kObjectType).Swap(d);
~~~~~~~~~~
- or equivalent, but sightly longer to type:
+ or equivalent, but slightly longer to type:
~~~~~~~~~~cpp
d.Swap(Value(kObjectType).Move());
~~~~~~~~~~
@@ -140,11 +140,11 @@
}
~~~~~~~~~~
- The most important requirement to take care of document and value life-cycle as well as consistent memory managent using the right allocator during the value transfer.
+ The most important requirement to take care of document and value life-cycle as well as consistent memory management using the right allocator during the value transfer.
Simple yet most efficient way to achieve that is to modify the `address` definition above to initialize it with allocator of the `person` document, then we just add the root member of the value:
~~~~~~~~~~cpp
- Documnet address(person.GetAllocator());
+ Document address(&person.GetAllocator());
...
person["person"].AddMember("address", address["address"], person.GetAllocator());
~~~~~~~~~~
@@ -174,7 +174,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres
3. Why do I need to provide the length of string?
- Since C string is null-terminated, the length of string needs to be computed via `strlen()`, with linear runtime complexity. This incurs an unncessary overhead of many operations, if the user already knows the length of string.
+ Since C string is null-terminated, the length of string needs to be computed via `strlen()`, with linear runtime complexity. This incurs an unnecessary overhead of many operations, if the user already knows the length of string.
Also, RapidJSON can handle `\u0000` (null character) within a string. If a string contains null characters, `strlen()` cannot return the true length of it. In such case user must provide the length of string explicitly.
@@ -204,7 +204,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres
2. Can it validate the encoding?
- Yes, just pass `kParseValidateEncodingFlag` to `Parse()`. If there is invalid encoding in the stream, it wil generate `kParseErrorStringInvalidEncoding` error.
+ Yes, just pass `kParseValidateEncodingFlag` to `Parse()`. If there is invalid encoding in the stream, it will generate `kParseErrorStringInvalidEncoding` error.
3. What is surrogate pair? Does RapidJSON support it?
@@ -236,7 +236,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres
4. What is BOM? How RapidJSON handle it?
- [Byte order mark (BOM)](http://en.wikipedia.org/wiki/Byte_order_mark) sometimes reside at the beginning of file/stream to indiciate the UTF encoding type of it.
+ [Byte order mark (BOM)](http://en.wikipedia.org/wiki/Byte_order_mark) sometimes reside at the beginning of file/stream to indicate the UTF encoding type of it.
RapidJSON's `EncodedInputStream` can detect/consume BOM. `EncodedOutputStream` can optionally write a BOM. See [Encoded Streams](doc/stream.md) for example.
@@ -248,7 +248,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres
1. Is RapidJSON really fast?
- Yes. It may be the fastest open source JSON library. There is a [benchmark](https://github.com/miloyip/nativejson-benchmark) for evaluating performance of C/C++ JSON libaries.
+ Yes. It may be the fastest open source JSON library. There is a [benchmark](https://github.com/miloyip/nativejson-benchmark) for evaluating performance of C/C++ JSON libraries.
2. Why is it fast?
@@ -256,19 +256,19 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres
3. What is SIMD? How it is applied in RapidJSON?
- [SIMD](http://en.wikipedia.org/wiki/SIMD) instructions can perform parallel computation in modern CPUs. RapidJSON support Intel's SSE2/SSE4.2 to accelerate whitespace skipping. This improves performance of parsing indent formatted JSON. Define `RAPIDJSON_SSE2` or `RAPIDJSON_SSE42` macro to enable this feature. However, running the executable on a machine without such instruction set support will make it crash.
+ [SIMD](http://en.wikipedia.org/wiki/SIMD) instructions can perform parallel computation in modern CPUs. RapidJSON support Intel's SSE2/SSE4.2 and ARM's Neon to accelerate whitespace/tabspace/carriage-return/line-feed skipping. This improves performance of parsing indent formatted JSON. Define `RAPIDJSON_SSE2`, `RAPIDJSON_SSE42` or `RAPIDJSON_NEON` macro to enable this feature. However, running the executable on a machine without such instruction set support will make it crash.
4. Does it consume a lot of memory?
The design of RapidJSON aims at reducing memory footprint.
- In the SAX API, `Reader` consumes memory portional to maximum depth of JSON tree, plus maximum length of JSON string.
+ In the SAX API, `Reader` consumes memory proportional to maximum depth of JSON tree, plus maximum length of JSON string.
In the DOM API, each `Value` consumes exactly 16/24 bytes for 32/64-bit architecture respectively. RapidJSON also uses a special memory allocator to minimize overhead of allocations.
5. What is the purpose of being high performance?
- Some applications need to process very large JSON files. Some server-side applications need to process huge amount of JSONs. Being high performance can improve both latency and throuput. In a broad sense, it will also save energy.
+ Some applications need to process very large JSON files. Some server-side applications need to process huge amount of JSONs. Being high performance can improve both latency and throughput. In a broad sense, it will also save energy.
## Gossip
diff --git a/3rdparty/rapidjson/doc/faq.zh-cn.md b/3rdparty/rapidjson/doc/faq.zh-cn.md
index ed100e11219..cf1124d826e 100644
--- a/3rdparty/rapidjson/doc/faq.zh-cn.md
+++ b/3rdparty/rapidjson/doc/faq.zh-cn.md
@@ -18,7 +18,7 @@
4. RapidJSON 是å…费的么?
- 是的,它在 MIT ç‰¹è¨±æ¢æ¬¾ä¸‹å…费。它å¯ç”¨äºŽå•†ä¸šè½¯ä»¶ã€‚详情请å‚看 [license.txt](https://github.com/miloyip/rapidjson/blob/master/license.txt)。
+ 是的,它在 MIT å议下å…费。它å¯ç”¨äºŽå•†ä¸šè½¯ä»¶ã€‚详情请å‚看 [license.txt](https://github.com/Tencent/rapidjson/blob/master/license.txt)。
5. RapidJSON 很å°ä¹ˆï¼Ÿå®ƒæœ‰ä½•ä¾èµ–?
@@ -44,7 +44,7 @@
10. RapidJSON 是如何被测试的?
- RapidJSON 包å«ä¸€ç»„å•元测试去执行自动测试。[Travis](https://travis-ci.org/miloyip/rapidjson/)(供 Linux å¹³å°ï¼‰åŠ [AppVeyor](https://ci.appveyor.com/project/miloyip/rapidjson/)(供 Windows å¹³å°ï¼‰ä¼šå¯¹æ‰€æœ‰ä¿®æ”¹è¿›è¡Œç¼–è¯‘åŠæ‰§è¡Œå•元测试。在 Linux 下还会使用 Valgrind 去检测内存泄æ¼ã€‚
+ RapidJSON 包å«ä¸€ç»„å•元测试去执行自动测试。[Travis](https://travis-ci.org/Tencent/rapidjson/)(供 Linux å¹³å°ï¼‰åŠ [AppVeyor](https://ci.appveyor.com/project/Tencent/rapidjson/)(供 Windows å¹³å°ï¼‰ä¼šå¯¹æ‰€æœ‰ä¿®æ”¹è¿›è¡Œç¼–è¯‘åŠæ‰§è¡Œå•元测试。在 Linux 下还会使用 Valgrind 去检测内存泄æ¼ã€‚
11. RapidJSON æ˜¯å¦æœ‰å®Œæ•´çš„æ–‡æ¡£ï¼Ÿ
@@ -64,13 +64,13 @@
JSON 常用于网页应用程åºï¼Œä»¥ä¼ é€ç»“构化数æ®ã€‚它也å¯ä½œä¸ºæ–‡ä»¶æ ¼å¼ç”¨äºŽæ•°æ®æŒä¹…化。
-2. RapidJSON 是å¦ç¬¦åˆ JSON 标准?
+3. RapidJSON 是å¦ç¬¦åˆ JSON 标准?
是。RapidJSON å®Œå…¨ç¬¦åˆ [RFC7159](http://www.ietf.org/rfc/rfc7159.txt) åŠ [ECMA-404](http://www.ecma-international.org/publications/standards/Ecma-404.htm)。它能处ç†ä¸€äº›ç‰¹æ®Šæƒ…å†µï¼Œä¾‹å¦‚æ”¯æŒ JSON å­—ç¬¦ä¸²ä¸­å«æœ‰ç©ºå­—符åŠä»£ç†å¯¹ï¼ˆsurrogate pair)。
-3. RapidJSON æ˜¯å¦æ”¯æŒå®½æ¾çš„语法?
+4. RapidJSON æ˜¯å¦æ”¯æŒå®½æ¾çš„语法?
- çŽ°æ—¶ä¸æ”¯æŒã€‚RapidJSON åªæ”¯æŒä¸¥æ ¼çš„æ ‡å‡†æ ¼å¼ã€‚宽æ¾è¯­æ³•现时在这 [issue](https://github.com/miloyip/rapidjson/issues/36) 中进行讨论。
+ ç›®å‰ä¸æ”¯æŒã€‚RapidJSON åªæ”¯æŒä¸¥æ ¼çš„æ ‡å‡†æ ¼å¼ã€‚宽æ¾è¯­æ³•å¯ä»¥åœ¨è¿™ä¸ª [issue](https://github.com/Tencent/rapidjson/issues/36) 中进行讨论。
## DOM 与 SAX
@@ -145,7 +145,7 @@
ä¸€ä¸ªç®€å•æœ‰æ•ˆçš„æ–¹æ³•就是修改上述 `address` å˜é‡çš„定义,让其使用 `person` çš„ allocator åˆå§‹åŒ–,然åŽå°†å…¶æ·»åŠ åˆ°æ ¹èŠ‚ç‚¹ã€‚
~~~~~~~~~~cpp
- Documnet address(person.GetAllocator());
+ Documnet address(&person.GetAllocator());
...
person["person"].AddMember("address", address["address"], person.GetAllocator());
~~~~~~~~~~
@@ -163,9 +163,9 @@
## Document/Value (DOM)
-1. 什么是转移语æ„?为什么?
+1. 什么是转移语义?为什么?
- `Value` ä¸ç”¨å¤åˆ¶è¯­æ„,而使用了转移语æ„ã€‚è¿™æ˜¯æŒ‡ï¼Œå½“æŠŠæ¥æºå€¼èµ‹å€¼äºŽç›®æ ‡å€¼æ—¶ï¼Œæ¥æºå€¼çš„æ‰€æœ‰æƒä¼šè½¬ç§»è‡³ç›®æ ‡å€¼ã€‚
+ `Value` ä¸ç”¨å¤åˆ¶è¯­ä¹‰ï¼Œè€Œä½¿ç”¨äº†è½¬ç§»è¯­ä¹‰ã€‚è¿™æ˜¯æŒ‡ï¼Œå½“æŠŠæ¥æºå€¼èµ‹å€¼äºŽç›®æ ‡å€¼æ—¶ï¼Œæ¥æºå€¼çš„æ‰€æœ‰æƒä¼šè½¬ç§»è‡³ç›®æ ‡å€¼ã€‚
由于转移快于å¤åˆ¶ï¼Œæ­¤è®¾è®¡å†³å®šå¼ºè¿«ä½¿ç”¨è€…注æ„到å¤åˆ¶çš„æ¶ˆè€—。
@@ -257,7 +257,7 @@
3. 什是是 SIMD?它如何用于 RapidJSON?
- [SIMD](http://en.wikipedia.org/wiki/SIMD) 指令å¯ä»¥åœ¨çް代 CPU 中执行并行è¿ç®—。RapidJSON 支æŒäº† Intel çš„ SSE2/SSE4.2 去加速跳过空白字符。在解æžå«ç¼©è¿›çš„ JSON 时,这能æå‡æ€§èƒ½ã€‚åªè¦å®šä¹‰å为 `RAPIDJSON_SSE2` 或 `RAPIDJSON_SSE42` çš„å®ï¼Œå°±èƒ½å¯åŠ¨è¿™ä¸ªåŠŸèƒ½ã€‚ç„¶è€Œï¼Œè‹¥åœ¨ä¸æ”¯æŒè¿™äº›æŒ‡ä»¤é›†çš„æœºå™¨ä¸Šæ‰§è¡Œè¿™äº›å¯æ‰§è¡Œæ–‡ä»¶ï¼Œä¼šå¯¼è‡´å´©æºƒã€‚
+ [SIMD](http://en.wikipedia.org/wiki/SIMD) 指令å¯ä»¥åœ¨çް代 CPU 中执行并行è¿ç®—。RapidJSON 支æŒä½¿ç”¨ Intel çš„ SSE2/SSE4.2 å’Œ ARM çš„ Neon æ¥åŠ é€Ÿå¯¹ç©ºç™½ç¬¦ã€åˆ¶è¡¨ç¬¦ã€å›žè½¦ç¬¦å’Œæ¢è¡Œç¬¦çš„过滤处ç†ã€‚在解æžå«ç¼©è¿›çš„ JSON 时,这能æå‡æ€§èƒ½ã€‚åªè¦å®šä¹‰å为 `RAPIDJSON_SSE2` ,`RAPIDJSON_SSE42` 或 `RAPIDJSON_NEON` çš„å®ï¼Œå°±èƒ½å¯åŠ¨è¿™ä¸ªåŠŸèƒ½ã€‚ç„¶è€Œï¼Œè‹¥åœ¨ä¸æ”¯æŒè¿™äº›æŒ‡ä»¤é›†çš„æœºå™¨ä¸Šæ‰§è¡Œè¿™äº›å¯æ‰§è¡Œæ–‡ä»¶ï¼Œä¼šå¯¼è‡´å´©æºƒã€‚
4. 它会消耗许多内存么?
@@ -271,7 +271,7 @@
有些应用程åºéœ€è¦å¤„ç†éžå¸¸å¤§çš„ JSON 文件。而有些åŽå°åº”用程åºéœ€è¦å¤„ç†å¤§é‡çš„ JSONã€‚è¾¾åˆ°é«˜æ€§èƒ½åŒæ—¶æ”¹å–„å»¶æ—¶åŠåžåé‡ã€‚更广义æ¥è¯´ï¼Œè¿™ä¹Ÿå¯ä»¥èŠ‚çœèƒ½æºã€‚
-## 八挂
+## å…«å¦
1. è°æ˜¯ RapidJSON 的开å‘者?
@@ -279,11 +279,11 @@
2. 为何你è¦å¼€å‘ RapidJSON?
- 在 2011 年开始这项目是,它仅一个兴趣项目。Milo Yip 是一个游æˆç¨‹åºå‘˜ï¼Œä»–在那时候认识到 JSON 并希望在未æ¥çš„项目中使用。由于 JSON 好åƒå¾ˆç®€å•,他希望写一个仅有头文件并且快速的程åºåº“。
+ 在 2011 å¹´å¼€å§‹è¿™é¡¹ç›®æ—¶ï¼Œå®ƒåªæ˜¯ä¸€ä¸ªå…´è¶£é¡¹ç›®ã€‚Milo Yip 是一个游æˆç¨‹åºå‘˜ï¼Œä»–在那时候认识到 JSON 并希望在未æ¥çš„项目中使用。由于 JSON 好åƒå¾ˆç®€å•,他希望写一个快速的仅有头文件的程åºåº“。
3. 为什么开å‘中段有一段长期空档?
- ä¸»è¦æ˜¯ä¸ªäººå› ç´ ï¼Œä¾‹å¦‚加入新家庭æˆå‘˜ã€‚å¦å¤–,Milo Yip 也花了许多业馀时间去翻译 Jason Gregory 的《Game Engine Architecture》至中文版《游æˆå¼•擎架构》。
+ ä¸»è¦æ˜¯ä¸ªäººå› ç´ ï¼Œä¾‹å¦‚加入新家庭æˆå‘˜ã€‚å¦å¤–,Milo Yip 也花了许多业余时间去翻译 Jason Gregory 的《Game Engine Architecture》至中文版《游æˆå¼•擎架构》。
4. 为什么这个项目从 Google Code æ¬åˆ° GitHub?
diff --git a/3rdparty/rapidjson/doc/features.md b/3rdparty/rapidjson/doc/features.md
index 732fb21f40e..4d159370ac1 100644
--- a/3rdparty/rapidjson/doc/features.md
+++ b/3rdparty/rapidjson/doc/features.md
@@ -22,14 +22,16 @@
* RapidJSON should be fully RFC4627/ECMA-404 compliance.
* Support JSON Pointer (RFC6901).
* Support JSON Schema Draft v4.
+* Support Swagger v2 schema.
+* Support OpenAPI v3.0.x schema.
* Support Unicode surrogate.
* Support null character (`"\u0000"`)
- * For example, `["Hello\u0000World"]` can be parsed and handled gracefully. There is API for getting/setting lengths of string.
+* For example, `["Hello\u0000World"]` can be parsed and handled gracefully. There is API for getting/setting lengths of string.
* Support optional relaxed syntax.
- * Single line (`// ...`) and multiple line (`/* ... */`) comments (`kParseCommentsFlag`).
- * Trailing commas at the end of objects and arrays (`kParseTrailingCommasFlag`).
- * `NaN`, `Inf`, `Infinity`, `-Inf` and `-Infinity` as `double` values (`kParseNanAndInfFlag`)
-* [NPM compliant](http://github.com/miloyip/rapidjson/blob/master/doc/npm.md).
+* Single line (`// ...`) and multiple line (`/* ... */`) comments (`kParseCommentsFlag`).
+* Trailing commas at the end of objects and arrays (`kParseTrailingCommasFlag`).
+* `NaN`, `Inf`, `Infinity`, `-Inf` and `-Infinity` as `double` values (`kParseNanAndInfFlag`)
+* [NPM compliant](http://github.com/Tencent/rapidjson/blob/master/doc/npm.md).
## Unicode
diff --git a/3rdparty/rapidjson/doc/features.zh-cn.md b/3rdparty/rapidjson/doc/features.zh-cn.md
index 19908a8ded7..7662cc13e00 100644
--- a/3rdparty/rapidjson/doc/features.zh-cn.md
+++ b/3rdparty/rapidjson/doc/features.zh-cn.md
@@ -29,7 +29,7 @@
* å•行(`// ...`)åŠå¤šè¡Œï¼ˆ`/* ... */`) 注释 (`kParseCommentsFlag`)。
* 在对象和数组结æŸå‰å«é€—å· (`kParseTrailingCommasFlag`)。
* `NaN`ã€`Inf`ã€`Infinity`ã€`-Inf` åŠ `-Infinity` 作为 `double` 值 (`kParseNanAndInfFlag`)
-* [NPM 兼容](https://github.com/miloyip/rapidjson/blob/master/doc/npm.md).
+* [NPM 兼容](https://github.com/Tencent/rapidjson/blob/master/doc/npm.md).
## Unicode
diff --git a/3rdparty/rapidjson/doc/internals.md b/3rdparty/rapidjson/doc/internals.md
index 49802a0fd7a..81fe9c16e74 100644
--- a/3rdparty/rapidjson/doc/internals.md
+++ b/3rdparty/rapidjson/doc/internals.md
@@ -28,7 +28,7 @@ Both SAX and DOM APIs depends on 3 additional concepts: `Allocator`, `Encoding`
## Data Layout {#DataLayout}
-`Value` is a [variant type](http://en.wikipedia.org/wiki/Variant_type). In RapidJSON's context, an instance of `Value` can contain 1 of 6 JSON value types. This is possible by using `union`. Each `Value` contains two members: `union Data data_` and a`unsigned flags_`. The `flags_` indiciates the JSON type, and also additional information.
+`Value` is a [variant type](http://en.wikipedia.org/wiki/Variant_type). In RapidJSON's context, an instance of `Value` can contain 1 of 6 JSON value types. This is possible by using `union`. Each `Value` contains two members: `union Data data_` and a`unsigned flags_`. The `flags_` indicates the JSON type, and also additional information.
The following tables show the data layout of each type. The 32-bit/64-bit columns indicates the size of the field in bytes.
@@ -79,7 +79,7 @@ The following tables show the data layout of each type. The 32-bit/64-bit column
| `unsigned u` | 32-bit unsigned integer |4 |4 |
| (zero padding) | 0 |4 |4 |
| (unused) | |4 |8 |
-| `unsigned flags_` | `kNumberType kNumberFlag kUIntFlag kUInt64Flag ...` |4 |4 |
+| `unsigned flags_` | `kNumberType kNumberFlag kUintFlag kUint64Flag ...` |4 |4 |
| Number (Int64) | |32-bit|64-bit|
|---------------------|-------------------------------------|:----:|:----:|
@@ -101,7 +101,7 @@ The following tables show the data layout of each type. The 32-bit/64-bit column
Here are some notes:
* To reduce memory consumption for 64-bit architecture, `SizeType` is typedef as `unsigned` instead of `size_t`.
-* Zero padding for 32-bit number may be placed after or before the actual type, according to the endianess. This makes possible for interpreting a 32-bit integer as a 64-bit integer, without any conversion.
+* Zero padding for 32-bit number may be placed after or before the actual type, according to the endianness. This makes possible for interpreting a 32-bit integer as a 64-bit integer, without any conversion.
* An `Int` is always an `Int64`, but the converse is not always true.
## Flags {#Flags}
@@ -183,17 +183,20 @@ void SkipWhitespace(InputStream& s) {
However, this requires 4 comparisons and a few branching for each character. This was found to be a hot spot.
-To accelerate this process, SIMD was applied to compare 16 characters with 4 white spaces for each iteration. Currently RapidJSON only supports SSE2 and SSE4.2 instructions for this. And it is only activated for UTF-8 memory streams, including string stream or *in situ* parsing.
+To accelerate this process, SIMD was applied to compare 16 characters with 4 white spaces for each iteration. Currently RapidJSON supports SSE2, SSE4.2 and ARM Neon instructions for this. And it is only activated for UTF-8 memory streams, including string stream or *in situ* parsing.
-To enable this optimization, need to define `RAPIDJSON_SSE2` or `RAPIDJSON_SSE42` before including `rapidjson.h`. Some compilers can detect the setting, as in `perftest.h`:
+To enable this optimization, need to define `RAPIDJSON_SSE2`, `RAPIDJSON_SSE42` or `RAPIDJSON_NEON` before including `rapidjson.h`. Some compilers can detect the setting, as in `perftest.h`:
~~~cpp
// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
+// Likewise, __ARM_NEON is used to detect Neon.
#if defined(__SSE4_2__)
# define RAPIDJSON_SSE42
#elif defined(__SSE2__)
# define RAPIDJSON_SSE2
+#elif defined(__ARM_NEON)
+# define RAPIDJSON_NEON
#endif
~~~
@@ -211,7 +214,7 @@ In [Intel® 64 and IA-32 Architectures Optimization Reference Manual
This is not feasible as RapidJSON should not enforce such requirement.
-To fix this issue, currently the routine process bytes up to the next aligned address. After tha, use aligned read to perform SIMD processing. Also see [#85](https://github.com/miloyip/rapidjson/issues/85).
+To fix this issue, currently the routine process bytes up to the next aligned address. After tha, use aligned read to perform SIMD processing. Also see [#85](https://github.com/Tencent/rapidjson/issues/85).
## Local Stream Copy {#LocalStreamCopy}
diff --git a/3rdparty/rapidjson/doc/internals.zh-cn.md b/3rdparty/rapidjson/doc/internals.zh-cn.md
new file mode 100644
index 00000000000..d414fc1402d
--- /dev/null
+++ b/3rdparty/rapidjson/doc/internals.zh-cn.md
@@ -0,0 +1,363 @@
+# 内部架构
+
+本部分记录了一些设计和实现细节。
+
+[TOC]
+
+# æž¶æž„ {#Architecture}
+
+## SAX 和 DOM
+
+下é¢çš„ UML 图显示了 SAX å’Œ DOM 的基本关系。
+
+![架构 UML 类图](diagram/architecture.png)
+
+关系的核心是 `Handler` 概念。在 SAX 一边,`Reader` 从æµè§£æž JSON 并将事件å‘é€åˆ° `Handler`。`Writer` 实现了 `Handler` 概念,用于处ç†ç›¸åŒçš„事件。在 DOM 一边,`Document` 实现了 `Handler` æ¦‚å¿µï¼Œç”¨äºŽé€šè¿‡è¿™äº›æ—¶é—´æ¥æž„建 DOM。`Value` 支æŒäº† `Value::Accept(Handler&)` 函数,它å¯ä»¥å°† DOM 转æ¢ä¸ºäº‹ä»¶è¿›è¡Œå‘é€ã€‚
+
+在这个设计,SAX 是ä¸ä¾èµ–于 DOM 的。甚至 `Reader` å’Œ `Writer` 之间也没有ä¾èµ–。这æä¾›äº†è¿žæŽ¥äº‹ä»¶å‘é€å™¨å’Œå¤„ç†å™¨çš„çµæ´»æ€§ã€‚除此之外,`Value` 也是ä¸ä¾èµ–于 SAX 的。所以,除了将 DOM åºåˆ—化为 JSON 之外,用户也å¯ä»¥å°†å…¶åºåˆ—化为 XML,或者åšä»»ä½•其他事情。
+
+## 工具类
+
+SAX å’Œ DOM API 都ä¾èµ–于3个é¢å¤–的概念:`Allocator`ã€`Encoding` å’Œ `Stream`。它们的继承层次结构如下图所示。
+
+![工具类 UML 类图](diagram/utilityclass.png)
+
+# 值(Value) {#Value}
+
+`Value` (实际上被定义为 `GenericValue<UTF8<>>`)是 DOM API 的核心。本部分æè¿°äº†å®ƒçš„设计。
+
+## æ•°æ®å¸ƒå±€ {#DataLayout}
+
+`Value` 是[å¯å˜ç±»åž‹](http://en.wikipedia.org/wiki/Variant_type)。在 RapidJSON 的上下文中,一个 `Value` 的实例å¯ä»¥åŒ…å«6ç§ JSON æ•°æ®ç±»åž‹ä¹‹ä¸€ã€‚通过使用 `union` ,这是å¯èƒ½å®žçŽ°çš„ã€‚æ¯ä¸€ä¸ª `Value` 包å«ä¸¤ä¸ªæˆå‘˜ï¼š`union Data data_` å’Œ `unsigned flags_`。`flags_` 表明了 JSON 类型,以åŠé™„加的信æ¯ã€‚
+
+下表显示了所有类型的数æ®å¸ƒå±€ã€‚32ä½/64ä½åˆ—表明了字段所å ç”¨çš„字节数。
+
+| Null | | 32ä½ | 64ä½ |
+|-------------------|----------------------------------|:----:|:----:|
+| (未使用) | |4 |8 |
+| (未使用) | |4 |4 |
+| (未使用) | |4 |4 |
+| `unsigned flags_` | `kNullType kNullFlag` |4 |4 |
+
+| Bool | | 32ä½ | 64ä½ |
+|-------------------|----------------------------------------------------|:----:|:----:|
+| (未使用) | |4 |8 |
+| (未使用) | |4 |4 |
+| (未使用) | |4 |4 |
+| `unsigned flags_` | `kBoolType` (either `kTrueFlag` or `kFalseFlag`) |4 |4 |
+
+| String | | 32ä½ | 64ä½ |
+|---------------------|-------------------------------------|:----:|:----:|
+| `Ch* str` | 指å‘字符串的指针(å¯èƒ½æ‹¥æœ‰æ‰€æœ‰æƒï¼‰ |4 |8 |
+| `SizeType length` | 字符串长度 |4 |4 |
+| (未使用) | |4 |4 |
+| `unsigned flags_` | `kStringType kStringFlag ...` |4 |4 |
+
+| Object | | 32ä½ | 64ä½ |
+|---------------------|-------------------------------------|:----:|:----:|
+| `Member* members` | æŒ‡å‘æˆå‘˜æ•°ç»„的指针(拥有所有æƒï¼‰ |4 |8 |
+| `SizeType size` | æˆå‘˜æ•°é‡ |4 |4 |
+| `SizeType capacity` | æˆå‘˜å®¹é‡ |4 |4 |
+| `unsigned flags_` | `kObjectType kObjectFlag` |4 |4 |
+
+| Array | | 32ä½ | 64ä½ |
+|---------------------|-------------------------------------|:----:|:----:|
+| `Value* values` | 指å‘值数组的指针(拥有所有æƒï¼‰ |4 |8 |
+| `SizeType size` | å€¼æ•°é‡ |4 |4 |
+| `SizeType capacity` | å€¼å®¹é‡ |4 |4 |
+| `unsigned flags_` | `kArrayType kArrayFlag` |4 |4 |
+
+| Number (Int) | | 32ä½ | 64ä½ |
+|---------------------|-------------------------------------|:----:|:----:|
+| `int i` | 32使œ‰ç¬¦å·æ•´æ•° |4 |4 |
+| (零填充) | 0 |4 |4 |
+| (未使用) | |4 |8 |
+| `unsigned flags_` | `kNumberType kNumberFlag kIntFlag kInt64Flag ...` |4 |4 |
+
+| Number (UInt) | | 32ä½ | 64ä½ |
+|---------------------|-------------------------------------|:----:|:----:|
+| `unsigned u` | 32使— ç¬¦å·æ•´æ•° |4 |4 |
+| (零填充) | 0 |4 |4 |
+| (未使用) | |4 |8 |
+| `unsigned flags_` | `kNumberType kNumberFlag kUintFlag kUint64Flag ...` |4 |4 |
+
+| Number (Int64) | | 32ä½ | 64ä½ |
+|---------------------|-------------------------------------|:----:|:----:|
+| `int64_t i64` | 64使œ‰ç¬¦å·æ•´æ•° |8 |8 |
+| (未使用) | |4 |8 |
+| `unsigned flags_` | `kNumberType kNumberFlag kInt64Flag ...` |4 |4 |
+
+| Number (Uint64) | | 32ä½ | 64ä½ |
+|---------------------|-------------------------------------|:----:|:----:|
+| `uint64_t i64` | 64使— ç¬¦å·æ•´æ•° |8 |8 |
+| (未使用) | |4 |8 |
+| `unsigned flags_` | `kNumberType kNumberFlag kInt64Flag ...` |4 |4 |
+
+| Number (Double) | | 32ä½ | 64ä½ |
+|---------------------|-------------------------------------|:----:|:----:|
+| `uint64_t i64` | åŒç²¾åº¦æµ®ç‚¹æ•° |8 |8 |
+| (未使用) | |4 |8 |
+| `unsigned flags_` |`kNumberType kNumberFlag kDoubleFlag`|4 |4 |
+
+è¿™é‡Œæœ‰ä¸€äº›éœ€è¦æ³¨æ„的地方:
+* 为了å‡å°‘在64使ž¶æž„上的内存消耗,`SizeType` 被定义为 `unsigned` è€Œä¸æ˜¯ `size_t`。
+* 32使•´æ•°çš„é›¶å¡«å……å¯èƒ½è¢«æ”¾åœ¨å®žé™…类型的å‰é¢æˆ–åŽé¢ï¼Œè¿™ä¾èµ–于字节åºã€‚这使得它å¯ä»¥å°†32使•´æ•°ä¸ç»è¿‡ä»»ä½•转æ¢å°±å¯ä»¥è§£é‡Šä¸º64使•´æ•°ã€‚
+* `Int` 永远是 `Int64`,å之ä¸ç„¶ã€‚
+
+## 标志 {#Flags}
+
+32ä½çš„ `flags_` 包å«äº† JSON 类型和其他信æ¯ã€‚如剿–‡ä¸­çš„表所述,æ¯ä¸€ç§ JSON 类型包å«äº†å†—余的 `kXXXType` å’Œ `kXXXFlag`ã€‚è¿™ä¸ªè®¾è®¡æ˜¯ä¸ºäº†ä¼˜åŒ–æµ‹è¯•ä½æ ‡å¿—(`IsNumber()`ï¼‰å’ŒèŽ·å–æ¯ä¸€ç§ç±»åž‹çš„åºåˆ—å·ï¼ˆ`GetType()`)。
+
+字符串有两个å¯é€‰çš„æ ‡å¿—。`kCopyFlag` 表明这个字符串拥有字符串拷è´çš„æ‰€æœ‰æƒã€‚而 `kInlineStrFlag` æ„味ç€ä½¿ç”¨äº†[短字符串优化](#ShortString)。
+
+æ•°å­—æ›´åŠ å¤æ‚一些。对于普通的整数值,它å¯ä»¥åŒ…å« `kIntFlag`ã€`kUintFlag`〠`kInt64Flag` å’Œ/或 `kUint64Flag`ï¼Œè¿™ç”±æ•´æ•°çš„èŒƒå›´å†³å®šã€‚å¸¦æœ‰å°æ•°æˆ–者超过64使‰€èƒ½è¡¨è¾¾çš„范围的整数的数字会被存储为带有 `kDoubleFlag` çš„ `double`。
+
+## 短字符串优化 {#ShortString}
+
+[Kosta](https://github.com/Kosta-Github) æä¾›äº†å¾ˆæ£’的短字符串优化。这个优化的xxx如下所述。除去 `flags_` ,`Value` 有12或16字节(对于32使ˆ–64ä½ï¼‰æ¥å­˜å‚¨å®žé™…的数æ®ã€‚è¿™ä¸ºåœ¨å…¶å†…éƒ¨ç›´æŽ¥å­˜å‚¨çŸ­å­—ç¬¦ä¸²è€Œä¸æ˜¯å­˜å‚¨å­—符串的指针创造了å¯èƒ½ã€‚对于1字节的字符类型(例如 `char`),它å¯ä»¥åœ¨ `Value` 类型内部存储至多11或15个字符的字符串。
+
+|ShortString (Ch=char)| | 32ä½ | 64ä½ |
+|---------------------|-------------------------------------|:----:|:----:|
+| `Ch str[MaxChars]` | 字符串缓冲区 |11 |15 |
+| `Ch invLength` | MaxChars - Length |1 |1 |
+| `unsigned flags_` | `kStringType kStringFlag ...` |4 |4 |
+
+这里使用了一项特殊的技术。它存储了 (MaxChars - length) 而ä¸ç›´æŽ¥å­˜å‚¨å­—符串的长度。这使得存储11个字符并且带有åŽç¼€ `\0` æˆä¸ºå¯èƒ½ã€‚
+
+这个优化å¯ä»¥å‡å°‘字符串拷è´å†…å­˜å ç”¨ã€‚它也改善了缓存一致性,并进一步æé«˜äº†è¿è¡Œæ—¶æ€§èƒ½ã€‚
+
+# 分é…器(Allocator) {#InternalAllocator}
+
+`Allocator` 是 RapidJSON 中的概念:
+~~~cpp
+concept Allocator {
+ static const bool kNeedFree; //!< 表明这个分é…器是å¦éœ€è¦è°ƒç”¨ Free()。
+
+ // 申请内存å—。
+ // \param size 内存å—的大å°ï¼Œä»¥å­—节记。
+ // \returns 指å‘内存å—的指针。
+ void* Malloc(size_t size);
+
+ // 调整内存å—的大å°ã€‚
+ // \param originalPtr 当å‰å†…å­˜å—的指针。空指针是被å…许的。
+ // \param originalSize 当å‰å¤§å°ï¼Œä»¥å­—节记。(设计问题:因为有些分é…器å¯èƒ½ä¸ä¼šè®°å½•它,显示的传递它å¯ä»¥èŠ‚çº¦å†…å­˜ã€‚ï¼‰
+ // \param newSize 新大å°ï¼Œä»¥å­—节记。
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
+
+ // 释放内存å—。
+ // \param ptr 指å‘内存å—的指针。空指针是被å…许的。
+ static void Free(void *ptr);
+};
+~~~
+
+éœ€è¦æ³¨æ„的是 `Malloc()` å’Œ `Realloc()` 是æˆå‘˜å‡½æ•°è€Œ `Free()` æ˜¯é™æ€æˆå‘˜å‡½æ•°ã€‚
+
+## MemoryPoolAllocator {#MemoryPoolAllocator}
+
+`MemoryPoolAllocator` 是 DOM 的默认内存分é…器。它åªç”³è¯·å†…存而ä¸é‡Šæ”¾å†…存。这对于构建 DOM æ ‘éžå¸¸åˆé€‚。
+
+在它的内部,它从基础的内存分é…器申请内存å—(默认为 `CrtAllocator`)并将这些内存å—存储为å•å‘链表。当用户请求申请内存,它会éµå¾ªä¸‹åˆ—步骤æ¥ç”³è¯·å†…存:
+
+1. 如果å¯ç”¨ï¼Œä½¿ç”¨ç”¨æˆ·æä¾›çš„ç¼“å†²åŒºã€‚ï¼ˆè§ [User Buffer section in DOM](doc/dom.md))
+2. 如果用户æä¾›çš„缓冲区已满,使用当å‰å†…å­˜å—。
+3. 如果当å‰å†…å­˜å—已满,申请新的内存å—。
+
+# è§£æžä¼˜åŒ– {#ParsingOptimization}
+
+## 使用 SIMD 跳过空格 {#SkipwhitespaceWithSIMD}
+
+当从æµä¸­è§£æž JSON 时,解æžå™¨éœ€è¦è·³è¿‡4ç§ç©ºæ ¼å­—符:
+
+1. 空格 (`U+0020`)
+2. 制表符 (`U+000B`)
+3. æ¢è¡Œ (`U+000A`)
+4. 回车 (`U+000D`)
+
+这是一份简å•的实现:
+~~~cpp
+void SkipWhitespace(InputStream& s) {
+ while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
+ s.Take();
+}
+~~~
+
+但是,这需è¦å¯¹æ¯ä¸ªå­—符进行4次比较以åŠä¸€äº›åˆ†æ”¯ã€‚这被å‘现是一个热点。
+
+为了加速这一处ç†ï¼ŒRapidJSON 使用 SIMD æ¥åœ¨ä¸€æ¬¡è¿­ä»£ä¸­æ¯”较16个字符和4ä¸ªç©ºæ ¼ã€‚ç›®å‰ RapidJSON æ”¯æŒ SSE2 , SSE4.2 å’Œ ARM Neon æŒ‡ä»¤ã€‚åŒæ—¶å®ƒä¹Ÿåªä¼šå¯¹ UTF-8 内存æµå¯ç”¨ï¼ŒåŒ…æ‹¬å­—ç¬¦ä¸²æµæˆ– *原ä½* è§£æžã€‚
+
+ä½ å¯ä»¥é€šè¿‡åœ¨åŒ…å« `rapidjson.h` 之å‰å®šä¹‰ `RAPIDJSON_SSE2` , `RAPIDJSON_SSE42` 或 `RAPIDJSON_NEON` æ¥å¯ç”¨è¿™ä¸ªä¼˜åŒ–。一些编译器å¯ä»¥æ£€æµ‹è¿™ä¸ªè®¾ç½®ï¼Œå¦‚ `perftest.h`:
+
+~~~cpp
+// __SSE2__ å’Œ __SSE4_2__ å¯è¢« gccã€clang å’Œ Intel 编译器识别:
+// 如果支æŒçš„è¯ï¼Œæˆ‘们在 gmake 中使用了 -march=native æ¥å¯ç”¨ -msse2 å’Œ -msse4.2
+// åŒæ ·çš„, __ARM_NEON 被用于识别Neon
+#if defined(__SSE4_2__)
+# define RAPIDJSON_SSE42
+#elif defined(__SSE2__)
+# define RAPIDJSON_SSE2
+#elif defined(__ARM_NEON)
+# define RAPIDJSON_NEON
+#endif
+~~~
+
+éœ€è¦æ³¨æ„çš„æ˜¯ï¼Œè¿™æ˜¯ç¼–è¯‘æœŸçš„è®¾ç½®ã€‚åœ¨ä¸æ”¯æŒè¿™äº›æŒ‡ä»¤çš„æœºå™¨ä¸Šè¿è¡Œå¯æ‰§è¡Œæ–‡ä»¶ä¼šä½¿å®ƒå´©æºƒã€‚
+
+### 页é¢å¯¹é½é—®é¢˜
+
+在 RapidJSON 的早期版本中,被报告了[一个问题](https://code.google.com/archive/p/rapidjson/issues/104):`SkipWhitespace_SIMD()` 会罕è§åœ°å¯¼è‡´å´©æºƒï¼ˆçº¦äº”å万分之一的几率)。在调查之åŽï¼Œæ€€ç–‘是 `_mm_loadu_si128()` 访问了 `'\0'` 之åŽçš„å†…å­˜ï¼Œå¹¶è¶Šè¿‡è¢«ä¿æŠ¤çš„é¡µé¢è¾¹ç•Œã€‚
+
+在 [Intel® 64 and IA-32 Architectures Optimization Reference Manual
+](http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-optimization-manual.html) 中,章节 10.2.1:
+
+> 为了支æŒéœ€è¦è´¹å¯¹é½çš„128ä½ SIMD 内存访问的算法,调用者的内存缓冲区申请应当考虑添加一些填充空间,这样被调用的函数å¯ä»¥å®‰å…¨åœ°å°†åœ°å€æŒ‡é’ˆç”¨äºŽæœªå¯¹é½çš„128ä½ SIMD 内存æ“作。
+> 在结åˆéžå¯¹é½çš„ SIMD 内存æ“作中,最å°çš„对é½å¤§å°åº”该等于 SIMD 寄存器的大å°ã€‚
+
+对于 RapidJSON æ¥è¯´ï¼Œè¿™æ˜¾ç„¶æ˜¯ä¸å¯è¡Œçš„,因为 RapidJSON ä¸åº”当强迫用户进行内存对é½ã€‚
+
+为了修å¤è¿™ä¸ªé—®é¢˜ï¼Œå½“å‰çš„代ç ä¼šå…ˆæŒ‰å­—节处ç†ç›´åˆ°ä¸‹ä¸€ä¸ªå¯¹é½çš„地å€ã€‚在这之åŽï¼Œä½¿ç”¨å¯¹é½è¯»å–æ¥è¿›è¡Œ SIMD 处ç†ã€‚è§ [#85](https://github.com/Tencent/rapidjson/issues/85)。
+
+## å±€éƒ¨æµæ‹·è´ {#LocalStreamCopy}
+
+在优化的过程中,我们å‘现一些编译器ä¸èƒ½å°†è®¿é—®æµçš„一些æˆå‘˜æ•°æ®æ”¾å…¥å±€éƒ¨å˜é‡æˆ–者寄存器中。测试结果显示,对于一些æµç±»åž‹ï¼Œåˆ›å»ºæµçš„æ‹·è´å¹¶å°†å…¶ç”¨äºŽå†…层循环中å¯ä»¥æ”¹å–„æ€§èƒ½ã€‚ä¾‹å¦‚ï¼Œå®žé™…ï¼ˆéž SIMD)的 `SkipWhitespace()` 被实现为:
+
+~~~cpp
+template<typename InputStream>
+void SkipWhitespace(InputStream& is) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ InputStream& s(copy.s);
+
+ while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
+ s.Take();
+}
+~~~
+
+基于æµçš„特å¾ï¼Œ`StreamLocalCopy` 会创建(或ä¸åˆ›å»ºï¼‰æµå¯¹è±¡çš„æ‹·è´ï¼Œåœ¨å±€éƒ¨ä½¿ç”¨å®ƒå¹¶å°†æµçš„çŠ¶æ€æ‹·è´å›žåŽŸæ¥çš„æµã€‚
+
+## è§£æžä¸ºåŒç²¾åº¦æµ®ç‚¹æ•° {#ParsingDouble}
+
+将字符串解æžä¸º `double` å¹¶ä¸ç®€å•。标准库函数 `strtod()` å¯ä»¥èƒœä»»è¿™é¡¹å·¥ä½œï¼Œä½†å®ƒæ¯”较缓慢。默认情况下,解æžå™¨ä½¿ç”¨é»˜è®¤çš„精度设置。这最多有 3[ULP](http://en.wikipedia.org/wiki/Unit_in_the_last_place) 的误差,并实现在 `internal::StrtodNormalPrecision()` 中。
+
+当使用 `kParseFullPrecisionFlag` 时,编译器会改为调用 `internal::StrtodFullPrecision()` ,这个函数会自动调用三个版本的转æ¢ã€‚
+1. [Fast-Path](http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/)。
+2. [double-conversion](https://github.com/floitsch/double-conversion) 中的自定义 DIY-FP 实现。
+3. (Clinger, William D. How to read floating point numbers accurately. Vol. 25. No. 6. ACM, 1990) 中的大整数算法。
+
+å¦‚æžœç¬¬ä¸€ä¸ªè½¬æ¢æ–¹æ³•失败,则å°è¯•ä½¿ç”¨ç¬¬äºŒç§æ–¹æ³•,以此类推。
+
+# 生æˆä¼˜åŒ– {#GenerationOptimization}
+
+## æ•´æ•°åˆ°å­—ç¬¦ä¸²çš„è½¬æ¢ {#itoa}
+
+整数到字符串转æ¢çš„æœ´ç´ ç®—法需è¦å¯¹æ¯ä¸€ä¸ªå进制ä½è¿›è¡Œä¸€æ¬¡é™¤æ³•。我们实现了若干版本并在 [itoa-benchmark](https://github.com/miloyip/itoa-benchmark) 中对它们进行了评估。
+
+虽然 SSE2 版本是最快的,但它和第二快的 `branchlut` å·®è·ä¸å¤§ã€‚而且 `branchlut` 是纯C++实现,所以我们在 RapidJSON 中使用了 `branchlut`。
+
+## åŒç²¾åº¦æµ®ç‚¹æ•°åˆ°å­—ç¬¦ä¸²çš„è½¬æ¢ {#dtoa}
+
+åŽŸæ¥ RapidJSON 使用 `snprintf(..., ..., "%g")` æ¥è¿›è¡ŒåŒç²¾åº¦æµ®ç‚¹æ•°åˆ°å­—符串的转æ¢ã€‚这是ä¸å‡†ç¡®çš„,因为默认的精度是6。éšåŽæˆ‘们å‘现它很缓慢,而且有其它的替代å“。
+
+Google çš„ V8 [double-conversion](https://github.com/floitsch/double-conversion
+) 实现了更新的ã€å¿«é€Ÿçš„被称为 Grisu3 的算法(Loitsch, Florian. "Printing floating-point numbers quickly and accurately with integers." ACM Sigplan Notices 45.6 (2010): 233-243.)。
+
+ç„¶è€Œï¼Œè¿™ä¸ªå®žçŽ°ä¸æ˜¯ä»…头文件的,所以我们实现了一个仅头文件的 Grisu2 版本。这个算法ä¿è¯äº†ç»“æžœæ°¸è¿œç²¾ç¡®ã€‚è€Œä¸”åœ¨å¤§å¤šæ•°æƒ…å†µä¸‹ï¼Œå®ƒä¼šç”Ÿæˆæœ€çŸ­çš„(å¯é€‰ï¼‰å­—符串表示。
+
+这个仅头文件的转æ¢å‡½æ•°åœ¨ [dtoa-benchmark](https://github.com/miloyip/dtoa-benchmark) 中进行评估。
+
+# è§£æžå™¨ {#Parser}
+
+## è¿­ä»£è§£æž {#IterativeParser}
+
+迭代解æžå™¨æ˜¯ä¸€ä¸ªä»¥éžé€’å½’æ–¹å¼å®žçŽ°çš„é€’å½’ä¸‹é™çš„ LL(1) è§£æžå™¨ã€‚
+
+### 语法 {#IterativeParserGrammar}
+
+è§£æžå™¨ä½¿ç”¨çš„语法是基于严格 JSON 语法的:
+~~~~~~~~~~
+S -> array | object
+array -> [ values ]
+object -> { members }
+values -> non-empty-values | ε
+non-empty-values -> value addition-values
+addition-values -> ε | , non-empty-values
+members -> non-empty-members | ε
+non-empty-members -> member addition-members
+addition-members -> ε | , non-empty-members
+member -> STRING : value
+value -> STRING | NUMBER | NULL | BOOLEAN | object | array
+~~~~~~~~~~
+
+注æ„到左因å­è¢«åŠ å…¥äº†éžç»ˆç»“符的 `values` å’Œ `members` æ¥ä¿è¯è¯­æ³•是 LL(1) 的。
+
+### è§£æžè¡¨ {#IterativeParserParsingTable}
+
+基于这份语法,我们å¯ä»¥æž„造 FIRST å’Œ FOLLOW 集åˆã€‚
+
+éžç»ˆç»“符的 FIRST 集åˆå¦‚下所示:
+
+| NON-TERMINAL | FIRST |
+|:-----------------:|:--------------------------------:|
+| array | [ |
+| object | { |
+| values | ε STRING NUMBER NULL BOOLEAN { [ |
+| addition-values | ε COMMA |
+| members | ε STRING |
+| addition-members | ε COMMA |
+| member | STRING |
+| value | STRING NUMBER NULL BOOLEAN { [ |
+| S | [ { |
+| non-empty-members | STRING |
+| non-empty-values | STRING NUMBER NULL BOOLEAN { [ |
+
+FOLLOW 集åˆå¦‚下所示:
+
+| NON-TERMINAL | FOLLOW |
+|:-----------------:|:-------:|
+| S | $ |
+| array | , $ } ] |
+| object | , $ } ] |
+| values | ] |
+| non-empty-values | ] |
+| addition-values | ] |
+| members | } |
+| non-empty-members | } |
+| addition-members | } |
+| member | , } |
+| value | , } ] |
+
+最终å¯ä»¥ä»Ž FIRST å’Œ FOLLOW 集åˆç”Ÿæˆè§£æžè¡¨ï¼š
+
+| NON-TERMINAL | [ | { | , | : | ] | } | STRING | NUMBER | NULL | BOOLEAN |
+|:-----------------:|:---------------------:|:---------------------:|:-------------------:|:-:|:-:|:-:|:-----------------------:|:---------------------:|:---------------------:|:---------------------:|
+| S | array | object | | | | | | | | |
+| array | [ values ] | | | | | | | | | |
+| object | | { members } | | | | | | | | |
+| values | non-empty-values | non-empty-values | | | ε | | non-empty-values | non-empty-values | non-empty-values | non-empty-values |
+| non-empty-values | value addition-values | value addition-values | | | | | value addition-values | value addition-values | value addition-values | value addition-values |
+| addition-values | | | , non-empty-values | | ε | | | | | |
+| members | | | | | | ε | non-empty-members | | | |
+| non-empty-members | | | | | | | member addition-members | | | |
+| addition-members | | | , non-empty-members | | | ε | | | | |
+| member | | | | | | | STRING : value | | | |
+| value | array | object | | | | | STRING | NUMBER | NULL | BOOLEAN |
+
+对于上é¢çš„语法分æžï¼Œè¿™é‡Œæœ‰ä¸€ä¸ªå¾ˆæ£’çš„[工具](http://hackingoff.com/compilers/predict-first-follow-set)。
+
+### 实现 {#IterativeParserImplementation}
+
+基于这份解æžè¡¨ï¼Œä¸€ä¸ªç›´æŽ¥çš„(常规的)将规则åå‘入栈的实现å¯ä»¥æ­£å¸¸å·¥ä½œã€‚
+
+在 RapidJSON 中,对直接的实现进行了一些修改:
+
+首先,在 RapidJSON 中,这份解æžè¡¨è¢«ç¼–ç ä¸ºçŠ¶æ€æœºã€‚
+规则由头部和主体组æˆã€‚
+状æ€è½¬æ¢ç”±è§„则构造。
+除此之外,é¢å¤–的状æ€è¢«æ·»åŠ åˆ°ä¸Ž `array` å’Œ `object` 有关的规则。
+é€šè¿‡è¿™ç§æ–¹å¼ï¼Œç”Ÿæˆæ•°ç»„值或对象æˆå‘˜å¯ä»¥åªç”¨ä¸€æ¬¡çжæ€è½¬ç§»ä¾¿å¯å®Œæˆï¼Œ
+而ä¸éœ€è¦åœ¨ç›´æŽ¥çš„实现中的多次出栈/入栈æ“作。
+è¿™ä¹Ÿä½¿å¾—ä¼°è®¡æ ˆçš„å¤§å°æ›´åŠ å®¹æ˜“ã€‚
+
+状æ€å›¾å¦‚如下所示:
+
+![状æ€å›¾](diagram/iterative-parser-states-diagram.png)
+
+第二,迭代解æžå™¨ä¹Ÿåœ¨å†…部栈ä¿å­˜äº†æ•°ç»„的值个数和对象æˆå‘˜çš„æ•°é‡ï¼Œè¿™ä¹Ÿä¸Žä¼ ç»Ÿçš„实现ä¸åŒã€‚
diff --git a/3rdparty/rapidjson/doc/misc/header.html b/3rdparty/rapidjson/doc/misc/header.html
index 2dbe7214658..a89ba46b492 100644
--- a/3rdparty/rapidjson/doc/misc/header.html
+++ b/3rdparty/rapidjson/doc/misc/header.html
@@ -18,7 +18,7 @@ $extrastylesheet
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-<div id="topbanner"><a href="https://github.com/miloyip/rapidjson" title="RapidJSON GitHub"><i class="githublogo"></i></a></div>
+<div id="topbanner"><a href="https://github.com/Tencent/rapidjson" title="RapidJSON GitHub"><i class="githublogo"></i></a></div>
$searchbox
<!--END TITLEAREA-->
<!-- end header part -->
diff --git a/3rdparty/rapidjson/doc/npm.md b/3rdparty/rapidjson/doc/npm.md
index 5efa7682137..6f4e85ad964 100644
--- a/3rdparty/rapidjson/doc/npm.md
+++ b/3rdparty/rapidjson/doc/npm.md
@@ -7,7 +7,7 @@
...
"dependencies": {
...
- "rapidjson": "git@github.com:miloyip/rapidjson.git"
+ "rapidjson": "git@github.com:Tencent/rapidjson.git"
},
...
"gypfile": true
diff --git a/3rdparty/rapidjson/doc/performance.md b/3rdparty/rapidjson/doc/performance.md
index 988e799e97a..6f9e1bf8b12 100644
--- a/3rdparty/rapidjson/doc/performance.md
+++ b/3rdparty/rapidjson/doc/performance.md
@@ -1,6 +1,6 @@
# Performance
-There is a [native JSON benchmark collection] [1] which evaluates speed, memory usage and code size of various operations among 37 JSON libaries.
+There is a [native JSON benchmark collection] [1] which evaluates speed, memory usage and code size of various operations among 37 JSON libraries.
[1]: https://github.com/miloyip/nativejson-benchmark
@@ -15,12 +15,12 @@ Additionally, you may refer to the following third-party benchmarks.
* [json_spirit](https://github.com/cierelabs/json_spirit)
* [jsoncpp](http://jsoncpp.sourceforge.net/)
* [libjson](http://sourceforge.net/projects/libjson/)
- * [rapidjson](https://github.com/miloyip/rapidjson/)
+ * [rapidjson](https://github.com/Tencent/rapidjson/)
* [QJsonDocument](http://qt-project.org/doc/qt-5.0/qtcore/qjsondocument.html)
* [JSON Parser Benchmarking](http://chadaustin.me/2013/01/json-parser-benchmarking/) by Chad Austin (Jan 2013)
* [sajson](https://github.com/chadaustin/sajson)
- * [rapidjson](https://github.com/miloyip/rapidjson/)
+ * [rapidjson](https://github.com/Tencent/rapidjson/)
* [vjson](https://code.google.com/p/vjson/)
* [YAJL](http://lloyd.github.com/yajl/)
* [Jansson](http://www.digip.org/jansson/)
diff --git a/3rdparty/rapidjson/doc/performance.zh-cn.md b/3rdparty/rapidjson/doc/performance.zh-cn.md
index c20c5050fec..2322c9c4903 100644
--- a/3rdparty/rapidjson/doc/performance.zh-cn.md
+++ b/3rdparty/rapidjson/doc/performance.zh-cn.md
@@ -15,12 +15,12 @@ RapidJSON 0.1 版本的性能测试文章ä½äºŽ [这里](https://code.google.com
* [json_spirit](https://github.com/cierelabs/json_spirit)
* [jsoncpp](http://jsoncpp.sourceforge.net/)
* [libjson](http://sourceforge.net/projects/libjson/)
- * [rapidjson](https://github.com/miloyip/rapidjson/)
+ * [rapidjson](https://github.com/Tencent/rapidjson/)
* [QJsonDocument](http://qt-project.org/doc/qt-5.0/qtcore/qjsondocument.html)
* [JSON Parser Benchmarking](http://chadaustin.me/2013/01/json-parser-benchmarking/) by Chad Austin (Jan 2013)
* [sajson](https://github.com/chadaustin/sajson)
- * [rapidjson](https://github.com/miloyip/rapidjson/)
+ * [rapidjson](https://github.com/Tencent/rapidjson/)
* [vjson](https://code.google.com/p/vjson/)
* [YAJL](http://lloyd.github.com/yajl/)
* [Jansson](http://www.digip.org/jansson/)
diff --git a/3rdparty/rapidjson/doc/pointer.md b/3rdparty/rapidjson/doc/pointer.md
index b343d78ed7c..9a0e5ca03ab 100644
--- a/3rdparty/rapidjson/doc/pointer.md
+++ b/3rdparty/rapidjson/doc/pointer.md
@@ -211,7 +211,7 @@ p.Stringify(sb);
std::cout << sb.GetString() << std::endl;
~~~
-It can also stringify to URI fragment reprsentation by `StringifyUriFragment()`.
+It can also stringify to URI fragment representation by `StringifyUriFragment()`.
# User-Supplied Tokens {#UserSuppliedTokens}
diff --git a/3rdparty/rapidjson/doc/pointer.zh-cn.md b/3rdparty/rapidjson/doc/pointer.zh-cn.md
index f58f55f3d49..239569d4a0b 100644
--- a/3rdparty/rapidjson/doc/pointer.zh-cn.md
+++ b/3rdparty/rapidjson/doc/pointer.zh-cn.md
@@ -181,7 +181,7 @@ private:
`Pointer` 在其建构函数里会解译æºå­—符串。若有解æžé”™è¯¯ï¼Œ`Pointer::IsValid()` 返回 `false`。你å¯ä½¿ç”¨ `Pointer::GetParseErrorCode()` å’Œ `GetParseErrorOffset()` 去获å–错信æ¯ã€‚
-è¦æ³¨æ„的是,所有解æžå‡½æ•°éƒ½å‡è®¾ pointer æ˜¯åˆæ³•çš„ã€‚å¯¹ä¸€ä¸ªéžæ³• pointer è§£æžä¼šåšæˆæ–­è¨€å¤±è´¥ã€‚
+è¦æ³¨æ„的是,所有解æžå‡½æ•°éƒ½å‡è®¾ pointer æ˜¯åˆæ³•çš„ã€‚å¯¹ä¸€ä¸ªéžæ³• pointer è§£æžä¼šé€ æˆæ–­è¨€å¤±è´¥ã€‚
# URI ç‰‡æ®µè¡¨ç¤ºæ–¹å¼ {#URIFragment}
diff --git a/3rdparty/rapidjson/doc/sax.md b/3rdparty/rapidjson/doc/sax.md
index 1d4fc2ae59c..d42d0438885 100644
--- a/3rdparty/rapidjson/doc/sax.md
+++ b/3rdparty/rapidjson/doc/sax.md
@@ -8,7 +8,7 @@ In RapidJSON, `Reader` (typedef of `GenericReader<...>`) is the SAX-style parser
# Reader {#Reader}
-`Reader` parses a JSON from a stream. While it reads characters from the stream, it analyze the characters according to the syntax of JSON, and publish events to a handler.
+`Reader` parses a JSON from a stream. While it reads characters from the stream, it analyzes the characters according to the syntax of JSON, and publishes events to a handler.
For example, here is a JSON.
@@ -24,7 +24,7 @@ For example, here is a JSON.
}
~~~~~~~~~~
-While a `Reader` parses this JSON, it publishes the following events to the handler sequentially:
+When a `Reader` parses this JSON, it publishes the following events to the handler sequentially:
~~~~~~~~~~
StartObject()
@@ -37,7 +37,7 @@ Bool(false)
Key("n", 1, true)
Null()
Key("i")
-UInt(123)
+Uint(123)
Key("pi")
Double(3.1416)
Key("a")
@@ -50,7 +50,7 @@ EndArray(4)
EndObject(7)
~~~~~~~~~~
-These events can be easily matched with the JSON, except some event parameters need further explanation. Let's see the `simplereader` example which produces exactly the same output as above:
+These events can be easily matched with the JSON, but some event parameters need further explanation. Let's see the `simplereader` example which produces exactly the same output as above:
~~~~~~~~~~cpp
#include "rapidjson/reader.h"
@@ -91,11 +91,11 @@ void main() {
}
~~~~~~~~~~
-Note that, RapidJSON uses template to statically bind the `Reader` type and the handler type, instead of using class with virtual functions. This paradigm can improve the performance by inlining functions.
+Note that RapidJSON uses templates to statically bind the `Reader` type and the handler type, instead of using classes with virtual functions. This paradigm can improve performance by inlining functions.
## Handler {#Handler}
-As the previous example showed, user needs to implement a handler, which consumes the events (function calls) from `Reader`. The handler must contain the following member functions.
+As shown in the previous example, the user needs to implement a handler which consumes the events (via function calls) from the `Reader`. The handler must contain the following member functions.
~~~~~~~~~~cpp
class Handler {
@@ -122,15 +122,15 @@ class Handler {
When the `Reader` encounters a JSON number, it chooses a suitable C++ type mapping. And then it calls *one* function out of `Int(int)`, `Uint(unsigned)`, `Int64(int64_t)`, `Uint64(uint64_t)` and `Double(double)`. If `kParseNumbersAsStrings` is enabled, `Reader` will always calls `RawNumber()` instead.
-`String(const char* str, SizeType length, bool copy)` is called when the `Reader` encounters a string. The first parameter is pointer to the string. The second parameter is the length of the string (excluding the null terminator). Note that RapidJSON supports null character `'\0'` inside a string. If such situation happens, `strlen(str) < length`. The last `copy` indicates whether the handler needs to make a copy of the string. For normal parsing, `copy = true`. Only when *insitu* parsing is used, `copy = false`. And beware that, the character type depends on the target encoding, which will be explained later.
+`String(const char* str, SizeType length, bool copy)` is called when the `Reader` encounters a string. The first parameter is pointer to the string. The second parameter is the length of the string (excluding the null terminator). Note that RapidJSON supports null character `\0` inside a string. If such situation happens, `strlen(str) < length`. The last `copy` indicates whether the handler needs to make a copy of the string. For normal parsing, `copy = true`. Only when *insitu* parsing is used, `copy = false`. And be aware that the character type depends on the target encoding, which will be explained later.
-When the `Reader` encounters the beginning of an object, it calls `StartObject()`. An object in JSON is a set of name-value pairs. If the object contains members it first calls `Key()` for the name of member, and then calls functions depending on the type of the value. These calls of name-value pairs repeats until calling `EndObject(SizeType memberCount)`. Note that the `memberCount` parameter is just an aid for the handler, user may not need this parameter.
+When the `Reader` encounters the beginning of an object, it calls `StartObject()`. An object in JSON is a set of name-value pairs. If the object contains members it first calls `Key()` for the name of member, and then calls functions depending on the type of the value. These calls of name-value pairs repeat until calling `EndObject(SizeType memberCount)`. Note that the `memberCount` parameter is just an aid for the handler; users who do not need this parameter may ignore it.
-Array is similar to object but simpler. At the beginning of an array, the `Reader` calls `BeginArary()`. If there is elements, it calls functions according to the types of element. Similarly, in the last call `EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid for the handler.
+Arrays are similar to objects, but simpler. At the beginning of an array, the `Reader` calls `BeginArray()`. If there is elements, it calls functions according to the types of element. Similarly, in the last call `EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid for the handler.
-Every handler functions returns a `bool`. Normally it should returns `true`. If the handler encounters an error, it can return `false` to notify event publisher to stop further processing.
+Every handler function returns a `bool`. Normally it should return `true`. If the handler encounters an error, it can return `false` to notify the event publisher to stop further processing.
-For example, when we parse a JSON with `Reader` and the handler detected that the JSON does not conform to the required schema, then the handler can return `false` and let the `Reader` stop further parsing. And the `Reader` will be in error state with error code `kParseErrorTermination`.
+For example, when we parse a JSON with `Reader` and the handler detects that the JSON does not conform to the required schema, the handler can return `false` and let the `Reader` stop further parsing. This will place the `Reader` in an error state, with error code `kParseErrorTermination`.
## GenericReader {#GenericReader}
@@ -149,19 +149,19 @@ typedef GenericReader<UTF8<>, UTF8<> > Reader;
} // namespace rapidjson
~~~~~~~~~~
-The `Reader` uses UTF-8 as both source and target encoding. The source encoding means the encoding in the JSON stream. The target encoding means the encoding of the `str` parameter in `String()` calls. For example, to parse a UTF-8 stream and outputs UTF-16 string events, you can define a reader by:
+The `Reader` uses UTF-8 as both source and target encoding. The source encoding means the encoding in the JSON stream. The target encoding means the encoding of the `str` parameter in `String()` calls. For example, to parse a UTF-8 stream and output UTF-16 string events, you can define a reader by:
~~~~~~~~~~cpp
GenericReader<UTF8<>, UTF16<> > reader;
~~~~~~~~~~
-Note that, the default character type of `UTF16` is `wchar_t`. So this `reader`needs to call `String(const wchar_t*, SizeType, bool)` of the handler.
+Note that, the default character type of `UTF16` is `wchar_t`. So this `reader` needs to call `String(const wchar_t*, SizeType, bool)` of the handler.
The third template parameter `Allocator` is the allocator type for internal data structure (actually a stack).
## Parsing {#SaxParsing}
-The one and only one function of `Reader` is to parse JSON.
+The main function of `Reader` is used to parse JSON.
~~~~~~~~~~cpp
template <unsigned parseFlags, typename InputStream, typename Handler>
@@ -172,7 +172,30 @@ template <typename InputStream, typename Handler>
bool Parse(InputStream& is, Handler& handler);
~~~~~~~~~~
-If an error occurs during parsing, it will return `false`. User can also calls `bool HasParseEror()`, `ParseErrorCode GetParseErrorCode()` and `size_t GetErrorOffset()` to obtain the error states. Actually `Document` uses these `Reader` functions to obtain parse errors. Please refer to [DOM](doc/dom.md) for details about parse error.
+If an error occurs during parsing, it will return `false`. User can also call `bool HasParseError()`, `ParseErrorCode GetParseErrorCode()` and `size_t GetErrorOffset()` to obtain the error states. In fact, `Document` uses these `Reader` functions to obtain parse errors. Please refer to [DOM](doc/dom.md) for details about parse errors.
+
+## Token-by-Token Parsing {#TokenByTokenParsing}
+
+Some users may wish to parse a JSON input stream a single token at a time, instead of immediately parsing an entire document without stopping. To parse JSON this way, instead of calling `Parse`, you can use the `IterativeParse` set of functions:
+
+~~~~~~~~~~cpp
+ void IterativeParseInit();
+
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ bool IterativeParseNext(InputStream& is, Handler& handler);
+
+ bool IterativeParseComplete();
+~~~~~~~~~~
+
+Here is an example of iteratively parsing JSON, token by token:
+
+~~~~~~~~~~cpp
+ reader.IterativeParseInit();
+ while (!reader.IterativeParseComplete()) {
+ reader.IterativeParseNext<kParseDefaultFlags>(is, handler);
+ // Your handler has been called once.
+ }
+~~~~~~~~~~
# Writer {#Writer}
diff --git a/3rdparty/rapidjson/doc/sax.zh-cn.md b/3rdparty/rapidjson/doc/sax.zh-cn.md
index b20286de927..9b11e7683d7 100644
--- a/3rdparty/rapidjson/doc/sax.zh-cn.md
+++ b/3rdparty/rapidjson/doc/sax.zh-cn.md
@@ -37,7 +37,7 @@ Bool(false)
Key("n", 1, true)
Null()
Key("i")
-UInt(123)
+Uint(123)
Key("pi")
Double(3.1416)
Key("a")
@@ -91,7 +91,7 @@ void main() {
}
~~~~~~~~~~
-æ³¨æ„ RapidJSON 使用模æ¿å޻陿€æŒ·å®š `Reader` 类型åŠå¤„ç†å™¨çš„ç±»å½¢ï¼Œè€Œä¸æ˜¯ä½¿ç”¨å«è™šå‡½æ•°çš„类。这个范å¼å¯ä»¥é€šè¿‡æŠŠå‡½æ•°å†…è”而改善性能。
+æ³¨æ„ RapidJSON 使用模æ¿å޻陿€æŒ·å®š `Reader` 类型åŠå¤„ç†å™¨çš„ç±»åž‹ï¼Œè€Œä¸æ˜¯ä½¿ç”¨å«è™šå‡½æ•°çš„类。这个范å¼å¯ä»¥é€šè¿‡æŠŠå‡½æ•°å†…è”而改善性能。
## 处ç†å™¨ {#Handler}
@@ -122,7 +122,7 @@ class Handler {
当 `Reader` é‡åˆ° JSON number,它会选择一个åˆé€‚çš„ C++ 类型映射,然åŽè°ƒç”¨ `Int(int)`ã€`Uint(unsigned)`ã€`Int64(int64_t)`ã€`Uint64(uint64_t)` åŠ `Double(double)` çš„ * 其中之一个 *。 若开å¯äº† `kParseNumbersAsStrings` 选项,`Reader` 便会改为调用 `RawNumber()`。
-当 `Reader` é‡åˆ° JSON string,它会调用 `String(const char* str, SizeType length, bool copy)`ã€‚ç¬¬ä¸€ä¸ªå‚æ•°æ˜¯å­—ç¬¦ä¸²çš„æŒ‡é’ˆã€‚ç¬¬äºŒä¸ªå‚æ•°æ˜¯å­—符串的长度(ä¸åŒ…å«ç©ºç»ˆæ­¢ç¬¦å·ï¼‰ã€‚æ³¨æ„ RapidJSON 支æŒå­—䏲䏭嫿œ‰ç©ºå­—符 `'\0'`ã€‚è‹¥å‡ºçŽ°è¿™ç§æƒ…况,便会有 `strlen(str) < length`。最åŽçš„ `copy` 傿•°è¡¨ç¤ºå¤„ç†å™¨æ˜¯å¦éœ€è¦å¤åˆ¶è¯¥å­—ç¬¦ä¸²ã€‚åœ¨æ­£å¸¸è§£æžæ—¶ï¼Œ`copy = true`。仅当使用原ä½è§£æžæ—¶ï¼Œ`copy = false`ã€‚æ­¤å¤–ï¼Œè¿˜è¦æ³¨æ„字符的类型与目标编ç ç›¸å…³ï¼Œæˆ‘们ç¨åŽä¼šå†è°ˆè¿™ä¸€ç‚¹ã€‚
+当 `Reader` é‡åˆ° JSON string,它会调用 `String(const char* str, SizeType length, bool copy)`ã€‚ç¬¬ä¸€ä¸ªå‚æ•°æ˜¯å­—ç¬¦ä¸²çš„æŒ‡é’ˆã€‚ç¬¬äºŒä¸ªå‚æ•°æ˜¯å­—符串的长度(ä¸åŒ…å«ç©ºç»ˆæ­¢ç¬¦å·ï¼‰ã€‚æ³¨æ„ RapidJSON 支æŒå­—䏲䏭嫿œ‰ç©ºå­—符 `\0`ã€‚è‹¥å‡ºçŽ°è¿™ç§æƒ…况,便会有 `strlen(str) < length`。最åŽçš„ `copy` 傿•°è¡¨ç¤ºå¤„ç†å™¨æ˜¯å¦éœ€è¦å¤åˆ¶è¯¥å­—ç¬¦ä¸²ã€‚åœ¨æ­£å¸¸è§£æžæ—¶ï¼Œ`copy = true`。仅当使用原ä½è§£æžæ—¶ï¼Œ`copy = false`ã€‚æ­¤å¤–ï¼Œè¿˜è¦æ³¨æ„字符的类型与目标编ç ç›¸å…³ï¼Œæˆ‘们ç¨åŽä¼šå†è°ˆè¿™ä¸€ç‚¹ã€‚
当 `Reader` é‡åˆ° JSON object 的开始之时,它会调用 `StartObject()`。JSON çš„ object 是一个键值对(æˆå‘˜ï¼‰çš„集åˆã€‚è‹¥ object åŒ…å«æˆå‘˜ï¼Œå®ƒä¼šå…ˆä¸ºæˆå‘˜çš„å字调用 `Key()`,然åŽå†æŒ‰å€¼çš„ç±»åž‹è°ƒç”¨å‡½æ•°ã€‚å®ƒä¸æ–­è°ƒç”¨è¿™äº›é”®å€¼å¯¹ï¼Œç›´è‡³æœ€ç»ˆè°ƒç”¨ `EndObject(SizeType memberCount)`ã€‚æ³¨æ„ `memberCount` 傿•°å¯¹å¤„ç†å™¨æ¥è¯´åªæ˜¯å助性质,使用者å¯èƒ½ä¸éœ€è¦æ­¤å‚数。
diff --git a/3rdparty/rapidjson/doc/schema.md b/3rdparty/rapidjson/doc/schema.md
index a83cebcae7c..4da4474b2e0 100644
--- a/3rdparty/rapidjson/doc/schema.md
+++ b/3rdparty/rapidjson/doc/schema.md
@@ -8,7 +8,7 @@ RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http://
[TOC]
-## Basic Usage
+# Basic Usage {#Basic}
First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into a `SchemaDocument`.
@@ -20,15 +20,23 @@ Secondly, construct a `SchemaValidator` with the `SchemaDocument`. It is similar
// ...
Document sd;
-if (!sd.Parse(schemaJson).HasParseError()) {
+if (sd.Parse(schemaJson).HasParseError()) {
// the schema is not a valid JSON.
// ...
}
+
SchemaDocument schema(sd); // Compile a Document to SchemaDocument
+if (!schema.GetError().ObjectEmpty()) {
+ // there was a problem compiling the schema
+ StringBuffer sb;
+ Writer<StringBuffer> w(sb);
+ schema.GetError().Accept(w);
+ printf("Invalid schema: %s\n", sb.GetString());
+}
// sd is no longer needed here.
Document d;
-if (!d.Parse(inputJson).HasParseError()) {
+if (d.Parse(inputJson).HasParseError()) {
// the input is not a valid JSON.
// ...
}
@@ -49,14 +57,14 @@ if (!d.Accept(validator)) {
Some notes:
-* One `SchemaDocment` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s.
+* One `SchemaDocument` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s.
* A `SchemaValidator` may be reused to validate multiple documents. To run it for other documents, call `validator.Reset()` first.
-## Validation during parsing/serialization
+# Validation during parsing/serialization {#Fused}
Unlike most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files.
-### DOM parsing
+## DOM parsing {#DOM}
For using DOM in parsing, `Document` needs some preparation and finalizing tasks, in addition to receiving SAX events, thus it needs some work to route the reader, validator and the document. `SchemaValidatingReader` is a helper class that doing such work.
@@ -97,7 +105,7 @@ if (!reader.GetParseResult()) {
}
~~~
-### SAX parsing
+## SAX parsing {#SAX}
For using SAX in parsing, it is much simpler. If it only need to validate the JSON without further processing, it is simply:
@@ -126,7 +134,7 @@ if (!reader.Parse(ss, validator)) {
}
~~~
-### Serialization
+## Serialization {#Serialization}
It is also possible to do validation during serializing. This can ensure the result JSON is valid according to the JSON schema.
@@ -144,7 +152,7 @@ if (!d.Accept(validator)) {
Of course, if your application only needs SAX-style serialization, it can simply send SAX events to `SchemaValidator` instead of `Writer`.
-## Remote Schema
+# Remote Schema {#Remote}
JSON Schema supports [`$ref` keyword](http://spacetelescope.github.io/understanding-json-schema/structuring.html), which is a [JSON pointer](doc/pointer.md) referencing to a local or remote schema. Local pointer is prefixed with `#`, while remote pointer is an relative or absolute URI. For example:
@@ -157,7 +165,7 @@ As `SchemaDocument` does not know how to resolve such URI, it needs a user-provi
~~~
class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
public:
- virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeTyp length) {
+ virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) {
// Resolve the uri and returns a pointer to that schema.
}
};
@@ -168,7 +176,7 @@ MyRemoteSchemaDocumentProvider provider;
SchemaDocument schema(sd, &provider);
~~~
-## Conformance
+# Conformance {#Conformance}
RapidJSON passed 262 out of 263 tests in [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4).
@@ -176,7 +184,7 @@ The failed test is "changed scope ref invalid" of "change resolution scope" in `
Besides, the `format` schema keyword for string values is ignored, since it is not required by the specification.
-### Regular Expression
+## Regular Expression {#Regex}
The schema keyword `pattern` and `patternProperties` uses regular expression to match the required pattern.
@@ -185,7 +193,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d
|Syntax|Description|
|------|-----------|
|`ab` | Concatenation |
-|`a|b` | Alternation |
+|<code>a&#124;b</code> | Alternation |
|`a?` | Zero or one |
|`a*` | Zero or more |
|`a+` | One or more |
@@ -202,7 +210,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d
|`[^abc]` | Negated character classes |
|`[^a-c]` | Negated character class range |
|`[\b]` | Backspace (U+0008) |
-|`\|`, `\\`, ... | Escape characters |
+|<code>\\&#124;</code>, `\\`, ... | Escape characters |
|`\f` | Form feed (U+000C) |
|`\n` | Line feed (U+000A) |
|`\r` | Carriage return (U+000D) |
@@ -211,7 +219,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d
For C++11 compiler, it is also possible to use the `std::regex` by defining `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` and `RAPIDJSON_SCHEMA_USE_STDREGEX=1`. If your schemas do not need `pattern` and `patternProperties`, you can set both macros to zero to disable this feature, which will reduce some code size.
-## Performance
+# Performance {#Performance}
Most C++ JSON libraries do not yet support JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js.
@@ -235,3 +243,271 @@ On a Mac Book Pro (2.8 GHz Intel Core i7), the following results are collected.
|[`jayschema`](https://github.com/natesilva/jayschema)|0.1%|21 (± 1.14%)|
That is, RapidJSON is about 1.5x faster than the fastest JavaScript library (ajv). And 1400x faster than the slowest one.
+
+# Schema violation reporting {#Reporting}
+
+(Unreleased as of 2017-09-20)
+
+When validating an instance against a JSON Schema,
+it is often desirable to report not only whether the instance is valid,
+but also the ways in which it violates the schema.
+
+The `SchemaValidator` class
+collects errors encountered during validation
+into a JSON `Value`.
+This error object can then be accessed as `validator.GetError()`.
+
+The structure of the error object is subject to change
+in future versions of RapidJSON,
+as there is no standard schema for violations.
+The details below this point are provisional only.
+
+## General provisions {#ReportingGeneral}
+
+Validation of an instance value against a schema
+produces an error value.
+The error value is always an object.
+An empty object `{}` indicates the instance is valid.
+
+* The name of each member
+ corresponds to the JSON Schema keyword that is violated.
+* The value is either an object describing a single violation,
+ or an array of such objects.
+
+Each violation object contains two string-valued members
+named `instanceRef` and `schemaRef`.
+`instanceRef` contains the URI fragment serialization
+of a JSON Pointer to the instance subobject
+in which the violation was detected.
+`schemaRef` contains the URI of the schema
+and the fragment serialization of a JSON Pointer
+to the subschema that was violated.
+
+Individual violation objects can contain other keyword-specific members.
+These are detailed further.
+
+For example, validating this instance:
+
+~~~json
+{"numbers": [1, 2, "3", 4, 5]}
+~~~
+
+against this schema:
+
+~~~json
+{
+ "type": "object",
+ "properties": {
+ "numbers": {"$ref": "numbers.schema.json"}
+ }
+}
+~~~
+
+where `numbers.schema.json` refers
+(via a suitable `IRemoteSchemaDocumentProvider`)
+to this schema:
+
+~~~json
+{
+ "type": "array",
+ "items": {"type": "number"}
+}
+~~~
+
+produces the following error object:
+
+~~~json
+{
+ "type": {
+ "instanceRef": "#/numbers/2",
+ "schemaRef": "numbers.schema.json#/items",
+ "expected": ["number"],
+ "actual": "string"
+ }
+}
+~~~
+
+## Validation keywords for numbers {#Numbers}
+
+### multipleOf {#multipleof}
+
+* `expected`: required number strictly greater than 0.
+ The value of the `multipleOf` keyword specified in the schema.
+* `actual`: required number.
+ The instance value.
+
+### maximum {#maximum}
+
+* `expected`: required number.
+ The value of the `maximum` keyword specified in the schema.
+* `exclusiveMaximum`: optional boolean.
+ This will be true if the schema specified `"exclusiveMaximum": true`,
+ and will be omitted otherwise.
+* `actual`: required number.
+ The instance value.
+
+### minimum {#minimum}
+
+* `expected`: required number.
+ The value of the `minimum` keyword specified in the schema.
+* `exclusiveMinimum`: optional boolean.
+ This will be true if the schema specified `"exclusiveMinimum": true`,
+ and will be omitted otherwise.
+* `actual`: required number.
+ The instance value.
+
+## Validation keywords for strings {#Strings}
+
+### maxLength {#maxLength}
+
+* `expected`: required number greater than or equal to 0.
+ The value of the `maxLength` keyword specified in the schema.
+* `actual`: required string.
+ The instance value.
+
+### minLength {#minLength}
+
+* `expected`: required number greater than or equal to 0.
+ The value of the `minLength` keyword specified in the schema.
+* `actual`: required string.
+ The instance value.
+
+### pattern {#pattern}
+
+* `actual`: required string.
+ The instance value.
+
+(The expected pattern is not reported
+because the internal representation in `SchemaDocument`
+does not store the pattern in original string form.)
+
+## Validation keywords for arrays {#Arrays}
+
+### additionalItems {#additionalItems}
+
+This keyword is reported
+when the value of `items` schema keyword is an array,
+the value of `additionalItems` is `false`,
+and the instance is an array
+with more items than specified in the `items` array.
+
+* `disallowed`: required integer greater than or equal to 0.
+ The index of the first item that has no corresponding schema.
+
+### maxItems and minItems {#maxItems-minItems}
+
+* `expected`: required integer greater than or equal to 0.
+ The value of `maxItems` (respectively, `minItems`)
+ specified in the schema.
+* `actual`: required integer greater than or equal to 0.
+ Number of items in the instance array.
+
+### uniqueItems {#uniqueItems}
+
+* `duplicates`: required array
+ whose items are integers greater than or equal to 0.
+ Indices of items of the instance that are equal.
+
+(RapidJSON only reports the first two equal items,
+for performance reasons.)
+
+## Validation keywords for objects
+
+### maxProperties and minProperties {#maxProperties-minProperties}
+
+* `expected`: required integer greater than or equal to 0.
+ The value of `maxProperties` (respectively, `minProperties`)
+ specified in the schema.
+* `actual`: required integer greater than or equal to 0.
+ Number of properties in the instance object.
+
+### required {#required}
+
+* `missing`: required array of one or more unique strings.
+ The names of properties
+ that are listed in the value of the `required` schema keyword
+ but not present in the instance object.
+
+### additionalProperties {#additionalProperties}
+
+This keyword is reported
+when the schema specifies `additionalProperties: false`
+and the name of a property of the instance is
+neither listed in the `properties` keyword
+nor matches any regular expression in the `patternProperties` keyword.
+
+* `disallowed`: required string.
+ Name of the offending property of the instance.
+
+(For performance reasons,
+RapidJSON only reports the first such property encountered.)
+
+### dependencies {#dependencies}
+
+* `errors`: required object with one or more properties.
+ Names and values of its properties are described below.
+
+Recall that JSON Schema Draft 04 supports
+*schema dependencies*,
+where presence of a named *controlling* property
+requires the instance object to be valid against a subschema,
+and *property dependencies*,
+where presence of a controlling property
+requires other *dependent* properties to be also present.
+
+For a violated schema dependency,
+`errors` will contain a property
+with the name of the controlling property
+and its value will be the error object
+produced by validating the instance object
+against the dependent schema.
+
+For a violated property dependency,
+`errors` will contain a property
+with the name of the controlling property
+and its value will be an array of one or more unique strings
+listing the missing dependent properties.
+
+## Validation keywords for any instance type {#AnyTypes}
+
+### enum {#enum}
+
+This keyword has no additional properties
+beyond `instanceRef` and `schemaRef`.
+
+* The allowed values are not listed
+ because `SchemaDocument` does not store them in original form.
+* The violating value is not reported
+ because it might be unwieldy.
+
+If you need to report these details to your users,
+you can access the necessary information
+by following `instanceRef` and `schemaRef`.
+
+### type {#type}
+
+* `expected`: required array of one or more unique strings,
+ each of which is one of the seven primitive types
+ defined by the JSON Schema Draft 04 Core specification.
+ Lists the types allowed by the `type` schema keyword.
+* `actual`: required string, also one of seven primitive types.
+ The primitive type of the instance.
+
+### allOf, anyOf, and oneOf {#allOf-anyOf-oneOf}
+
+* `errors`: required array of at least one object.
+ There will be as many items as there are subschemas
+ in the `allOf`, `anyOf` or `oneOf` schema keyword, respectively.
+ Each item will be the error value
+ produced by validating the instance
+ against the corresponding subschema.
+
+For `allOf`, at least one error value will be non-empty.
+For `anyOf`, all error values will be non-empty.
+For `oneOf`, either all error values will be non-empty,
+or more than one will be empty.
+
+### not {#not}
+
+This keyword has no additional properties
+apart from `instanceRef` and `schemaRef`.
diff --git a/3rdparty/rapidjson/doc/schema.zh-cn.md b/3rdparty/rapidjson/doc/schema.zh-cn.md
index a01c1b10e1d..c85177f9fd0 100644
--- a/3rdparty/rapidjson/doc/schema.zh-cn.md
+++ b/3rdparty/rapidjson/doc/schema.zh-cn.md
@@ -8,7 +8,7 @@ RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/document
[TOC]
-## 基本用法
+# 基本用法 {#BasicUsage}
é¦–å…ˆï¼Œä½ è¦æŠŠ JSON Schema è§£æžæˆ `Document`ï¼Œå†æŠŠå®ƒç¼–è¯‘æˆä¸€ä¸ª `SchemaDocument`。
@@ -20,7 +20,7 @@ RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/document
// ...
Document sd;
-if (!sd.Parse(schemaJson).HasParseError()) {
+if (sd.Parse(schemaJson).HasParseError()) {
// æ­¤ schema 䏿˜¯åˆæ³•çš„ JSON
// ...
}
@@ -28,7 +28,7 @@ SchemaDocument schema(sd); // 把一个 Document 编译至 SchemaDocument
// 之åŽä¸å†éœ€è¦ sd
Document d;
-if (!d.Parse(inputJson).HasParseError()) {
+if (d.Parse(inputJson).HasParseError()) {
// è¾“å…¥ä¸æ˜¯ä¸€ä¸ªåˆæ³•çš„ JSON
// ...
}
@@ -52,11 +52,11 @@ if (!d.Accept(validator)) {
* 一个 `SchemaDocment` 能被多个 `SchemaValidator` 引用。它ä¸ä¼šè¢« `SchemaValidator` 修改。
* å¯ä»¥é‡å¤ä½¿ç”¨ä¸€ä¸ª `SchemaValidator` æ¥æ ¡éªŒå¤šä¸ªæ–‡ä»¶ã€‚在校验其他文件å‰ï¼Œé¡»å…ˆè°ƒç”¨ `validator.Reset()`。
-## 在解æžï¼ç”Ÿæˆæ—¶è¿›è¡Œæ ¡éªŒ
+# 在解æžï¼ç”Ÿæˆæ—¶è¿›è¡Œæ ¡éªŒ {#ParsingSerialization}
与大部分 JSON Schema 校验器有所ä¸åŒï¼ŒRapidJSON æä¾›äº†ä¸€ä¸ªåŸºäºŽ SAX çš„ schema 校验器实现。因此,你å¯ä»¥åœ¨è¾“å…¥æµè§£æž JSON çš„åŒæ—¶è¿›è¡Œæ ¡éªŒã€‚若校验器é‡åˆ°ä¸€ä¸ªä¸Ž schema ä¸ç¬¦çš„值,就会立å³ç»ˆæ­¢è§£æžã€‚这设计对于解æžå¤§åž‹ JSON 文件时特别有用。
-### DOM è§£æž
+## DOM è§£æž {#DomParsing}
在使用 DOM è¿›è¡Œè§£æžæ—¶ï¼Œ`Document` 除了接收 SAX 事件外,还需åšä¸€äº›å‡†å¤‡åŠç»“æŸå·¥ä½œï¼Œå› æ­¤ï¼Œä¸ºäº†è¿žæŽ¥ `Reader`ã€`SchemaValidator` å’Œ `Document` è¦åšå¤šä¸€ç‚¹äº‹æƒ…。`SchemaValidatingReader` 是一个辅助类去åšé‚£äº›å·¥ä½œã€‚
@@ -97,7 +97,7 @@ if (!reader.GetParseResult()) {
}
~~~
-### SAX è§£æž
+## SAX è§£æž {#SaxParsing}
使用 SAX è§£æžæ—¶ï¼Œæƒ…况就简å•得多。若åªéœ€è¦æ ¡éªŒ JSON 而无需进一步处ç†ï¼Œé‚£ä¹ˆä»…需è¦ï¼š
@@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) {
}
~~~
-### 生æˆ
+## ç”Ÿæˆ {#Serialization}
我们也å¯ä»¥åœ¨ç”Ÿæˆï¼ˆserialization)的时候进行校验。这能确ä¿è¾“出的 JSON 符åˆä¸€ä¸ª JSON Schema。
@@ -144,7 +144,7 @@ if (!d.Accept(validator)) {
å½“ç„¶ï¼Œå¦‚æžœä½ çš„åº”ç”¨ä»…éœ€è¦ SAX 风格的生æˆï¼Œé‚£ä¹ˆåªéœ€è¦æŠŠ SAX 事件由原æ¥å‘é€åˆ° `Writer`,改为å‘é€åˆ° `SchemaValidator`。
-## 远程 Schema
+# 远程 Schema {#RemoteSchema}
JSON Schema æ”¯æŒ [`$ref` 关键字](http://spacetelescope.github.io/understanding-json-schema/structuring.html),它是一个 [JSON pointer](doc/pointer.zh-cn.md) 引用至一个本地(local)或远程(remote) schema。本地指针的首字符是 `#`,而远程指针是一个相对或ç»å¯¹ URI。例如:
@@ -157,7 +157,7 @@ JSON Schema æ”¯æŒ [`$ref` 关键字](http://spacetelescope.github.io/understand
~~~
class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
public:
- virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeTyp length) {
+ virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) {
// Resolve the uri and returns a pointer to that schema.
}
};
@@ -168,7 +168,7 @@ MyRemoteSchemaDocumentProvider provider;
SchemaDocument schema(sd, &provider);
~~~
-## 标准的符åˆç¨‹åº¦
+# 标准的符åˆç¨‹åº¦ {#Conformance}
RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4) 中 263 个测试的 262 个。
@@ -176,7 +176,7 @@ RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON
除此以外,关于字符串类型的 `format` schema 关键字也会被忽略,因为标准中并没需求必须实现。
-### 正则表达å¼
+## æ­£åˆ™è¡¨è¾¾å¼ {#RegEx}
`pattern` åŠ `patternProperties` 这两个 schema 关键字使用了正则表达å¼åŽ»åŒ¹é…æ‰€éœ€çš„æ¨¡å¼ã€‚
@@ -185,7 +185,7 @@ RapidJSON 实现了一个简å•çš„ NFA 正则表达å¼å¼•擎,并预设使用ã€
|语法|æè¿°|
|------|-----------|
|`ab` | ä¸²è” |
-|`a|b` | 交替 |
+|<code>a&#124;b</code> | 交替 |
|`a?` | 零或一次 |
|`a*` | 零或多次 |
|`a+` | 一或多次 |
@@ -202,7 +202,7 @@ RapidJSON 实现了一个简å•çš„ NFA 正则表达å¼å¼•擎,并预设使用ã€
|`[^abc]` | 字符组å–å |
|`[^a-c]` | 字符组范围å–å |
|`[\b]` | 退格符 (U+0008) |
-|`\|`, `\\`, ... | 转义字符 |
+|<code>\\&#124;</code>, `\\`, ... | 转义字符 |
|`\f` | 馈页 (U+000C) |
|`\n` | 馈行 (U+000A) |
|`\r` | 回车 (U+000D) |
@@ -211,7 +211,7 @@ RapidJSON 实现了一个简å•çš„ NFA 正则表达å¼å¼•擎,并预设使用ã€
对于使用 C++11 编译器的使用者,也å¯ä½¿ç”¨ `std::regex`,åªéœ€å®šä¹‰ `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` åŠ `RAPIDJSON_SCHEMA_USE_STDREGEX=1`。若你的 schema 无需使用 `pattern` 或 `patternProperties`,å¯ä»¥æŠŠä¸¤ä¸ªå®éƒ½è®¾ä¸ºé›¶ï¼Œä»¥ç¦ç”¨æ­¤åŠŸèƒ½ï¼Œè¿™æ ·åšå¯èŠ‚çœä¸€äº›ä»£ç ä½“积。
-## 性能
+# 性能 {#Performance}
大部分 C++ JSON åº“éƒ½æœªæ”¯æŒ JSON Schema。因此我们å°è¯•按照 [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) 去评估 RapidJSON çš„ JSON Schema 校验器。该评测测试了 11 个è¿è¡Œåœ¨ node.js 上的 JavaScript 库。
diff --git a/3rdparty/rapidjson/doc/stream.md b/3rdparty/rapidjson/doc/stream.md
index b79ce537acd..5d0b0f35ee6 100644
--- a/3rdparty/rapidjson/doc/stream.md
+++ b/3rdparty/rapidjson/doc/stream.md
@@ -1,6 +1,6 @@
# Stream
-In RapidJSON, `rapidjson::Stream` is a concept for reading/writing JSON. Here we first show how to use streams provided. And then see how to create a custom stream.
+In RapidJSON, `rapidjson::Stream` is a concept for reading/writing JSON. Here we'll first show you how to use provided streams. And then see how to create a custom stream.
[TOC]
@@ -42,6 +42,7 @@ Note that, `StringStream` is a typedef of `GenericStringStream<UTF8<> >`, user m
~~~~~~~~~~cpp
#include "rapidjson/stringbuffer.h"
+#include <rapidjson/writer.h>
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
@@ -50,7 +51,7 @@ d.Accept(writer);
const char* output = buffer.GetString();
~~~~~~~~~~
-When the buffer is full, it will increases the capacity automatically. The default capacity is 256 characters (256 bytes for UTF8, 512 bytes for UTF16, etc.). User can provide an allocator and a initial capacity.
+When the buffer is full, it will increases the capacity automatically. The default capacity is 256 characters (256 bytes for UTF8, 512 bytes for UTF16, etc.). User can provide an allocator and an initial capacity.
~~~~~~~~~~cpp
StringBuffer buffer1(0, 1024); // Use its allocator, initial size = 1024
@@ -88,7 +89,7 @@ d.ParseStream(is);
fclose(fp);
~~~~~~~~~~
-Different from string streams, `FileReadStream` is byte stream. It does not handle encodings. If the file is not UTF-8, the byte stream can be wrapped in a `EncodedInputStream`. It will be discussed very soon.
+Different from string streams, `FileReadStream` is byte stream. It does not handle encodings. If the file is not UTF-8, the byte stream can be wrapped in a `EncodedInputStream`. We will discuss more about this later in this tutorial.
Apart from reading file, user can also use `FileReadStream` to read `stdin`.
@@ -98,6 +99,7 @@ Apart from reading file, user can also use `FileReadStream` to read `stdin`.
~~~~~~~~~~cpp
#include "rapidjson/filewritestream.h"
+#include <rapidjson/writer.h>
#include <cstdio>
using namespace rapidjson;
@@ -117,15 +119,15 @@ d.Accept(writer);
fclose(fp);
~~~~~~~~~~
-It can also directs the output to `stdout`.
+It can also redirect the output to `stdout`.
# iostream Wrapper {#iostreamWrapper}
-Due to users' requests, RapidJSON provided official wrappers for `std::basic_istream` and `std::basic_ostream`. However, please note that the performance will be much lower than the other streams above.
+Due to users' requests, RapidJSON also provides official wrappers for `std::basic_istream` and `std::basic_ostream`. However, please note that the performance will be much lower than the other streams above.
## IStreamWrapper {#IStreamWrapper}
-`IStreamWrapper` wraps any class drived from `std::istream`, such as `std::istringstream`, `std::stringstream`, `std::ifstream`, `std::fstream`, into RapidJSON's input stream.
+`IStreamWrapper` wraps any class derived from `std::istream`, such as `std::istringstream`, `std::stringstream`, `std::ifstream`, `std::fstream`, into RapidJSON's input stream.
~~~cpp
#include <rapidjson/document.h>
@@ -179,7 +181,7 @@ As mentioned above, UTF-8 byte streams can be read directly. However, UTF-16 and
Besides, it also need to handle [byte order mark (BOM)](http://en.wikipedia.org/wiki/Byte_order_mark). When reading from a byte stream, it is needed to detect or just consume the BOM if exists. When writing to a byte stream, it can optionally write BOM.
-If the encoding of stream is known in compile-time, you may use `EncodedInputStream` and `EncodedOutputStream`. If the stream can be UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE JSON, and it is only known in runtime, you may use `AutoUTFInputStream` and `AutoUTFOutputStream`. These streams are defined in `rapidjson/encodedstream.h`.
+If the encoding of stream is known during compile-time, you may use `EncodedInputStream` and `EncodedOutputStream`. If the stream can be UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE JSON, and it is only known in runtime, you may use `AutoUTFInputStream` and `AutoUTFOutputStream`. These streams are defined in `rapidjson/encodedstream.h`.
Note that, these encoded streams can be applied to streams other than file. For example, you may have a file in memory, or a custom byte stream, be wrapped in encoded streams.
@@ -215,6 +217,7 @@ fclose(fp);
~~~~~~~~~~cpp
#include "rapidjson/filewritestream.h" // FileWriteStream
#include "rapidjson/encodedstream.h" // EncodedOutputStream
+#include <rapidjson/writer.h>
#include <cstdio>
Document d; // Document is GenericDocument<UTF8<> >
@@ -228,7 +231,7 @@ FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
typedef EncodedOutputStream<UTF32LE<>, FileWriteStream> OutputStream;
OutputStream eos(bos, true); // Write BOM
-Writer<OutputStream, UTF32LE<>, UTF8<>> writer(eos);
+Writer<OutputStream, UTF8<>, UTF32LE<>> writer(eos);
d.Accept(writer); // This generates UTF32-LE file from UTF-8 in memory
fclose(fp);
diff --git a/3rdparty/rapidjson/doc/stream.zh-cn.md b/3rdparty/rapidjson/doc/stream.zh-cn.md
index f2c54f798ea..6e379bbd6b5 100644
--- a/3rdparty/rapidjson/doc/stream.zh-cn.md
+++ b/3rdparty/rapidjson/doc/stream.zh-cn.md
@@ -42,6 +42,7 @@ d.Parse(json);
~~~~~~~~~~cpp
#include "rapidjson/stringbuffer.h"
+#include <rapidjson/writer.h>
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
@@ -98,6 +99,7 @@ fclose(fp);
~~~~~~~~~~cpp
#include "rapidjson/filewritestream.h"
+#include <rapidjson/writer.h>
#include <cstdio>
using namespace rapidjson;
@@ -215,6 +217,7 @@ fclose(fp);
~~~~~~~~~~cpp
#include "rapidjson/filewritestream.h" // FileWriteStream
#include "rapidjson/encodedstream.h" // EncodedOutputStream
+#include <rapidjson/writer.h>
#include <cstdio>
Document d; // Document 为 GenericDocument<UTF8<> >
@@ -228,7 +231,7 @@ FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
typedef EncodedOutputStream<UTF32LE<>, FileWriteStream> OutputStream;
OutputStream eos(bos, true); // 写入 BOM
-Writer<OutputStream, UTF32LE<>, UTF8<>> writer(eos);
+Writer<OutputStream, UTF8<>, UTF32LE<>> writer(eos);
d.Accept(writer); // 这里从内存的 UTF-8 ç”Ÿæˆ UTF32-LE 文件
fclose(fp);
diff --git a/3rdparty/rapidjson/doc/tutorial.md b/3rdparty/rapidjson/doc/tutorial.md
index cb76b4b0b78..a86aafdfc03 100644
--- a/3rdparty/rapidjson/doc/tutorial.md
+++ b/3rdparty/rapidjson/doc/tutorial.md
@@ -2,7 +2,7 @@
This tutorial introduces the basics of the Document Object Model(DOM) API.
-As shown in [Usage at a glance](@ref index), a JSON can be parsed into DOM, and then the DOM can be queried and modified easily, and finally be converted back to JSON.
+As shown in [Usage at a glance](@ref index), JSON can be parsed into a DOM, and then the DOM can be queried and modified easily, and finally be converted back to JSON.
[TOC]
@@ -12,9 +12,9 @@ Each JSON value is stored in a type called `Value`. A `Document`, representing t
# Query Value {#QueryValue}
-In this section, we will use excerpt of `example/tutorial/tutorial.cpp`.
+In this section, we will use excerpt from `example/tutorial/tutorial.cpp`.
-Assumes we have a JSON stored in a C string (`const char* json`):
+Assume we have the following JSON stored in a C string (`const char* json`):
~~~~~~~~~~js
{
"hello": "world",
@@ -55,7 +55,7 @@ printf("hello = %s\n", document["hello"].GetString());
~~~~~~~~~~
~~~~~~~~~~
-world
+hello = world
~~~~~~~~~~
JSON true/false values are represented as `bool`.
@@ -65,16 +65,16 @@ printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
~~~~~~~~~~
~~~~~~~~~~
-true
+t = true
~~~~~~~~~~
-JSON null can be queryed by `IsNull()`.
+JSON null can be queried with `IsNull()`.
~~~~~~~~~~cpp
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
~~~~~~~~~~
~~~~~~~~~~
-null
+n = null
~~~~~~~~~~
JSON number type represents all numeric values. However, C++ needs more specific type for manipulation.
@@ -82,10 +82,10 @@ JSON number type represents all numeric values. However, C++ needs more specific
~~~~~~~~~~cpp
assert(document["i"].IsNumber());
-// In this case, IsUint()/IsInt64()/IsUInt64() also return true.
+// In this case, IsUint()/IsInt64()/IsUint64() also return true.
assert(document["i"].IsInt());
printf("i = %d\n", document["i"].GetInt());
-// Alternative (int)document["i"]
+// Alternatively (int)document["i"]
assert(document["pi"].IsNumber());
assert(document["pi"].IsDouble());
@@ -113,17 +113,17 @@ a[2] = 3
a[3] = 4
~~~~~~~~~~
-Note that, RapidJSON does not automatically convert values between JSON types. If a value is a string, it is invalid to call `GetInt()`, for example. In debug mode it will fail an assertion. In release mode, the behavior is undefined.
+Note that, RapidJSON does not automatically convert values between JSON types. For example, if a value is a string, it is invalid to call `GetInt()`. In debug mode it will fail on assertion. In release mode, the behavior is undefined.
-In the following, details about querying individual types are discussed.
+In the following sections we discuss details about querying individual types.
## Query Array {#QueryArray}
-By default, `SizeType` is typedef of `unsigned`. In most systems, array is limited to store up to 2^32-1 elements.
+By default, `SizeType` is typedef of `unsigned`. In most systems, an array is limited to store up to 2^32-1 elements.
-You may access the elements in array by integer literal, for example, `a[0]`, `a[1]`, `a[2]`.
+You may access the elements in an array by integer literal, for example, `a[0]`, `a[1]`, `a[2]`.
-Array is similar to `std::vector`, instead of using indices, you may also use iterator to access all the elements.
+Array is similar to `std::vector`: instead of using indices, you may also use iterator to access all the elements.
~~~~~~~~~~cpp
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
printf("%d ", itr->GetInt());
@@ -144,7 +144,7 @@ for (auto& v : a.GetArray())
## Query Object {#QueryObject}
-Similar to array, we can access all object members by iterator:
+Similar to Array, we can access all object members by iterator:
~~~~~~~~~~cpp
static const char* kTypeNames[] =
@@ -168,9 +168,9 @@ Type of member pi is Number
Type of member a is Array
~~~~~~~~~~
-Note that, when `operator[](const char*)` cannot find the member, it will fail an assertion.
+Note that, when `operator[](const char*)` cannot find the member, it will fail on assertion.
-If we are unsure whether a member exists, we need to call `HasMember()` before calling `operator[](const char*)`. However, this incurs two lookup. A better way is to call `FindMember()`, which can check the existence of member and obtain its value at once:
+If we are unsure whether a member exists, we need to call `HasMember()` before calling `operator[](const char*)`. However, this incurs two lookup. A better way is to call `FindMember()`, which can check the existence of a member and obtain its value at once:
~~~~~~~~~~cpp
Value::ConstMemberIterator itr = document.FindMember("hello");
@@ -190,11 +190,11 @@ for (auto& m : document.GetObject())
## Querying Number {#QueryNumber}
-JSON provide a single numerical type called Number. Number can be integer or real numbers. RFC 4627 says the range of Number is specified by parser.
+JSON provides a single numerical type called Number. Number can be an integer or a real number. RFC 4627 says the range of Number is specified by the parser implementation.
-As C++ provides several integer and floating point number types, the DOM tries to handle these with widest possible range and good performance.
+As C++ provides several integer and floating point number types, the DOM tries to handle these with the widest possible range and good performance.
-When a Number is parsed, it is stored in the DOM as either one of the following type:
+When a Number is parsed, it is stored in the DOM as one of the following types:
Type | Description
-----------|---------------------------------------
@@ -204,7 +204,7 @@ Type | Description
`int64_t` | 64-bit signed integer
`double` | 64-bit double precision floating point
-When querying a number, you can check whether the number can be obtained as target type:
+When querying a number, you can check whether the number can be obtained as the target type:
Checking | Obtaining
------------------|---------------------
@@ -215,24 +215,24 @@ Checking | Obtaining
`bool IsInt64()` | `int64_t GetInt64()`
`bool IsDouble()` | `double GetDouble()`
-Note that, an integer value may be obtained in various ways without conversion. For example, A value `x` containing 123 will make `x.IsInt() == x.IsUint() == x.IsInt64() == x.IsUint64() == true`. But a value `y` containing -3000000000 will only makes `x.IsInt64() == true`.
+Note that, an integer value may be obtained in various ways without conversion. For example, A value `x` containing 123 will make `x.IsInt() == x.IsUint() == x.IsInt64() == x.IsUint64() == true`. But a value `y` containing -3000000000 will only make `x.IsInt64() == true`.
-When obtaining the numeric values, `GetDouble()` will convert internal integer representation to a `double`. Note that, `int` and `unsigned` can be safely convert to `double`, but `int64_t` and `uint64_t` may lose precision (since mantissa of `double` is only 52-bits).
+When obtaining the numeric values, `GetDouble()` will convert internal integer representation to a `double`. Note that, `int` and `unsigned` can be safely converted to `double`, but `int64_t` and `uint64_t` may lose precision (since mantissa of `double` is only 52-bits).
## Query String {#QueryString}
-In addition to `GetString()`, the `Value` class also contains `GetStringLength()`. Here explains why.
+In addition to `GetString()`, the `Value` class also contains `GetStringLength()`. Here explains why:
-According to RFC 4627, JSON strings can contain Unicode character `U+0000`, which must be escaped as `"\u0000"`. The problem is that, C/C++ often uses null-terminated string, which treats ``\0'` as the terminator symbol.
+According to RFC 4627, JSON strings can contain Unicode character `U+0000`, which must be escaped as `"\u0000"`. The problem is that, C/C++ often uses null-terminated string, which treats `\0` as the terminator symbol.
-To conform RFC 4627, RapidJSON supports string containing `U+0000`. If you need to handle this, you can use `GetStringLength()` API to obtain the correct length of string.
+To conform with RFC 4627, RapidJSON supports string containing `U+0000` character. If you need to handle this, you can use `GetStringLength()` to obtain the correct string length.
-For example, after parsing a the following JSON to `Document d`:
+For example, after parsing the following JSON to `Document d`:
~~~~~~~~~~js
{ "s" : "a\u0000b" }
~~~~~~~~~~
-The correct length of the value `"a\u0000b"` is 3. But `strlen()` returns 1.
+The correct length of the string `"a\u0000b"` is 3, as returned by `GetStringLength()`. But `strlen()` returns 1.
`GetStringLength()` can also improve performance, as user may often need to call `strlen()` for allocating buffer.
@@ -246,7 +246,7 @@ which accepts the length of string as parameter. This constructor supports stori
## Comparing values
-You can use `==` and `!=` to compare values. Two values are equal if and only if they are have same type and contents. You can also compare values with primitive types. Here is an example.
+You can use `==` and `!=` to compare values. Two values are equal if and only if they have same type and contents. You can also compare values with primitive types. Here is an example:
~~~~~~~~~~cpp
if (document["hello"] == document["n"]) /*...*/; // Compare values
@@ -264,7 +264,7 @@ Note that, currently if an object contains duplicated named member, comparing eq
There are several ways to create values. After a DOM tree is created and/or modified, it can be saved as JSON again using `Writer`.
## Change Value Type {#ChangeValueType}
-When creating a Value or Document by default constructor, its type is Null. To change its type, call `SetXXX()` or assignment operator, for example:
+When creating a `Value` or `Document` by default constructor, its type is Null. To change its type, call `SetXXX()` or assignment operator, for example:
~~~~~~~~~~cpp
Document d; // Null
@@ -285,7 +285,7 @@ Value u(123u); // calls Value(unsigned)
Value d(1.5); // calls Value(double)
~~~~~~~~~~
-To create empty object or array, you may use `SetObject()`/`SetArray()` after default constructor, or using the `Value(Type)` in one shot:
+To create empty object or array, you may use `SetObject()`/`SetArray()` after default constructor, or using the `Value(Type)` in one call:
~~~~~~~~~~cpp
Value o(kObjectType);
@@ -299,7 +299,7 @@ A very special decision during design of RapidJSON is that, assignment of value
~~~~~~~~~~cpp
Value a(123);
Value b(456);
-b = a; // a becomes a Null value, b becomes number 123.
+a = b; // b becomes a Null value, a becomes number 456.
~~~~~~~~~~
![Assignment with move semantics.](diagram/move1.png)
@@ -360,14 +360,14 @@ a.PushBack(Value(42).Move(), allocator); // same as above
~~~~~~~~~~
## Create String {#CreateString}
-RapidJSON provide two strategies for storing string.
+RapidJSON provides two strategies for storing string.
1. copy-string: allocates a buffer, and then copy the source data into it.
2. const-string: simply store a pointer of string.
-Copy-string is always safe because it owns a copy of the data. Const-string can be used for storing string literal, and in-situ parsing which we will mentioned in Document section.
+Copy-string is always safe because it owns a copy of the data. Const-string can be used for storing a string literal, and for in-situ parsing which will be mentioned in the DOM section.
-To make memory allocation customizable, RapidJSON requires user to pass an instance of allocator, whenever an operation may require allocation. This design is needed to prevent storing a allocator (or Document) pointer per Value.
+To make memory allocation customizable, RapidJSON requires users to pass an instance of allocator, whenever an operation may require allocation. This design is needed to prevent storing an allocator (or Document) pointer per Value.
Therefore, when we assign a copy-string, we call this overloaded `SetString()` with allocator:
@@ -385,7 +385,7 @@ In this example, we get the allocator from a `Document` instance. This is a comm
Besides, the above `SetString()` requires length. This can handle null characters within a string. There is another `SetString()` overloaded function without the length parameter. And it assumes the input is null-terminated and calls a `strlen()`-like function to obtain the length.
-Finally, for string literal or string with safe life-cycle can use const-string version of `SetString()`, which lacks allocator parameter. For string literals (or constant character arrays), simply passing the literal as parameter is safe and efficient:
+Finally, for a string literal or string with a safe life-cycle one can use the const-string version of `SetString()`, which lacks an allocator parameter. For string literals (or constant character arrays), simply passing the literal as parameter is safe and efficient:
~~~~~~~~~~cpp
Value s;
@@ -393,7 +393,7 @@ s.SetString("rapidjson"); // can contain null character, length derived at co
s = "rapidjson"; // shortcut, same as above
~~~~~~~~~~
-For character pointer, the RapidJSON requires to mark it as safe before using it without copying. This can be achieved by using the `StringRef` function:
+For a character pointer, RapidJSON requires it to be marked as safe before using it without copying. This can be achieved by using the `StringRef` function:
~~~~~~~~~cpp
const char * cstr = getenv("USER");
@@ -408,7 +408,7 @@ s = StringRef(cstr,cstr_len); // shortcut, same as above
~~~~~~~~~
## Modify Array {#ModifyArray}
-Value with array type provides similar APIs as `std::vector`.
+Value with array type provides an API similar to `std::vector`.
* `Clear()`
* `Reserve(SizeType, Allocator&)`
@@ -418,7 +418,7 @@ Value with array type provides similar APIs as `std::vector`.
* `ValueIterator Erase(ConstValueIterator pos)`
* `ValueIterator Erase(ConstValueIterator first, ConstValueIterator last)`
-Note that, `Reserve(...)` and `PushBack(...)` may allocate memory for the array elements, therefore require an allocator.
+Note that, `Reserve(...)` and `PushBack(...)` may allocate memory for the array elements, therefore requiring an allocator.
Here is an example of `PushBack()`:
@@ -433,7 +433,7 @@ for (int i = 5; i <= 10; i++)
a.PushBack("Lua", allocator).PushBack("Mio", allocator);
~~~~~~~~~~
-Differs from STL, `PushBack()`/`PopBack()` returns the array reference itself. This is called _fluent interface_.
+This API differs from STL in that `PushBack()`/`PopBack()` return the array reference itself. This is called _fluent interface_.
If you want to add a non-constant string or a string without sufficient lifetime (see [Create String](#CreateString)) to the array, you need to create a string Value by using the copy-string API. To avoid the need for an intermediate variable, you can use a [temporary value](#TemporaryValues) in place:
@@ -448,7 +448,7 @@ contact.PushBack(val, document.GetAllocator());
~~~~~~~~~~
## Modify Object {#ModifyObject}
-Object is a collection of key-value pairs (members). Each key must be a string value. To modify an object, either add or remove members. THe following APIs are for adding members:
+The Object class is a collection of key-value pairs (members). Each key must be a string value. To modify an object, either add or remove members. The following API is for adding members:
* `Value& AddMember(Value&, Value&, Allocator& allocator)`
* `Value& AddMember(StringRefType, Value&, Allocator&)`
@@ -462,7 +462,7 @@ contact.AddMember("name", "Milo", document.GetAllocator());
contact.AddMember("married", true, document.GetAllocator());
~~~~~~~~~~
-The name parameter with `StringRefType` is similar to the interface of `SetString` function for string values. These overloads are used to avoid the need for copying the `name` string, as constant key names are very common in JSON objects.
+The name parameter with `StringRefType` is similar to the interface of the `SetString` function for string values. These overloads are used to avoid the need for copying the `name` string, since constant key names are very common in JSON objects.
If you need to create a name from a non-constant string or a string without sufficient lifetime (see [Create String](#CreateString)), you need to create a string Value by using the copy-string API. To avoid the need for an intermediate variable, you can use a [temporary value](#TemporaryValues) in place:
diff --git a/3rdparty/rapidjson/doc/tutorial.zh-cn.md b/3rdparty/rapidjson/doc/tutorial.zh-cn.md
index 61fb0b24399..8b24ff11f6f 100644
--- a/3rdparty/rapidjson/doc/tutorial.zh-cn.md
+++ b/3rdparty/rapidjson/doc/tutorial.zh-cn.md
@@ -82,7 +82,7 @@ JSON Number 类型表示所有数值。然而,C++ 需è¦ä½¿ç”¨æ›´ä¸“门的类å
~~~~~~~~~~cpp
assert(document["i"].IsNumber());
-// 在此情况下,IsUint()/IsInt64()/IsUInt64() 也会返回 true
+// 在此情况下,IsUint()/IsInt64()/IsUint64() 也会返回 true
assert(document["i"].IsInt());
printf("i = %d\n", document["i"].GetInt());
// å¦ä¸€ç§ç”¨æ³•: (int)document["i"]
@@ -250,7 +250,7 @@ string(const char* s, size_t count);
~~~~~~~~~~cpp
if (document["hello"] == document["n"]) /*...*/; // 比较两个值
-if (document["hello"] == "world") /*...*/; // 与字符串家é¢é‡ä½œæ¯”较
+if (document["hello"] == "world") /*...*/; // 与字符串字é¢é‡ä½œæ¯”较
if (document["i"] != 123) /*...*/; // 与整数作比较
if (document["pi"] != 3.14) /*...*/; // 与 double 作比较
~~~~~~~~~~
@@ -292,9 +292,9 @@ Value o(kObjectType);
Value a(kArrayType);
~~~~~~~~~~
-## 转移语æ„(Move Semantics) {#MoveSemantics}
+## 转移语义(Move Semantics) {#MoveSemantics}
-在设计 RapidJSON 时有一个éžå¸¸ç‰¹åˆ«çš„决定,就是 Value èµ‹å€¼å¹¶ä¸æ˜¯æŠŠæ¥æº Value å¤åˆ¶è‡³ç›®çš„ Valueï¼Œè€Œæ˜¯æŠŠæŠŠæ¥æº Value 转移(move)至目的 Value。例如:
+在设计 RapidJSON 时有一个éžå¸¸ç‰¹åˆ«çš„决定,就是 Value èµ‹å€¼å¹¶ä¸æ˜¯æŠŠæ¥æº Value å¤åˆ¶è‡³ç›®çš„ Valueï¼Œè€Œæ˜¯æŠŠæ¥æº Value 转移(move)至目的 Value。例如:
~~~~~~~~~~cpp
Value a(123);
@@ -302,13 +302,13 @@ Value b(456);
b = a; // a å˜æˆ Null,b å˜æˆæ•°å­— 123。
~~~~~~~~~~
-![使用移动语æ„赋值。](diagram/move1.png)
+![使用移动语义赋值。](diagram/move1.png)
-ä¸ºä»€ä¹ˆï¼Ÿæ­¤è¯­æ„æœ‰ä½•优点?
+为什么?此语义有何优点?
最简å•的答案就是性能。对于固定大å°çš„ JSON 类型(Numberã€Trueã€Falseã€Null),å¤åˆ¶å®ƒä»¬æ˜¯ç®€å•å¿«æ·ã€‚然而,对于å¯å˜å¤§å°çš„ JSON 类型(Stringã€Arrayã€Object),å¤åˆ¶å®ƒä»¬ä¼šäº§ç”Ÿå¤§é‡å¼€é”€ï¼Œè€Œä¸”这些开销常常ä¸è¢«å¯Ÿè§‰ã€‚尤其是当我们需è¦åˆ›å»ºä¸´æ—¶ Object,把它å¤åˆ¶è‡³å¦ä¸€å˜é‡ï¼Œç„¶åŽå†æžæž„它。
-例如,若使用正常 * å¤åˆ¶ * 语æ„:
+例如,若使用正常 * å¤åˆ¶ * 语义:
~~~~~~~~~~cpp
Value o(kObjectType);
@@ -321,15 +321,15 @@ Value o(kObjectType);
}
~~~~~~~~~~
-![å¤åˆ¶è¯­æ„产生大é‡çš„å¤åˆ¶æ“作。](diagram/move2.png)
+![å¤åˆ¶è¯­ä¹‰äº§ç”Ÿå¤§é‡çš„å¤åˆ¶æ“作。](diagram/move2.png)
那个 `o` Object 需è¦åˆ†é…一个和 contacts 相åŒå¤§å°çš„缓冲区,对 conacts åšæ·±åº¦å¤åˆ¶ï¼Œå¹¶æœ€ç»ˆè¦æžæž„ contactsã€‚è¿™æ ·ä¼šäº§ç”Ÿå¤§é‡æ— å¿…è¦çš„内存分é…ï¼é‡Šæ”¾ï¼Œä»¥åŠå†…å­˜å¤åˆ¶ã€‚
有一些方案å¯é¿å…实质地å¤åˆ¶è¿™äº›æ•°æ®ï¼Œä¾‹å¦‚引用计数(reference counting)ã€åžƒåœ¾å›žæ”¶ï¼ˆgarbage collection, GC)。
-为了使 RapidJSON 简å•åŠå¿«é€Ÿï¼Œæˆ‘们选择了对赋值采用 * 转移 * 语æ„。这方法与 `std::auto_ptr` 相似,都是在赋值时转移拥有æƒã€‚转移快得多简å•得多,åªéœ€è¦æžæž„原æ¥çš„ Valueï¼ŒæŠŠæ¥æº `memcpy()` è‡³ç›®æ ‡ï¼Œæœ€åŽæŠŠæ¥æºè®¾ç½®ä¸º Null 类型。
+为了使 RapidJSON 简å•åŠå¿«é€Ÿï¼Œæˆ‘们选择了对赋值采用 * 转移 * 语义。这方法与 `std::auto_ptr` 相似,都是在赋值时转移拥有æƒã€‚转移快得多简å•得多,åªéœ€è¦æžæž„原æ¥çš„ Valueï¼ŒæŠŠæ¥æº `memcpy()` è‡³ç›®æ ‡ï¼Œæœ€åŽæŠŠæ¥æºè®¾ç½®ä¸º Null 类型。
-因此,使用转移语æ„åŽï¼Œä¸Šé¢çš„例å­å˜æˆï¼š
+因此,使用转移语义åŽï¼Œä¸Šé¢çš„例å­å˜æˆï¼š
~~~~~~~~~~cpp
Value o(kObjectType);
@@ -341,11 +341,11 @@ Value o(kObjectType);
}
~~~~~~~~~~
-![转移语æ„ä¸éœ€å¤åˆ¶ã€‚](diagram/move3.png)
+![转移语义ä¸éœ€å¤åˆ¶ã€‚](diagram/move3.png)
-在 C++11 中这称为转移赋值æ“作(move assignment operator)。由于 RapidJSON æ”¯æŒ C++03,它在赋值æ“作采用转移语æ„,其它修改形函数如 `AddMember()`, `PushBack()` 也采用转移语æ„。
+在 C++11 中这称为转移赋值æ“作(move assignment operator)。由于 RapidJSON æ”¯æŒ C++03,它在赋值æ“作采用转移语义,其它修改型函数如 `AddMember()`, `PushBack()` 也采用转移语义。
-### 转移语æ„åŠä¸´æ—¶å€¼ {#TemporaryValues}
+### 转移语义åŠä¸´æ—¶å€¼ {#TemporaryValues}
有时候,我们想直接构造一个 Value 并传递给一个“转移â€å‡½æ•°ï¼ˆå¦‚ `PushBack()`ã€`AddMember()`)。由于临时对象是ä¸èƒ½è½¬æ¢ä¸ºæ­£å¸¸çš„ Value 引用,我们加入了一个方便的 `Move()` 函数:
@@ -383,11 +383,12 @@ memset(buffer, 0, sizeof(buffer));
å¦å¤–,上é¢çš„ `SetString()` 需è¦é•¿åº¦å‚数。这个 API 能处ç†å«æœ‰ç©ºå­—符的字符串。å¦ä¸€ä¸ª `SetString()` é‡è½½å‡½æ•°æ²¡æœ‰é•¿åº¦å‚数,它å‡è®¾è¾“入是空字符结尾的,并会调用类似 `strlen()` 的函数去获å–长度。
-最åŽï¼Œå¯¹äºŽå­—符串字é¢é‡æˆ–有安全生命周期的字符串,å¯ä»¥ä½¿ç”¨ const-string 版本的 `SetString()`,它没有 allocator 傿•°ã€‚对于字符串家é¢é‡ï¼ˆæˆ–字符数组常é‡ï¼‰ï¼Œåªéœ€ç®€å•地传递字é¢é‡ï¼Œåˆå®‰å…¨åˆé«˜æ•ˆï¼š
+最åŽï¼Œå¯¹äºŽå­—符串字é¢é‡æˆ–有安全生命周期的字符串,å¯ä»¥ä½¿ç”¨ const-string 版本的 `SetString()`,它没有
+allocator 傿•°ã€‚对于字符串字é¢é‡ï¼ˆæˆ–字符数组常é‡ï¼‰ï¼Œåªéœ€ç®€å•地传递字é¢é‡ï¼Œåˆå®‰å…¨åˆé«˜æ•ˆï¼š
~~~~~~~~~~cpp
Value s;
-s.SetString("rapidjson"); // å¯åŒ…å«ç©ºå­—ç¬¦ï¼Œé•¿åº¦åœ¨ç¼–è¯‘èæŽ¨å¯¼
+s.SetString("rapidjson"); // å¯åŒ…å«ç©ºå­—符,长度在编译期推导
s = "rapidjson"; // 上行的缩写
~~~~~~~~~~
@@ -446,7 +447,7 @@ contact.PushBack(val, document.GetAllocator());
~~~~~~~~~~
## 修改 Object {#ModifyObject}
-Object 是键值对的集åˆã€‚æ¯ä¸ªé”®å¿…须为 String。è¦ä¿®æ”¹ Object,方法是增加或移除æˆå‘˜ã€‚以下的 API 用æ¥å¢žåŠ åŸŽå‘˜ï¼š
+Object 是键值对的集åˆã€‚æ¯ä¸ªé”®å¿…须为 String。è¦ä¿®æ”¹ Object,方法是增加或移除æˆå‘˜ã€‚以下的 API 用æ¥å¢žåŠ æˆå‘˜ï¼š
* `Value& AddMember(Value&, Value&, Allocator& allocator)`
* `Value& AddMember(StringRefType, Value&, Allocator&)`
diff --git a/3rdparty/rapidjson/example/CMakeLists.txt b/3rdparty/rapidjson/example/CMakeLists.txt
index 4d448ccc0f4..9f53c9aadc6 100644
--- a/3rdparty/rapidjson/example/CMakeLists.txt
+++ b/3rdparty/rapidjson/example/CMakeLists.txt
@@ -10,6 +10,7 @@ set(EXAMPLES
filterkey
filterkeydom
jsonx
+ lookaheadparser
messagereader
parsebyparts
pretty
@@ -18,19 +19,22 @@ set(EXAMPLES
serialize
simpledom
simplereader
+ simplepullreader
simplewriter
+ sortkeys
tutorial)
include_directories("../include/")
add_definitions(-D__STDC_FORMAT_MACROS)
+set_property(DIRECTORY PROPERTY COMPILE_OPTIONS ${EXTRA_CXX_FLAGS})
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -Werror -Wall -Wextra -Weffc++ -Wswitch-default")
-elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()
+add_executable(archivertest archiver/archiver.cpp archiver/archivertest.cpp)
+
foreach (example ${EXAMPLES})
add_executable(${example} ${example}/${example}.cpp)
endforeach()
diff --git a/3rdparty/rapidjson/example/archiver/archiver.cpp b/3rdparty/rapidjson/example/archiver/archiver.cpp
new file mode 100644
index 00000000000..59ae4c41016
--- /dev/null
+++ b/3rdparty/rapidjson/example/archiver/archiver.cpp
@@ -0,0 +1,292 @@
+#include "archiver.h"
+#include <cassert>
+#include <stack>
+#include "rapidjson/document.h"
+#include "rapidjson/prettywriter.h"
+#include "rapidjson/stringbuffer.h"
+
+using namespace rapidjson;
+
+struct JsonReaderStackItem {
+ enum State {
+ BeforeStart, //!< An object/array is in the stack but it is not yet called by StartObject()/StartArray().
+ Started, //!< An object/array is called by StartObject()/StartArray().
+ Closed //!< An array is closed after read all element, but before EndArray().
+ };
+
+ JsonReaderStackItem(const Value* value, State state) : value(value), state(state), index() {}
+
+ const Value* value;
+ State state;
+ SizeType index; // For array iteration
+};
+
+typedef std::stack<JsonReaderStackItem> JsonReaderStack;
+
+#define DOCUMENT reinterpret_cast<Document*>(mDocument)
+#define STACK (reinterpret_cast<JsonReaderStack*>(mStack))
+#define TOP (STACK->top())
+#define CURRENT (*TOP.value)
+
+JsonReader::JsonReader(const char* json) : mDocument(), mStack(), mError(false) {
+ mDocument = new Document;
+ DOCUMENT->Parse(json);
+ if (DOCUMENT->HasParseError())
+ mError = true;
+ else {
+ mStack = new JsonReaderStack;
+ STACK->push(JsonReaderStackItem(DOCUMENT, JsonReaderStackItem::BeforeStart));
+ }
+}
+
+JsonReader::~JsonReader() {
+ delete DOCUMENT;
+ delete STACK;
+}
+
+// Archive concept
+JsonReader& JsonReader::StartObject() {
+ if (!mError) {
+ if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::BeforeStart)
+ TOP.state = JsonReaderStackItem::Started;
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::EndObject() {
+ if (!mError) {
+ if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started)
+ Next();
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::Member(const char* name) {
+ if (!mError) {
+ if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started) {
+ Value::ConstMemberIterator memberItr = CURRENT.FindMember(name);
+ if (memberItr != CURRENT.MemberEnd())
+ STACK->push(JsonReaderStackItem(&memberItr->value, JsonReaderStackItem::BeforeStart));
+ else
+ mError = true;
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+bool JsonReader::HasMember(const char* name) const {
+ if (!mError && CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started)
+ return CURRENT.HasMember(name);
+ return false;
+}
+
+JsonReader& JsonReader::StartArray(size_t* size) {
+ if (!mError) {
+ if (CURRENT.IsArray() && TOP.state == JsonReaderStackItem::BeforeStart) {
+ TOP.state = JsonReaderStackItem::Started;
+ if (size)
+ *size = CURRENT.Size();
+
+ if (!CURRENT.Empty()) {
+ const Value* value = &CURRENT[TOP.index];
+ STACK->push(JsonReaderStackItem(value, JsonReaderStackItem::BeforeStart));
+ }
+ else
+ TOP.state = JsonReaderStackItem::Closed;
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::EndArray() {
+ if (!mError) {
+ if (CURRENT.IsArray() && TOP.state == JsonReaderStackItem::Closed)
+ Next();
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::operator&(bool& b) {
+ if (!mError) {
+ if (CURRENT.IsBool()) {
+ b = CURRENT.GetBool();
+ Next();
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::operator&(unsigned& u) {
+ if (!mError) {
+ if (CURRENT.IsUint()) {
+ u = CURRENT.GetUint();
+ Next();
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::operator&(int& i) {
+ if (!mError) {
+ if (CURRENT.IsInt()) {
+ i = CURRENT.GetInt();
+ Next();
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::operator&(double& d) {
+ if (!mError) {
+ if (CURRENT.IsNumber()) {
+ d = CURRENT.GetDouble();
+ Next();
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::operator&(std::string& s) {
+ if (!mError) {
+ if (CURRENT.IsString()) {
+ s = CURRENT.GetString();
+ Next();
+ }
+ else
+ mError = true;
+ }
+ return *this;
+}
+
+JsonReader& JsonReader::SetNull() {
+ // This function is for JsonWriter only.
+ mError = true;
+ return *this;
+}
+
+void JsonReader::Next() {
+ if (!mError) {
+ assert(!STACK->empty());
+ STACK->pop();
+
+ if (!STACK->empty() && CURRENT.IsArray()) {
+ if (TOP.state == JsonReaderStackItem::Started) { // Otherwise means reading array item pass end
+ if (TOP.index < CURRENT.Size() - 1) {
+ const Value* value = &CURRENT[++TOP.index];
+ STACK->push(JsonReaderStackItem(value, JsonReaderStackItem::BeforeStart));
+ }
+ else
+ TOP.state = JsonReaderStackItem::Closed;
+ }
+ else
+ mError = true;
+ }
+ }
+}
+
+#undef DOCUMENT
+#undef STACK
+#undef TOP
+#undef CURRENT
+
+////////////////////////////////////////////////////////////////////////////////
+// JsonWriter
+
+#define WRITER reinterpret_cast<PrettyWriter<StringBuffer>*>(mWriter)
+#define STREAM reinterpret_cast<StringBuffer*>(mStream)
+
+JsonWriter::JsonWriter() : mWriter(), mStream() {
+ mStream = new StringBuffer;
+ mWriter = new PrettyWriter<StringBuffer>(*STREAM);
+}
+
+JsonWriter::~JsonWriter() {
+ delete WRITER;
+ delete STREAM;
+}
+
+const char* JsonWriter::GetString() const {
+ return STREAM->GetString();
+}
+
+JsonWriter& JsonWriter::StartObject() {
+ WRITER->StartObject();
+ return *this;
+}
+
+JsonWriter& JsonWriter::EndObject() {
+ WRITER->EndObject();
+ return *this;
+}
+
+JsonWriter& JsonWriter::Member(const char* name) {
+ WRITER->String(name, static_cast<SizeType>(strlen(name)));
+ return *this;
+}
+
+bool JsonWriter::HasMember(const char*) const {
+ // This function is for JsonReader only.
+ assert(false);
+ return false;
+}
+
+JsonWriter& JsonWriter::StartArray(size_t*) {
+ WRITER->StartArray();
+ return *this;
+}
+
+JsonWriter& JsonWriter::EndArray() {
+ WRITER->EndArray();
+ return *this;
+}
+
+JsonWriter& JsonWriter::operator&(bool& b) {
+ WRITER->Bool(b);
+ return *this;
+}
+
+JsonWriter& JsonWriter::operator&(unsigned& u) {
+ WRITER->Uint(u);
+ return *this;
+}
+
+JsonWriter& JsonWriter::operator&(int& i) {
+ WRITER->Int(i);
+ return *this;
+}
+
+JsonWriter& JsonWriter::operator&(double& d) {
+ WRITER->Double(d);
+ return *this;
+}
+
+JsonWriter& JsonWriter::operator&(std::string& s) {
+ WRITER->String(s.c_str(), static_cast<SizeType>(s.size()));
+ return *this;
+}
+
+JsonWriter& JsonWriter::SetNull() {
+ WRITER->Null();
+ return *this;
+}
+
+#undef STREAM
+#undef WRITER
diff --git a/3rdparty/rapidjson/example/archiver/archiver.h b/3rdparty/rapidjson/example/archiver/archiver.h
new file mode 100644
index 00000000000..285ca73d6ab
--- /dev/null
+++ b/3rdparty/rapidjson/example/archiver/archiver.h
@@ -0,0 +1,145 @@
+#ifndef ARCHIVER_H_
+#define ARCHIVER_H_
+
+#include <cstddef>
+#include <string>
+
+/**
+\class Archiver
+\brief Archiver concept
+
+Archiver can be a reader or writer for serialization or deserialization respectively.
+
+class Archiver {
+public:
+ /// \returns true if the archiver is in normal state. false if it has errors.
+ operator bool() const;
+
+ /// Starts an object
+ Archiver& StartObject();
+
+ /// After calling StartObject(), assign a member with a name
+ Archiver& Member(const char* name);
+
+ /// After calling StartObject(), check if a member presents
+ bool HasMember(const char* name) const;
+
+ /// Ends an object
+ Archiver& EndObject();
+
+ /// Starts an array
+ /// \param size If Archiver::IsReader is true, the size of array is written.
+ Archiver& StartArray(size_t* size = 0);
+
+ /// Ends an array
+ Archiver& EndArray();
+
+ /// Read/Write primitive types.
+ Archiver& operator&(bool& b);
+ Archiver& operator&(unsigned& u);
+ Archiver& operator&(int& i);
+ Archiver& operator&(double& d);
+ Archiver& operator&(std::string& s);
+
+ /// Write primitive types.
+ Archiver& SetNull();
+
+ //! Whether it is a reader.
+ static const bool IsReader;
+
+ //! Whether it is a writer.
+ static const bool IsWriter;
+};
+*/
+
+/// Represents a JSON reader which implements Archiver concept.
+class JsonReader {
+public:
+ /// Constructor.
+ /**
+ \param json A non-const source json string for in-situ parsing.
+ \note in-situ means the source JSON string will be modified after parsing.
+ */
+ JsonReader(const char* json);
+
+ /// Destructor.
+ ~JsonReader();
+
+ // Archive concept
+
+ operator bool() const { return !mError; }
+
+ JsonReader& StartObject();
+ JsonReader& Member(const char* name);
+ bool HasMember(const char* name) const;
+ JsonReader& EndObject();
+
+ JsonReader& StartArray(size_t* size = 0);
+ JsonReader& EndArray();
+
+ JsonReader& operator&(bool& b);
+ JsonReader& operator&(unsigned& u);
+ JsonReader& operator&(int& i);
+ JsonReader& operator&(double& d);
+ JsonReader& operator&(std::string& s);
+
+ JsonReader& SetNull();
+
+ static const bool IsReader = true;
+ static const bool IsWriter = !IsReader;
+
+private:
+ JsonReader(const JsonReader&);
+ JsonReader& operator=(const JsonReader&);
+
+ void Next();
+
+ // PIMPL
+ void* mDocument; ///< DOM result of parsing.
+ void* mStack; ///< Stack for iterating the DOM
+ bool mError; ///< Whether an error has occurred.
+};
+
+class JsonWriter {
+public:
+ /// Constructor.
+ JsonWriter();
+
+ /// Destructor.
+ ~JsonWriter();
+
+ /// Obtains the serialized JSON string.
+ const char* GetString() const;
+
+ // Archive concept
+
+ operator bool() const { return true; }
+
+ JsonWriter& StartObject();
+ JsonWriter& Member(const char* name);
+ bool HasMember(const char* name) const;
+ JsonWriter& EndObject();
+
+ JsonWriter& StartArray(size_t* size = 0);
+ JsonWriter& EndArray();
+
+ JsonWriter& operator&(bool& b);
+ JsonWriter& operator&(unsigned& u);
+ JsonWriter& operator&(int& i);
+ JsonWriter& operator&(double& d);
+ JsonWriter& operator&(std::string& s);
+ JsonWriter& SetNull();
+
+ static const bool IsReader = false;
+ static const bool IsWriter = !IsReader;
+
+private:
+ JsonWriter(const JsonWriter&);
+ JsonWriter& operator=(const JsonWriter&);
+
+ // PIMPL idiom
+ void* mWriter; ///< JSON writer.
+ void* mStream; ///< Stream buffer.
+};
+
+#endif // ARCHIVER_H__
diff --git a/3rdparty/rapidjson/example/archiver/archivertest.cpp b/3rdparty/rapidjson/example/archiver/archivertest.cpp
new file mode 100644
index 00000000000..417a421a318
--- /dev/null
+++ b/3rdparty/rapidjson/example/archiver/archivertest.cpp
@@ -0,0 +1,287 @@
+#include "archiver.h"
+#include <iostream>
+#include <vector>
+
+//////////////////////////////////////////////////////////////////////////////
+// Test1: simple object
+
+struct Student {
+ Student() : name(), age(), height(), canSwim() {}
+ Student(const std::string name, unsigned age, double height, bool canSwim) :
+ name(name), age(age), height(height), canSwim(canSwim)
+ {}
+
+ std::string name;
+ unsigned age;
+ double height;
+ bool canSwim;
+};
+
+template <typename Archiver>
+Archiver& operator&(Archiver& ar, Student& s) {
+ ar.StartObject();
+ ar.Member("name") & s.name;
+ ar.Member("age") & s.age;
+ ar.Member("height") & s.height;
+ ar.Member("canSwim") & s.canSwim;
+ return ar.EndObject();
+}
+
+std::ostream& operator<<(std::ostream& os, const Student& s) {
+ return os << s.name << " " << s.age << " " << s.height << " " << s.canSwim;
+}
+
+void test1() {
+ std::string json;
+
+ // Serialize
+ {
+ Student s("Lua", 9, 150.5, true);
+
+ JsonWriter writer;
+ writer & s;
+ json = writer.GetString();
+ std::cout << json << std::endl;
+ }
+
+ // Deserialize
+ {
+ Student s;
+ JsonReader reader(json.c_str());
+ reader & s;
+ std::cout << s << std::endl;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Test2: std::vector <=> JSON array
+//
+// You can map a JSON array to other data structures as well
+
+struct Group {
+ Group() : groupName(), students() {}
+ std::string groupName;
+ std::vector<Student> students;
+};
+
+template <typename Archiver>
+Archiver& operator&(Archiver& ar, Group& g) {
+ ar.StartObject();
+
+ ar.Member("groupName");
+ ar & g.groupName;
+
+ ar.Member("students");
+ size_t studentCount = g.students.size();
+ ar.StartArray(&studentCount);
+ if (ar.IsReader)
+ g.students.resize(studentCount);
+ for (size_t i = 0; i < studentCount; i++)
+ ar & g.students[i];
+ ar.EndArray();
+
+ return ar.EndObject();
+}
+
+std::ostream& operator<<(std::ostream& os, const Group& g) {
+ os << g.groupName << std::endl;
+ for (std::vector<Student>::const_iterator itr = g.students.begin(); itr != g.students.end(); ++itr)
+ os << *itr << std::endl;
+ return os;
+}
+
+void test2() {
+ std::string json;
+
+ // Serialize
+ {
+ Group g;
+ g.groupName = "Rainbow";
+
+ Student s1("Lua", 9, 150.5, true);
+ Student s2("Mio", 7, 120.0, false);
+ g.students.push_back(s1);
+ g.students.push_back(s2);
+
+ JsonWriter writer;
+ writer & g;
+ json = writer.GetString();
+ std::cout << json << std::endl;
+ }
+
+ // Deserialize
+ {
+ Group g;
+ JsonReader reader(json.c_str());
+ reader & g;
+ std::cout << g << std::endl;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Test3: polymorphism & friend
+//
+// Note that friendship is not necessary but make things simpler.
+
+class Shape {
+public:
+ virtual ~Shape() {}
+ virtual const char* GetType() const = 0;
+ virtual void Print(std::ostream& os) const = 0;
+
+protected:
+ Shape() : x_(), y_() {}
+ Shape(double x, double y) : x_(x), y_(y) {}
+
+ template <typename Archiver>
+ friend Archiver& operator&(Archiver& ar, Shape& s);
+
+ double x_, y_;
+};
+
+template <typename Archiver>
+Archiver& operator&(Archiver& ar, Shape& s) {
+ ar.Member("x") & s.x_;
+ ar.Member("y") & s.y_;
+ return ar;
+}
+
+class Circle : public Shape {
+public:
+ Circle() : radius_() {}
+ Circle(double x, double y, double radius) : Shape(x, y), radius_(radius) {}
+ ~Circle() {}
+
+ const char* GetType() const { return "Circle"; }
+
+ void Print(std::ostream& os) const {
+ os << "Circle (" << x_ << ", " << y_ << ")" << " radius = " << radius_;
+ }
+
+private:
+ template <typename Archiver>
+ friend Archiver& operator&(Archiver& ar, Circle& c);
+
+ double radius_;
+};
+
+template <typename Archiver>
+Archiver& operator&(Archiver& ar, Circle& c) {
+ ar & static_cast<Shape&>(c);
+ ar.Member("radius") & c.radius_;
+ return ar;
+}
+
+class Box : public Shape {
+public:
+ Box() : width_(), height_() {}
+ Box(double x, double y, double width, double height) : Shape(x, y), width_(width), height_(height) {}
+ ~Box() {}
+
+ const char* GetType() const { return "Box"; }
+
+ void Print(std::ostream& os) const {
+ os << "Box (" << x_ << ", " << y_ << ")" << " width = " << width_ << " height = " << height_;
+ }
+
+private:
+ template <typename Archiver>
+ friend Archiver& operator&(Archiver& ar, Box& b);
+
+ double width_, height_;
+};
+
+template <typename Archiver>
+Archiver& operator&(Archiver& ar, Box& b) {
+ ar & static_cast<Shape&>(b);
+ ar.Member("width") & b.width_;
+ ar.Member("height") & b.height_;
+ return ar;
+}
+
+class Canvas {
+public:
+ Canvas() : shapes_() {}
+ ~Canvas() { Clear(); }
+
+ void Clear() {
+ for (std::vector<Shape*>::iterator itr = shapes_.begin(); itr != shapes_.end(); ++itr)
+ delete *itr;
+ }
+
+ void AddShape(Shape* shape) { shapes_.push_back(shape); }
+
+ void Print(std::ostream& os) {
+ for (std::vector<Shape*>::iterator itr = shapes_.begin(); itr != shapes_.end(); ++itr) {
+ (*itr)->Print(os);
+ std::cout << std::endl;
+ }
+ }
+
+private:
+ template <typename Archiver>
+ friend Archiver& operator&(Archiver& ar, Canvas& c);
+
+ std::vector<Shape*> shapes_;
+};
+
+template <typename Archiver>
+Archiver& operator&(Archiver& ar, Shape*& shape) {
+ std::string type = ar.IsReader ? "" : shape->GetType();
+ ar.StartObject();
+ ar.Member("type") & type;
+ if (type == "Circle") {
+ if (ar.IsReader) shape = new Circle;
+ ar & static_cast<Circle&>(*shape);
+ }
+ else if (type == "Box") {
+ if (ar.IsReader) shape = new Box;
+ ar & static_cast<Box&>(*shape);
+ }
+ return ar.EndObject();
+}
+
+template <typename Archiver>
+Archiver& operator&(Archiver& ar, Canvas& c) {
+ size_t shapeCount = c.shapes_.size();
+ ar.StartArray(&shapeCount);
+ if (ar.IsReader) {
+ c.Clear();
+ c.shapes_.resize(shapeCount);
+ }
+ for (size_t i = 0; i < shapeCount; i++)
+ ar & c.shapes_[i];
+ return ar.EndArray();
+}
+
+void test3() {
+ std::string json;
+
+ // Serialize
+ {
+ Canvas c;
+ c.AddShape(new Circle(1.0, 2.0, 3.0));
+ c.AddShape(new Box(4.0, 5.0, 6.0, 7.0));
+
+ JsonWriter writer;
+ writer & c;
+ json = writer.GetString();
+ std::cout << json << std::endl;
+ }
+
+ // Deserialize
+ {
+ Canvas c;
+ JsonReader reader(json.c_str());
+ reader & c;
+ c.Print(std::cout);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+int main() {
+ test1();
+ test2();
+ test3();
+}
diff --git a/3rdparty/rapidjson/example/jsonx/jsonx.cpp b/3rdparty/rapidjson/example/jsonx/jsonx.cpp
index 1346b578c39..954aa2b9077 100644
--- a/3rdparty/rapidjson/example/jsonx/jsonx.cpp
+++ b/3rdparty/rapidjson/example/jsonx/jsonx.cpp
@@ -1,4 +1,4 @@
-// JSON to JSONx conversion exmaple, using SAX API.
+// JSON to JSONx conversion example, using SAX API.
// JSONx is an IBM standard format to represent JSON as XML.
// https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html
// This example parses JSON text from stdin with validation,
diff --git a/3rdparty/rapidjson/example/lookaheadparser/lookaheadparser.cpp b/3rdparty/rapidjson/example/lookaheadparser/lookaheadparser.cpp
new file mode 100644
index 00000000000..f627f4d8636
--- /dev/null
+++ b/3rdparty/rapidjson/example/lookaheadparser/lookaheadparser.cpp
@@ -0,0 +1,350 @@
+#include "rapidjson/reader.h"
+#include "rapidjson/document.h"
+#include <iostream>
+
+RAPIDJSON_DIAG_PUSH
+#ifdef __GNUC__
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+// This example demonstrates JSON token-by-token parsing with an API that is
+// more direct; you don't need to design your logic around a handler object and
+// callbacks. Instead, you retrieve values from the JSON stream by calling
+// GetInt(), GetDouble(), GetString() and GetBool(), traverse into structures
+// by calling EnterObject() and EnterArray(), and skip over unwanted data by
+// calling SkipValue(). When you know your JSON's structure, this can be quite
+// convenient.
+//
+// If you aren't sure of what's next in the JSON data, you can use PeekType() and
+// PeekValue() to look ahead to the next object before reading it.
+//
+// If you call the wrong retrieval method--e.g. GetInt when the next JSON token is
+// not an int, EnterObject or EnterArray when there isn't actually an object or array
+// to read--the stream parsing will end immediately and no more data will be delivered.
+//
+// After calling EnterObject, you retrieve keys via NextObjectKey() and values via
+// the normal getters. When NextObjectKey() returns null, you have exited the
+// object, or you can call SkipObject() to skip to the end of the object
+// immediately. If you fetch the entire object (i.e. NextObjectKey() returned null),
+// you should not call SkipObject().
+//
+// After calling EnterArray(), you must alternate between calling NextArrayValue()
+// to see if the array has more data, and then retrieving values via the normal
+// getters. You can call SkipArray() to skip to the end of the array immediately.
+// If you fetch the entire array (i.e. NextArrayValue() returned null),
+// you should not call SkipArray().
+//
+// This parser uses in-situ strings, so the JSON buffer will be altered during the
+// parse.
+
+using namespace rapidjson;
+
+
+class LookaheadParserHandler {
+public:
+ bool Null() { st_ = kHasNull; v_.SetNull(); return true; }
+ bool Bool(bool b) { st_ = kHasBool; v_.SetBool(b); return true; }
+ bool Int(int i) { st_ = kHasNumber; v_.SetInt(i); return true; }
+ bool Uint(unsigned u) { st_ = kHasNumber; v_.SetUint(u); return true; }
+ bool Int64(int64_t i) { st_ = kHasNumber; v_.SetInt64(i); return true; }
+ bool Uint64(uint64_t u) { st_ = kHasNumber; v_.SetUint64(u); return true; }
+ bool Double(double d) { st_ = kHasNumber; v_.SetDouble(d); return true; }
+ bool RawNumber(const char*, SizeType, bool) { return false; }
+ bool String(const char* str, SizeType length, bool) { st_ = kHasString; v_.SetString(str, length); return true; }
+ bool StartObject() { st_ = kEnteringObject; return true; }
+ bool Key(const char* str, SizeType length, bool) { st_ = kHasKey; v_.SetString(str, length); return true; }
+ bool EndObject(SizeType) { st_ = kExitingObject; return true; }
+ bool StartArray() { st_ = kEnteringArray; return true; }
+ bool EndArray(SizeType) { st_ = kExitingArray; return true; }
+
+protected:
+ LookaheadParserHandler(char* str);
+ void ParseNext();
+
+protected:
+ enum LookaheadParsingState {
+ kInit,
+ kError,
+ kHasNull,
+ kHasBool,
+ kHasNumber,
+ kHasString,
+ kHasKey,
+ kEnteringObject,
+ kExitingObject,
+ kEnteringArray,
+ kExitingArray
+ };
+
+ Value v_;
+ LookaheadParsingState st_;
+ Reader r_;
+ InsituStringStream ss_;
+
+ static const int parseFlags = kParseDefaultFlags | kParseInsituFlag;
+};
+
+LookaheadParserHandler::LookaheadParserHandler(char* str) : v_(), st_(kInit), r_(), ss_(str) {
+ r_.IterativeParseInit();
+ ParseNext();
+}
+
+void LookaheadParserHandler::ParseNext() {
+ if (r_.HasParseError()) {
+ st_ = kError;
+ return;
+ }
+
+ r_.IterativeParseNext<parseFlags>(ss_, *this);
+}
+
+class LookaheadParser : protected LookaheadParserHandler {
+public:
+ LookaheadParser(char* str) : LookaheadParserHandler(str) {}
+
+ bool EnterObject();
+ bool EnterArray();
+ const char* NextObjectKey();
+ bool NextArrayValue();
+ int GetInt();
+ double GetDouble();
+ const char* GetString();
+ bool GetBool();
+ void GetNull();
+
+ void SkipObject();
+ void SkipArray();
+ void SkipValue();
+ Value* PeekValue();
+ int PeekType(); // returns a rapidjson::Type, or -1 for no value (at end of object/array)
+
+ bool IsValid() { return st_ != kError; }
+
+protected:
+ void SkipOut(int depth);
+};
+
+bool LookaheadParser::EnterObject() {
+ if (st_ != kEnteringObject) {
+ st_ = kError;
+ return false;
+ }
+
+ ParseNext();
+ return true;
+}
+
+bool LookaheadParser::EnterArray() {
+ if (st_ != kEnteringArray) {
+ st_ = kError;
+ return false;
+ }
+
+ ParseNext();
+ return true;
+}
+
+const char* LookaheadParser::NextObjectKey() {
+ if (st_ == kHasKey) {
+ const char* result = v_.GetString();
+ ParseNext();
+ return result;
+ }
+
+ if (st_ != kExitingObject) {
+ st_ = kError;
+ return 0;
+ }
+
+ ParseNext();
+ return 0;
+}
+
+bool LookaheadParser::NextArrayValue() {
+ if (st_ == kExitingArray) {
+ ParseNext();
+ return false;
+ }
+
+ if (st_ == kError || st_ == kExitingObject || st_ == kHasKey) {
+ st_ = kError;
+ return false;
+ }
+
+ return true;
+}
+
+int LookaheadParser::GetInt() {
+ if (st_ != kHasNumber || !v_.IsInt()) {
+ st_ = kError;
+ return 0;
+ }
+
+ int result = v_.GetInt();
+ ParseNext();
+ return result;
+}
+
+double LookaheadParser::GetDouble() {
+ if (st_ != kHasNumber) {
+ st_ = kError;
+ return 0.;
+ }
+
+ double result = v_.GetDouble();
+ ParseNext();
+ return result;
+}
+
+bool LookaheadParser::GetBool() {
+ if (st_ != kHasBool) {
+ st_ = kError;
+ return false;
+ }
+
+ bool result = v_.GetBool();
+ ParseNext();
+ return result;
+}
+
+void LookaheadParser::GetNull() {
+ if (st_ != kHasNull) {
+ st_ = kError;
+ return;
+ }
+
+ ParseNext();
+}
+
+const char* LookaheadParser::GetString() {
+ if (st_ != kHasString) {
+ st_ = kError;
+ return 0;
+ }
+
+ const char* result = v_.GetString();
+ ParseNext();
+ return result;
+}
+
+void LookaheadParser::SkipOut(int depth) {
+ do {
+ if (st_ == kEnteringArray || st_ == kEnteringObject) {
+ ++depth;
+ }
+ else if (st_ == kExitingArray || st_ == kExitingObject) {
+ --depth;
+ }
+ else if (st_ == kError) {
+ return;
+ }
+
+ ParseNext();
+ }
+ while (depth > 0);
+}
+
+void LookaheadParser::SkipValue() {
+ SkipOut(0);
+}
+
+void LookaheadParser::SkipArray() {
+ SkipOut(1);
+}
+
+void LookaheadParser::SkipObject() {
+ SkipOut(1);
+}
+
+Value* LookaheadParser::PeekValue() {
+ if (st_ >= kHasNull && st_ <= kHasKey) {
+ return &v_;
+ }
+
+ return 0;
+}
+
+int LookaheadParser::PeekType() {
+ if (st_ >= kHasNull && st_ <= kHasKey) {
+ return v_.GetType();
+ }
+
+ if (st_ == kEnteringArray) {
+ return kArrayType;
+ }
+
+ if (st_ == kEnteringObject) {
+ return kObjectType;
+ }
+
+ return -1;
+}
+
+//-------------------------------------------------------------------------
+
+int main() {
+ using namespace std;
+
+ char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null,"
+ "\"i\":123, \"pi\": 3.1416, \"a\":[-1, 2, 3, 4, \"array\", []], \"skipArrays\":[1, 2, [[[3]]]], "
+ "\"skipObject\":{ \"i\":0, \"t\":true, \"n\":null, \"d\":123.45 }, "
+ "\"skipNested\":[[[[{\"\":0}, {\"\":[-9.87]}]]], [], []], "
+ "\"skipString\":\"zzz\", \"reachedEnd\":null, \"t\":true }";
+
+ LookaheadParser r(json);
+
+ RAPIDJSON_ASSERT(r.PeekType() == kObjectType);
+
+ r.EnterObject();
+ while (const char* key = r.NextObjectKey()) {
+ if (0 == strcmp(key, "hello")) {
+ RAPIDJSON_ASSERT(r.PeekType() == kStringType);
+ cout << key << ":" << r.GetString() << endl;
+ }
+ else if (0 == strcmp(key, "t") || 0 == strcmp(key, "f")) {
+ RAPIDJSON_ASSERT(r.PeekType() == kTrueType || r.PeekType() == kFalseType);
+ cout << key << ":" << r.GetBool() << endl;
+ continue;
+ }
+ else if (0 == strcmp(key, "n")) {
+ RAPIDJSON_ASSERT(r.PeekType() == kNullType);
+ r.GetNull();
+ cout << key << endl;
+ continue;
+ }
+ else if (0 == strcmp(key, "pi")) {
+ RAPIDJSON_ASSERT(r.PeekType() == kNumberType);
+ cout << key << ":" << r.GetDouble() << endl;
+ continue;
+ }
+ else if (0 == strcmp(key, "a")) {
+ RAPIDJSON_ASSERT(r.PeekType() == kArrayType);
+
+ r.EnterArray();
+
+ cout << key << ":[ ";
+ while (r.NextArrayValue()) {
+ if (r.PeekType() == kNumberType) {
+ cout << r.GetDouble() << " ";
+ }
+ else if (r.PeekType() == kStringType) {
+ cout << r.GetString() << " ";
+ }
+ else {
+ r.SkipArray();
+ break;
+ }
+ }
+
+ cout << "]" << endl;
+ }
+ else {
+ cout << key << ":skipped" << endl;
+ r.SkipValue();
+ }
+ }
+
+ return 0;
+}
+
+RAPIDJSON_DIAG_POP
diff --git a/3rdparty/rapidjson/example/parsebyparts/parsebyparts.cpp b/3rdparty/rapidjson/example/parsebyparts/parsebyparts.cpp
index 57eed005dea..ff735394ec9 100644
--- a/3rdparty/rapidjson/example/parsebyparts/parsebyparts.cpp
+++ b/3rdparty/rapidjson/example/parsebyparts/parsebyparts.cpp
@@ -21,12 +21,15 @@ public:
AsyncDocumentParser(Document& d)
: stream_(*this)
, d_(d)
- , parseThread_(&AsyncDocumentParser::Parse, this)
+ , parseThread_()
, mutex_()
, notEmpty_()
, finish_()
, completed_()
- {}
+ {
+ // Create and execute thread after all member variables are initialized.
+ parseThread_ = std::thread(&AsyncDocumentParser::Parse, this);
+ }
~AsyncDocumentParser() {
if (!parseThread_.joinable())
@@ -140,7 +143,7 @@ int main() {
AsyncDocumentParser<> parser(d);
const char json1[] = " { \"hello\" : \"world\", \"t\" : tr";
- //const char json1[] = " { \"hello\" : \"world\", \"t\" : trX"; // Fot test parsing error
+ //const char json1[] = " { \"hello\" : \"world\", \"t\" : trX"; // For test parsing error
const char json2[] = "ue, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.14";
const char json3[] = "16, \"a\":[1, 2, 3, 4] } ";
diff --git a/3rdparty/rapidjson/example/schemavalidator/schemavalidator.cpp b/3rdparty/rapidjson/example/schemavalidator/schemavalidator.cpp
index ce36ea95f00..6ce3c39e597 100644
--- a/3rdparty/rapidjson/example/schemavalidator/schemavalidator.cpp
+++ b/3rdparty/rapidjson/example/schemavalidator/schemavalidator.cpp
@@ -2,13 +2,132 @@
// The example validates JSON text from stdin with a JSON schema specified in the argument.
+#define RAPIDJSON_HAS_STDSTRING 1
+
#include "rapidjson/error/en.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/schema.h"
#include "rapidjson/stringbuffer.h"
+#include "rapidjson/prettywriter.h"
+#include <string>
+#include <iostream>
+#include <sstream>
using namespace rapidjson;
+typedef GenericValue<UTF8<>, CrtAllocator > ValueType;
+
+// Forward ref
+static void CreateErrorMessages(const ValueType& errors, size_t depth, const char* context);
+
+// Convert GenericValue to std::string
+static std::string GetString(const ValueType& val) {
+ std::ostringstream s;
+ if (val.IsString())
+ s << val.GetString();
+ else if (val.IsDouble())
+ s << val.GetDouble();
+ else if (val.IsUint())
+ s << val.GetUint();
+ else if (val.IsInt())
+ s << val.GetInt();
+ else if (val.IsUint64())
+ s << val.GetUint64();
+ else if (val.IsInt64())
+ s << val.GetInt64();
+ else if (val.IsBool() && val.GetBool())
+ s << "true";
+ else if (val.IsBool())
+ s << "false";
+ else if (val.IsFloat())
+ s << val.GetFloat();
+ return s.str();
+}
+
+// Create the error message for a named error
+// The error object can either be empty or contain at least member properties:
+// {"errorCode": <code>, "instanceRef": "<pointer>", "schemaRef": "<pointer>" }
+// Additional properties may be present for use as inserts.
+// An "errors" property may be present if there are child errors.
+static void HandleError(const char* errorName, const ValueType& error, size_t depth, const char* context) {
+ if (!error.ObjectEmpty()) {
+ // Get error code and look up error message text (English)
+ int code = error["errorCode"].GetInt();
+ std::string message(GetValidateError_En(static_cast<ValidateErrorCode>(code)));
+ // For each member property in the error, see if its name exists as an insert in the error message and if so replace with the stringified property value
+ // So for example - "Number '%actual' is not a multiple of the 'multipleOf' value '%expected'." - we would expect "actual" and "expected" members.
+ for (ValueType::ConstMemberIterator insertsItr = error.MemberBegin();
+ insertsItr != error.MemberEnd(); ++insertsItr) {
+ std::string insertName("%");
+ insertName += insertsItr->name.GetString(); // eg "%actual"
+ size_t insertPos = message.find(insertName);
+ if (insertPos != std::string::npos) {
+ std::string insertString("");
+ const ValueType &insert = insertsItr->value;
+ if (insert.IsArray()) {
+ // Member is an array so create comma-separated list of items for the insert string
+ for (ValueType::ConstValueIterator itemsItr = insert.Begin(); itemsItr != insert.End(); ++itemsItr) {
+ if (itemsItr != insert.Begin()) insertString += ",";
+ insertString += GetString(*itemsItr);
+ }
+ } else {
+ insertString += GetString(insert);
+ }
+ message.replace(insertPos, insertName.length(), insertString);
+ }
+ }
+ // Output error message, references, context
+ std::string indent(depth * 2, ' ');
+ std::cout << indent << "Error Name: " << errorName << std::endl;
+ std::cout << indent << "Message: " << message.c_str() << std::endl;
+ std::cout << indent << "Instance: " << error["instanceRef"].GetString() << std::endl;
+ std::cout << indent << "Schema: " << error["schemaRef"].GetString() << std::endl;
+ if (depth > 0) std::cout << indent << "Context: " << context << std::endl;
+ std::cout << std::endl;
+
+ // If child errors exist, apply the process recursively to each error structure.
+ // This occurs for "oneOf", "allOf", "anyOf" and "dependencies" errors, so pass the error name as context.
+ if (error.HasMember("errors")) {
+ depth++;
+ const ValueType &childErrors = error["errors"];
+ if (childErrors.IsArray()) {
+ // Array - each item is an error structure - example
+ // "anyOf": {"errorCode": ..., "errors":[{"pattern": {"errorCode\": ...\"}}, {"pattern": {"errorCode\": ...}}]
+ for (ValueType::ConstValueIterator errorsItr = childErrors.Begin();
+ errorsItr != childErrors.End(); ++errorsItr) {
+ CreateErrorMessages(*errorsItr, depth, errorName);
+ }
+ } else if (childErrors.IsObject()) {
+ // Object - each member is an error structure - example
+ // "dependencies": {"errorCode": ..., "errors": {"address": {"required": {"errorCode": ...}}, "name": {"required": {"errorCode": ...}}}
+ for (ValueType::ConstMemberIterator propsItr = childErrors.MemberBegin();
+ propsItr != childErrors.MemberEnd(); ++propsItr) {
+ CreateErrorMessages(propsItr->value, depth, errorName);
+ }
+ }
+ }
+ }
+}
+
+// Create error message for all errors in an error structure
+// Context is used to indicate whether the error structure has a parent 'dependencies', 'allOf', 'anyOf' or 'oneOf' error
+static void CreateErrorMessages(const ValueType& errors, size_t depth = 0, const char* context = 0) {
+ // Each member property contains one or more errors of a given type
+ for (ValueType::ConstMemberIterator errorTypeItr = errors.MemberBegin(); errorTypeItr != errors.MemberEnd(); ++errorTypeItr) {
+ const char* errorName = errorTypeItr->name.GetString();
+ const ValueType& errorContent = errorTypeItr->value;
+ if (errorContent.IsArray()) {
+ // Member is an array where each item is an error - eg "type": [{"errorCode": ...}, {"errorCode": ...}]
+ for (ValueType::ConstValueIterator contentItr = errorContent.Begin(); contentItr != errorContent.End(); ++contentItr) {
+ HandleError(errorName, *contentItr, depth, context);
+ }
+ } else if (errorContent.IsObject()) {
+ // Member is an object which is a single error - eg "type": {"errorCode": ... }
+ HandleError(errorName, errorContent, depth, context);
+ }
+ }
+}
+
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: schemavalidator schema.json < input.json\n");
@@ -64,9 +183,17 @@ int main(int argc, char *argv[]) {
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
fprintf(stderr, "Invalid schema: %s\n", sb.GetString());
fprintf(stderr, "Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
+ fprintf(stderr, "Invalid code: %d\n", validator.GetInvalidSchemaCode());
+ fprintf(stderr, "Invalid message: %s\n", GetValidateError_En(validator.GetInvalidSchemaCode()));
sb.Clear();
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
fprintf(stderr, "Invalid document: %s\n", sb.GetString());
+ // Detailed violation report is available as a JSON value
+ sb.Clear();
+ PrettyWriter<StringBuffer> w(sb);
+ validator.GetError().Accept(w);
+ fprintf(stderr, "Error report:\n%s\n", sb.GetString());
+ CreateErrorMessages(validator.GetError());
return EXIT_FAILURE;
}
}
diff --git a/3rdparty/rapidjson/example/simplepullreader/simplepullreader.cpp b/3rdparty/rapidjson/example/simplepullreader/simplepullreader.cpp
new file mode 100644
index 00000000000..a4fb1161a4c
--- /dev/null
+++ b/3rdparty/rapidjson/example/simplepullreader/simplepullreader.cpp
@@ -0,0 +1,53 @@
+#include "rapidjson/reader.h"
+#include <iostream>
+#include <sstream>
+
+using namespace rapidjson;
+using namespace std;
+
+// If you can require C++11, you could use std::to_string here
+template <typename T> std::string stringify(T x) {
+ std::stringstream ss;
+ ss << x;
+ return ss.str();
+}
+
+struct MyHandler {
+ const char* type;
+ std::string data;
+
+ MyHandler() : type(), data() {}
+
+ bool Null() { type = "Null"; data.clear(); return true; }
+ bool Bool(bool b) { type = "Bool:"; data = b? "true": "false"; return true; }
+ bool Int(int i) { type = "Int:"; data = stringify(i); return true; }
+ bool Uint(unsigned u) { type = "Uint:"; data = stringify(u); return true; }
+ bool Int64(int64_t i) { type = "Int64:"; data = stringify(i); return true; }
+ bool Uint64(uint64_t u) { type = "Uint64:"; data = stringify(u); return true; }
+ bool Double(double d) { type = "Double:"; data = stringify(d); return true; }
+ bool RawNumber(const char* str, SizeType length, bool) { type = "Number:"; data = std::string(str, length); return true; }
+ bool String(const char* str, SizeType length, bool) { type = "String:"; data = std::string(str, length); return true; }
+ bool StartObject() { type = "StartObject"; data.clear(); return true; }
+ bool Key(const char* str, SizeType length, bool) { type = "Key:"; data = std::string(str, length); return true; }
+ bool EndObject(SizeType memberCount) { type = "EndObject:"; data = stringify(memberCount); return true; }
+ bool StartArray() { type = "StartArray"; data.clear(); return true; }
+ bool EndArray(SizeType elementCount) { type = "EndArray:"; data = stringify(elementCount); return true; }
+private:
+ MyHandler(const MyHandler& noCopyConstruction);
+ MyHandler& operator=(const MyHandler& noAssignment);
+};
+
+int main() {
+ const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
+
+ MyHandler handler;
+ Reader reader;
+ StringStream ss(json);
+ reader.IterativeParseInit();
+ while (!reader.IterativeParseComplete()) {
+ reader.IterativeParseNext<kParseDefaultFlags>(ss, handler);
+ cout << handler.type << handler.data << endl;
+ }
+
+ return 0;
+}
diff --git a/3rdparty/rapidjson/example/sortkeys/sortkeys.cpp b/3rdparty/rapidjson/example/sortkeys/sortkeys.cpp
new file mode 100644
index 00000000000..7ede9fb938b
--- /dev/null
+++ b/3rdparty/rapidjson/example/sortkeys/sortkeys.cpp
@@ -0,0 +1,62 @@
+#include "rapidjson/document.h"
+#include "rapidjson/filewritestream.h"
+#include <rapidjson/prettywriter.h>
+
+#include <algorithm>
+#include <iostream>
+
+using namespace rapidjson;
+using namespace std;
+
+static void printIt(const Value &doc) {
+ char writeBuffer[65536];
+ FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+ PrettyWriter<FileWriteStream> writer(os);
+ doc.Accept(writer);
+ cout << endl;
+}
+
+struct NameComparator {
+ bool operator()(const Value::Member &lhs, const Value::Member &rhs) const {
+ return (strcmp(lhs.name.GetString(), rhs.name.GetString()) < 0);
+ }
+};
+
+int main() {
+ Document d(kObjectType);
+ Document::AllocatorType &allocator = d.GetAllocator();
+
+ d.AddMember("zeta", Value().SetBool(false), allocator);
+ d.AddMember("gama", Value().SetString("test string", allocator), allocator);
+ d.AddMember("delta", Value().SetInt(123), allocator);
+ d.AddMember("alpha", Value(kArrayType).Move(), allocator);
+
+ printIt(d);
+
+/*
+{
+ "zeta": false,
+ "gama": "test string",
+ "delta": 123,
+ "alpha": []
+}
+*/
+
+// C++11 supports std::move() of Value so it always have no problem for std::sort().
+// Some C++03 implementations of std::sort() requires copy constructor which causes compilation error.
+// Needs a sorting function only depends on std::swap() instead.
+#if __cplusplus >= 201103L || (!defined(__GLIBCXX__) && (!defined(_MSC_VER) || _MSC_VER >= 1900))
+ std::sort(d.MemberBegin(), d.MemberEnd(), NameComparator());
+
+ printIt(d);
+
+/*
+{
+ "alpha": [],
+ "delta": 123,
+ "gama": "test string",
+ "zeta": false
+}
+*/
+#endif
+}
diff --git a/3rdparty/rapidjson/example/traverseaspointer.cpp b/3rdparty/rapidjson/example/traverseaspointer.cpp
new file mode 100644
index 00000000000..7e0c89923e4
--- /dev/null
+++ b/3rdparty/rapidjson/example/traverseaspointer.cpp
@@ -0,0 +1,39 @@
+#include "rapidjson/document.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/pointer.h"
+#include "rapidjson/stringbuffer.h"
+#include <iostream>
+
+using namespace rapidjson;
+
+void traverse(const Value& v, const Pointer& p) {
+ StringBuffer sb;
+ p.Stringify(sb);
+ std::cout << sb.GetString() << std::endl;
+
+ switch (v.GetType()) {
+ case kArrayType:
+ for (SizeType i = 0; i != v.Size(); ++i)
+ traverse(v[i], p.Append(i));
+ break;
+ case kObjectType:
+ for (Value::ConstMemberIterator m = v.MemberBegin(); m != v.MemberEnd(); ++m)
+ traverse(m->value, p.Append(m->name.GetString(), m->name.GetStringLength()));
+ break;
+ default:
+ break;
+ }
+}
+
+int main(int, char*[]) {
+ char readBuffer[65536];
+ FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+ Document d;
+ d.ParseStream(is);
+
+ Pointer root;
+ traverse(d, root);
+
+ return 0;
+}
diff --git a/3rdparty/rapidjson/example/tutorial/tutorial.cpp b/3rdparty/rapidjson/example/tutorial/tutorial.cpp
index c8bfcc14c18..d6021c66891 100644
--- a/3rdparty/rapidjson/example/tutorial/tutorial.cpp
+++ b/3rdparty/rapidjson/example/tutorial/tutorial.cpp
@@ -57,7 +57,7 @@ int main(int, char*[]) {
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
assert(document["i"].IsNumber()); // Number is a JSON type, but C++ needs more specific type.
- assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUInt64() also return true.
+ assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUint64() also return true.
printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"]
assert(document["pi"].IsNumber());
diff --git a/3rdparty/rapidjson/include/rapidjson/allocators.h b/3rdparty/rapidjson/include/rapidjson/allocators.h
index 98affe03fbf..ddcf4781bea 100644
--- a/3rdparty/rapidjson/include/rapidjson/allocators.h
+++ b/3rdparty/rapidjson/include/rapidjson/allocators.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -16,6 +16,14 @@
#define RAPIDJSON_ALLOCATORS_H_
#include "rapidjson.h"
+#include "internal/meta.h"
+
+#include <memory>
+#include <limits>
+
+#if RAPIDJSON_HAS_CXX11
+#include <type_traits>
+#endif
RAPIDJSON_NAMESPACE_BEGIN
@@ -52,6 +60,19 @@ concept Allocator {
\endcode
*/
+
+/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-defined kDefaultChunkCapacity definition.
+
+ User can define this as any \c size that is a power of 2.
+*/
+
+#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
+#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
+#endif
+
+
///////////////////////////////////////////////////////////////////////////////
// CrtAllocator
@@ -64,19 +85,26 @@ public:
static const bool kNeedFree = true;
void* Malloc(size_t size) {
if (size) // behavior of malloc(0) is implementation defined.
- return std::malloc(size);
+ return RAPIDJSON_MALLOC(size);
else
return NULL; // standardize to returning NULL.
}
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
(void)originalSize;
if (newSize == 0) {
- std::free(originalPtr);
+ RAPIDJSON_FREE(originalPtr);
return NULL;
}
- return std::realloc(originalPtr, newSize);
+ return RAPIDJSON_REALLOC(originalPtr, newSize);
+ }
+ static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); }
+
+ bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
+ return true;
+ }
+ bool operator!=(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
+ return false;
}
- static void Free(void *ptr) { std::free(ptr); }
};
///////////////////////////////////////////////////////////////////////////////
@@ -100,16 +128,64 @@ public:
*/
template <typename BaseAllocator = CrtAllocator>
class MemoryPoolAllocator {
+ //! Chunk header for perpending to each chunk.
+ /*! Chunks are stored as a singly linked list.
+ */
+ struct ChunkHeader {
+ size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
+ size_t size; //!< Current size of allocated memory in bytes.
+ ChunkHeader *next; //!< Next chunk in the linked list.
+ };
+
+ struct SharedData {
+ ChunkHeader *chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
+ BaseAllocator* ownBaseAllocator; //!< base allocator created by this object.
+ size_t refcount;
+ bool ownBuffer;
+ };
+
+ static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData));
+ static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader));
+
+ static inline ChunkHeader *GetChunkHead(SharedData *shared)
+ {
+ return reinterpret_cast<ChunkHeader*>(reinterpret_cast<uint8_t*>(shared) + SIZEOF_SHARED_DATA);
+ }
+ static inline uint8_t *GetChunkBuffer(SharedData *shared)
+ {
+ return reinterpret_cast<uint8_t*>(shared->chunkHead) + SIZEOF_CHUNK_HEADER;
+ }
+
+ static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
+
public:
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
+ static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy
//! Constructor with chunkSize.
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
+ explicit
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
- chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ chunk_capacity_(chunkSize),
+ baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()),
+ shared_(static_cast<SharedData*>(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0))
{
+ RAPIDJSON_ASSERT(baseAllocator_ != 0);
+ RAPIDJSON_ASSERT(shared_ != 0);
+ if (baseAllocator) {
+ shared_->ownBaseAllocator = 0;
+ }
+ else {
+ shared_->ownBaseAllocator = baseAllocator_;
+ }
+ shared_->chunkHead = GetChunkHead(shared_);
+ shared_->chunkHead->capacity = 0;
+ shared_->chunkHead->size = 0;
+ shared_->chunkHead->next = 0;
+ shared_->ownBuffer = true;
+ shared_->refcount = 1;
}
//! Constructor with user-supplied buffer.
@@ -123,41 +199,101 @@ public:
\param baseAllocator The allocator for allocating memory chunks.
*/
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
- chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ chunk_capacity_(chunkSize),
+ baseAllocator_(baseAllocator),
+ shared_(static_cast<SharedData*>(AlignBuffer(buffer, size)))
{
- RAPIDJSON_ASSERT(buffer != 0);
- RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
- chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
- chunkHead_->capacity = size - sizeof(ChunkHeader);
- chunkHead_->size = 0;
- chunkHead_->next = 0;
+ RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER);
+ shared_->chunkHead = GetChunkHead(shared_);
+ shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER;
+ shared_->chunkHead->size = 0;
+ shared_->chunkHead->next = 0;
+ shared_->ownBaseAllocator = 0;
+ shared_->ownBuffer = false;
+ shared_->refcount = 1;
}
+ MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT :
+ chunk_capacity_(rhs.chunk_capacity_),
+ baseAllocator_(rhs.baseAllocator_),
+ shared_(rhs.shared_)
+ {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
+ ++shared_->refcount;
+ }
+ MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT
+ {
+ RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
+ ++rhs.shared_->refcount;
+ this->~MemoryPoolAllocator();
+ baseAllocator_ = rhs.baseAllocator_;
+ chunk_capacity_ = rhs.chunk_capacity_;
+ shared_ = rhs.shared_;
+ return *this;
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT :
+ chunk_capacity_(rhs.chunk_capacity_),
+ baseAllocator_(rhs.baseAllocator_),
+ shared_(rhs.shared_)
+ {
+ RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
+ rhs.shared_ = 0;
+ }
+ MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT
+ {
+ RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
+ this->~MemoryPoolAllocator();
+ baseAllocator_ = rhs.baseAllocator_;
+ chunk_capacity_ = rhs.chunk_capacity_;
+ shared_ = rhs.shared_;
+ rhs.shared_ = 0;
+ return *this;
+ }
+#endif
+
//! Destructor.
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
*/
- ~MemoryPoolAllocator() {
+ ~MemoryPoolAllocator() RAPIDJSON_NOEXCEPT {
+ if (!shared_) {
+ // do nothing if moved
+ return;
+ }
+ if (shared_->refcount > 1) {
+ --shared_->refcount;
+ return;
+ }
Clear();
- RAPIDJSON_DELETE(ownBaseAllocator_);
+ BaseAllocator *a = shared_->ownBaseAllocator;
+ if (shared_->ownBuffer) {
+ baseAllocator_->Free(shared_);
+ }
+ RAPIDJSON_DELETE(a);
}
- //! Deallocates all memory chunks, excluding the user-supplied buffer.
- void Clear() {
- while (chunkHead_ && chunkHead_ != userBuffer_) {
- ChunkHeader* next = chunkHead_->next;
- baseAllocator_->Free(chunkHead_);
- chunkHead_ = next;
+ //! Deallocates all memory chunks, excluding the first/user one.
+ void Clear() RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
+ for (;;) {
+ ChunkHeader* c = shared_->chunkHead;
+ if (!c->next) {
+ break;
+ }
+ shared_->chunkHead = c->next;
+ baseAllocator_->Free(c);
}
- if (chunkHead_ && chunkHead_ == userBuffer_)
- chunkHead_->size = 0; // Clear user buffer
+ shared_->chunkHead->size = 0;
}
//! Computes the total capacity of allocated memory chunks.
/*! \return total capacity in bytes.
*/
- size_t Capacity() const {
+ size_t Capacity() const RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
size_t capacity = 0;
- for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
capacity += c->capacity;
return capacity;
}
@@ -165,25 +301,35 @@ public:
//! Computes the memory blocks allocated.
/*! \return total used bytes.
*/
- size_t Size() const {
+ size_t Size() const RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
size_t size = 0;
- for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ for (ChunkHeader* c = shared_->chunkHead; c != 0; c = c->next)
size += c->size;
return size;
}
+ //! Whether the allocator is shared.
+ /*! \return true or false.
+ */
+ bool Shared() const RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
+ return shared_->refcount > 1;
+ }
+
//! Allocates a memory block. (concept Allocator)
void* Malloc(size_t size) {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
if (!size)
return NULL;
size = RAPIDJSON_ALIGN(size);
- if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
+ if (RAPIDJSON_UNLIKELY(shared_->chunkHead->size + size > shared_->chunkHead->capacity))
if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
return NULL;
- void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
- chunkHead_->size += size;
+ void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size;
+ shared_->chunkHead->size += size;
return buffer;
}
@@ -192,6 +338,7 @@ public:
if (originalPtr == 0)
return Malloc(newSize);
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
if (newSize == 0)
return NULL;
@@ -203,10 +350,10 @@ public:
return originalPtr;
// Simply expand it if it is the last allocation and there is sufficient space
- if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
+ if (originalPtr == GetChunkBuffer(shared_) + shared_->chunkHead->size - originalSize) {
size_t increment = static_cast<size_t>(newSize - originalSize);
- if (chunkHead_->size + increment <= chunkHead_->capacity) {
- chunkHead_->size += increment;
+ if (shared_->chunkHead->size + increment <= shared_->chunkHead->capacity) {
+ shared_->chunkHead->size += increment;
return originalPtr;
}
}
@@ -222,50 +369,325 @@ public:
}
//! Frees a memory block (concept Allocator)
- static void Free(void *ptr) { (void)ptr; } // Do nothing
+ static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing
-private:
- //! Copy constructor is not permitted.
- MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
- //! Copy assignment operator is not permitted.
- MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
+ //! Compare (equality) with another MemoryPoolAllocator
+ bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
+ RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
+ return shared_ == rhs.shared_;
+ }
+ //! Compare (inequality) with another MemoryPoolAllocator
+ bool operator!=(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
+ return !operator==(rhs);
+ }
+private:
//! Creates a new chunk.
/*! \param capacity Capacity of the chunk in bytes.
\return true if success.
*/
bool AddChunk(size_t capacity) {
if (!baseAllocator_)
- ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
- if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
+ shared_->ownBaseAllocator = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
+ if (ChunkHeader* chunk = static_cast<ChunkHeader*>(baseAllocator_->Malloc(SIZEOF_CHUNK_HEADER + capacity))) {
chunk->capacity = capacity;
chunk->size = 0;
- chunk->next = chunkHead_;
- chunkHead_ = chunk;
+ chunk->next = shared_->chunkHead;
+ shared_->chunkHead = chunk;
return true;
}
else
return false;
}
- static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
-
- //! Chunk header for perpending to each chunk.
- /*! Chunks are stored as a singly linked list.
- */
- struct ChunkHeader {
- size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
- size_t size; //!< Current size of allocated memory in bytes.
- ChunkHeader *next; //!< Next chunk in the linked list.
- };
+ static inline void* AlignBuffer(void* buf, size_t &size)
+ {
+ RAPIDJSON_NOEXCEPT_ASSERT(buf != 0);
+ const uintptr_t mask = sizeof(void*) - 1;
+ const uintptr_t ubuf = reinterpret_cast<uintptr_t>(buf);
+ if (RAPIDJSON_UNLIKELY(ubuf & mask)) {
+ const uintptr_t abuf = (ubuf + mask) & ~mask;
+ RAPIDJSON_ASSERT(size >= abuf - ubuf);
+ buf = reinterpret_cast<void*>(abuf);
+ size -= abuf - ubuf;
+ }
+ return buf;
+ }
- ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
- void *userBuffer_; //!< User supplied buffer.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
- BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
+ SharedData *shared_; //!< The shared data of the allocator
+};
+
+namespace internal {
+ template<typename, typename = void>
+ struct IsRefCounted :
+ public FalseType
+ { };
+ template<typename T>
+ struct IsRefCounted<T, typename internal::EnableIfCond<T::kRefCounted>::Type> :
+ public TrueType
+ { };
+}
+
+template<typename T, typename A>
+inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n)
+{
+ RAPIDJSON_NOEXCEPT_ASSERT(old_n <= std::numeric_limits<size_t>::max() / sizeof(T) && new_n <= std::numeric_limits<size_t>::max() / sizeof(T));
+ return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T)));
+}
+
+template<typename T, typename A>
+inline T *Malloc(A& a, size_t n = 1)
+{
+ return Realloc<T, A>(a, NULL, 0, n);
+}
+
+template<typename T, typename A>
+inline void Free(A& a, T *p, size_t n = 1)
+{
+ static_cast<void>(Realloc<T, A>(a, p, n, 0));
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited
+#endif
+
+template <typename T, typename BaseAllocator = CrtAllocator>
+class StdAllocator :
+ public std::allocator<T>
+{
+ typedef std::allocator<T> allocator_type;
+#if RAPIDJSON_HAS_CXX11
+ typedef std::allocator_traits<allocator_type> traits_type;
+#else
+ typedef allocator_type traits_type;
+#endif
+
+public:
+ typedef BaseAllocator BaseAllocatorType;
+
+ StdAllocator() RAPIDJSON_NOEXCEPT :
+ allocator_type(),
+ baseAllocator_()
+ { }
+
+ StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
+ allocator_type(rhs),
+ baseAllocator_(rhs.baseAllocator_)
+ { }
+
+ template<typename U>
+ StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
+ allocator_type(rhs),
+ baseAllocator_(rhs.baseAllocator_)
+ { }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT :
+ allocator_type(std::move(rhs)),
+ baseAllocator_(std::move(rhs.baseAllocator_))
+ { }
+#endif
+#if RAPIDJSON_HAS_CXX11
+ using propagate_on_container_move_assignment = std::true_type;
+ using propagate_on_container_swap = std::true_type;
+#endif
+
+ /* implicit */
+ StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT :
+ allocator_type(),
+ baseAllocator_(allocator)
+ { }
+
+ ~StdAllocator() RAPIDJSON_NOEXCEPT
+ { }
+
+ template<typename U>
+ struct rebind {
+ typedef StdAllocator<U, BaseAllocator> other;
+ };
+
+ typedef typename traits_type::size_type size_type;
+ typedef typename traits_type::difference_type difference_type;
+
+ typedef typename traits_type::value_type value_type;
+ typedef typename traits_type::pointer pointer;
+ typedef typename traits_type::const_pointer const_pointer;
+
+#if RAPIDJSON_HAS_CXX11
+
+ typedef typename std::add_lvalue_reference<value_type>::type &reference;
+ typedef typename std::add_lvalue_reference<typename std::add_const<value_type>::type>::type &const_reference;
+
+ pointer address(reference r) const RAPIDJSON_NOEXCEPT
+ {
+ return std::addressof(r);
+ }
+ const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
+ {
+ return std::addressof(r);
+ }
+
+ size_type max_size() const RAPIDJSON_NOEXCEPT
+ {
+ return traits_type::max_size(*this);
+ }
+
+ template <typename ...Args>
+ void construct(pointer p, Args&&... args)
+ {
+ traits_type::construct(*this, p, std::forward<Args>(args)...);
+ }
+ void destroy(pointer p)
+ {
+ traits_type::destroy(*this, p);
+ }
+
+#else // !RAPIDJSON_HAS_CXX11
+
+ typedef typename allocator_type::reference reference;
+ typedef typename allocator_type::const_reference const_reference;
+
+ pointer address(reference r) const RAPIDJSON_NOEXCEPT
+ {
+ return allocator_type::address(r);
+ }
+ const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT
+ {
+ return allocator_type::address(r);
+ }
+
+ size_type max_size() const RAPIDJSON_NOEXCEPT
+ {
+ return allocator_type::max_size();
+ }
+
+ void construct(pointer p, const_reference r)
+ {
+ allocator_type::construct(p, r);
+ }
+ void destroy(pointer p)
+ {
+ allocator_type::destroy(p);
+ }
+
+#endif // !RAPIDJSON_HAS_CXX11
+
+ template <typename U>
+ U* allocate(size_type n = 1, const void* = 0)
+ {
+ return RAPIDJSON_NAMESPACE::Malloc<U>(baseAllocator_, n);
+ }
+ template <typename U>
+ void deallocate(U* p, size_type n = 1)
+ {
+ RAPIDJSON_NAMESPACE::Free<U>(baseAllocator_, p, n);
+ }
+
+ pointer allocate(size_type n = 1, const void* = 0)
+ {
+ return allocate<value_type>(n);
+ }
+ void deallocate(pointer p, size_type n = 1)
+ {
+ deallocate<value_type>(p, n);
+ }
+
+#if RAPIDJSON_HAS_CXX11
+ using is_always_equal = std::is_empty<BaseAllocator>;
+#endif
+
+ template<typename U>
+ bool operator==(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
+ {
+ return baseAllocator_ == rhs.baseAllocator_;
+ }
+ template<typename U>
+ bool operator!=(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT
+ {
+ return !operator==(rhs);
+ }
+
+ //! rapidjson Allocator concept
+ static const bool kNeedFree = BaseAllocator::kNeedFree;
+ static const bool kRefCounted = internal::IsRefCounted<BaseAllocator>::Value;
+ void* Malloc(size_t size)
+ {
+ return baseAllocator_.Malloc(size);
+ }
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize)
+ {
+ return baseAllocator_.Realloc(originalPtr, originalSize, newSize);
+ }
+ static void Free(void *ptr) RAPIDJSON_NOEXCEPT
+ {
+ BaseAllocator::Free(ptr);
+ }
+
+private:
+ template <typename, typename>
+ friend class StdAllocator; // access to StdAllocator<!T>.*
+
+ BaseAllocator baseAllocator_;
};
+#if !RAPIDJSON_HAS_CXX17 // std::allocator<void> deprecated in C++17
+template <typename BaseAllocator>
+class StdAllocator<void, BaseAllocator> :
+ public std::allocator<void>
+{
+ typedef std::allocator<void> allocator_type;
+
+public:
+ typedef BaseAllocator BaseAllocatorType;
+
+ StdAllocator() RAPIDJSON_NOEXCEPT :
+ allocator_type(),
+ baseAllocator_()
+ { }
+
+ StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT :
+ allocator_type(rhs),
+ baseAllocator_(rhs.baseAllocator_)
+ { }
+
+ template<typename U>
+ StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT :
+ allocator_type(rhs),
+ baseAllocator_(rhs.baseAllocator_)
+ { }
+
+ /* implicit */
+ StdAllocator(const BaseAllocator& baseAllocator) RAPIDJSON_NOEXCEPT :
+ allocator_type(),
+ baseAllocator_(baseAllocator)
+ { }
+
+ ~StdAllocator() RAPIDJSON_NOEXCEPT
+ { }
+
+ template<typename U>
+ struct rebind {
+ typedef StdAllocator<U, BaseAllocator> other;
+ };
+
+ typedef typename allocator_type::value_type value_type;
+
+private:
+ template <typename, typename>
+ friend class StdAllocator; // access to StdAllocator<!T>.*
+
+ BaseAllocator baseAllocator_;
+};
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ENCODINGS_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/cursorstreamwrapper.h b/3rdparty/rapidjson/include/rapidjson/cursorstreamwrapper.h
new file mode 100644
index 00000000000..fd6513db14a
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/cursorstreamwrapper.h
@@ -0,0 +1,78 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_
+#define RAPIDJSON_CURSORSTREAMWRAPPER_H_
+
+#include "stream.h"
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+
+//! Cursor stream wrapper for counting line and column number if error exists.
+/*!
+ \tparam InputStream Any stream that implements Stream Concept
+*/
+template <typename InputStream, typename Encoding = UTF8<> >
+class CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ CursorStreamWrapper(InputStream& is):
+ GenericStreamWrapper<InputStream, Encoding>(is), line_(1), col_(0) {}
+
+ // counting line and column number
+ Ch Take() {
+ Ch ch = this->is_.Take();
+ if(ch == '\n') {
+ line_ ++;
+ col_ = 0;
+ } else {
+ col_ ++;
+ }
+ return ch;
+ }
+
+ //! Get the error line number, if error exists.
+ size_t GetLine() const { return line_; }
+ //! Get the error column number, if error exists.
+ size_t GetColumn() const { return col_; }
+
+private:
+ size_t line_; //!< Current Line
+ size_t col_; //!< Current Column
+};
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_POP
+#endif
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_POP
+#endif
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/document.h b/3rdparty/rapidjson/include/rapidjson/document.h
index 19f5a6a5ff9..2cd9a70a600 100644
--- a/3rdparty/rapidjson/include/rapidjson/document.h
+++ b/3rdparty/rapidjson/include/rapidjson/document.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -24,32 +24,39 @@
#include "encodedstream.h"
#include <new> // placement new
#include <limits>
-
-RAPIDJSON_DIAG_PUSH
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
-RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
+#ifdef __cpp_lib_three_way_comparison
+#include <compare>
#endif
+RAPIDJSON_DIAG_PUSH
#ifdef __clang__
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
RAPIDJSON_DIAG_OFF(c++98-compat)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_OFF(effc++)
-#if __GNUC__ >= 6
-RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions
-#endif
#endif // __GNUC__
+#ifdef GetObject
+// see https://github.com/Tencent/rapidjson/issues/1448
+// a former included windows.h might have defined a macro called GetObject, which affects
+// GetObject defined here. This ensures the macro does not get applied
+#pragma push_macro("GetObject")
+#define RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
+#undef GetObject
+#endif
+
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
-#include <iterator> // std::iterator, std::random_access_iterator_tag
+#include <iterator> // std::random_access_iterator_tag
#endif
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
-#include <utility> // std::move
+#if RAPIDJSON_USE_MEMBERSMAP
+#include <map> // std::multimap
#endif
RAPIDJSON_NAMESPACE_BEGIN
@@ -61,6 +68,48 @@ class GenericValue;
template <typename Encoding, typename Allocator, typename StackAllocator>
class GenericDocument;
+/*! \def RAPIDJSON_DEFAULT_ALLOCATOR
+ \ingroup RAPIDJSON_CONFIG
+ \brief Allows to choose default allocator.
+
+ User can define this to use CrtAllocator or MemoryPoolAllocator.
+*/
+#ifndef RAPIDJSON_DEFAULT_ALLOCATOR
+#define RAPIDJSON_DEFAULT_ALLOCATOR ::RAPIDJSON_NAMESPACE::MemoryPoolAllocator<::RAPIDJSON_NAMESPACE::CrtAllocator>
+#endif
+
+/*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR
+ \ingroup RAPIDJSON_CONFIG
+ \brief Allows to choose default stack allocator for Document.
+
+ User can define this to use CrtAllocator or MemoryPoolAllocator.
+*/
+#ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR
+#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR ::RAPIDJSON_NAMESPACE::CrtAllocator
+#endif
+
+/*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY
+ \ingroup RAPIDJSON_CONFIG
+ \brief User defined kDefaultObjectCapacity value.
+
+ User can define this as any natural number.
+*/
+#ifndef RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY
+// number of objects that rapidjson::Value allocates memory for by default
+#define RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY 16
+#endif
+
+/*! \def RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY
+ \ingroup RAPIDJSON_CONFIG
+ \brief User defined kDefaultArrayCapacity value.
+
+ User can define this as any natural number.
+*/
+#ifndef RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY
+// number of array elements that rapidjson::Value allocates memory for by default
+#define RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY 16
+#endif
+
//! Name-value pair in a JSON object value.
/*!
This class was internal to GenericValue. It used to be a inner struct.
@@ -68,9 +117,45 @@ class GenericDocument;
https://code.google.com/p/rapidjson/issues/detail?id=64
*/
template <typename Encoding, typename Allocator>
-struct GenericMember {
+class GenericMember {
+public:
GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
GenericValue<Encoding, Allocator> value; //!< value of member.
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericMember(GenericMember&& rhs) RAPIDJSON_NOEXCEPT
+ : name(std::move(rhs.name)),
+ value(std::move(rhs.value))
+ {
+ }
+
+ //! Move assignment in C++11
+ GenericMember& operator=(GenericMember&& rhs) RAPIDJSON_NOEXCEPT {
+ return *this = static_cast<GenericMember&>(rhs);
+ }
+#endif
+
+ //! Assignment with move semantics.
+ /*! \param rhs Source of the assignment. Its name and value will become a null value after assignment.
+ */
+ GenericMember& operator=(GenericMember& rhs) RAPIDJSON_NOEXCEPT {
+ if (RAPIDJSON_LIKELY(this != &rhs)) {
+ name = rhs.name;
+ value = rhs.value;
+ }
+ return *this;
+ }
+
+ // swap() for std::sort() and other potential use in STL.
+ friend inline void swap(GenericMember& a, GenericMember& b) RAPIDJSON_NOEXCEPT {
+ a.name.Swap(b.name);
+ a.value.Swap(b.value);
+ }
+
+private:
+ //! Copy constructor is not permitted.
+ GenericMember(const GenericMember& rhs);
};
///////////////////////////////////////////////////////////////////////////////
@@ -98,16 +183,13 @@ struct GenericMember {
\see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
*/
template <bool Const, typename Encoding, typename Allocator>
-class GenericMemberIterator
- : public std::iterator<std::random_access_iterator_tag
- , typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {
+class GenericMemberIterator {
friend class GenericValue<Encoding,Allocator>;
template <bool, typename, typename> friend class GenericMemberIterator;
typedef GenericMember<Encoding,Allocator> PlainType;
typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
- typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;
public:
//! Iterator type itself
@@ -117,12 +199,21 @@ public:
//! Non-constant iterator type
typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;
+ /** \name std::iterator_traits support */
+ //@{
+ typedef ValueType value_type;
+ typedef ValueType * pointer;
+ typedef ValueType & reference;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::random_access_iterator_tag iterator_category;
+ //@}
+
//! Pointer to (const) GenericMember
- typedef typename BaseType::pointer Pointer;
+ typedef pointer Pointer;
//! Reference to (const) GenericMember
- typedef typename BaseType::reference Reference;
+ typedef reference Reference;
//! Signed integer type (e.g. \c ptrdiff_t)
- typedef typename BaseType::difference_type DifferenceType;
+ typedef difference_type DifferenceType;
//! Default constructor (singular value)
/*! Creates an iterator pointing to no element.
@@ -168,12 +259,16 @@ public:
//! @name relations
//@{
- bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }
- bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }
- bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }
- bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }
- bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }
- bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }
+ template <bool Const_> bool operator==(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ == that.ptr_; }
+ template <bool Const_> bool operator!=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ != that.ptr_; }
+ template <bool Const_> bool operator<=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ <= that.ptr_; }
+ template <bool Const_> bool operator>=(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ >= that.ptr_; }
+ template <bool Const_> bool operator< (const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ < that.ptr_; }
+ template <bool Const_> bool operator> (const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ > that.ptr_; }
+
+#ifdef __cpp_lib_three_way_comparison
+ template <bool Const_> std::strong_ordering operator<=>(const GenericMemberIterator<Const_, Encoding, Allocator>& that) const { return ptr_ <=> that.ptr_; }
+#endif
//@}
//! @name dereference
@@ -198,17 +293,19 @@ private:
// class-based member iterator implementation disabled, use plain pointers
template <bool Const, typename Encoding, typename Allocator>
-struct GenericMemberIterator;
+class GenericMemberIterator;
//! non-const GenericMemberIterator
template <typename Encoding, typename Allocator>
-struct GenericMemberIterator<false,Encoding,Allocator> {
+class GenericMemberIterator<false,Encoding,Allocator> {
+public:
//! use plain pointer as iterator type
typedef GenericMember<Encoding,Allocator>* Iterator;
};
//! const GenericMemberIterator
template <typename Encoding, typename Allocator>
-struct GenericMemberIterator<true,Encoding,Allocator> {
+class GenericMemberIterator<true,Encoding,Allocator> {
+public:
//! use plain const pointer as iterator type
typedef const GenericMember<Encoding,Allocator>* Iterator;
};
@@ -300,7 +397,7 @@ struct GenericStringRef {
*/
#endif
explicit GenericStringRef(const CharType* str)
- : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); }
+ : s(str), length(NotNullStrLen(str)) {}
//! Create constant string reference from pointer and length
#ifndef __clang__ // -Wdocumentation
@@ -312,7 +409,7 @@ struct GenericStringRef {
*/
#endif
GenericStringRef(const CharType* str, SizeType len)
- : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); }
+ : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); }
GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}
@@ -323,6 +420,14 @@ struct GenericStringRef {
const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
private:
+ SizeType NotNullStrLen(const CharType* str) {
+ RAPIDJSON_ASSERT(str != 0);
+ return internal::StrLen(str);
+ }
+
+ /// Empty string - used when passing in a NULL pointer
+ static const Ch emptyString[];
+
//! Disallow construction from non-const array
template<SizeType N>
GenericStringRef(CharType (&str)[N]) /* = delete */;
@@ -330,6 +435,9 @@ private:
GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */;
};
+template<typename CharType>
+const CharType GenericStringRef<CharType>::emptyString[] = { CharType() };
+
//! Mark a character pointer as constant string
/*! Mark a plain character pointer as a "string literal". This function
can be used to avoid copying a character string to be referenced as a
@@ -344,7 +452,7 @@ private:
*/
template<typename CharType>
inline GenericStringRef<CharType> StringRef(const CharType* str) {
- return GenericStringRef<CharType>(str, internal::StrLen(str));
+ return GenericStringRef<CharType>(str);
}
//! Mark a character pointer as constant string
@@ -434,6 +542,26 @@ struct TypeHelper<ValueType, unsigned> {
static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
};
+#ifdef _MSC_VER
+RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int));
+template<typename ValueType>
+struct TypeHelper<ValueType, long> {
+ static bool Is(const ValueType& v) { return v.IsInt(); }
+ static long Get(const ValueType& v) { return v.GetInt(); }
+ static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); }
+ static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
+};
+
+RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned));
+template<typename ValueType>
+struct TypeHelper<ValueType, unsigned long> {
+ static bool Is(const ValueType& v) { return v.IsUint(); }
+ static unsigned long Get(const ValueType& v) { return v.GetUint(); }
+ static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); }
+ static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
+};
+#endif
+
template<typename ValueType>
struct TypeHelper<ValueType, int64_t> {
static bool Is(const ValueType& v) { return v.IsInt64(); }
@@ -507,7 +635,7 @@ struct TypeHelper<ValueType, typename ValueType::Object> {
static bool Is(const ValueType& v) { return v.IsObject(); }
static ObjectType Get(ValueType& v) { return v.GetObject(); }
static ValueType& Set(ValueType& v, ObjectType data) { return v = data; }
- static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; }
+ static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; }
};
template<typename ValueType>
@@ -536,7 +664,7 @@ template <bool, typename> class GenericObject;
\tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
\tparam Allocator Allocator type for allocating memory of object, array and string.
*/
-template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+template <typename Encoding, typename Allocator = RAPIDJSON_DEFAULT_ALLOCATOR >
class GenericValue {
public:
//! Name-value pair in an object.
@@ -590,11 +718,11 @@ public:
\note Default content for number is zero.
*/
explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {
- static const uint16_t defaultFlags[7] = {
+ static const uint16_t defaultFlags[] = {
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
kNumberAnyFlag
};
- RAPIDJSON_ASSERT(type <= kNumberType);
+ RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType);
data_.f.flags = defaultFlags[type];
// Use ShortString to store empty string.
@@ -607,10 +735,40 @@ public:
\tparam SourceAllocator allocator of \c rhs
\param rhs Value to copy from (read-only)
\param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().
+ \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer)
\see CopyFrom()
*/
- template< typename SourceAllocator >
- GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);
+ template <typename SourceAllocator>
+ GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {
+ switch (rhs.GetType()) {
+ case kObjectType:
+ DoCopyMembers(rhs, allocator, copyConstStrings);
+ break;
+ case kArrayType: {
+ SizeType count = rhs.data_.a.size;
+ GenericValue* le = reinterpret_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
+ const GenericValue<Encoding,SourceAllocator>* re = rhs.GetElementsPointer();
+ for (SizeType i = 0; i < count; i++)
+ new (&le[i]) GenericValue(re[i], allocator, copyConstStrings);
+ data_.f.flags = kArrayFlag;
+ data_.a.size = data_.a.capacity = count;
+ SetElementsPointer(le);
+ }
+ break;
+ case kStringType:
+ if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) {
+ data_.f.flags = rhs.data_.f.flags;
+ data_ = *reinterpret_cast<const Data*>(&rhs.data_);
+ }
+ else
+ SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
+ break;
+ default:
+ data_.f.flags = rhs.data_.f.flags;
+ data_ = *reinterpret_cast<const Data*>(&rhs.data_);
+ break;
+ }
+ }
//! Constructor for boolean value.
/*! \param b Boolean value
@@ -672,6 +830,9 @@ public:
//! Constructor for double value.
explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; }
+ //! Constructor for float value.
+ explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast<double>(f); data_.f.flags = kNumberDoubleFlag; }
+
//! Constructor for constant string (i.e. do not make a copy of string)
GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }
@@ -717,25 +878,30 @@ public:
/*! Need to destruct elements of array, members of object, or copy-string.
*/
~GenericValue() {
- if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ // With RAPIDJSON_USE_MEMBERSMAP, the maps need to be destroyed to release
+ // their Allocator if it's refcounted (e.g. MemoryPoolAllocator).
+ if (Allocator::kNeedFree || (RAPIDJSON_USE_MEMBERSMAP+0 &&
+ internal::IsRefCounted<Allocator>::Value)) {
switch(data_.f.flags) {
case kArrayFlag:
{
GenericValue* e = GetElementsPointer();
for (GenericValue* v = e; v != e + data_.a.size; ++v)
v->~GenericValue();
- Allocator::Free(e);
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ Allocator::Free(e);
+ }
}
break;
case kObjectFlag:
- for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
- m->~Member();
- Allocator::Free(GetMembersPointer());
+ DoFreeMembers();
break;
case kCopyStringFlag:
- Allocator::Free(const_cast<Ch*>(GetStringPointer()));
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ Allocator::Free(const_cast<Ch*>(GetStringPointer()));
+ }
break;
default:
@@ -753,9 +919,15 @@ public:
/*! \param rhs Source of the assignment. It will become a null value after assignment.
*/
GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
- RAPIDJSON_ASSERT(this != &rhs);
- this->~GenericValue();
- RawAssign(rhs);
+ if (RAPIDJSON_LIKELY(this != &rhs)) {
+ // Can't destroy "this" before assigning "rhs", otherwise "rhs"
+ // could be used after free if it's an sub-Value of "this",
+ // hence the temporary danse.
+ GenericValue temp;
+ temp.RawAssign(rhs);
+ this->~GenericValue();
+ RawAssign(temp);
+ }
return *this;
}
@@ -800,12 +972,13 @@ public:
\tparam SourceAllocator Allocator type of \c rhs
\param rhs Value to copy from (read-only)
\param allocator Allocator to use for copying
+ \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer)
*/
template <typename SourceAllocator>
- GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
+ GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {
RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&rhs));
this->~GenericValue();
- new (this) GenericValue(rhs, allocator);
+ new (this) GenericValue(rhs, allocator, copyConstStrings);
return *this;
}
@@ -846,7 +1019,7 @@ public:
//! Equal-to operator
/*!
\note If an object contains duplicated named member, comparing equality with any object is always \c false.
- \note Linear time complexity (number of all values in the subtree and total lengths of all strings).
+ \note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings).
*/
template <typename SourceAllocator>
bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
@@ -905,6 +1078,7 @@ public:
*/
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
+#ifndef __cpp_impl_three_way_comparison
//! Not-equal-to operator
/*! \return !(*this == rhs)
*/
@@ -929,6 +1103,7 @@ public:
*/
template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
//@}
+#endif
//!@name Type
//@{
@@ -955,14 +1130,14 @@ public:
uint64_t u = GetUint64();
volatile double d = static_cast<double>(u);
return (d >= 0.0)
- && (d < static_cast<double>(std::numeric_limits<uint64_t>::max()))
+ && (d < static_cast<double>((std::numeric_limits<uint64_t>::max)()))
&& (u == static_cast<uint64_t>(d));
}
if (IsInt64()) {
int64_t i = GetInt64();
volatile double d = static_cast<double>(i);
- return (d >= static_cast<double>(std::numeric_limits<int64_t>::min()))
- && (d < static_cast<double>(std::numeric_limits<int64_t>::max()))
+ return (d >= static_cast<double>((std::numeric_limits<int64_t>::min)()))
+ && (d < static_cast<double>((std::numeric_limits<int64_t>::max)()))
&& (i == static_cast<int64_t>(d));
}
return true; // double, int, uint are always lossless
@@ -979,8 +1154,8 @@ public:
bool IsLosslessFloat() const {
if (!IsNumber()) return false;
double a = GetDouble();
- if (a < static_cast<double>(-std::numeric_limits<float>::max())
- || a > static_cast<double>(std::numeric_limits<float>::max()))
+ if (a < static_cast<double>(-(std::numeric_limits<float>::max)())
+ || a > static_cast<double>((std::numeric_limits<float>::max)()))
return false;
double b = static_cast<double>(static_cast<float>(a));
return a >= b && a <= b; // Prevent -Wfloat-equal
@@ -1015,6 +1190,9 @@ public:
//! Get the number of members in the object.
SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
+ //! Get the capacity of object.
+ SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; }
+
//! Check whether the object is empty.
bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
@@ -1052,13 +1230,28 @@ public:
else {
RAPIDJSON_ASSERT(false); // see above note
- // This will generate -Wexit-time-destructors in clang
- // static GenericValue NullValue;
- // return NullValue;
-
- // Use static buffer and placement-new to prevent destruction
- static char buffer[sizeof(GenericValue)];
+#if RAPIDJSON_HAS_CXX11
+ // Use thread-local storage to prevent races between threads.
+ // Use static buffer and placement-new to prevent destruction, with
+ // alignas() to ensure proper alignment.
+ alignas(GenericValue) thread_local static char buffer[sizeof(GenericValue)];
+ return *new (buffer) GenericValue();
+#elif defined(_MSC_VER) && _MSC_VER < 1900
+ // There's no way to solve both thread locality and proper alignment
+ // simultaneously.
+ __declspec(thread) static char buffer[sizeof(GenericValue)];
return *new (buffer) GenericValue();
+#elif defined(__GNUC__) || defined(__clang__)
+ // This will generate -Wexit-time-destructors in clang, but that's
+ // better than having under-alignment.
+ __thread static GenericValue buffer;
+ return buffer;
+#else
+ // Don't know what compiler this is, so don't know how to ensure
+ // thread-locality.
+ static GenericValue buffer;
+ return buffer;
+#endif
}
}
template <typename SourceAllocator>
@@ -1083,6 +1276,18 @@ public:
/*! \pre IsObject() == true */
MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }
+ //! Request the object to have enough capacity to store members.
+ /*! \param newCapacity The capacity that the object at least need to have.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note Linear time complexity.
+ */
+ GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) {
+ RAPIDJSON_ASSERT(IsObject());
+ DoReserveMembers(newCapacity, allocator);
+ return *this;
+ }
+
//! Check whether a member exists in the object.
/*!
\param name Member name to be searched.
@@ -1153,11 +1358,7 @@ public:
MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(name.IsString());
- MemberIterator member = MemberBegin();
- for ( ; member != MemberEnd(); ++member)
- if (name.StringEqual(member->name))
- break;
- return member;
+ return DoFindMember(name);
}
template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
@@ -1186,23 +1387,7 @@ public:
GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(name.IsString());
-
- ObjectData& o = data_.o;
- if (o.size >= o.capacity) {
- if (o.capacity == 0) {
- o.capacity = kDefaultObjectCapacity;
- SetMembersPointer(reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member))));
- }
- else {
- SizeType oldCapacity = o.capacity;
- o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
- SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member))));
- }
- }
- Member* members = GetMembersPointer();
- members[o.size].name.RawAssign(name);
- members[o.size].value.RawAssign(value);
- o.size++;
+ DoAddMember(name, value, allocator);
return *this;
}
@@ -1336,9 +1521,7 @@ public:
*/
void RemoveAllMembers() {
RAPIDJSON_ASSERT(IsObject());
- for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
- m->~Member();
- data_.o.size = 0;
+ DoClearMembers();
}
//! Remove a member in object by its name.
@@ -1382,14 +1565,7 @@ public:
RAPIDJSON_ASSERT(data_.o.size > 0);
RAPIDJSON_ASSERT(GetMembersPointer() != 0);
RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
-
- MemberIterator last(GetMembersPointer() + (data_.o.size - 1));
- if (data_.o.size > 1 && m != last)
- *m = *last; // Move the last one to this place
- else
- m->~Member(); // Only one left, just destroy
- --data_.o.size;
- return m;
+ return DoRemoveMember(m);
}
//! Remove a member from an object by iterator.
@@ -1421,13 +1597,7 @@ public:
RAPIDJSON_ASSERT(first >= MemberBegin());
RAPIDJSON_ASSERT(first <= last);
RAPIDJSON_ASSERT(last <= MemberEnd());
-
- MemberIterator pos = MemberBegin() + (first - MemberBegin());
- for (MemberIterator itr = pos; itr != last; ++itr)
- itr->~Member();
- std::memmove(&*pos, &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
- data_.o.size -= static_cast<SizeType>(last - first);
- return pos;
+ return DoEraseMembers(first, last);
}
//! Erase a member in object by its name.
@@ -1456,7 +1626,9 @@ public:
}
Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
+ Object GetObj() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
+ ConstObject GetObj() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
//@}
@@ -1628,8 +1800,8 @@ public:
RAPIDJSON_ASSERT(last <= End());
ValueIterator pos = Begin() + (first - Begin());
for (ValueIterator itr = pos; itr != last; ++itr)
- itr->~GenericValue();
- std::memmove(pos, last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
+ itr->~GenericValue();
+ std::memmove(static_cast<void*>(pos), last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
data_.a.size -= static_cast<SizeType>(last - first);
return pos;
}
@@ -1671,19 +1843,19 @@ public:
GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
- GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(f); return *this; }
+ GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast<double>(f)); return *this; }
//@}
//!@name String
//@{
- const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); }
+ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return DataString(data_); }
//! Get the length of string.
/*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
*/
- SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
+ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return DataStringLength(data_); }
//! Set this value as a string without copying source string.
/*! This version has better performance with supplied length, and also support string containing null character.
@@ -1710,7 +1882,7 @@ public:
\return The value itself for fluent API.
\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
*/
- GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }
+ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); }
//! Set this value as a string by copying from source string.
/*! \param s source string.
@@ -1718,7 +1890,15 @@ public:
\return The value itself for fluent API.
\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
*/
- GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
+ GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); }
+
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string reference
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+ */
+ GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; }
#if RAPIDJSON_HAS_STDSTRING
//! Set this value as a string by copying from source string.
@@ -1728,7 +1908,7 @@ public:
\post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
\note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
*/
- GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }
+ GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(StringRef(s), allocator); }
#endif
//@}
@@ -1786,7 +1966,7 @@ public:
case kArrayType:
if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
return false;
- for (const GenericValue* v = Begin(); v != End(); ++v)
+ for (ConstValueIterator v = Begin(); v != End(); ++v)
if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
return false;
return handler.EndArray(data_.a.size);
@@ -1822,25 +2002,26 @@ private:
// Initial flags of different types.
kNullFlag = kNullType,
- kTrueFlag = kTrueType | kBoolFlag,
- kFalseFlag = kFalseType | kBoolFlag,
- kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
- kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
- kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
- kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
- kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
- kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
- kConstStringFlag = kStringType | kStringFlag,
- kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
- kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
+ // These casts are added to suppress the warning on MSVC about bitwise operations between enums of different types.
+ kTrueFlag = static_cast<int>(kTrueType) | static_cast<int>(kBoolFlag),
+ kFalseFlag = static_cast<int>(kFalseType) | static_cast<int>(kBoolFlag),
+ kNumberIntFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kIntFlag | kInt64Flag),
+ kNumberUintFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag),
+ kNumberInt64Flag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kInt64Flag),
+ kNumberUint64Flag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kUint64Flag),
+ kNumberDoubleFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kDoubleFlag),
+ kNumberAnyFlag = static_cast<int>(kNumberType) | static_cast<int>(kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag),
+ kConstStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag),
+ kCopyStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag | kCopyFlag),
+ kShortStringFlag = static_cast<int>(kStringType) | static_cast<int>(kStringFlag | kCopyFlag | kInlineStrFlag),
kObjectFlag = kObjectType,
kArrayFlag = kArrayType,
kTypeMask = 0x07
};
- static const SizeType kDefaultArrayCapacity = 16;
- static const SizeType kDefaultObjectCapacity = 16;
+ static const SizeType kDefaultArrayCapacity = RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY;
+ static const SizeType kDefaultObjectCapacity = RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY;
struct Flag {
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
@@ -1923,6 +2104,13 @@ private:
Flag f;
}; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION
+ static RAPIDJSON_FORCEINLINE const Ch* DataString(const Data& data) {
+ return (data.f.flags & kInlineStrFlag) ? data.ss.str : RAPIDJSON_GETPOINTER(Ch, data.s.str);
+ }
+ static RAPIDJSON_FORCEINLINE SizeType DataStringLength(const Data& data) {
+ return (data.f.flags & kInlineStrFlag) ? data.ss.GetLength() : data.s.length;
+ }
+
RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }
RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }
RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }
@@ -1930,13 +2118,293 @@ private:
RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }
RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }
+#if RAPIDJSON_USE_MEMBERSMAP
+
+ struct MapTraits {
+ struct Less {
+ bool operator()(const Data& s1, const Data& s2) const {
+ SizeType n1 = DataStringLength(s1), n2 = DataStringLength(s2);
+ int cmp = std::memcmp(DataString(s1), DataString(s2), sizeof(Ch) * (n1 < n2 ? n1 : n2));
+ return cmp < 0 || (cmp == 0 && n1 < n2);
+ }
+ };
+ typedef std::pair<const Data, SizeType> Pair;
+ typedef std::multimap<Data, SizeType, Less, StdAllocator<Pair, Allocator> > Map;
+ typedef typename Map::iterator Iterator;
+ };
+ typedef typename MapTraits::Map Map;
+ typedef typename MapTraits::Less MapLess;
+ typedef typename MapTraits::Pair MapPair;
+ typedef typename MapTraits::Iterator MapIterator;
+
+ //
+ // Layout of the members' map/array, re(al)located according to the needed capacity:
+ //
+ // {Map*}<>{capacity}<>{Member[capacity]}<>{MapIterator[capacity]}
+ //
+ // (where <> stands for the RAPIDJSON_ALIGN-ment, if needed)
+ //
+
+ static RAPIDJSON_FORCEINLINE size_t GetMapLayoutSize(SizeType capacity) {
+ return RAPIDJSON_ALIGN(sizeof(Map*)) +
+ RAPIDJSON_ALIGN(sizeof(SizeType)) +
+ RAPIDJSON_ALIGN(capacity * sizeof(Member)) +
+ capacity * sizeof(MapIterator);
+ }
+
+ static RAPIDJSON_FORCEINLINE SizeType &GetMapCapacity(Map* &map) {
+ return *reinterpret_cast<SizeType*>(reinterpret_cast<uintptr_t>(&map) +
+ RAPIDJSON_ALIGN(sizeof(Map*)));
+ }
+
+ static RAPIDJSON_FORCEINLINE Member* GetMapMembers(Map* &map) {
+ return reinterpret_cast<Member*>(reinterpret_cast<uintptr_t>(&map) +
+ RAPIDJSON_ALIGN(sizeof(Map*)) +
+ RAPIDJSON_ALIGN(sizeof(SizeType)));
+ }
+
+ static RAPIDJSON_FORCEINLINE MapIterator* GetMapIterators(Map* &map) {
+ return reinterpret_cast<MapIterator*>(reinterpret_cast<uintptr_t>(&map) +
+ RAPIDJSON_ALIGN(sizeof(Map*)) +
+ RAPIDJSON_ALIGN(sizeof(SizeType)) +
+ RAPIDJSON_ALIGN(GetMapCapacity(map) * sizeof(Member)));
+ }
+
+ static RAPIDJSON_FORCEINLINE Map* &GetMap(Member* members) {
+ RAPIDJSON_ASSERT(members != 0);
+ return *reinterpret_cast<Map**>(reinterpret_cast<uintptr_t>(members) -
+ RAPIDJSON_ALIGN(sizeof(SizeType)) -
+ RAPIDJSON_ALIGN(sizeof(Map*)));
+ }
+
+ // Some compilers' debug mechanisms want all iterators to be destroyed, for their accounting..
+ RAPIDJSON_FORCEINLINE MapIterator DropMapIterator(MapIterator& rhs) {
+#if RAPIDJSON_HAS_CXX11
+ MapIterator ret = std::move(rhs);
+#else
+ MapIterator ret = rhs;
+#endif
+ rhs.~MapIterator();
+ return ret;
+ }
+
+ Map* &DoReallocMap(Map** oldMap, SizeType newCapacity, Allocator& allocator) {
+ Map **newMap = static_cast<Map**>(allocator.Malloc(GetMapLayoutSize(newCapacity)));
+ GetMapCapacity(*newMap) = newCapacity;
+ if (!oldMap) {
+ *newMap = new (allocator.Malloc(sizeof(Map))) Map(MapLess(), allocator);
+ }
+ else {
+ *newMap = *oldMap;
+ size_t count = (*oldMap)->size();
+ std::memcpy(static_cast<void*>(GetMapMembers(*newMap)),
+ static_cast<void*>(GetMapMembers(*oldMap)),
+ count * sizeof(Member));
+ MapIterator *oldIt = GetMapIterators(*oldMap),
+ *newIt = GetMapIterators(*newMap);
+ while (count--) {
+ new (&newIt[count]) MapIterator(DropMapIterator(oldIt[count]));
+ }
+ Allocator::Free(oldMap);
+ }
+ return *newMap;
+ }
+
+ RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) {
+ return GetMapMembers(DoReallocMap(0, capacity, allocator));
+ }
+
+ void DoReserveMembers(SizeType newCapacity, Allocator& allocator) {
+ ObjectData& o = data_.o;
+ if (newCapacity > o.capacity) {
+ Member* oldMembers = GetMembersPointer();
+ Map **oldMap = oldMembers ? &GetMap(oldMembers) : 0,
+ *&newMap = DoReallocMap(oldMap, newCapacity, allocator);
+ RAPIDJSON_SETPOINTER(Member, o.members, GetMapMembers(newMap));
+ o.capacity = newCapacity;
+ }
+ }
+
+ template <typename SourceAllocator>
+ MemberIterator DoFindMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ if (Member* members = GetMembersPointer()) {
+ Map* &map = GetMap(members);
+ MapIterator mit = map->find(reinterpret_cast<const Data&>(name.data_));
+ if (mit != map->end()) {
+ return MemberIterator(&members[mit->second]);
+ }
+ }
+ return MemberEnd();
+ }
+
+ void DoClearMembers() {
+ if (Member* members = GetMembersPointer()) {
+ Map* &map = GetMap(members);
+ MapIterator* mit = GetMapIterators(map);
+ for (SizeType i = 0; i < data_.o.size; i++) {
+ map->erase(DropMapIterator(mit[i]));
+ members[i].~Member();
+ }
+ data_.o.size = 0;
+ }
+ }
+
+ void DoFreeMembers() {
+ if (Member* members = GetMembersPointer()) {
+ GetMap(members)->~Map();
+ for (SizeType i = 0; i < data_.o.size; i++) {
+ members[i].~Member();
+ }
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ Map** map = &GetMap(members);
+ Allocator::Free(*map);
+ Allocator::Free(map);
+ }
+ }
+ }
+
+#else // !RAPIDJSON_USE_MEMBERSMAP
+
+ RAPIDJSON_FORCEINLINE Member* DoAllocMembers(SizeType capacity, Allocator& allocator) {
+ return Malloc<Member>(allocator, capacity);
+ }
+
+ void DoReserveMembers(SizeType newCapacity, Allocator& allocator) {
+ ObjectData& o = data_.o;
+ if (newCapacity > o.capacity) {
+ Member* newMembers = Realloc<Member>(allocator, GetMembersPointer(), o.capacity, newCapacity);
+ RAPIDJSON_SETPOINTER(Member, o.members, newMembers);
+ o.capacity = newCapacity;
+ }
+ }
+
+ template <typename SourceAllocator>
+ MemberIterator DoFindMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ MemberIterator member = MemberBegin();
+ for ( ; member != MemberEnd(); ++member)
+ if (name.StringEqual(member->name))
+ break;
+ return member;
+ }
+
+ void DoClearMembers() {
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ data_.o.size = 0;
+ }
+
+ void DoFreeMembers() {
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ Allocator::Free(GetMembersPointer());
+ }
+
+#endif // !RAPIDJSON_USE_MEMBERSMAP
+
+ void DoAddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
+ ObjectData& o = data_.o;
+ if (o.size >= o.capacity)
+ DoReserveMembers(o.capacity ? (o.capacity + (o.capacity + 1) / 2) : kDefaultObjectCapacity, allocator);
+ Member* members = GetMembersPointer();
+ Member* m = members + o.size;
+ m->name.RawAssign(name);
+ m->value.RawAssign(value);
+#if RAPIDJSON_USE_MEMBERSMAP
+ Map* &map = GetMap(members);
+ MapIterator* mit = GetMapIterators(map);
+ new (&mit[o.size]) MapIterator(map->insert(MapPair(m->name.data_, o.size)));
+#endif
+ ++o.size;
+ }
+
+ MemberIterator DoRemoveMember(MemberIterator m) {
+ ObjectData& o = data_.o;
+ Member* members = GetMembersPointer();
+#if RAPIDJSON_USE_MEMBERSMAP
+ Map* &map = GetMap(members);
+ MapIterator* mit = GetMapIterators(map);
+ SizeType mpos = static_cast<SizeType>(&*m - members);
+ map->erase(DropMapIterator(mit[mpos]));
+#endif
+ MemberIterator last(members + (o.size - 1));
+ if (o.size > 1 && m != last) {
+#if RAPIDJSON_USE_MEMBERSMAP
+ new (&mit[mpos]) MapIterator(DropMapIterator(mit[&*last - members]));
+ mit[mpos]->second = mpos;
+#endif
+ *m = *last; // Move the last one to this place
+ }
+ else {
+ m->~Member(); // Only one left, just destroy
+ }
+ --o.size;
+ return m;
+ }
+
+ MemberIterator DoEraseMembers(ConstMemberIterator first, ConstMemberIterator last) {
+ ObjectData& o = data_.o;
+ MemberIterator beg = MemberBegin(),
+ pos = beg + (first - beg),
+ end = MemberEnd();
+#if RAPIDJSON_USE_MEMBERSMAP
+ Map* &map = GetMap(GetMembersPointer());
+ MapIterator* mit = GetMapIterators(map);
+#endif
+ for (MemberIterator itr = pos; itr != last; ++itr) {
+#if RAPIDJSON_USE_MEMBERSMAP
+ map->erase(DropMapIterator(mit[itr - beg]));
+#endif
+ itr->~Member();
+ }
+#if RAPIDJSON_USE_MEMBERSMAP
+ if (first != last) {
+ // Move remaining members/iterators
+ MemberIterator next = pos + (last - first);
+ for (MemberIterator itr = pos; next != end; ++itr, ++next) {
+ std::memcpy(static_cast<void*>(&*itr), &*next, sizeof(Member));
+ SizeType mpos = static_cast<SizeType>(itr - beg);
+ new (&mit[mpos]) MapIterator(DropMapIterator(mit[next - beg]));
+ mit[mpos]->second = mpos;
+ }
+ }
+#else
+ std::memmove(static_cast<void*>(&*pos), &*last,
+ static_cast<size_t>(end - last) * sizeof(Member));
+#endif
+ o.size -= static_cast<SizeType>(last - first);
+ return pos;
+ }
+
+ template <typename SourceAllocator>
+ void DoCopyMembers(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings) {
+ RAPIDJSON_ASSERT(rhs.GetType() == kObjectType);
+
+ data_.f.flags = kObjectFlag;
+ SizeType count = rhs.data_.o.size;
+ Member* lm = DoAllocMembers(count, allocator);
+ const typename GenericValue<Encoding,SourceAllocator>::Member* rm = rhs.GetMembersPointer();
+#if RAPIDJSON_USE_MEMBERSMAP
+ Map* &map = GetMap(lm);
+ MapIterator* mit = GetMapIterators(map);
+#endif
+ for (SizeType i = 0; i < count; i++) {
+ new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);
+ new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);
+#if RAPIDJSON_USE_MEMBERSMAP
+ new (&mit[i]) MapIterator(map->insert(MapPair(lm[i].name.data_, i)));
+#endif
+ }
+ data_.o.size = data_.o.capacity = count;
+ SetMembersPointer(lm);
+ }
+
// Initialize this value as array with initial data, without calling destructor.
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
data_.f.flags = kArrayFlag;
if (count) {
GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
SetElementsPointer(e);
- std::memcpy(e, values, count * sizeof(GenericValue));
+ std::memcpy(static_cast<void*>(e), values, count * sizeof(GenericValue));
}
else
SetElementsPointer(0);
@@ -1947,9 +2415,16 @@ private:
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
data_.f.flags = kObjectFlag;
if (count) {
- Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
+ Member* m = DoAllocMembers(count, allocator);
SetMembersPointer(m);
- std::memcpy(m, members, count * sizeof(Member));
+ std::memcpy(static_cast<void*>(m), members, count * sizeof(Member));
+#if RAPIDJSON_USE_MEMBERSMAP
+ Map* &map = GetMap(m);
+ MapIterator* mit = GetMapIterators(map);
+ for (SizeType i = 0; i < count; i++) {
+ new (&mit[i]) MapIterator(map->insert(MapPair(m[i].name.data_, i)));
+ }
+#endif
}
else
SetMembersPointer(0);
@@ -2020,12 +2495,13 @@ typedef GenericValue<UTF8<> > Value;
\tparam StackAllocator Allocator for allocating memory for stack during parsing.
\warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue.
*/
-template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator>
+template <typename Encoding, typename Allocator = RAPIDJSON_DEFAULT_ALLOCATOR, typename StackAllocator = RAPIDJSON_DEFAULT_STACK_ALLOCATOR >
class GenericDocument : public GenericValue<Encoding, Allocator> {
public:
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document.
typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+ typedef StackAllocator StackAllocatorType; //!< StackAllocator type from template parameter.
//! Constructor
/*! Creates an empty document of specified type.
@@ -2038,7 +2514,7 @@ public:
GenericValue<Encoding, Allocator>(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
{
if (!allocator_)
- ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
}
//! Constructor
@@ -2051,7 +2527,7 @@ public:
allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
{
if (!allocator_)
- ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
@@ -2070,6 +2546,13 @@ public:
#endif
~GenericDocument() {
+ // Clear the ::ValueType before ownAllocator is destroyed, ~ValueType()
+ // runs last and may access its elements or members which would be freed
+ // with an allocator like MemoryPoolAllocator (CrtAllocator does not
+ // free its data when destroyed, but MemoryPoolAllocator does).
+ if (ownAllocator_) {
+ ValueType::SetNull();
+ }
Destroy();
}
@@ -2112,6 +2595,10 @@ public:
return *this;
}
+ // Allow Swap with ValueType.
+ // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names.
+ using ValueType::Swap;
+
//! free-standing swap function helper
/*!
Helper function to enable support for common swap implementation pattern based on \c std::swap:
@@ -2243,7 +2730,7 @@ public:
template <unsigned parseFlags, typename SourceEncoding>
GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
- MemoryStream ms(static_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch));
+ MemoryStream ms(reinterpret_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch));
EncodedInputStream<SourceEncoding, MemoryStream> is(ms);
ParseStream<parseFlags, SourceEncoding>(is);
return *this;
@@ -2280,7 +2767,7 @@ public:
//!@name Handling parse errors
//!@{
- //! Whether a parse error has occured in the last parsing.
+ //! Whether a parse error has occurred in the last parsing.
bool HasParseError() const { return parseResult_.IsError(); }
//! Get the \ref ParseErrorCode of last parsing.
@@ -2401,34 +2888,6 @@ private:
//! GenericDocument with UTF8 encoding
typedef GenericDocument<UTF8<> > Document;
-// defined here due to the dependency on GenericDocument
-template <typename Encoding, typename Allocator>
-template <typename SourceAllocator>
-inline
-GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator)
-{
- switch (rhs.GetType()) {
- case kObjectType:
- case kArrayType: { // perform deep copy via SAX Handler
- GenericDocument<Encoding,Allocator> d(&allocator);
- rhs.Accept(d);
- RawAssign(*d.stack_.template Pop<GenericValue>(1));
- }
- break;
- case kStringType:
- if (rhs.data_.f.flags == kConstStringFlag) {
- data_.f.flags = rhs.data_.f.flags;
- data_ = *reinterpret_cast<const Data*>(&rhs.data_);
- } else {
- SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
- }
- break;
- default:
- data_.f.flags = rhs.data_.f.flags;
- data_ = *reinterpret_cast<const Data*>(&rhs.data_);
- break;
- }
-}
//! Helper class for accessing Value of array type.
/*!
@@ -2454,6 +2913,7 @@ public:
GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; }
~GenericArray() {}
+ operator ValueType&() const { return value_; }
SizeType Size() const { return value_.Size(); }
SizeType Capacity() const { return value_.Capacity(); }
bool Empty() const { return value_.Empty(); }
@@ -2509,7 +2969,9 @@ public:
GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; }
~GenericObject() {}
+ operator ValueType&() const { return value_; }
SizeType MemberCount() const { return value_.MemberCount(); }
+ SizeType MemberCapacity() const { return value_.MemberCapacity(); }
bool ObjectEmpty() const { return value_.ObjectEmpty(); }
template <typename T> ValueType& operator[](T* name) const { return value_[name]; }
template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; }
@@ -2518,6 +2980,7 @@ public:
#endif
MemberIterator MemberBegin() const { return value_.MemberBegin(); }
MemberIterator MemberEnd() const { return value_.MemberEnd(); }
+ GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; }
bool HasMember(const Ch* name) const { return value_.HasMember(name); }
#if RAPIDJSON_HAS_STDSTRING
bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); }
@@ -2543,7 +3006,7 @@ public:
GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
- void RemoveAllMembers() { return value_.RemoveAllMembers(); }
+ void RemoveAllMembers() { value_.RemoveAllMembers(); }
bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); }
#if RAPIDJSON_HAS_STDSTRING
bool RemoveMember(const std::basic_string<Ch>& name) const { return value_.RemoveMember(name); }
@@ -2572,4 +3035,9 @@ private:
RAPIDJSON_NAMESPACE_END
RAPIDJSON_DIAG_POP
+#ifdef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
+#pragma pop_macro("GetObject")
+#undef RAPIDJSON_WINDOWS_GETOBJECT_WORKAROUND_APPLIED
+#endif
+
#endif // RAPIDJSON_DOCUMENT_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/encodedstream.h b/3rdparty/rapidjson/include/rapidjson/encodedstream.h
index 145068386a0..cf046b89235 100644
--- a/3rdparty/rapidjson/include/rapidjson/encodedstream.h
+++ b/3rdparty/rapidjson/include/rapidjson/encodedstream.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -200,7 +200,7 @@ private:
// xx xx xx xx UTF-8
if (!hasBOM_) {
- unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
+ int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
switch (pattern) {
case 0x08: type_ = kUTF32BE; break;
case 0x0A: type_ = kUTF16BE; break;
diff --git a/3rdparty/rapidjson/include/rapidjson/encodings.h b/3rdparty/rapidjson/include/rapidjson/encodings.h
index baa7c2b17f8..50ad18bdc08 100644
--- a/3rdparty/rapidjson/include/rapidjson/encodings.h
+++ b/3rdparty/rapidjson/include/rapidjson/encodings.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -17,7 +17,7 @@
#include "rapidjson.h"
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__clang__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
RAPIDJSON_DIAG_OFF(4702) // unreachable code
@@ -144,9 +144,9 @@ struct UTF8 {
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
-#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
-#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
-#define TAIL() COPY(); TRANS(0x70)
+#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
+#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
+#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
typename InputStream::Ch c = is.Take();
if (!(c & 0x80)) {
*codepoint = static_cast<unsigned char>(c);
@@ -157,48 +157,48 @@ struct UTF8 {
if (type >= 32) {
*codepoint = 0;
} else {
- *codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
+ *codepoint = (0xFFu >> type) & static_cast<unsigned char>(c);
}
bool result = true;
switch (type) {
- case 2: TAIL(); return result;
- case 3: TAIL(); TAIL(); return result;
- case 4: COPY(); TRANS(0x50); TAIL(); return result;
- case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
- case 6: TAIL(); TAIL(); TAIL(); return result;
- case 10: COPY(); TRANS(0x20); TAIL(); return result;
- case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
+ case 2: RAPIDJSON_TAIL(); return result;
+ case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+ case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
+ case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+ case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+ case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
+ case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
default: return false;
}
-#undef COPY
-#undef TRANS
-#undef TAIL
+#undef RAPIDJSON_COPY
+#undef RAPIDJSON_TRANS
+#undef RAPIDJSON_TAIL
}
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
-#define COPY() os.Put(c = is.Take())
-#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
-#define TAIL() COPY(); TRANS(0x70)
+#define RAPIDJSON_COPY() os.Put(c = is.Take())
+#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
+#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70)
Ch c;
- COPY();
+ RAPIDJSON_COPY();
if (!(c & 0x80))
return true;
bool result = true;
switch (GetRange(static_cast<unsigned char>(c))) {
- case 2: TAIL(); return result;
- case 3: TAIL(); TAIL(); return result;
- case 4: COPY(); TRANS(0x50); TAIL(); return result;
- case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
- case 6: TAIL(); TAIL(); TAIL(); return result;
- case 10: COPY(); TRANS(0x20); TAIL(); return result;
- case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
+ case 2: RAPIDJSON_TAIL(); return result;
+ case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+ case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result;
+ case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+ case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
+ case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result;
+ case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result;
default: return false;
}
-#undef COPY
-#undef TRANS
-#undef TAIL
+#undef RAPIDJSON_COPY
+#undef RAPIDJSON_TRANS
+#undef RAPIDJSON_TAIL
}
static unsigned char GetRange(unsigned char c) {
@@ -283,7 +283,7 @@ struct UTF16 {
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
unsigned v = codepoint - 0x10000;
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
- os.Put((v & 0x3FF) | 0xDC00);
+ os.Put(static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
}
}
@@ -299,7 +299,7 @@ struct UTF16 {
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
unsigned v = codepoint - 0x10000;
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
- PutUnsafe(os, (v & 0x3FF) | 0xDC00);
+ PutUnsafe(os, static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
}
}
@@ -384,7 +384,7 @@ struct UTF16BE : UTF16<CharType> {
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
- c |= static_cast<uint8_t>(is.Take());
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
return static_cast<CharType>(c);
}
@@ -620,28 +620,28 @@ struct AutoUTF {
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
template<typename OutputStream>
- RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
+ static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) {
typedef void (*EncodeFunc)(OutputStream&, unsigned);
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
(*f[os.GetType()])(os, codepoint);
}
template<typename OutputStream>
- RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+ static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
typedef void (*EncodeFunc)(OutputStream&, unsigned);
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
(*f[os.GetType()])(os, codepoint);
}
template <typename InputStream>
- RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
+ static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) {
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
return (*f[is.GetType()])(is, codepoint);
}
template <typename InputStream, typename OutputStream>
- RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
return (*f[is.GetType()])(is, os);
@@ -658,7 +658,7 @@ template<typename SourceEncoding, typename TargetEncoding>
struct Transcoder {
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
template<typename InputStream, typename OutputStream>
- RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint))
return false;
@@ -667,7 +667,7 @@ struct Transcoder {
}
template<typename InputStream, typename OutputStream>
- RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint))
return false;
@@ -677,7 +677,7 @@ struct Transcoder {
//! Validate one Unicode codepoint from an encoded stream.
template<typename InputStream, typename OutputStream>
- RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
return Transcode(is, os); // Since source/target encoding is different, must transcode.
}
};
@@ -690,26 +690,26 @@ inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
template<typename Encoding>
struct Transcoder<Encoding, Encoding> {
template<typename InputStream, typename OutputStream>
- RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
return true;
}
template<typename InputStream, typename OutputStream>
- RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
return true;
}
template<typename InputStream, typename OutputStream>
- RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
return Encoding::Validate(is, os); // source/target encoding are the same
}
};
RAPIDJSON_NAMESPACE_END
-#if defined(__GNUC__) || defined(_MSC_VER)
+#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__))
RAPIDJSON_DIAG_POP
#endif
diff --git a/3rdparty/rapidjson/include/rapidjson/error/en.h b/3rdparty/rapidjson/include/rapidjson/error/en.h
index 2db838bff23..c87b04eb133 100644
--- a/3rdparty/rapidjson/include/rapidjson/error/en.h
+++ b/3rdparty/rapidjson/include/rapidjson/error/en.h
@@ -1,15 +1,15 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_EN_H_
@@ -39,13 +39,13 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
-
+
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
-
+
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
-
+
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
@@ -65,6 +65,108 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
}
}
+//! Maps error code of validation into error message.
+/*!
+ \ingroup RAPIDJSON_ERRORS
+ \param validateErrorCode Error code obtained from validator.
+ \return the error message.
+ \note User can make a copy of this function for localization.
+ Using switch-case is safer for future modification of error codes.
+*/
+inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode validateErrorCode) {
+ switch (validateErrorCode) {
+ case kValidateErrors: return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred");
+ case kValidateErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
+
+ case kValidateErrorMultipleOf: return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'.");
+ case kValidateErrorMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'.");
+ case kValidateErrorExclusiveMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'.");
+ case kValidateErrorMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'.");
+ case kValidateErrorExclusiveMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'.");
+
+ case kValidateErrorMaxLength: return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'.");
+ case kValidateErrorMinLength: return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'.");
+ case kValidateErrorPattern: return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression.");
+
+ case kValidateErrorMaxItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'.");
+ case kValidateErrorMinItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'.");
+ case kValidateErrorUniqueItems: return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true.");
+ case kValidateErrorAdditionalItems: return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema.");
+
+ case kValidateErrorMaxProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'.");
+ case kValidateErrorMinProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'.");
+ case kValidateErrorRequired: return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'.");
+ case kValidateErrorAdditionalProperties: return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema.");
+ case kValidateErrorPatternProperties: return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema.");
+ case kValidateErrorDependencies: return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors.");
+
+ case kValidateErrorEnum: return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values.");
+ case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'.");
+
+ case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors.");
+ case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf', indices '%matches'.");
+ case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors.");
+ case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors.");
+ case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'.");
+
+ case kValidateErrorReadOnly: return RAPIDJSON_ERROR_STRING("Property is read-only but has been provided when validation is for writing.");
+ case kValidateErrorWriteOnly: return RAPIDJSON_ERROR_STRING("Property is write-only but has been provided when validation is for reading.");
+
+ default: return RAPIDJSON_ERROR_STRING("Unknown error.");
+ }
+}
+
+//! Maps error code of schema document compilation into error message.
+/*!
+ \ingroup RAPIDJSON_ERRORS
+ \param schemaErrorCode Error code obtained from compiling the schema document.
+ \return the error message.
+ \note User can make a copy of this function for localization.
+ Using switch-case is safer for future modification of error codes.
+*/
+ inline const RAPIDJSON_ERROR_CHARTYPE* GetSchemaError_En(SchemaErrorCode schemaErrorCode) {
+ switch (schemaErrorCode) {
+ case kSchemaErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
+
+ case kSchemaErrorStartUnknown: return RAPIDJSON_ERROR_STRING("Pointer '%value' to start of schema does not resolve to a location in the document.");
+ case kSchemaErrorRefPlainName: return RAPIDJSON_ERROR_STRING("$ref fragment '%value' must be a JSON pointer.");
+ case kSchemaErrorRefInvalid: return RAPIDJSON_ERROR_STRING("$ref must not be an empty string.");
+ case kSchemaErrorRefPointerInvalid: return RAPIDJSON_ERROR_STRING("$ref fragment '%value' is not a valid JSON pointer at offset '%offset'.");
+ case kSchemaErrorRefUnknown: return RAPIDJSON_ERROR_STRING("$ref '%value' does not resolve to a location in the target document.");
+ case kSchemaErrorRefCyclical: return RAPIDJSON_ERROR_STRING("$ref '%value' is cyclical.");
+ case kSchemaErrorRefNoRemoteProvider: return RAPIDJSON_ERROR_STRING("$ref is remote but there is no remote provider.");
+ case kSchemaErrorRefNoRemoteSchema: return RAPIDJSON_ERROR_STRING("$ref '%value' is remote but the remote provider did not return a schema.");
+ case kSchemaErrorRegexInvalid: return RAPIDJSON_ERROR_STRING("Invalid regular expression '%value' in 'pattern' or 'patternProperties'.");
+ case kSchemaErrorSpecUnknown: return RAPIDJSON_ERROR_STRING("JSON schema draft or OpenAPI version is not recognized.");
+ case kSchemaErrorSpecUnsupported: return RAPIDJSON_ERROR_STRING("JSON schema draft or OpenAPI version is not supported.");
+ case kSchemaErrorSpecIllegal: return RAPIDJSON_ERROR_STRING("Both JSON schema draft and OpenAPI version found in document.");
+ case kSchemaErrorReadOnlyAndWriteOnly: return RAPIDJSON_ERROR_STRING("Property must not be both 'readOnly' and 'writeOnly'.");
+
+ default: return RAPIDJSON_ERROR_STRING("Unknown error.");
+ }
+ }
+
+//! Maps error code of pointer parse into error message.
+/*!
+ \ingroup RAPIDJSON_ERRORS
+ \param pointerParseErrorCode Error code obtained from pointer parse.
+ \return the error message.
+ \note User can make a copy of this function for localization.
+ Using switch-case is safer for future modification of error codes.
+*/
+inline const RAPIDJSON_ERROR_CHARTYPE* GetPointerParseError_En(PointerParseErrorCode pointerParseErrorCode) {
+ switch (pointerParseErrorCode) {
+ case kPointerParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
+
+ case kPointerParseErrorTokenMustBeginWithSolidus: return RAPIDJSON_ERROR_STRING("A token must begin with a '/'.");
+ case kPointerParseErrorInvalidEscape: return RAPIDJSON_ERROR_STRING("Invalid escape.");
+ case kPointerParseErrorInvalidPercentEncoding: return RAPIDJSON_ERROR_STRING("Invalid percent encoding in URI fragment.");
+ case kPointerParseErrorCharacterMustPercentEncode: return RAPIDJSON_ERROR_STRING("A character must be percent encoded in a URI fragment.");
+
+ default: return RAPIDJSON_ERROR_STRING("Unknown error.");
+ }
+}
+
RAPIDJSON_NAMESPACE_END
#ifdef __clang__
diff --git a/3rdparty/rapidjson/include/rapidjson/error/error.h b/3rdparty/rapidjson/include/rapidjson/error/error.h
index 95cb31a72fe..cae345db36d 100644
--- a/3rdparty/rapidjson/include/rapidjson/error/error.h
+++ b/3rdparty/rapidjson/include/rapidjson/error/error.h
@@ -1,15 +1,15 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_ERROR_H_
@@ -42,7 +42,7 @@ RAPIDJSON_DIAG_OFF(padded)
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ERROR_STRING
-//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
+//! Macro for converting string literal to \ref RAPIDJSON_ERROR_CHARTYPE[].
/*! \ingroup RAPIDJSON_ERRORS
By default this conversion macro does nothing.
On Windows, user can define this macro as \c _T(x) for supporting both
@@ -104,6 +104,8 @@ enum ParseErrorCode {
\see GenericReader::Parse, GenericDocument::Parse
*/
struct ParseResult {
+ //!! Unspecified boolean type
+ typedef bool (ParseResult::*BooleanType)() const;
public:
//! Default constructor, no error.
ParseResult() : code_(kParseErrorNone), offset_(0) {}
@@ -115,8 +117,8 @@ public:
//! Get the error offset, if \ref IsError(), 0 otherwise.
size_t Offset() const { return offset_; }
- //! Conversion to \c bool, returns \c true, iff !\ref IsError().
- operator bool() const { return !IsError(); }
+ //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError().
+ operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; }
//! Whether the result is an error.
bool IsError() const { return code_ != kParseErrorNone; }
@@ -124,6 +126,10 @@ public:
bool operator==(ParseErrorCode code) const { return code_ == code; }
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
+ bool operator!=(const ParseResult& that) const { return !(*this == that); }
+ bool operator!=(ParseErrorCode code) const { return !(*this == code); }
+ friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; }
+
//! Reset error code.
void Clear() { Set(kParseErrorNone); }
//! Update error code and offset.
@@ -146,6 +152,130 @@ private:
*/
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
+///////////////////////////////////////////////////////////////////////////////
+// ValidateErrorCode
+
+//! Error codes when validating.
+/*! \ingroup RAPIDJSON_ERRORS
+ \see GenericSchemaValidator
+*/
+enum ValidateErrorCode {
+ kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set.
+ kValidateErrorNone = 0, //!< No error.
+
+ kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value.
+ kValidateErrorMaximum, //!< Number is greater than the 'maximum' value.
+ kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value.
+ kValidateErrorMinimum, //!< Number is less than the 'minimum' value.
+ kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value.
+
+ kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value.
+ kValidateErrorMinLength, //!< String is longer than the 'maxLength' value.
+ kValidateErrorPattern, //!< String does not match the 'pattern' regular expression.
+
+ kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value.
+ kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value.
+ kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true.
+ kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema.
+
+ kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value.
+ kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value.
+ kValidateErrorRequired, //!< Object is missing one or more members required by the schema.
+ kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema.
+ kValidateErrorPatternProperties, //!< See other errors.
+ kValidateErrorDependencies, //!< Object has missing property or schema dependencies.
+
+ kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values.
+ kValidateErrorType, //!< Property has a type that is not allowed by the schema.
+
+ kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'.
+ kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'.
+ kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'.
+ kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'.
+ kValidateErrorNot, //!< Property matched the sub-schema specified by 'not'.
+
+ kValidateErrorReadOnly, //!< Property is read-only but has been provided when validation is for writing
+ kValidateErrorWriteOnly //!< Property is write-only but has been provided when validation is for reading
+};
+
+//! Function pointer type of GetValidateError().
+/*! \ingroup RAPIDJSON_ERRORS
+
+ This is the prototype for \c GetValidateError_X(), where \c X is a locale.
+ User can dynamically change locale in runtime, e.g.:
+\code
+ GetValidateErrorFunc GetValidateError = GetValidateError_En; // or whatever
+ const RAPIDJSON_ERROR_CHARTYPE* s = GetValidateError(validator.GetInvalidSchemaCode());
+\endcode
+*/
+typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode);
+
+///////////////////////////////////////////////////////////////////////////////
+// SchemaErrorCode
+
+//! Error codes when validating.
+/*! \ingroup RAPIDJSON_ERRORS
+ \see GenericSchemaValidator
+*/
+enum SchemaErrorCode {
+ kSchemaErrorNone = 0, //!< No error.
+
+ kSchemaErrorStartUnknown, //!< Pointer to start of schema does not resolve to a location in the document
+ kSchemaErrorRefPlainName, //!< $ref fragment must be a JSON pointer
+ kSchemaErrorRefInvalid, //!< $ref must not be an empty string
+ kSchemaErrorRefPointerInvalid, //!< $ref fragment is not a valid JSON pointer at offset
+ kSchemaErrorRefUnknown, //!< $ref does not resolve to a location in the target document
+ kSchemaErrorRefCyclical, //!< $ref is cyclical
+ kSchemaErrorRefNoRemoteProvider, //!< $ref is remote but there is no remote provider
+ kSchemaErrorRefNoRemoteSchema, //!< $ref is remote but the remote provider did not return a schema
+ kSchemaErrorRegexInvalid, //!< Invalid regular expression in 'pattern' or 'patternProperties'
+ kSchemaErrorSpecUnknown, //!< JSON schema draft or OpenAPI version is not recognized
+ kSchemaErrorSpecUnsupported, //!< JSON schema draft or OpenAPI version is not supported
+ kSchemaErrorSpecIllegal, //!< Both JSON schema draft and OpenAPI version found in document
+ kSchemaErrorReadOnlyAndWriteOnly //!< Property must not be both 'readOnly' and 'writeOnly'
+};
+
+//! Function pointer type of GetSchemaError().
+/*! \ingroup RAPIDJSON_ERRORS
+
+ This is the prototype for \c GetSchemaError_X(), where \c X is a locale.
+ User can dynamically change locale in runtime, e.g.:
+\code
+ GetSchemaErrorFunc GetSchemaError = GetSchemaError_En; // or whatever
+ const RAPIDJSON_ERROR_CHARTYPE* s = GetSchemaError(validator.GetInvalidSchemaCode());
+\endcode
+*/
+typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetSchemaErrorFunc)(SchemaErrorCode);
+
+///////////////////////////////////////////////////////////////////////////////
+// PointerParseErrorCode
+
+//! Error code of JSON pointer parsing.
+/*! \ingroup RAPIDJSON_ERRORS
+ \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
+*/
+enum PointerParseErrorCode {
+ kPointerParseErrorNone = 0, //!< The parse is successful
+
+ kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/'
+ kPointerParseErrorInvalidEscape, //!< Invalid escape
+ kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment
+ kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment
+};
+
+//! Function pointer type of GetPointerParseError().
+/*! \ingroup RAPIDJSON_ERRORS
+
+ This is the prototype for \c GetPointerParseError_X(), where \c X is a locale.
+ User can dynamically change locale in runtime, e.g.:
+\code
+ GetPointerParseErrorFunc GetPointerParseError = GetPointerParseError_En; // or whatever
+ const RAPIDJSON_ERROR_CHARTYPE* s = GetPointerParseError(pointer.GetParseErrorCode());
+\endcode
+*/
+typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetPointerParseErrorFunc)(PointerParseErrorCode);
+
+
RAPIDJSON_NAMESPACE_END
#ifdef __clang__
diff --git a/3rdparty/rapidjson/include/rapidjson/filereadstream.h b/3rdparty/rapidjson/include/rapidjson/filereadstream.h
index b56ea13b342..f8bb43cb0cf 100644
--- a/3rdparty/rapidjson/include/rapidjson/filereadstream.h
+++ b/3rdparty/rapidjson/include/rapidjson/filereadstream.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -59,7 +59,7 @@ public:
// For encoding detection only.
const Ch* Peek4() const {
- return (current_ + 4 <= bufferLast_) ? current_ : 0;
+ return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
}
private:
@@ -68,7 +68,7 @@ private:
++current_;
else if (!eof_) {
count_ += readCount_;
- readCount_ = fread(buffer_, 1, bufferSize_, fp_);
+ readCount_ = std::fread(buffer_, 1, bufferSize_, fp_);
bufferLast_ = buffer_ + readCount_ - 1;
current_ = buffer_;
diff --git a/3rdparty/rapidjson/include/rapidjson/filewritestream.h b/3rdparty/rapidjson/include/rapidjson/filewritestream.h
index 6378dd60ed4..5d89588c218 100644
--- a/3rdparty/rapidjson/include/rapidjson/filewritestream.h
+++ b/3rdparty/rapidjson/include/rapidjson/filewritestream.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -25,7 +25,7 @@ RAPIDJSON_DIAG_OFF(unreachable-code)
RAPIDJSON_NAMESPACE_BEGIN
-//! Wrapper of C file stream for input using fread().
+//! Wrapper of C file stream for output using fwrite().
/*!
\note implements Stream concept
*/
@@ -62,7 +62,7 @@ public:
void Flush() {
if (current_ != buffer_) {
- size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
+ size_t result = std::fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
if (result < static_cast<size_t>(current_ - buffer_)) {
// failure deliberately ignored at this time
// added to avoid warn_unused_result build errors
diff --git a/3rdparty/rapidjson/include/rapidjson/fwd.h b/3rdparty/rapidjson/include/rapidjson/fwd.h
index e8104e841bc..d62f77f0ecf 100644
--- a/3rdparty/rapidjson/include/rapidjson/fwd.h
+++ b/3rdparty/rapidjson/include/rapidjson/fwd.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -102,7 +102,7 @@ class PrettyWriter;
// document.h
template <typename Encoding, typename Allocator>
-struct GenericMember;
+class GenericMember;
template <bool Const, typename Encoding, typename Allocator>
class GenericMemberIterator;
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/biginteger.h b/3rdparty/rapidjson/include/rapidjson/internal/biginteger.h
index 9d3e88c9981..af487380389 100644
--- a/3rdparty/rapidjson/include/rapidjson/internal/biginteger.h
+++ b/3rdparty/rapidjson/include/rapidjson/internal/biginteger.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -17,9 +17,13 @@
#include "../rapidjson.h"
-#if defined(_MSC_VER) && defined(_M_AMD64)
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64)
#include <intrin.h> // for _umul128
+#if !defined(_ARM64EC_)
#pragma intrinsic(_umul128)
+#else
+#pragma comment(lib,"softintrin")
+#endif
#endif
RAPIDJSON_NAMESPACE_BEGIN
@@ -37,7 +41,8 @@ public:
digits_[0] = u;
}
- BigInteger(const char* decimals, size_t length) : count_(1) {
+ template<typename Ch>
+ BigInteger(const Ch* decimals, size_t length) : count_(1) {
RAPIDJSON_ASSERT(length > 0);
digits_[0] = 0;
size_t i = 0;
@@ -133,7 +138,7 @@ public:
RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
if (interShift == 0) {
- std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
+ std::memmove(digits_ + offset, digits_, count_ * sizeof(Type));
count_ += offset;
}
else {
@@ -221,7 +226,8 @@ public:
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
private:
- void AppendDecimal64(const char* begin, const char* end) {
+ template<typename Ch>
+ void AppendDecimal64(const Ch* begin, const Ch* end) {
uint64_t u = ParseUint64(begin, end);
if (IsZero())
*this = u;
@@ -236,11 +242,12 @@ private:
digits_[count_++] = digit;
}
- static uint64_t ParseUint64(const char* begin, const char* end) {
+ template<typename Ch>
+ static uint64_t ParseUint64(const Ch* begin, const Ch* end) {
uint64_t r = 0;
- for (const char* p = begin; p != end; ++p) {
- RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
- r = r * 10u + static_cast<unsigned>(*p - '0');
+ for (const Ch* p = begin; p != end; ++p) {
+ RAPIDJSON_ASSERT(*p >= Ch('0') && *p <= Ch('9'));
+ r = r * 10u + static_cast<unsigned>(*p - Ch('0'));
}
return r;
}
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/clzll.h b/3rdparty/rapidjson/include/rapidjson/internal/clzll.h
new file mode 100644
index 00000000000..8fc5118aa47
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/internal/clzll.h
@@ -0,0 +1,71 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_CLZLL_H_
+#define RAPIDJSON_CLZLL_H_
+
+#include "../rapidjson.h"
+
+#if defined(_MSC_VER) && !defined(UNDER_CE)
+#include <intrin.h>
+#if defined(_WIN64)
+#pragma intrinsic(_BitScanReverse64)
+#else
+#pragma intrinsic(_BitScanReverse)
+#endif
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline uint32_t clzll(uint64_t x) {
+ // Passing 0 to __builtin_clzll is UB in GCC and results in an
+ // infinite loop in the software implementation.
+ RAPIDJSON_ASSERT(x != 0);
+
+#if defined(_MSC_VER) && !defined(UNDER_CE)
+ unsigned long r = 0;
+#if defined(_WIN64)
+ _BitScanReverse64(&r, x);
+#else
+ // Scan the high 32 bits.
+ if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
+ return 63 - (r + 32);
+
+ // Scan the low 32 bits.
+ _BitScanReverse(&r, static_cast<uint32_t>(x & 0xFFFFFFFF));
+#endif // _WIN64
+
+ return 63 - r;
+#elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll)
+ // __builtin_clzll wrapper
+ return static_cast<uint32_t>(__builtin_clzll(x));
+#else
+ // naive version
+ uint32_t r = 0;
+ while (!(x & (static_cast<uint64_t>(1) << 63))) {
+ x <<= 1;
+ ++r;
+ }
+
+ return r;
+#endif // _MSC_VER
+}
+
+#define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_CLZLL_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/diyfp.h b/3rdparty/rapidjson/include/rapidjson/internal/diyfp.h
index c9fefdc6139..f7d46539a90 100644
--- a/3rdparty/rapidjson/include/rapidjson/internal/diyfp.h
+++ b/3rdparty/rapidjson/include/rapidjson/internal/diyfp.h
@@ -1,15 +1,15 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
@@ -20,11 +20,16 @@
#define RAPIDJSON_DIYFP_H_
#include "../rapidjson.h"
+#include "clzll.h"
+#include <limits>
-#if defined(_MSC_VER) && defined(_M_AMD64)
+#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
#include <intrin.h>
-#pragma intrinsic(_BitScanReverse64)
+#if !defined(_ARM64EC_)
#pragma intrinsic(_umul128)
+#else
+#pragma comment(lib,"softintrin")
+#endif
#endif
RAPIDJSON_NAMESPACE_BEGIN
@@ -56,7 +61,7 @@ struct DiyFp {
if (biased_e != 0) {
f = significand + kDpHiddenBit;
e = biased_e - kDpExponentBias;
- }
+ }
else {
f = significand;
e = kDpMinExponent + 1;
@@ -99,21 +104,8 @@ struct DiyFp {
}
DiyFp Normalize() const {
-#if defined(_MSC_VER) && defined(_M_AMD64)
- unsigned long index;
- _BitScanReverse64(&index, f);
- return DiyFp(f << (63 - index), e - (63 - index));
-#elif defined(__GNUC__) && __GNUC__ >= 4
- int s = __builtin_clzll(f);
+ int s = static_cast<int>(clzll(f));
return DiyFp(f << s, e - s);
-#else
- DiyFp res = *this;
- while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
- res.f <<= 1;
- res.e--;
- }
- return res;
-#endif
}
DiyFp NormalizeBoundary() const {
@@ -141,7 +133,16 @@ struct DiyFp {
double d;
uint64_t u64;
}u;
- const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
+ RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask);
+ if (e < kDpDenormalExponent) {
+ // Underflow.
+ return 0.0;
+ }
+ if (e >= kDpMaxExponent) {
+ // Overflow.
+ return std::numeric_limits<double>::infinity();
+ }
+ const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
static_cast<uint64_t>(e + kDpExponentBias);
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
return u.d;
@@ -220,9 +221,10 @@ inline DiyFp GetCachedPowerByIndex(size_t index) {
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
907, 933, 960, 986, 1013, 1039, 1066
};
+ RAPIDJSON_ASSERT(index < 87);
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
}
-
+
inline DiyFp GetCachedPower(int e, int* K) {
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
@@ -238,10 +240,11 @@ inline DiyFp GetCachedPower(int e, int* K) {
}
inline DiyFp GetCachedPower10(int exp, int *outExp) {
- unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
- *outExp = -348 + static_cast<int>(index) * 8;
- return GetCachedPowerByIndex(index);
- }
+ RAPIDJSON_ASSERT(exp >= -348);
+ unsigned index = static_cast<unsigned>(exp + 348) / 8u;
+ *outExp = -348 + static_cast<int>(index) * 8;
+ return GetCachedPowerByIndex(index);
+}
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/dtoa.h b/3rdparty/rapidjson/include/rapidjson/internal/dtoa.h
index 8d6350e626d..cd456721a71 100644
--- a/3rdparty/rapidjson/include/rapidjson/internal/dtoa.h
+++ b/3rdparty/rapidjson/include/rapidjson/internal/dtoa.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -41,7 +41,7 @@ inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uin
}
}
-inline unsigned CountDecimalDigit32(uint32_t n) {
+inline int CountDecimalDigit32(uint32_t n) {
// Simple pure C++ implementation was faster than __builtin_clz version in this situation.
if (n < 10) return 1;
if (n < 100) return 2;
@@ -58,12 +58,16 @@ inline unsigned CountDecimalDigit32(uint32_t n) {
}
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
- static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
+ static const uint64_t kPow10[] = { 1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL, 10000000ULL, 100000000ULL,
+ 1000000000ULL, 10000000000ULL, 100000000000ULL, 1000000000000ULL,
+ 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL,
+ 10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL,
+ 10000000000000000000ULL };
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
const DiyFp wp_w = Mp - W;
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
uint64_t p2 = Mp.f & (one.f - 1);
- unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
+ int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
*len = 0;
while (kappa > 0) {
@@ -86,7 +90,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
if (tmp <= delta) {
*K += kappa;
- GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
+ GrisuRound(buffer, *len, delta, tmp, kPow10[kappa] << -one.e, wp_w.f);
return;
}
}
@@ -102,8 +106,8 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
kappa--;
if (p2 < delta) {
*K += kappa;
- int index = -static_cast<int>(kappa);
- GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0));
+ int index = -kappa;
+ GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 20 ? kPow10[index] : 0));
return;
}
}
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/ieee754.h b/3rdparty/rapidjson/include/rapidjson/internal/ieee754.h
index 82bb0b99e5c..68c9e96649b 100644
--- a/3rdparty/rapidjson/include/rapidjson/internal/ieee754.h
+++ b/3rdparty/rapidjson/include/rapidjson/internal/ieee754.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -48,13 +48,13 @@ public:
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
- static unsigned EffectiveSignificandSize(int order) {
+ static int EffectiveSignificandSize(int order) {
if (order >= -1021)
return 53;
else if (order <= -1074)
return 0;
else
- return static_cast<unsigned>(order) + 1074;
+ return order + 1074;
}
private:
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/itoa.h b/3rdparty/rapidjson/include/rapidjson/internal/itoa.h
index 01a4e7e72d7..9fe8c932ffa 100644
--- a/3rdparty/rapidjson/include/rapidjson/internal/itoa.h
+++ b/3rdparty/rapidjson/include/rapidjson/internal/itoa.h
@@ -1,15 +1,15 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ITOA_
@@ -37,12 +37,14 @@ inline const char* GetDigitsLut() {
}
inline char* u32toa(uint32_t value, char* buffer) {
+ RAPIDJSON_ASSERT(buffer != 0);
+
const char* cDigitsLut = GetDigitsLut();
if (value < 10000) {
const uint32_t d1 = (value / 100) << 1;
const uint32_t d2 = (value % 100) << 1;
-
+
if (value >= 1000)
*buffer++ = cDigitsLut[d1];
if (value >= 100)
@@ -55,13 +57,13 @@ inline char* u32toa(uint32_t value, char* buffer) {
// value = bbbbcccc
const uint32_t b = value / 10000;
const uint32_t c = value % 10000;
-
+
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
-
+
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
-
+
if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
@@ -69,7 +71,7 @@ inline char* u32toa(uint32_t value, char* buffer) {
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
-
+
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
@@ -77,10 +79,10 @@ inline char* u32toa(uint32_t value, char* buffer) {
}
else {
// value = aabbbbcccc in decimal
-
+
const uint32_t a = value / 100000000; // 1 to 42
value %= 100000000;
-
+
if (a >= 10) {
const unsigned i = a << 1;
*buffer++ = cDigitsLut[i];
@@ -91,13 +93,13 @@ inline char* u32toa(uint32_t value, char* buffer) {
const uint32_t b = value / 10000; // 0 to 9999
const uint32_t c = value % 10000; // 0 to 9999
-
+
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
-
+
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
-
+
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
@@ -111,6 +113,7 @@ inline char* u32toa(uint32_t value, char* buffer) {
}
inline char* i32toa(int32_t value, char* buffer) {
+ RAPIDJSON_ASSERT(buffer != 0);
uint32_t u = static_cast<uint32_t>(value);
if (value < 0) {
*buffer++ = '-';
@@ -121,6 +124,7 @@ inline char* i32toa(int32_t value, char* buffer) {
}
inline char* u64toa(uint64_t value, char* buffer) {
+ RAPIDJSON_ASSERT(buffer != 0);
const char* cDigitsLut = GetDigitsLut();
const uint64_t kTen8 = 100000000;
const uint64_t kTen9 = kTen8 * 10;
@@ -131,13 +135,13 @@ inline char* u64toa(uint64_t value, char* buffer) {
const uint64_t kTen14 = kTen8 * 1000000;
const uint64_t kTen15 = kTen8 * 10000000;
const uint64_t kTen16 = kTen8 * kTen8;
-
+
if (value < kTen8) {
uint32_t v = static_cast<uint32_t>(value);
if (v < 10000) {
const uint32_t d1 = (v / 100) << 1;
const uint32_t d2 = (v % 100) << 1;
-
+
if (v >= 1000)
*buffer++ = cDigitsLut[d1];
if (v >= 100)
@@ -150,13 +154,13 @@ inline char* u64toa(uint64_t value, char* buffer) {
// value = bbbbcccc
const uint32_t b = v / 10000;
const uint32_t c = v % 10000;
-
+
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
-
+
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
-
+
if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
@@ -164,7 +168,7 @@ inline char* u64toa(uint64_t value, char* buffer) {
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
-
+
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
@@ -174,22 +178,22 @@ inline char* u64toa(uint64_t value, char* buffer) {
else if (value < kTen16) {
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
-
+
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
-
+
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
-
+
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
-
+
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
-
+
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
@@ -207,9 +211,8 @@ inline char* u64toa(uint64_t value, char* buffer) {
*buffer++ = cDigitsLut[d3 + 1];
if (value >= kTen9)
*buffer++ = cDigitsLut[d4];
- if (value >= kTen8)
- *buffer++ = cDigitsLut[d4 + 1];
-
+
+ *buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
@@ -222,7 +225,7 @@ inline char* u64toa(uint64_t value, char* buffer) {
else {
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
value %= kTen16;
-
+
if (a < 10)
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
else if (a < 100) {
@@ -232,7 +235,7 @@ inline char* u64toa(uint64_t value, char* buffer) {
}
else if (a < 1000) {
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
-
+
const uint32_t i = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
@@ -245,28 +248,28 @@ inline char* u64toa(uint64_t value, char* buffer) {
*buffer++ = cDigitsLut[j];
*buffer++ = cDigitsLut[j + 1];
}
-
+
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
-
+
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
-
+
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
-
+
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
-
+
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
-
+
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
-
+
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
-
+
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
@@ -284,11 +287,12 @@ inline char* u64toa(uint64_t value, char* buffer) {
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
}
-
+
return buffer;
}
inline char* i64toa(int64_t value, char* buffer) {
+ RAPIDJSON_ASSERT(buffer != 0);
uint64_t u = static_cast<uint64_t>(value);
if (value < 0) {
*buffer++ = '-';
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/meta.h b/3rdparty/rapidjson/include/rapidjson/internal/meta.h
index 5a9aaa42866..27092dc0d69 100644
--- a/3rdparty/rapidjson/include/rapidjson/internal/meta.h
+++ b/3rdparty/rapidjson/include/rapidjson/internal/meta.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -21,7 +21,8 @@
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
-#if defined(_MSC_VER)
+
+#if defined(_MSC_VER) && !defined(__clang__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(6334)
#endif
@@ -174,7 +175,11 @@ template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type;
RAPIDJSON_NAMESPACE_END
//@endcond
-#if defined(__GNUC__) || defined(_MSC_VER)
+#if defined(_MSC_VER) && !defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/pow10.h b/3rdparty/rapidjson/include/rapidjson/internal/pow10.h
index 02f475d705f..eae1a43ed1a 100644
--- a/3rdparty/rapidjson/include/rapidjson/internal/pow10.h
+++ b/3rdparty/rapidjson/include/rapidjson/internal/pow10.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/regex.h b/3rdparty/rapidjson/include/rapidjson/internal/regex.h
index 422a5240bf5..6446c403af9 100644
--- a/3rdparty/rapidjson/include/rapidjson/internal/regex.h
+++ b/3rdparty/rapidjson/include/rapidjson/internal/regex.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -23,7 +23,9 @@
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
-RAPIDJSON_DIAG_OFF(implicit-fallthrough)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
#ifdef __GNUC__
@@ -31,11 +33,6 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
-#endif
-
#ifndef RAPIDJSON_REGEX_VERBOSE
#define RAPIDJSON_REGEX_VERBOSE 0
#endif
@@ -44,11 +41,39 @@ RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
///////////////////////////////////////////////////////////////////////////////
+// DecodedStream
+
+template <typename SourceStream, typename Encoding>
+class DecodedStream {
+public:
+ DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
+ unsigned Peek() { return codepoint_; }
+ unsigned Take() {
+ unsigned c = codepoint_;
+ if (c) // No further decoding when '\0'
+ Decode();
+ return c;
+ }
+
+private:
+ void Decode() {
+ if (!Encoding::Decode(ss_, &codepoint_))
+ codepoint_ = 0;
+ }
+
+ SourceStream& ss_;
+ unsigned codepoint_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
// GenericRegex
static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
static const SizeType kRegexInvalidRange = ~SizeType(0);
+template <typename Encoding, typename Allocator>
+class GenericRegexSearch;
+
//! Regular expression engine with subset of ECMAscript grammar.
/*!
Supported regular expression syntax:
@@ -84,45 +109,29 @@ static const SizeType kRegexInvalidRange = ~SizeType(0);
template <typename Encoding, typename Allocator = CrtAllocator>
class GenericRegex {
public:
+ typedef Encoding EncodingType;
typedef typename Encoding::Ch Ch;
+ template <typename, typename> friend class GenericRegexSearch;
GenericRegex(const Ch* source, Allocator* allocator = 0) :
- states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
- stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_()
+ ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_),
+ states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
+ anchorBegin_(), anchorEnd_()
{
GenericStringStream<Encoding> ss(source);
- DecodedStream<GenericStringStream<Encoding> > ds(ss);
+ DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
Parse(ds);
}
- ~GenericRegex() {
- Allocator::Free(stateSet_);
+ ~GenericRegex()
+ {
+ RAPIDJSON_DELETE(ownAllocator_);
}
bool IsValid() const {
return root_ != kRegexInvalidState;
}
- template <typename InputStream>
- bool Match(InputStream& is) const {
- return SearchWithAnchoring(is, true, true);
- }
-
- bool Match(const Ch* s) const {
- GenericStringStream<Encoding> is(s);
- return Match(is);
- }
-
- template <typename InputStream>
- bool Search(InputStream& is) const {
- return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);
- }
-
- bool Search(const Ch* s) const {
- GenericStringStream<Encoding> is(s);
- return Search(is);
- }
-
private:
enum Operator {
kZeroOrOne,
@@ -157,28 +166,6 @@ private:
SizeType minIndex;
};
- template <typename SourceStream>
- class DecodedStream {
- public:
- DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
- unsigned Peek() { return codepoint_; }
- unsigned Take() {
- unsigned c = codepoint_;
- if (c) // No further decoding when '\0'
- Decode();
- return c;
- }
-
- private:
- void Decode() {
- if (!Encoding::Decode(ss_, &codepoint_))
- codepoint_ = 0;
- }
-
- SourceStream& ss_;
- unsigned codepoint_;
- };
-
State& GetState(SizeType index) {
RAPIDJSON_ASSERT(index < stateCount_);
return states_.template Bottom<State>()[index];
@@ -200,11 +187,10 @@ private:
}
template <typename InputStream>
- void Parse(DecodedStream<InputStream>& ds) {
- Allocator allocator;
- Stack<Allocator> operandStack(&allocator, 256); // Frag
- Stack<Allocator> operatorStack(&allocator, 256); // Operator
- Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
+ void Parse(DecodedStream<InputStream, Encoding>& ds) {
+ Stack<Allocator> operandStack(allocator_, 256); // Frag
+ Stack<Allocator> operatorStack(allocator_, 256); // Operator
+ Stack<Allocator> atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis)
*atomCountStack.template Push<unsigned>() = 0;
@@ -301,6 +287,7 @@ private:
if (!CharacterEscape(ds, &codepoint))
return; // Unsupported escape character
// fall through to default
+ RAPIDJSON_DELIBERATE_FALLTHROUGH;
default: // Pattern character
PushOperand(operandStack, codepoint);
@@ -327,14 +314,6 @@ private:
printf("\n");
#endif
}
-
- // Preallocate buffer for SearchWithAnchoring()
- RAPIDJSON_ASSERT(stateSet_ == 0);
- if (stateCount_ > 0) {
- stateSet_ = static_cast<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize()));
- state0_.template Reserve<SizeType>(stateCount_);
- state1_.template Reserve<SizeType>(stateCount_);
- }
}
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
@@ -413,8 +392,7 @@ private:
}
return false;
- default:
- RAPIDJSON_ASSERT(op == kOneOrMore);
+ case kOneOrMore:
if (operandStack.GetSize() >= sizeof(Frag)) {
Frag e = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(kRegexInvalidState, e.start, 0);
@@ -423,6 +401,10 @@ private:
return true;
}
return false;
+
+ default:
+ // syntax error (e.g. unclosed kLeftParenthesis)
+ return false;
}
}
@@ -483,7 +465,7 @@ private:
}
template <typename InputStream>
- bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) {
+ bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
unsigned r = 0;
if (ds.Peek() < '0' || ds.Peek() > '9')
return false;
@@ -497,7 +479,7 @@ private:
}
template <typename InputStream>
- bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) {
+ bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {
bool isBegin = true;
bool negate = false;
int step = 0;
@@ -535,6 +517,7 @@ private:
else if (!CharacterEscape(ds, &codepoint))
return false;
// fall through to default
+ RAPIDJSON_DELIBERATE_FALLTHROUGH;
default:
switch (step) {
@@ -544,6 +527,7 @@ private:
break;
}
// fall through to step 0 for other characters
+ RAPIDJSON_DELIBERATE_FALLTHROUGH;
case 0:
{
@@ -575,7 +559,7 @@ private:
}
template <typename InputStream>
- bool CharacterEscape(DecodedStream<InputStream>& ds, unsigned* escapedCodepoint) {
+ bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
unsigned codepoint;
switch (codepoint = ds.Take()) {
case '^':
@@ -603,34 +587,95 @@ private:
}
}
+ Allocator* ownAllocator_;
+ Allocator* allocator_;
+ Stack<Allocator> states_;
+ Stack<Allocator> ranges_;
+ SizeType root_;
+ SizeType stateCount_;
+ SizeType rangeCount_;
+
+ static const unsigned kInfinityQuantifier = ~0u;
+
+ // For SearchWithAnchoring()
+ bool anchorBegin_;
+ bool anchorEnd_;
+};
+
+template <typename RegexType, typename Allocator = CrtAllocator>
+class GenericRegexSearch {
+public:
+ typedef typename RegexType::EncodingType Encoding;
+ typedef typename Encoding::Ch Ch;
+
+ GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) :
+ regex_(regex), allocator_(allocator), ownAllocator_(0),
+ state0_(allocator, 0), state1_(allocator, 0), stateSet_()
+ {
+ RAPIDJSON_ASSERT(regex_.IsValid());
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
+ stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
+ state0_.template Reserve<SizeType>(regex_.stateCount_);
+ state1_.template Reserve<SizeType>(regex_.stateCount_);
+ }
+
+ ~GenericRegexSearch() {
+ Allocator::Free(stateSet_);
+ RAPIDJSON_DELETE(ownAllocator_);
+ }
+
template <typename InputStream>
- bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const {
- RAPIDJSON_ASSERT(IsValid());
- DecodedStream<InputStream> ds(is);
+ bool Match(InputStream& is) {
+ return SearchWithAnchoring(is, true, true);
+ }
+
+ bool Match(const Ch* s) {
+ GenericStringStream<Encoding> is(s);
+ return Match(is);
+ }
+
+ template <typename InputStream>
+ bool Search(InputStream& is) {
+ return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
+ }
+
+ bool Search(const Ch* s) {
+ GenericStringStream<Encoding> is(s);
+ return Search(is);
+ }
+
+private:
+ typedef typename RegexType::State State;
+ typedef typename RegexType::Range Range;
+
+ template <typename InputStream>
+ bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
+ DecodedStream<InputStream, Encoding> ds(is);
state0_.Clear();
Stack<Allocator> *current = &state0_, *next = &state1_;
const size_t stateSetSize = GetStateSetSize();
std::memset(stateSet_, 0, stateSetSize);
- bool matched = AddState(*current, root_);
+ bool matched = AddState(*current, regex_.root_);
unsigned codepoint;
while (!current->Empty() && (codepoint = ds.Take()) != 0) {
std::memset(stateSet_, 0, stateSetSize);
next->Clear();
matched = false;
for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
- const State& sr = GetState(*s);
+ const State& sr = regex_.GetState(*s);
if (sr.codepoint == codepoint ||
- sr.codepoint == kAnyCharacterClass ||
- (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
+ sr.codepoint == RegexType::kAnyCharacterClass ||
+ (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
{
matched = AddState(*next, sr.out) || matched;
if (!anchorEnd && matched)
return true;
}
if (!anchorBegin)
- AddState(*next, root_);
+ AddState(*next, regex_.root_);
}
internal::Swap(current, next);
}
@@ -639,62 +684,55 @@ private:
}
size_t GetStateSetSize() const {
- return (stateCount_ + 31) / 32 * 4;
+ return (regex_.stateCount_ + 31) / 32 * 4;
}
// Return whether the added states is a match state
- bool AddState(Stack<Allocator>& l, SizeType index) const {
+ bool AddState(Stack<Allocator>& l, SizeType index) {
RAPIDJSON_ASSERT(index != kRegexInvalidState);
- const State& s = GetState(index);
+ const State& s = regex_.GetState(index);
if (s.out1 != kRegexInvalidState) { // Split
bool matched = AddState(l, s.out);
return AddState(l, s.out1) || matched;
}
- else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) {
- stateSet_[index >> 5] |= (1 << (index & 31));
+ else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) {
+ stateSet_[index >> 5] |= (1u << (index & 31));
*l.template PushUnsafe<SizeType>() = index;
}
return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
}
bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
- bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0;
+ bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
while (rangeIndex != kRegexInvalidRange) {
- const Range& r = GetRange(rangeIndex);
- if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end)
+ const Range& r = regex_.GetRange(rangeIndex);
+ if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
return yes;
rangeIndex = r.next;
}
return !yes;
}
- Stack<Allocator> states_;
- Stack<Allocator> ranges_;
- SizeType root_;
- SizeType stateCount_;
- SizeType rangeCount_;
-
- static const unsigned kInfinityQuantifier = ~0u;
-
- // For SearchWithAnchoring()
- uint32_t* stateSet_; // allocated by states_.GetAllocator()
- mutable Stack<Allocator> state0_;
- mutable Stack<Allocator> state1_;
- bool anchorBegin_;
- bool anchorEnd_;
+ const RegexType& regex_;
+ Allocator* allocator_;
+ Allocator* ownAllocator_;
+ Stack<Allocator> state0_;
+ Stack<Allocator> state1_;
+ uint32_t* stateSet_;
};
typedef GenericRegex<UTF8<> > Regex;
+typedef GenericRegexSearch<Regex> RegexSearch;
} // namespace internal
RAPIDJSON_NAMESPACE_END
-#ifdef __clang__
+#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
-#ifdef _MSC_VER
+#if defined(__clang__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/stack.h b/3rdparty/rapidjson/include/rapidjson/internal/stack.h
index 022c9aab411..73abd706e97 100644
--- a/3rdparty/rapidjson/include/rapidjson/internal/stack.h
+++ b/3rdparty/rapidjson/include/rapidjson/internal/stack.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -17,6 +17,7 @@
#include "../allocators.h"
#include "swap.h"
+#include <cstddef>
#if defined(__clang__)
RAPIDJSON_DIAG_PUSH
@@ -100,7 +101,7 @@ public:
void ShrinkToFit() {
if (Empty()) {
// If the stack is empty, completely deallocate the memory.
- Allocator::Free(stack_);
+ Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
stack_ = 0;
stackTop_ = 0;
stackEnd_ = 0;
@@ -114,7 +115,7 @@ public:
template<typename T>
RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
// Expand the stack if needed
- if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
+ if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
Expand<T>(count);
}
@@ -126,7 +127,8 @@ public:
template<typename T>
RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
- RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
+ RAPIDJSON_ASSERT(stackTop_);
+ RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
T* ret = reinterpret_cast<T*>(stackTop_);
stackTop_ += sizeof(T) * count;
return ret;
@@ -183,7 +185,7 @@ private:
size_t newCapacity;
if (stack_ == 0) {
if (!allocator_)
- ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
newCapacity = initialCapacity_;
} else {
newCapacity = GetCapacity();
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/strfunc.h b/3rdparty/rapidjson/include/rapidjson/internal/strfunc.h
index 2edfae52678..b698a8f43fa 100644
--- a/3rdparty/rapidjson/include/rapidjson/internal/strfunc.h
+++ b/3rdparty/rapidjson/include/rapidjson/internal/strfunc.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -16,6 +16,7 @@
#define RAPIDJSON_INTERNAL_STRFUNC_H_
#include "../stream.h"
+#include <cwchar>
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
@@ -28,14 +29,41 @@ namespace internal {
*/
template <typename Ch>
inline SizeType StrLen(const Ch* s) {
+ RAPIDJSON_ASSERT(s != 0);
const Ch* p = s;
while (*p) ++p;
return SizeType(p - s);
}
+template <>
+inline SizeType StrLen(const char* s) {
+ return SizeType(std::strlen(s));
+}
+
+template <>
+inline SizeType StrLen(const wchar_t* s) {
+ return SizeType(std::wcslen(s));
+}
+
+//! Custom strcmpn() which works on different character types.
+/*! \tparam Ch Character type (e.g. char, wchar_t, short)
+ \param s1 Null-terminated input string.
+ \param s2 Null-terminated input string.
+ \return 0 if equal
+*/
+template<typename Ch>
+inline int StrCmp(const Ch* s1, const Ch* s2) {
+ RAPIDJSON_ASSERT(s1 != 0);
+ RAPIDJSON_ASSERT(s2 != 0);
+ while(*s1 && (*s1 == *s2)) { s1++; s2++; }
+ return static_cast<unsigned>(*s1) < static_cast<unsigned>(*s2) ? -1 : static_cast<unsigned>(*s1) > static_cast<unsigned>(*s2);
+}
+
//! Returns number of code points in a encoded string.
template<typename Encoding>
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
+ RAPIDJSON_ASSERT(s != 0);
+ RAPIDJSON_ASSERT(outCount != 0);
GenericStringStream<Encoding> is(s);
const typename Encoding::Ch* end = s + length;
SizeType count = 0;
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/strtod.h b/3rdparty/rapidjson/include/rapidjson/internal/strtod.h
index 289c413b07b..55f0e380bfa 100644
--- a/3rdparty/rapidjson/include/rapidjson/internal/strtod.h
+++ b/3rdparty/rapidjson/include/rapidjson/internal/strtod.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -19,6 +19,8 @@
#include "biginteger.h"
#include "diyfp.h"
#include "pow10.h"
+#include <climits>
+#include <limits>
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
@@ -126,46 +128,47 @@ inline bool StrtodFast(double d, int p, double* result) {
}
// Compute an approximation and see if it is within 1/2 ULP
-inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
+template<typename Ch>
+inline bool StrtodDiyFp(const Ch* decimals, int dLen, int dExp, double* result) {
uint64_t significand = 0;
- size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
- for (; i < length; i++) {
+ int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
+ for (; i < dLen; i++) {
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
- (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
+ (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > Ch('5')))
break;
- significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
+ significand = significand * 10u + static_cast<unsigned>(decimals[i] - Ch('0'));
}
- if (i < length && decimals[i] >= '5') // Rounding
+ if (i < dLen && decimals[i] >= Ch('5')) // Rounding
significand++;
- size_t remaining = length - i;
- const unsigned kUlpShift = 3;
- const unsigned kUlp = 1 << kUlpShift;
+ int remaining = dLen - i;
+ const int kUlpShift = 3;
+ const int kUlp = 1 << kUlpShift;
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
DiyFp v(significand, 0);
v = v.Normalize();
error <<= -v.e;
- const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
+ dExp += remaining;
int actualExp;
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
if (actualExp != dExp) {
static const DiyFp kPow10[] = {
- DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
- DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
- DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
- DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
- DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
- DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
- DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
+ DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1
+ DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2
+ DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3
+ DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4
+ DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5
+ DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6
+ DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7
};
- int adjustment = dExp - actualExp - 1;
- RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
- v = v * kPow10[adjustment];
- if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
+ int adjustment = dExp - actualExp;
+ RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8);
+ v = v * kPow10[adjustment - 1];
+ if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit
error += kUlp / 2;
}
@@ -177,17 +180,17 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
v = v.Normalize();
error <<= oldExp - v.e;
- const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
- unsigned precisionSize = 64 - effectiveSignificandSize;
+ const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
+ int precisionSize = 64 - effectiveSignificandSize;
if (precisionSize + kUlpShift >= 64) {
- unsigned scaleExp = (precisionSize + kUlpShift) - 63;
+ int scaleExp = (precisionSize + kUlpShift) - 63;
v.f >>= scaleExp;
v.e += scaleExp;
- error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
+ error = (error >> scaleExp) + 1 + kUlp;
precisionSize -= scaleExp;
}
- DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
+ DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
@@ -203,9 +206,10 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
}
-inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
- const BigInteger dInt(decimals, length);
- const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
+template<typename Ch>
+inline double StrtodBigInteger(double approx, const Ch* decimals, int dLen, int dExp) {
+ RAPIDJSON_ASSERT(dLen >= 0);
+ const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
Double a(approx);
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
if (cmp < 0)
@@ -221,46 +225,66 @@ inline double StrtodBigInteger(double approx, const char* decimals, size_t lengt
return a.NextPositiveDouble();
}
-inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
+template<typename Ch>
+inline double StrtodFullPrecision(double d, int p, const Ch* decimals, size_t length, size_t decimalPosition, int exp) {
RAPIDJSON_ASSERT(d >= 0.0);
RAPIDJSON_ASSERT(length >= 1);
- double result;
+ double result = 0.0;
if (StrtodFast(d, p, &result))
return result;
+ RAPIDJSON_ASSERT(length <= INT_MAX);
+ int dLen = static_cast<int>(length);
+
+ RAPIDJSON_ASSERT(length >= decimalPosition);
+ RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);
+ int dExpAdjust = static_cast<int>(length - decimalPosition);
+
+ RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust);
+ int dExp = exp - dExpAdjust;
+
+ // Make sure length+dExp does not overflow
+ RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen);
+
// Trim leading zeros
- while (*decimals == '0' && length > 1) {
- length--;
+ while (dLen > 0 && *decimals == '0') {
+ dLen--;
decimals++;
- decimalPosition--;
}
// Trim trailing zeros
- while (decimals[length - 1] == '0' && length > 1) {
- length--;
- decimalPosition--;
- exp++;
+ while (dLen > 0 && decimals[dLen - 1] == '0') {
+ dLen--;
+ dExp++;
+ }
+
+ if (dLen == 0) { // Buffer only contains zeros.
+ return 0.0;
}
// Trim right-most digits
- const int kMaxDecimalDigit = 780;
- if (static_cast<int>(length) > kMaxDecimalDigit) {
- int delta = (static_cast<int>(length) - kMaxDecimalDigit);
- exp += delta;
- decimalPosition -= static_cast<unsigned>(delta);
- length = kMaxDecimalDigit;
+ const int kMaxDecimalDigit = 767 + 1;
+ if (dLen > kMaxDecimalDigit) {
+ dExp += dLen - kMaxDecimalDigit;
+ dLen = kMaxDecimalDigit;
}
- // If too small, underflow to zero
- if (int(length) + exp < -324)
+ // If too small, underflow to zero.
+ // Any x <= 10^-324 is interpreted as zero.
+ if (dLen + dExp <= -324)
return 0.0;
- if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
+ // If too large, overflow to infinity.
+ // Any x >= 10^309 is interpreted as +infinity.
+ if (dLen + dExp > 309)
+ return std::numeric_limits<double>::infinity();
+
+ if (StrtodDiyFp(decimals, dLen, dExp, &result))
return result;
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
- return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
+ return StrtodBigInteger(result, decimals, dLen, dExp);
}
} // namespace internal
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/swap.h b/3rdparty/rapidjson/include/rapidjson/internal/swap.h
index 666e49f97b6..2cf92f93a1d 100644
--- a/3rdparty/rapidjson/include/rapidjson/internal/swap.h
+++ b/3rdparty/rapidjson/include/rapidjson/internal/swap.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
diff --git a/3rdparty/rapidjson/include/rapidjson/istreamwrapper.h b/3rdparty/rapidjson/include/rapidjson/istreamwrapper.h
index f5fe28977eb..01437ec0127 100644
--- a/3rdparty/rapidjson/include/rapidjson/istreamwrapper.h
+++ b/3rdparty/rapidjson/include/rapidjson/istreamwrapper.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -17,13 +17,12 @@
#include "stream.h"
#include <iosfwd>
+#include <ios>
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
-#endif
-
-#ifdef _MSC_VER
+#elif defined(_MSC_VER)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
#endif
@@ -50,57 +49,71 @@ template <typename StreamType>
class BasicIStreamWrapper {
public:
typedef typename StreamType::char_type Ch;
- BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
- Ch Peek() const {
- typename StreamType::int_type c = stream_.peek();
- return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0';
+ //! Constructor.
+ /*!
+ \param stream stream opened for read.
+ */
+ BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
+ Read();
}
- Ch Take() {
- typename StreamType::int_type c = stream_.get();
- if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
- count_++;
- return static_cast<Ch>(c);
- }
- else
- return '\0';
+ //! Constructor.
+ /*!
+ \param stream stream opened for read.
+ \param buffer user-supplied buffer.
+ \param bufferSize size of buffer in bytes. Must >=4 bytes.
+ */
+ BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
+ RAPIDJSON_ASSERT(bufferSize >= 4);
+ Read();
}
- // tellg() may return -1 when failed. So we count by ourself.
- size_t Tell() const { return count_; }
+ Ch Peek() const { return *current_; }
+ Ch Take() { Ch c = *current_; Read(); return c; }
+ size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
- Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ // Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
- void Flush() { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only.
const Ch* Peek4() const {
- RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
- int i;
- bool hasError = false;
- for (i = 0; i < 4; ++i) {
- typename StreamType::int_type c = stream_.get();
- if (c == StreamType::traits_type::eof()) {
- hasError = true;
- stream_.clear();
- break;
- }
- peekBuffer_[i] = static_cast<Ch>(c);
- }
- for (--i; i >= 0; --i)
- stream_.putback(peekBuffer_[i]);
- return !hasError ? peekBuffer_ : 0;
+ return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
}
private:
+ BasicIStreamWrapper();
BasicIStreamWrapper(const BasicIStreamWrapper&);
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
- StreamType& stream_;
- size_t count_; //!< Number of characters read. Note:
- mutable Ch peekBuffer_[4];
+ void Read() {
+ if (current_ < bufferLast_)
+ ++current_;
+ else if (!eof_) {
+ count_ += readCount_;
+ readCount_ = bufferSize_;
+ bufferLast_ = buffer_ + readCount_ - 1;
+ current_ = buffer_;
+
+ if (!stream_.read(buffer_, static_cast<std::streamsize>(bufferSize_))) {
+ readCount_ = static_cast<size_t>(stream_.gcount());
+ *(bufferLast_ = buffer_ + readCount_) = '\0';
+ eof_ = true;
+ }
+ }
+ }
+
+ StreamType &stream_;
+ Ch peekBuffer_[4], *buffer_;
+ size_t bufferSize_;
+ Ch *bufferLast_;
+ Ch *current_;
+ size_t readCount_;
+ size_t count_; //!< Number of characters read
+ bool eof_;
};
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
diff --git a/3rdparty/rapidjson/include/rapidjson/memorybuffer.h b/3rdparty/rapidjson/include/rapidjson/memorybuffer.h
index 39bee1dec1c..ffbc41ed1f7 100644
--- a/3rdparty/rapidjson/include/rapidjson/memorybuffer.h
+++ b/3rdparty/rapidjson/include/rapidjson/memorybuffer.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
diff --git a/3rdparty/rapidjson/include/rapidjson/memorystream.h b/3rdparty/rapidjson/include/rapidjson/memorystream.h
index 1d71d8a4f0e..77af6c999e9 100644
--- a/3rdparty/rapidjson/include/rapidjson/memorystream.h
+++ b/3rdparty/rapidjson/include/rapidjson/memorystream.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
diff --git a/3rdparty/rapidjson/include/rapidjson/ostreamwrapper.h b/3rdparty/rapidjson/include/rapidjson/ostreamwrapper.h
index 6f4667c08ad..11ed4d33f92 100644
--- a/3rdparty/rapidjson/include/rapidjson/ostreamwrapper.h
+++ b/3rdparty/rapidjson/include/rapidjson/ostreamwrapper.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
diff --git a/3rdparty/rapidjson/include/rapidjson/pointer.h b/3rdparty/rapidjson/include/rapidjson/pointer.h
index 0206ac1c8b6..05b1704dd45 100644
--- a/3rdparty/rapidjson/include/rapidjson/pointer.h
+++ b/3rdparty/rapidjson/include/rapidjson/pointer.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -16,14 +16,14 @@
#define RAPIDJSON_POINTER_H_
#include "document.h"
+#include "uri.h"
#include "internal/itoa.h"
+#include "error/error.h" // PointerParseErrorCode
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(switch-enum)
-#endif
-
-#ifdef _MSC_VER
+#elif defined(_MSC_VER)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
@@ -32,19 +32,6 @@ RAPIDJSON_NAMESPACE_BEGIN
static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
-//! Error code of parsing.
-/*! \ingroup RAPIDJSON_ERRORS
- \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
-*/
-enum PointerParseErrorCode {
- kPointerParseErrorNone = 0, //!< The parse is successful
-
- kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/'
- kPointerParseErrorInvalidEscape, //!< Invalid escape
- kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment
- kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment
-};
-
///////////////////////////////////////////////////////////////////////////////
// GenericPointer
@@ -70,10 +57,10 @@ enum PointerParseErrorCode {
supplied tokens eliminates these.
GenericPointer depends on GenericDocument and GenericValue.
-
+
\tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >
\tparam Allocator The allocator type for allocating memory for internal representation.
-
+
\note GenericPointer uses same encoding of ValueType.
However, Allocator of GenericPointer is independent of Allocator of Value.
*/
@@ -82,8 +69,10 @@ class GenericPointer {
public:
typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
typedef typename ValueType::Ch Ch; //!< Character type from Value
+ typedef GenericUri<ValueType, Allocator> UriType;
- //! A token is the basic units of internal representation.
+
+ //! A token is the basic units of internal representation.
/*!
A JSON pointer string representation "/foo/123" is parsed to two tokens:
"foo" and 123. 123 will be represented in both numeric form and string form.
@@ -165,7 +154,12 @@ public:
GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
//! Copy constructor.
- GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+ GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+ *this = rhs;
+ }
+
+ //! Copy constructor.
+ GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
*this = rhs;
}
@@ -197,6 +191,36 @@ public:
return *this;
}
+ //! Swap the content of this pointer with an other.
+ /*!
+ \param other The pointer to swap with.
+ \note Constant complexity.
+ */
+ GenericPointer& Swap(GenericPointer& other) RAPIDJSON_NOEXCEPT {
+ internal::Swap(allocator_, other.allocator_);
+ internal::Swap(ownAllocator_, other.ownAllocator_);
+ internal::Swap(nameBuffer_, other.nameBuffer_);
+ internal::Swap(tokens_, other.tokens_);
+ internal::Swap(tokenCount_, other.tokenCount_);
+ internal::Swap(parseErrorOffset_, other.parseErrorOffset_);
+ internal::Swap(parseErrorCode_, other.parseErrorCode_);
+ return *this;
+ }
+
+ //! free-standing swap function helper
+ /*!
+ Helper function to enable support for common swap implementation pattern based on \c std::swap:
+ \code
+ void swap(MyClass& a, MyClass& b) {
+ using std::swap;
+ swap(a.pointer, b.pointer);
+ // ...
+ }
+ \endcode
+ \see Swap()
+ */
+ friend inline void swap(GenericPointer& a, GenericPointer& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
+
//@}
//!@name Append token
@@ -240,7 +264,7 @@ public:
template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
Append(T* name, Allocator* allocator = 0) const {
- return Append(name, StrLen(name), allocator);
+ return Append(name, internal::StrLen(name), allocator);
}
#if RAPIDJSON_HAS_STDSTRING
@@ -274,7 +298,7 @@ public:
else {
Ch name[21];
for (size_t i = 0; i <= length; i++)
- name[i] = buffer[i];
+ name[i] = static_cast<Ch>(buffer[i]);
Token token = { name, length, index };
return Append(token, allocator);
}
@@ -353,6 +377,33 @@ public:
*/
bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
+ //! Less than operator.
+ /*!
+ \note Invalid pointers are always greater than valid ones.
+ */
+ bool operator<(const GenericPointer& rhs) const {
+ if (!IsValid())
+ return false;
+ if (!rhs.IsValid())
+ return true;
+
+ if (tokenCount_ != rhs.tokenCount_)
+ return tokenCount_ < rhs.tokenCount_;
+
+ for (size_t i = 0; i < tokenCount_; i++) {
+ if (tokens_[i].index != rhs.tokens_[i].index)
+ return tokens_[i].index < rhs.tokens_[i].index;
+
+ if (tokens_[i].length != rhs.tokens_[i].length)
+ return tokens_[i].length < rhs.tokens_[i].length;
+
+ if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length))
+ return cmp < 0;
+ }
+
+ return false;
+ }
+
//@}
//!@name Stringify
@@ -428,10 +479,11 @@ public:
v = &((*v)[t->index]);
}
else {
- typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+ typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
if (m == v->MemberEnd()) {
v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
- v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end
+ m = v->MemberEnd();
+ v = &(--m)->value; // Assumes AddMember() appends at the end
exist = false;
}
else
@@ -459,6 +511,70 @@ public:
//@}
+ //!@name Compute URI
+ //@{
+
+ //! Compute the in-scope URI for a subtree.
+ // For use with JSON pointers into JSON schema documents.
+ /*!
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+ \param rootUri Root URI
+ \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
+ \param allocator Allocator for Uris
+ \return Uri if it can be resolved. Otherwise null.
+
+ \note
+ There are only 3 situations when a URI cannot be resolved:
+ 1. A value in the path is not an array nor object.
+ 2. An object value does not contain the token.
+ 3. A token is out of range of an array value.
+
+ Use unresolvedTokenIndex to retrieve the token index.
+ */
+ UriType GetUri(ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const {
+ static const Ch kIdString[] = { 'i', 'd', '\0' };
+ static const ValueType kIdValue(kIdString, 2);
+ UriType base = UriType(rootUri, allocator);
+ RAPIDJSON_ASSERT(IsValid());
+ ValueType* v = &root;
+ for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
+ switch (v->GetType()) {
+ case kObjectType:
+ {
+ // See if we have an id, and if so resolve with the current base
+ typename ValueType::MemberIterator m = v->FindMember(kIdValue);
+ if (m != v->MemberEnd() && (m->value).IsString()) {
+ UriType here = UriType(m->value, allocator).Resolve(base, allocator);
+ base = here;
+ }
+ m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
+ if (m == v->MemberEnd())
+ break;
+ v = &m->value;
+ }
+ continue;
+ case kArrayType:
+ if (t->index == kPointerInvalidIndex || t->index >= v->Size())
+ break;
+ v = &((*v)[t->index]);
+ continue;
+ default:
+ break;
+ }
+
+ // Error: unresolved token
+ if (unresolvedTokenIndex)
+ *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
+ return UriType(allocator);
+ }
+ return base;
+ }
+
+ UriType GetUri(const ValueType& root, const UriType& rootUri, size_t* unresolvedTokenIndex = 0, Allocator* allocator = 0) const {
+ return GetUri(const_cast<ValueType&>(root), rootUri, unresolvedTokenIndex, allocator);
+ }
+
+
//!@name Query value
//@{
@@ -483,7 +599,7 @@ public:
switch (v->GetType()) {
case kObjectType:
{
- typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+ typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
if (m == v->MemberEnd())
break;
v = &m->value;
@@ -532,14 +648,14 @@ public:
*/
ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
bool alreadyExist;
- Value& v = Create(root, allocator, &alreadyExist);
+ ValueType& v = Create(root, allocator, &alreadyExist);
return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
}
//! Query a value in a subtree with default null-terminated string.
ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {
bool alreadyExist;
- Value& v = Create(root, allocator, &alreadyExist);
+ ValueType& v = Create(root, allocator, &alreadyExist);
return alreadyExist ? v : v.SetString(defaultValue, allocator);
}
@@ -547,7 +663,7 @@ public:
//! Query a value in a subtree with default std::basic_string.
ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {
bool alreadyExist;
- Value& v = Create(root, allocator, &alreadyExist);
+ ValueType& v = Create(root, allocator, &alreadyExist);
return alreadyExist ? v : v.SetString(defaultValue, allocator);
}
#endif
@@ -573,7 +689,7 @@ public:
ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const {
return GetWithDefault(document, defaultValue, document.GetAllocator());
}
-
+
#if RAPIDJSON_HAS_STDSTRING
//! Query a value in a document with default std::basic_string.
template <typename stackAllocator>
@@ -719,7 +835,7 @@ public:
switch (v->GetType()) {
case kObjectType:
{
- typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+ typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
if (m == v->MemberEnd())
return false;
v = &m->value;
@@ -758,7 +874,7 @@ private:
*/
Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {
if (!allocator_) // allocator is independently owned.
- ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
@@ -806,7 +922,7 @@ private:
// Create own allocator if user did not supply.
if (!allocator_)
- ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
// Count number of '/' as tokenCount
tokenCount_ = 0;
@@ -867,7 +983,7 @@ private:
}
i++;
-
+
// Escaping "~0" -> '~', "~1" -> '/'
if (c == '~') {
if (i < length) {
@@ -1029,8 +1145,8 @@ private:
unsigned char u = static_cast<unsigned char>(c);
static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
os_.Put('%');
- os_.Put(hexDigits[u >> 4]);
- os_.Put(hexDigits[u & 15]);
+ os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u >> 4]));
+ os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u & 15]));
}
private:
OutputStream& os_;
@@ -1347,11 +1463,7 @@ bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
RAPIDJSON_NAMESPACE_END
-#ifdef __clang__
-RAPIDJSON_DIAG_POP
-#endif
-
-#ifdef _MSC_VER
+#if defined(__clang__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif
diff --git a/3rdparty/rapidjson/include/rapidjson/prettywriter.h b/3rdparty/rapidjson/include/rapidjson/prettywriter.h
index 0dcb0fee923..fe45df1d10f 100644
--- a/3rdparty/rapidjson/include/rapidjson/prettywriter.h
+++ b/3rdparty/rapidjson/include/rapidjson/prettywriter.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -22,6 +22,11 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
RAPIDJSON_NAMESPACE_BEGIN
//! Combination of PrettyWriter format flags.
@@ -34,7 +39,7 @@ enum PrettyFormatOptions {
//! Writer with indentation and spacing.
/*!
- \tparam OutputStream Type of ouptut os.
+ \tparam OutputStream Type of output os.
\tparam SourceEncoding Encoding of source string.
\tparam TargetEncoding Encoding of output stream.
\tparam StackAllocator Type of allocator for allocating memory of stack.
@@ -42,7 +47,7 @@ enum PrettyFormatOptions {
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
public:
- typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
+ typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> Base;
typedef typename Base::Ch Ch;
//! Constructor
@@ -55,7 +60,12 @@ public:
explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
- Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
+ Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ PrettyWriter(PrettyWriter&& rhs) :
+ Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
+#endif
//! Set custom indentation.
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
@@ -82,24 +92,26 @@ public:
*/
//@{
- bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
- bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
- bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
- bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
- bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
- bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
- bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
+ bool Null() { PrettyPrefix(kNullType); return Base::EndValue(Base::WriteNull()); }
+ bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); }
+ bool Int(int i) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); }
+ bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); }
+ bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); }
+ bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64)); }
+ bool Double(double d) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); }
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
+ RAPIDJSON_ASSERT(str != 0);
(void)copy;
PrettyPrefix(kNumberType);
- return Base::WriteString(str, length);
+ return Base::EndValue(Base::WriteString(str, length));
}
bool String(const Ch* str, SizeType length, bool copy = false) {
+ RAPIDJSON_ASSERT(str != 0);
(void)copy;
PrettyPrefix(kStringType);
- return Base::WriteString(str, length);
+ return Base::EndValue(Base::WriteString(str, length));
}
#if RAPIDJSON_HAS_STDSTRING
@@ -124,19 +136,21 @@ public:
bool EndObject(SizeType memberCount = 0) {
(void)memberCount;
- RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
- RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
+ RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object
+ RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object
+ RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value
+
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
if (!empty) {
Base::os_->Put('\n');
WriteIndent();
}
- bool ret = Base::WriteEndObject();
+ bool ret = Base::EndValue(Base::WriteEndObject());
(void)ret;
RAPIDJSON_ASSERT(ret == true);
if (Base::level_stack_.Empty()) // end of json text
- Base::os_->Flush();
+ Base::Flush();
return true;
}
@@ -156,11 +170,11 @@ public:
Base::os_->Put('\n');
WriteIndent();
}
- bool ret = Base::WriteEndArray();
+ bool ret = Base::EndValue(Base::WriteEndArray());
(void)ret;
RAPIDJSON_ASSERT(ret == true);
if (Base::level_stack_.Empty()) // end of json text
- Base::os_->Flush();
+ Base::Flush();
return true;
}
@@ -184,7 +198,11 @@ public:
\param type Type of the root of json.
\note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
*/
- bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); }
+ bool RawValue(const Ch* json, size_t length, Type type) {
+ RAPIDJSON_ASSERT(json != 0);
+ PrettyPrefix(type);
+ return Base::EndValue(Base::WriteRawValue(json, length));
+ }
protected:
void PrettyPrefix(Type type) {
@@ -233,7 +251,7 @@ protected:
void WriteIndent() {
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
- PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
+ PutN(*Base::os_, static_cast<typename OutputStream::Ch>(indentChar_), count);
}
Ch indentChar_;
@@ -248,6 +266,10 @@ private:
RAPIDJSON_NAMESPACE_END
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
diff --git a/3rdparty/rapidjson/include/rapidjson/rapidjson.h b/3rdparty/rapidjson/include/rapidjson/rapidjson.h
index 053b2ce43f9..5ea69479501 100644
--- a/3rdparty/rapidjson/include/rapidjson/rapidjson.h
+++ b/3rdparty/rapidjson/include/rapidjson/rapidjson.h
@@ -1,15 +1,15 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_RAPIDJSON_H_
@@ -17,7 +17,7 @@
/*!\file rapidjson.h
\brief common definitions and configuration
-
+
\see RAPIDJSON_CONFIG
*/
@@ -26,7 +26,7 @@
Some RapidJSON features are configurable to adapt the library to a wide
variety of platforms, environments and usage scenarios. Most of the
- features can be configured in terms of overriden or predefined
+ features can be configured in terms of overridden or predefined
preprocessor macros at compile-time.
Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
@@ -49,6 +49,11 @@
// token stringification
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
#define RAPIDJSON_DO_STRINGIFY(x) #x
+
+// token concatenation
+#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
+#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
+#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
//!@endcond
/*! \def RAPIDJSON_MAJOR_VERSION
@@ -120,6 +125,19 @@
#endif
///////////////////////////////////////////////////////////////////////////////
+// __cplusplus macro
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+
+#if defined(_MSC_VER)
+#define RAPIDJSON_CPLUSPLUS _MSVC_LANG
+#else
+#define RAPIDJSON_CPLUSPLUS __cplusplus
+#endif
+
+//!@endcond
+
+///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_HAS_STDSTRING
#ifndef RAPIDJSON_HAS_STDSTRING
@@ -145,6 +163,24 @@
#endif // RAPIDJSON_HAS_STDSTRING
///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_USE_MEMBERSMAP
+
+/*! \def RAPIDJSON_USE_MEMBERSMAP
+ \ingroup RAPIDJSON_CONFIG
+ \brief Enable RapidJSON support for object members handling in a \c std::multimap
+
+ By defining this preprocessor symbol to \c 1, \ref rapidjson::GenericValue object
+ members are stored in a \c std::multimap for faster lookup and deletion times, a
+ trade off with a slightly slower insertion time and a small object allocat(or)ed
+ memory overhead.
+
+ \hideinitializer
+*/
+#ifndef RAPIDJSON_USE_MEMBERSMAP
+#define RAPIDJSON_USE_MEMBERSMAP 0 // not by default
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_NO_INT64DEFINE
/*! \def RAPIDJSON_NO_INT64DEFINE
@@ -159,7 +195,7 @@
*/
#ifndef RAPIDJSON_NO_INT64DEFINE
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
-#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013
+#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013
#include "msinttypes/stdint.h"
#include "msinttypes/inttypes.h"
#else
@@ -214,7 +250,7 @@
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# else
-# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
# endif // __BYTE_ORDER__
// Detect with GLIBC's endian.h
# elif defined(__GLIBC__)
@@ -224,7 +260,7 @@
# elif (__BYTE_ORDER == __BIG_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# else
-# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
# endif // __GLIBC__
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
@@ -236,12 +272,12 @@
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
-# elif defined(_MSC_VER) && defined(_M_ARM)
+# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
# define RAPIDJSON_ENDIAN
# else
-# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
# endif
#endif // RAPIDJSON_ENDIAN
@@ -264,16 +300,11 @@
/*! \ingroup RAPIDJSON_CONFIG
\param x pointer to align
- Some machines require strict data alignment. Currently the default uses 4 bytes
- alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.
+ Some machines require strict data alignment. The default is 8 bytes.
User can customize by defining the RAPIDJSON_ALIGN function macro.
*/
#ifndef RAPIDJSON_ALIGN
-#if RAPIDJSON_64BIT == 1
-#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
-#else
-#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
-#endif
+#define RAPIDJSON_ALIGN(x) (((x) + static_cast<size_t>(7u)) & ~static_cast<size_t>(7u))
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -320,17 +351,17 @@
#endif
///////////////////////////////////////////////////////////////////////////////
-// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
+// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD
/*! \def RAPIDJSON_SIMD
\ingroup RAPIDJSON_CONFIG
- \brief Enable SSE2/SSE4.2 optimization.
+ \brief Enable SSE2/SSE4.2/Neon optimization.
RapidJSON supports optimized implementations for some parsing operations
- based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible
- processors.
+ based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel
+ or ARM compatible processors.
- To enable these optimizations, two different symbols can be defined;
+ To enable these optimizations, three different symbols can be defined;
\code
// Enable SSE2 optimization.
#define RAPIDJSON_SSE2
@@ -339,13 +370,17 @@
#define RAPIDJSON_SSE42
\endcode
- \c RAPIDJSON_SSE42 takes precedence, if both are defined.
+ // Enable ARM Neon optimization.
+ #define RAPIDJSON_NEON
+ \endcode
+
+ \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined.
If any of these symbols is defined, RapidJSON defines the macro
\c RAPIDJSON_SIMD to indicate the availability of the optimized code.
*/
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \
- || defined(RAPIDJSON_DOXYGEN_RUNNING)
+ || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING)
#define RAPIDJSON_SIMD
#endif
@@ -405,7 +440,15 @@ RAPIDJSON_NAMESPACE_END
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_STATIC_ASSERT
-// Adopt from boost
+// Prefer C++11 static_assert, if available
+#ifndef RAPIDJSON_STATIC_ASSERT
+#if RAPIDJSON_CPLUSPLUS >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
+#define RAPIDJSON_STATIC_ASSERT(x) \
+ static_assert(x, RAPIDJSON_STRINGIFY(x))
+#endif // C++11
+#endif // RAPIDJSON_STATIC_ASSERT
+
+// Adopt C++03 implementation from boost
#ifndef RAPIDJSON_STATIC_ASSERT
#ifndef __clang__
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
@@ -413,14 +456,10 @@ RAPIDJSON_NAMESPACE_END
RAPIDJSON_NAMESPACE_BEGIN
template <bool x> struct STATIC_ASSERTION_FAILURE;
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
-template<int x> struct StaticAssertTest {};
+template <size_t x> struct StaticAssertTest {};
RAPIDJSON_NAMESPACE_END
-#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
-#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
-#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
-
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
#else
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
@@ -438,7 +477,7 @@ RAPIDJSON_NAMESPACE_END
typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
-#endif
+#endif // RAPIDJSON_STATIC_ASSERT
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY
@@ -474,7 +513,7 @@ RAPIDJSON_NAMESPACE_END
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
-#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
+#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
#define RAPIDJSON_MULTILINEMACRO_END \
} while((void)0, 0)
@@ -482,6 +521,12 @@ RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_VERSION_CODE(x,y,z) \
(((x)*100000) + ((y)*100) + (z))
+#if defined(__has_builtin)
+#define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x)
+#else
+#define RAPIDJSON_HAS_BUILTIN(x) 0
+#endif
+
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
@@ -527,16 +572,23 @@ RAPIDJSON_NAMESPACE_END
///////////////////////////////////////////////////////////////////////////////
// C++11 features
+#ifndef RAPIDJSON_HAS_CXX11
+#define RAPIDJSON_HAS_CXX11 (RAPIDJSON_CPLUSPLUS >= 201103L)
+#endif
+
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
-#if defined(__clang__)
+#if RAPIDJSON_HAS_CXX11
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
+#elif defined(__clang__)
#if __has_feature(cxx_rvalue_references) && \
- (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
+ (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
#else
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
#endif
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
- (defined(_MSC_VER) && _MSC_VER >= 1600)
+ (defined(_MSC_VER) && _MSC_VER >= 1600) || \
+ (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
#else
@@ -544,46 +596,120 @@ RAPIDJSON_NAMESPACE_END
#endif
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
-#if defined(__clang__)
+#if RAPIDJSON_HAS_CXX11
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
+#elif defined(__clang__)
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
-#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))
-// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
+ (defined(_MSC_VER) && _MSC_VER >= 1900) || \
+ (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
#else
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
#endif
#endif
+#ifndef RAPIDJSON_NOEXCEPT
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
#define RAPIDJSON_NOEXCEPT noexcept
#else
-#define RAPIDJSON_NOEXCEPT /* noexcept */
+#define RAPIDJSON_NOEXCEPT throw()
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
+#endif
// no automatic detection, yet
#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
+#if (defined(_MSC_VER) && _MSC_VER >= 1700)
+#define RAPIDJSON_HAS_CXX11_TYPETRAITS 1
+#else
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
#endif
+#endif
#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
#if defined(__clang__)
#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
-#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
- (defined(_MSC_VER) && _MSC_VER >= 1700)
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
+ (defined(_MSC_VER) && _MSC_VER >= 1700) || \
+ (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
#else
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
#endif
#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
+///////////////////////////////////////////////////////////////////////////////
+// C++17 features
+
+#ifndef RAPIDJSON_HAS_CXX17
+#define RAPIDJSON_HAS_CXX17 (RAPIDJSON_CPLUSPLUS >= 201703L)
+#endif
+
+#if RAPIDJSON_HAS_CXX17
+# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]]
+#elif defined(__has_cpp_attribute)
+# if __has_cpp_attribute(clang::fallthrough)
+# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[clang::fallthrough]]
+# elif __has_cpp_attribute(fallthrough)
+# define RAPIDJSON_DELIBERATE_FALLTHROUGH __attribute__((fallthrough))
+# else
+# define RAPIDJSON_DELIBERATE_FALLTHROUGH
+# endif
+#else
+# define RAPIDJSON_DELIBERATE_FALLTHROUGH
+#endif
+
//!@endcond
+//! Assertion (in non-throwing contexts).
+ /*! \ingroup RAPIDJSON_CONFIG
+ Some functions provide a \c noexcept guarantee, if the compiler supports it.
+ In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to
+ throw an exception. This macro adds a separate customization point for
+ such cases.
+
+ Defaults to C \c assert() (as \ref RAPIDJSON_ASSERT), if \c noexcept is
+ supported, and to \ref RAPIDJSON_ASSERT otherwise.
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NOEXCEPT_ASSERT
+
+#ifndef RAPIDJSON_NOEXCEPT_ASSERT
+#ifdef RAPIDJSON_ASSERT_THROWS
+#include <cassert>
+#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x)
+#else
+#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x)
+#endif // RAPIDJSON_ASSERT_THROWS
+#endif // RAPIDJSON_NOEXCEPT_ASSERT
+
+///////////////////////////////////////////////////////////////////////////////
+// malloc/realloc/free
+
+#ifndef RAPIDJSON_MALLOC
+///! customization point for global \c malloc
+#define RAPIDJSON_MALLOC(size) std::malloc(size)
+#endif
+#ifndef RAPIDJSON_REALLOC
+///! customization point for global \c realloc
+#define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size)
+#endif
+#ifndef RAPIDJSON_FREE
+///! customization point for global \c free
+#define RAPIDJSON_FREE(ptr) std::free(ptr)
+#endif
+
///////////////////////////////////////////////////////////////////////////////
// new/delete
#ifndef RAPIDJSON_NEW
///! customization point for global \c new
-#define RAPIDJSON_NEW(x) new x
+#define RAPIDJSON_NEW(TypeName) new TypeName
#endif
#ifndef RAPIDJSON_DELETE
///! customization point for global \c delete
@@ -605,7 +731,7 @@ enum Type {
kFalseType = 1, //!< false
kTrueType = 2, //!< true
kObjectType = 3, //!< object
- kArrayType = 4, //!< array
+ kArrayType = 4, //!< array
kStringType = 5, //!< string
kNumberType = 6 //!< number
};
diff --git a/3rdparty/rapidjson/include/rapidjson/reader.h b/3rdparty/rapidjson/include/rapidjson/reader.h
index 19f8849b14c..55546601e29 100644
--- a/3rdparty/rapidjson/include/rapidjson/reader.h
+++ b/3rdparty/rapidjson/include/rapidjson/reader.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -20,6 +20,7 @@
#include "allocators.h"
#include "stream.h"
#include "encodedstream.h"
+#include "internal/clzll.h"
#include "internal/meta.h"
#include "internal/stack.h"
#include "internal/strtod.h"
@@ -33,12 +34,8 @@
#include <nmmintrin.h>
#elif defined(RAPIDJSON_SSE2)
#include <emmintrin.h>
-#endif
-
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
-RAPIDJSON_DIAG_OFF(4702) // unreachable code
+#elif defined(RAPIDJSON_NEON)
+#include <arm_neon.h>
#endif
#ifdef __clang__
@@ -46,6 +43,10 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(old-style-cast)
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
#endif
#ifdef __GNUC__
@@ -153,6 +154,7 @@ enum ParseFlag {
kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings.
kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays.
kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles.
+ kParseEscapedApostropheFlag = 512, //!< Allow escaped apostrophe in strings.
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
};
@@ -299,16 +301,9 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
for (;; p += 16) {
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
- const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
- if (r != 0) { // some of characters is non-whitespace
-#ifdef _MSC_VER // Find the index of first non-whitespace
- unsigned long offset;
- _BitScanForward(&offset, r);
- return p + offset;
-#else
- return p + __builtin_ffs(r) - 1;
-#endif
- }
+ const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY);
+ if (r != 16) // some of characters is non-whitespace
+ return p + r;
}
}
@@ -325,16 +320,9 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
for (; p <= end - 16; p += 16) {
const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
- const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
- if (r != 0) { // some of characters is non-whitespace
-#ifdef _MSC_VER // Find the index of first non-whitespace
- unsigned long offset;
- _BitScanForward(&offset, r);
- return p + offset;
-#else
- return p + __builtin_ffs(r) - 1;
-#endif
- }
+ const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY);
+ if (r != 16) // some of characters is non-whitespace
+ return p + r;
}
return SkipWhitespace(p, end);
@@ -425,7 +413,92 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
return SkipWhitespace(p, end);
}
-#endif // RAPIDJSON_SSE2
+#elif defined(RAPIDJSON_NEON)
+
+//! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+ // Fast return for single non-whitespace
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // 16-byte align to the next boundary
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ const uint8x16_t w0 = vmovq_n_u8(' ');
+ const uint8x16_t w1 = vmovq_n_u8('\n');
+ const uint8x16_t w2 = vmovq_n_u8('\r');
+ const uint8x16_t w3 = vmovq_n_u8('\t');
+
+ for (;; p += 16) {
+ const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
+ uint8x16_t x = vceqq_u8(s, w0);
+ x = vorrq_u8(x, vceqq_u8(s, w1));
+ x = vorrq_u8(x, vceqq_u8(s, w2));
+ x = vorrq_u8(x, vceqq_u8(s, w3));
+
+ x = vmvnq_u8(x); // Negate
+ x = vrev64q_u8(x); // Rev in 64
+ uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
+ uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
+
+ if (low == 0) {
+ if (high != 0) {
+ uint32_t lz = internal::clzll(high);
+ return p + 8 + (lz >> 3);
+ }
+ } else {
+ uint32_t lz = internal::clzll(low);
+ return p + (lz >> 3);
+ }
+ }
+}
+
+inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
+ // Fast return for single non-whitespace
+ if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
+ ++p;
+ else
+ return p;
+
+ const uint8x16_t w0 = vmovq_n_u8(' ');
+ const uint8x16_t w1 = vmovq_n_u8('\n');
+ const uint8x16_t w2 = vmovq_n_u8('\r');
+ const uint8x16_t w3 = vmovq_n_u8('\t');
+
+ for (; p <= end - 16; p += 16) {
+ const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
+ uint8x16_t x = vceqq_u8(s, w0);
+ x = vorrq_u8(x, vceqq_u8(s, w1));
+ x = vorrq_u8(x, vceqq_u8(s, w2));
+ x = vorrq_u8(x, vceqq_u8(s, w3));
+
+ x = vmvnq_u8(x); // Negate
+ x = vrev64q_u8(x); // Rev in 64
+ uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
+ uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
+
+ if (low == 0) {
+ if (high != 0) {
+ uint32_t lz = internal::clzll(high);
+ return p + 8 + (lz >> 3);
+ }
+ } else {
+ uint32_t lz = internal::clzll(low);
+ return p + (lz >> 3);
+ }
+ }
+
+ return SkipWhitespace(p, end);
+}
+
+#endif // RAPIDJSON_NEON
#ifdef RAPIDJSON_SIMD
//! Template function specialization for InsituStringStream
@@ -471,7 +544,8 @@ public:
/*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
\param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
*/
- GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}
+ GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) :
+ stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {}
//! Parse JSON text.
/*! \tparam parseFlags Combination of \ref ParseFlag.
@@ -527,7 +601,84 @@ public:
return Parse<kParseDefaultFlags>(is, handler);
}
- //! Whether a parse error has occured in the last parsing.
+ //! Initialize JSON text token-by-token parsing
+ /*!
+ */
+ void IterativeParseInit() {
+ parseResult_.Clear();
+ state_ = IterativeParsingStartState;
+ }
+
+ //! Parse one token from JSON text
+ /*! \tparam InputStream Type of input stream, implementing Stream concept
+ \tparam Handler Type of handler, implementing Handler concept.
+ \param is Input stream to be parsed.
+ \param handler The handler to receive events.
+ \return Whether the parsing is successful.
+ */
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ bool IterativeParseNext(InputStream& is, Handler& handler) {
+ while (RAPIDJSON_LIKELY(is.Peek() != '\0')) {
+ SkipWhitespaceAndComments<parseFlags>(is);
+
+ Token t = Tokenize(is.Peek());
+ IterativeParsingState n = Predict(state_, t);
+ IterativeParsingState d = Transit<parseFlags>(state_, t, n, is, handler);
+
+ // If we've finished or hit an error...
+ if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) {
+ // Report errors.
+ if (d == IterativeParsingErrorState) {
+ HandleError(state_, is);
+ return false;
+ }
+
+ // Transition to the finish state.
+ RAPIDJSON_ASSERT(d == IterativeParsingFinishState);
+ state_ = d;
+
+ // If StopWhenDone is not set...
+ if (!(parseFlags & kParseStopWhenDoneFlag)) {
+ // ... and extra non-whitespace data is found...
+ SkipWhitespaceAndComments<parseFlags>(is);
+ if (is.Peek() != '\0') {
+ // ... this is considered an error.
+ HandleError(state_, is);
+ return false;
+ }
+ }
+
+ // Success! We are done!
+ return true;
+ }
+
+ // Transition to the new state.
+ state_ = d;
+
+ // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now.
+ if (!IsIterativeParsingDelimiterState(n))
+ return true;
+ }
+
+ // We reached the end of file.
+ stack_.Clear();
+
+ if (state_ != IterativeParsingFinishState) {
+ HandleError(state_, is);
+ return false;
+ }
+
+ return true;
+ }
+
+ //! Check if token-by-token parsing JSON text is complete
+ /*! \return Whether the JSON has been fully decoded.
+ */
+ RAPIDJSON_FORCEINLINE bool IterativeParseComplete() const {
+ return IsIterativeParsingCompleteState(state_);
+ }
+
+ //! Whether a parse error has occurred in the last parsing.
bool HasParseError() const { return parseResult_.IsError(); }
//! Get the \ref ParseErrorCode of last parsing.
@@ -575,7 +726,7 @@ private:
}
}
else if (RAPIDJSON_LIKELY(Consume(is, '/')))
- while (is.Peek() != '\0' && is.Take() != '\n');
+ while (is.Peek() != '\0' && is.Take() != '\n') {}
else
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
@@ -750,7 +901,7 @@ private:
return false;
}
- // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
+ // Helper function to parse four hexadecimal digits in \uXXXX in ParseString().
template<typename InputStream>
unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
unsigned codepoint = 0;
@@ -841,7 +992,7 @@ private:
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
static const char escape[256] = {
- Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
+ Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/',
Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -857,26 +1008,38 @@ private:
Ch c = is.Peek();
if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
- size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset
+ size_t escapeOffset = is.Tell(); // For invalid escaping, report the initial '\\' as error offset
is.Take();
Ch e = is.Peek();
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {
is.Take();
os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
}
+ else if ((parseFlags & kParseEscapedApostropheFlag) && RAPIDJSON_LIKELY(e == '\'')) { // Allow escaped apostrophe
+ is.Take();
+ os.Put('\'');
+ }
else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
is.Take();
unsigned codepoint = ParseHex4(is, escapeOffset);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
- if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
- // Handle UTF-16 surrogate pair
- if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
- RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
- unsigned codepoint2 = ParseHex4(is, escapeOffset);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
- if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
+ if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDFFF)) {
+ // high surrogate, check if followed by valid low surrogate
+ if (RAPIDJSON_LIKELY(codepoint <= 0xDBFF)) {
+ // Handle UTF-16 surrogate pair
+ if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
+ unsigned codepoint2 = ParseHex4(is, escapeOffset);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
+ codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
+ }
+ // single low surrogate
+ else
+ {
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
- codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
+ }
}
TEncoding::Encode(os, codepoint);
}
@@ -892,7 +1055,7 @@ private:
if (c == '\0')
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());
else
- RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell());
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell());
}
else {
size_t offset = is.Tell();
@@ -927,7 +1090,7 @@ private:
// The rest of string using SIMD
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
- static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+ static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
@@ -936,7 +1099,7 @@ private:
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
- const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
@@ -948,11 +1111,13 @@ private:
#else
length = static_cast<SizeType>(__builtin_ffs(r) - 1);
#endif
- char* q = reinterpret_cast<char*>(os.Push(length));
- for (size_t i = 0; i < length; i++)
- q[i] = p[i];
+ if (length != 0) {
+ char* q = reinterpret_cast<char*>(os.Push(length));
+ for (size_t i = 0; i < length; i++)
+ q[i] = p[i];
- p += length;
+ p += length;
+ }
break;
}
_mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s);
@@ -988,7 +1153,7 @@ private:
// The rest of string using SIMD
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
- static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+ static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
@@ -997,7 +1162,7 @@ private:
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
- const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
@@ -1036,7 +1201,7 @@ private:
// The rest of string using SIMD
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
- static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+ static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
@@ -1045,7 +1210,7 @@ private:
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
- const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
@@ -1064,27 +1229,199 @@ private:
is.src_ = is.dst_ = p;
}
-#endif
+#elif defined(RAPIDJSON_NEON)
+ // StringStream -> StackStream<char>
+ static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {
+ const char* p = is.src_;
+
+ // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+ is.src_ = p;
+ return;
+ }
+ else
+ os.Put(*p++);
- template<typename InputStream, bool backup, bool pushOnTake>
+ // The rest of string using SIMD
+ const uint8x16_t s0 = vmovq_n_u8('"');
+ const uint8x16_t s1 = vmovq_n_u8('\\');
+ const uint8x16_t s2 = vmovq_n_u8('\b');
+ const uint8x16_t s3 = vmovq_n_u8(32);
+
+ for (;; p += 16) {
+ const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
+ uint8x16_t x = vceqq_u8(s, s0);
+ x = vorrq_u8(x, vceqq_u8(s, s1));
+ x = vorrq_u8(x, vceqq_u8(s, s2));
+ x = vorrq_u8(x, vcltq_u8(s, s3));
+
+ x = vrev64q_u8(x); // Rev in 64
+ uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
+ uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
+
+ SizeType length = 0;
+ bool escaped = false;
+ if (low == 0) {
+ if (high != 0) {
+ uint32_t lz = internal::clzll(high);
+ length = 8 + (lz >> 3);
+ escaped = true;
+ }
+ } else {
+ uint32_t lz = internal::clzll(low);
+ length = lz >> 3;
+ escaped = true;
+ }
+ if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
+ if (length != 0) {
+ char* q = reinterpret_cast<char*>(os.Push(length));
+ for (size_t i = 0; i < length; i++)
+ q[i] = p[i];
+
+ p += length;
+ }
+ break;
+ }
+ vst1q_u8(reinterpret_cast<uint8_t *>(os.Push(16)), s);
+ }
+
+ is.src_ = p;
+ }
+
+ // InsituStringStream -> InsituStringStream
+ static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) {
+ RAPIDJSON_ASSERT(&is == &os);
+ (void)os;
+
+ if (is.src_ == is.dst_) {
+ SkipUnescapedString(is);
+ return;
+ }
+
+ char* p = is.src_;
+ char *q = is.dst_;
+
+ // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+ is.src_ = p;
+ is.dst_ = q;
+ return;
+ }
+ else
+ *q++ = *p++;
+
+ // The rest of string using SIMD
+ const uint8x16_t s0 = vmovq_n_u8('"');
+ const uint8x16_t s1 = vmovq_n_u8('\\');
+ const uint8x16_t s2 = vmovq_n_u8('\b');
+ const uint8x16_t s3 = vmovq_n_u8(32);
+
+ for (;; p += 16, q += 16) {
+ const uint8x16_t s = vld1q_u8(reinterpret_cast<uint8_t *>(p));
+ uint8x16_t x = vceqq_u8(s, s0);
+ x = vorrq_u8(x, vceqq_u8(s, s1));
+ x = vorrq_u8(x, vceqq_u8(s, s2));
+ x = vorrq_u8(x, vcltq_u8(s, s3));
+
+ x = vrev64q_u8(x); // Rev in 64
+ uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
+ uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
+
+ SizeType length = 0;
+ bool escaped = false;
+ if (low == 0) {
+ if (high != 0) {
+ uint32_t lz = internal::clzll(high);
+ length = 8 + (lz >> 3);
+ escaped = true;
+ }
+ } else {
+ uint32_t lz = internal::clzll(low);
+ length = lz >> 3;
+ escaped = true;
+ }
+ if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
+ for (const char* pend = p + length; p != pend; ) {
+ *q++ = *p++;
+ }
+ break;
+ }
+ vst1q_u8(reinterpret_cast<uint8_t *>(q), s);
+ }
+
+ is.src_ = p;
+ is.dst_ = q;
+ }
+
+ // When read/write pointers are the same for insitu stream, just skip unescaped characters
+ static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) {
+ RAPIDJSON_ASSERT(is.src_ == is.dst_);
+ char* p = is.src_;
+
+ // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ for (; p != nextAligned; p++)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+ is.src_ = is.dst_ = p;
+ return;
+ }
+
+ // The rest of string using SIMD
+ const uint8x16_t s0 = vmovq_n_u8('"');
+ const uint8x16_t s1 = vmovq_n_u8('\\');
+ const uint8x16_t s2 = vmovq_n_u8('\b');
+ const uint8x16_t s3 = vmovq_n_u8(32);
+
+ for (;; p += 16) {
+ const uint8x16_t s = vld1q_u8(reinterpret_cast<uint8_t *>(p));
+ uint8x16_t x = vceqq_u8(s, s0);
+ x = vorrq_u8(x, vceqq_u8(s, s1));
+ x = vorrq_u8(x, vceqq_u8(s, s2));
+ x = vorrq_u8(x, vcltq_u8(s, s3));
+
+ x = vrev64q_u8(x); // Rev in 64
+ uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
+ uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
+
+ if (low == 0) {
+ if (high != 0) {
+ uint32_t lz = internal::clzll(high);
+ p += 8 + (lz >> 3);
+ break;
+ }
+ } else {
+ uint32_t lz = internal::clzll(low);
+ p += lz >> 3;
+ break;
+ }
+ }
+
+ is.src_ = is.dst_ = p;
+ }
+#endif // RAPIDJSON_NEON
+
+ template<typename InputStream, typename StackCharacter, bool backup, bool pushOnTake>
class NumberStream;
- template<typename InputStream>
- class NumberStream<InputStream, false, false> {
+ template<typename InputStream, typename StackCharacter>
+ class NumberStream<InputStream, StackCharacter, false, false> {
public:
typedef typename InputStream::Ch Ch;
NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; }
- ~NumberStream() {}
RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
- RAPIDJSON_FORCEINLINE void Push(char) {}
+ RAPIDJSON_FORCEINLINE void Push(char) {}
size_t Tell() { return is.Tell(); }
size_t Length() { return 0; }
- const char* Pop() { return 0; }
+ const StackCharacter* Pop() { return 0; }
protected:
NumberStream& operator=(const NumberStream&);
@@ -1092,47 +1429,47 @@ private:
InputStream& is;
};
- template<typename InputStream>
- class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> {
- typedef NumberStream<InputStream, false, false> Base;
+ template<typename InputStream, typename StackCharacter>
+ class NumberStream<InputStream, StackCharacter, true, false> : public NumberStream<InputStream, StackCharacter, false, false> {
+ typedef NumberStream<InputStream, StackCharacter, false, false> Base;
public:
- NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}
- ~NumberStream() {}
+ NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s), stackStream(reader.stack_) {}
RAPIDJSON_FORCEINLINE Ch TakePush() {
- stackStream.Put(static_cast<char>(Base::is.Peek()));
+ stackStream.Put(static_cast<StackCharacter>(Base::is.Peek()));
return Base::is.Take();
}
- RAPIDJSON_FORCEINLINE void Push(char c) {
+ RAPIDJSON_FORCEINLINE void Push(StackCharacter c) {
stackStream.Put(c);
}
size_t Length() { return stackStream.Length(); }
- const char* Pop() {
+ const StackCharacter* Pop() {
stackStream.Put('\0');
return stackStream.Pop();
}
private:
- StackStream<char> stackStream;
+ StackStream<StackCharacter> stackStream;
};
- template<typename InputStream>
- class NumberStream<InputStream, true, true> : public NumberStream<InputStream, true, false> {
- typedef NumberStream<InputStream, true, false> Base;
+ template<typename InputStream, typename StackCharacter>
+ class NumberStream<InputStream, StackCharacter, true, true> : public NumberStream<InputStream, StackCharacter, true, false> {
+ typedef NumberStream<InputStream, StackCharacter, true, false> Base;
public:
- NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}
- ~NumberStream() {}
+ NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s) {}
RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }
};
template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseNumber(InputStream& is, Handler& handler) {
+ typedef typename internal::SelectIf<internal::BoolType<(parseFlags & kParseNumbersAsStringsFlag) != 0>, typename TargetEncoding::Ch, char>::Type NumberCharacter;
+
internal::StreamLocalCopy<InputStream> copy(is);
- NumberStream<InputStream,
+ NumberStream<InputStream, NumberCharacter,
((parseFlags & kParseNumbersAsStringsFlag) != 0) ?
((parseFlags & kParseInsituFlag) == 0) :
((parseFlags & kParseFullPrecisionFlag) != 0),
@@ -1185,18 +1522,27 @@ private:
}
// Parse NaN or Infinity here
else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) {
- useNanOrInf = true;
- if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) {
- d = std::numeric_limits<double>::quiet_NaN();
+ if (Consume(s, 'N')) {
+ if (Consume(s, 'a') && Consume(s, 'N')) {
+ d = std::numeric_limits<double>::quiet_NaN();
+ useNanOrInf = true;
+ }
}
- else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) {
- d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());
- if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n')
- && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y'))))
- RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+ else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) {
+ if (Consume(s, 'n') && Consume(s, 'f')) {
+ d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());
+ useNanOrInf = true;
+
+ if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n')
+ && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) {
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+ }
+ }
}
- else
+
+ if (RAPIDJSON_UNLIKELY(!useNanOrInf)) {
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+ }
}
else
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
@@ -1231,8 +1577,6 @@ private:
// Force double for big integer
if (useDouble) {
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
- if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
- RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
d = d * 10 + (s.TakePush() - '0');
}
}
@@ -1302,9 +1646,18 @@ private:
if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
exp = static_cast<int>(s.Take() - '0');
if (expMinus) {
+ // (exp + expFrac) must not underflow int => we're detecting when -exp gets
+ // dangerously close to INT_MIN (a pessimistic next digit 9 would push it into
+ // underflow territory):
+ //
+ // -(exp * 10 + 9) + expFrac >= INT_MIN
+ // <=> exp <= (expFrac - INT_MIN - 9) / 10
+ RAPIDJSON_ASSERT(expFrac <= 0);
+ int maxExp = (expFrac + 2147483639) / 10;
+
while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
exp = exp * 10 + static_cast<int>(s.Take() - '0');
- if (exp >= 214748364) { // Issue #313: prevent overflow exponent
+ if (RAPIDJSON_UNLIKELY(exp > maxExp)) {
while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent
s.Take();
}
@@ -1341,10 +1694,10 @@ private:
}
else {
SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
- StringStream srcStream(s.Pop());
+ GenericStringStream<UTF8<NumberCharacter> > srcStream(s.Pop());
StackStream<typename TargetEncoding::Ch> dstStream(stack_);
while (numCharsToCopy--) {
- Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream);
+ Transcoder<UTF8<typename TargetEncoding::Ch>, TargetEncoding>::Transcode(srcStream, dstStream);
}
dstStream.Put('\0');
const typename TargetEncoding::Ch* str = dstStream.Pop();
@@ -1354,7 +1707,7 @@ private:
}
else {
size_t length = s.Length();
- const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
+ const NumberCharacter* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
if (useDouble) {
int p = exp + expFrac;
@@ -1363,6 +1716,13 @@ private:
else
d = internal::StrtodNormalPrecision(d, p);
+ // Use > max, instead of == inf, to fix bogus warning -Wfloat-equal
+ if (d > (std::numeric_limits<double>::max)()) {
+ // Overflow
+ // TODO: internal::StrtodX should report overflow (or underflow)
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
+ }
+
cont = handler.Double(minus ? -d : d);
}
else if (useNanOrInf) {
@@ -1408,29 +1768,31 @@ private:
// States
enum IterativeParsingState {
- IterativeParsingStartState = 0,
- IterativeParsingFinishState,
- IterativeParsingErrorState,
+ IterativeParsingFinishState = 0, // sink states at top
+ IterativeParsingErrorState, // sink states at top
+ IterativeParsingStartState,
// Object states
IterativeParsingObjectInitialState,
IterativeParsingMemberKeyState,
- IterativeParsingKeyValueDelimiterState,
IterativeParsingMemberValueState,
- IterativeParsingMemberDelimiterState,
IterativeParsingObjectFinishState,
// Array states
IterativeParsingArrayInitialState,
IterativeParsingElementState,
- IterativeParsingElementDelimiterState,
IterativeParsingArrayFinishState,
// Single value state
- IterativeParsingValueState
- };
+ IterativeParsingValueState,
+
+ // Delimiter states (at bottom)
+ IterativeParsingElementDelimiterState,
+ IterativeParsingMemberDelimiterState,
+ IterativeParsingKeyValueDelimiterState,
- enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
+ cIterativeParsingStateCount
+ };
// Tokens
enum Token {
@@ -1452,7 +1814,7 @@ private:
kTokenCount
};
- RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {
+ RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const {
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#define N NumberToken
@@ -1479,9 +1841,21 @@ private:
return NumberToken;
}
- RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {
+ RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) const {
// current state x one lookahead token -> new state
static const char G[cIterativeParsingStateCount][kTokenCount] = {
+ // Finish(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // Error(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
// Start
{
IterativeParsingArrayInitialState, // Left bracket
@@ -1496,18 +1870,6 @@ private:
IterativeParsingValueState, // Null
IterativeParsingValueState // Number
},
- // Finish(sink state)
- {
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState
- },
- // Error(sink state)
- {
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState
- },
// ObjectInitial
{
IterativeParsingErrorState, // Left bracket
@@ -1536,20 +1898,6 @@ private:
IterativeParsingErrorState, // Null
IterativeParsingErrorState // Number
},
- // KeyValueDelimiter
- {
- IterativeParsingArrayInitialState, // Left bracket(push MemberValue state)
- IterativeParsingErrorState, // Right bracket
- IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state)
- IterativeParsingErrorState, // Right curly bracket
- IterativeParsingErrorState, // Comma
- IterativeParsingErrorState, // Colon
- IterativeParsingMemberValueState, // String
- IterativeParsingMemberValueState, // False
- IterativeParsingMemberValueState, // True
- IterativeParsingMemberValueState, // Null
- IterativeParsingMemberValueState // Number
- },
// MemberValue
{
IterativeParsingErrorState, // Left bracket
@@ -1564,20 +1912,6 @@ private:
IterativeParsingErrorState, // Null
IterativeParsingErrorState // Number
},
- // MemberDelimiter
- {
- IterativeParsingErrorState, // Left bracket
- IterativeParsingErrorState, // Right bracket
- IterativeParsingErrorState, // Left curly bracket
- IterativeParsingObjectFinishState, // Right curly bracket
- IterativeParsingErrorState, // Comma
- IterativeParsingErrorState, // Colon
- IterativeParsingMemberKeyState, // String
- IterativeParsingErrorState, // False
- IterativeParsingErrorState, // True
- IterativeParsingErrorState, // Null
- IterativeParsingErrorState // Number
- },
// ObjectFinish(sink state)
{
IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
@@ -1612,6 +1946,18 @@ private:
IterativeParsingErrorState, // Null
IterativeParsingErrorState // Number
},
+ // ArrayFinish(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // Single Value (sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
// ElementDelimiter
{
IterativeParsingArrayInitialState, // Left bracket(push Element state)
@@ -1626,18 +1972,34 @@ private:
IterativeParsingElementState, // Null
IterativeParsingElementState // Number
},
- // ArrayFinish(sink state)
+ // MemberDelimiter
{
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingObjectFinishState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberKeyState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
},
- // Single Value (sink state)
+ // KeyValueDelimiter
{
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState
- }
+ IterativeParsingArrayInitialState, // Left bracket(push MemberValue state)
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state)
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberValueState, // String
+ IterativeParsingMemberValueState, // False
+ IterativeParsingMemberValueState, // True
+ IterativeParsingMemberValueState, // Null
+ IterativeParsingMemberValueState // Number
+ },
}; // End of G
return static_cast<IterativeParsingState>(G[state][token]);
@@ -1818,6 +2180,14 @@ private:
}
}
+ RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) const {
+ return s >= IterativeParsingElementDelimiterState;
+ }
+
+ RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) const {
+ return s <= IterativeParsingErrorState;
+ }
+
template <unsigned parseFlags, typename InputStream, typename Handler>
ParseResult IterativeParse(InputStream& is, Handler& handler) {
parseResult_.Clear();
@@ -1856,6 +2226,7 @@ private:
static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
internal::Stack<StackAllocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
ParseResult parseResult_;
+ IterativeParsingState state_;
}; // class GenericReader
//! Reader with UTF8 encoding and default allocator.
@@ -1863,7 +2234,7 @@ typedef GenericReader<UTF8<>, UTF8<> > Reader;
RAPIDJSON_NAMESPACE_END
-#ifdef __clang__
+#if defined(__clang__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif
@@ -1872,8 +2243,4 @@ RAPIDJSON_DIAG_POP
RAPIDJSON_DIAG_POP
#endif
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_POP
-#endif
-
#endif // RAPIDJSON_READER_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/schema.h b/3rdparty/rapidjson/include/rapidjson/schema.h
index 8497d303155..439133fa674 100644
--- a/3rdparty/rapidjson/include/rapidjson/schema.h
+++ b/3rdparty/rapidjson/include/rapidjson/schema.h
@@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available->
-//
+//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
//
// Licensed under the MIT License (the "License"); you may not use this file except
@@ -7,9 +7,9 @@
//
// http://opensource->org/licenses/MIT
//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied-> See the License for the
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied-> See the License for the
// specific language governing permissions and limitations under the License->
#ifndef RAPIDJSON_SCHEMA_H_
@@ -17,6 +17,9 @@
#include "document.h"
#include "pointer.h"
+#include "stringbuffer.h"
+#include "error/en.h"
+#include "uri.h"
#include <cmath> // abs, floor
#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
@@ -25,7 +28,7 @@
#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
#endif
-#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
+#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
#define RAPIDJSON_SCHEMA_USE_STDREGEX 1
#else
#define RAPIDJSON_SCHEMA_USE_STDREGEX 0
@@ -47,10 +50,6 @@
#define RAPIDJSON_SCHEMA_VERBOSE 0
#endif
-#if RAPIDJSON_SCHEMA_VERBOSE
-#include "stringbuffer.h"
-#endif
-
RAPIDJSON_DIAG_PUSH
#if defined(__GNUC__)
@@ -62,9 +61,7 @@ RAPIDJSON_DIAG_OFF(weak-vtables)
RAPIDJSON_DIAG_OFF(exit-time-destructors)
RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
RAPIDJSON_DIAG_OFF(variadic-macros)
-#endif
-
-#ifdef _MSC_VER
+#elif defined(_MSC_VER)
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
@@ -77,51 +74,164 @@ RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
-inline void PrintInvalidKeyword(const char* keyword) {
- printf("Fail keyword: %s\n", keyword);
+inline void PrintInvalidKeywordData(const char* keyword) {
+ printf(" Fail keyword: '%s'\n", keyword);
+}
+
+inline void PrintInvalidKeywordData(const wchar_t* keyword) {
+ wprintf(L" Fail keyword: '%ls'\n", keyword);
+}
+
+inline void PrintInvalidDocumentData(const char* document) {
+ printf(" Fail document: '%s'\n", document);
+}
+
+inline void PrintInvalidDocumentData(const wchar_t* document) {
+ wprintf(L" Fail document: '%ls'\n", document);
+}
+
+inline void PrintValidatorPointersData(const char* s, const char* d, unsigned depth) {
+ printf(" Sch: %*s'%s'\n Doc: %*s'%s'\n", depth * 4, " ", s, depth * 4, " ", d);
+}
+
+inline void PrintValidatorPointersData(const wchar_t* s, const wchar_t* d, unsigned depth) {
+ wprintf(L" Sch: %*ls'%ls'\n Doc: %*ls'%ls'\n", depth * 4, L" ", s, depth * 4, L" ", d);
+}
+
+inline void PrintSchemaIdsData(const char* base, const char* local, const char* resolved) {
+ printf(" Resolving id: Base: '%s', Local: '%s', Resolved: '%s'\n", base, local, resolved);
+}
+
+inline void PrintSchemaIdsData(const wchar_t* base, const wchar_t* local, const wchar_t* resolved) {
+ wprintf(L" Resolving id: Base: '%ls', Local: '%ls', Resolved: '%ls'\n", base, local, resolved);
+}
+
+inline void PrintMethodData(const char* method) {
+ printf("%s\n", method);
+}
+
+inline void PrintMethodData(const char* method, bool b) {
+ printf("%s, Data: '%s'\n", method, b ? "true" : "false");
+}
+
+inline void PrintMethodData(const char* method, int64_t i) {
+ printf("%s, Data: '%" PRId64 "'\n", method, i);
}
-inline void PrintInvalidKeyword(const wchar_t* keyword) {
- wprintf(L"Fail keyword: %ls\n", keyword);
+inline void PrintMethodData(const char* method, uint64_t u) {
+ printf("%s, Data: '%" PRIu64 "'\n", method, u);
}
-inline void PrintInvalidDocument(const char* document) {
- printf("Fail document: %s\n\n", document);
+inline void PrintMethodData(const char* method, double d) {
+ printf("%s, Data: '%lf'\n", method, d);
}
-inline void PrintInvalidDocument(const wchar_t* document) {
- wprintf(L"Fail document: %ls\n\n", document);
+inline void PrintMethodData(const char* method, const char* s) {
+ printf("%s, Data: '%s'\n", method, s);
}
-inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
- printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
+inline void PrintMethodData(const char* method, const wchar_t* s) {
+ wprintf(L"%hs, Data: '%ls'\n", method, s);
}
-inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
- wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
+inline void PrintMethodData(const char* method, const char* s1, const char* s2) {
+ printf("%s, Data: '%s', '%s'\n", method, s1, s2);
+}
+
+inline void PrintMethodData(const char* method, const wchar_t* s1, const wchar_t* s2) {
+ wprintf(L"%hs, Data: '%ls', '%ls'\n", method, s1, s2);
}
} // namespace internal
#endif // RAPIDJSON_SCHEMA_VERBOSE
-///////////////////////////////////////////////////////////////////////////////
-// RAPIDJSON_INVALID_KEYWORD_RETURN
-
+#ifndef RAPIDJSON_SCHEMA_PRINT
#if RAPIDJSON_SCHEMA_VERBOSE
-#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
+#define RAPIDJSON_SCHEMA_PRINT(name, ...) internal::Print##name##Data(__VA_ARGS__)
#else
-#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
+#define RAPIDJSON_SCHEMA_PRINT(name, ...)
+#endif
#endif
-#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_INVALID_KEYWORD_RETURN
+
+#define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\
RAPIDJSON_MULTILINEMACRO_BEGIN\
- context.invalidKeyword = keyword.GetString();\
- RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
+ context.invalidCode = code;\
+ context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\
+ RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, context.invalidKeyword);\
return false;\
RAPIDJSON_MULTILINEMACRO_END
///////////////////////////////////////////////////////////////////////////////
+// ValidateFlag
+
+/*! \def RAPIDJSON_VALIDATE_DEFAULT_FLAGS
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-defined kValidateDefaultFlags definition.
+
+ User can define this as any \c ValidateFlag combinations.
+*/
+#ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS
+#define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags
+#endif
+
+//! Combination of validate flags
+/*! \see
+ */
+enum ValidateFlag {
+ kValidateNoFlags = 0, //!< No flags are set.
+ kValidateContinueOnErrorFlag = 1, //!< Don't stop after first validation error.
+ kValidateReadFlag = 2, //!< Validation is for a read semantic.
+ kValidateWriteFlag = 4, //!< Validation is for a write semantic.
+ kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Specification
+enum SchemaDraft {
+ kDraftUnknown = -1,
+ kDraftNone = 0,
+ kDraft03 = 3,
+ kDraftMin = 4, //!< Current minimum supported draft
+ kDraft04 = 4,
+ kDraft05 = 5,
+ kDraftMax = 5, //!< Current maximum supported draft
+ kDraft06 = 6,
+ kDraft07 = 7,
+ kDraft2019_09 = 8,
+ kDraft2020_12 = 9
+};
+
+enum OpenApiVersion {
+ kVersionUnknown = -1,
+ kVersionNone = 0,
+ kVersionMin = 2, //!< Current minimum supported version
+ kVersion20 = 2,
+ kVersion30 = 3,
+ kVersionMax = 3, //!< Current maximum supported version
+ kVersion31 = 4,
+};
+
+struct Specification {
+ Specification(SchemaDraft d) : draft(d), oapi(kVersionNone) {}
+ Specification(OpenApiVersion o) : oapi(o) {
+ if (oapi == kVersion20) draft = kDraft04;
+ else if (oapi == kVersion30) draft = kDraft05;
+ else if (oapi == kVersion31) draft = kDraft2020_12;
+ else draft = kDraft04;
+ }
+ ~Specification() {}
+ bool IsSupported() const {
+ return ((draft >= kDraftMin && draft <= kDraftMax) && ((oapi == kVersionNone) || (oapi >= kVersionMin && oapi <= kVersionMax)));
+ }
+ SchemaDraft draft;
+ OpenApiVersion oapi;
+};
+
+///////////////////////////////////////////////////////////////////////////////
// Forward declarations
template <typename ValueType, typename Allocator>
@@ -139,6 +249,8 @@ class ISchemaValidator {
public:
virtual ~ISchemaValidator() {}
virtual bool IsValid() const = 0;
+ virtual void SetValidateFlags(unsigned flags) = 0;
+ virtual unsigned GetValidateFlags() const = 0;
};
///////////////////////////////////////////////////////////////////////////////
@@ -148,7 +260,7 @@ template <typename SchemaType>
class ISchemaStateFactory {
public:
virtual ~ISchemaStateFactory() {}
- virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
+ virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&, const bool inheritContinueOnErrors) = 0;
virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
virtual void* CreateHasher() = 0;
virtual uint64_t GetHashCode(void* hasher) = 0;
@@ -158,6 +270,65 @@ public:
};
///////////////////////////////////////////////////////////////////////////////
+// IValidationErrorHandler
+
+template <typename SchemaType>
+class IValidationErrorHandler {
+public:
+ typedef typename SchemaType::Ch Ch;
+ typedef typename SchemaType::SValue SValue;
+
+ virtual ~IValidationErrorHandler() {}
+
+ virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0;
+ virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0;
+ virtual void NotMultipleOf(double actual, const SValue& expected) = 0;
+ virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0;
+ virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
+ virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0;
+ virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0;
+ virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
+ virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0;
+
+ virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0;
+ virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0;
+ virtual void DoesNotMatch(const Ch* str, SizeType length) = 0;
+
+ virtual void DisallowedItem(SizeType index) = 0;
+ virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0;
+ virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0;
+ virtual void DuplicateItems(SizeType index1, SizeType index2) = 0;
+
+ virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0;
+ virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0;
+ virtual void StartMissingProperties() = 0;
+ virtual void AddMissingProperty(const SValue& name) = 0;
+ virtual bool EndMissingProperties() = 0;
+ virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0;
+ virtual void DisallowedProperty(const Ch* name, SizeType length) = 0;
+
+ virtual void StartDependencyErrors() = 0;
+ virtual void StartMissingDependentProperties() = 0;
+ virtual void AddMissingDependentProperty(const SValue& targetName) = 0;
+ virtual void EndMissingDependentProperties(const SValue& sourceName) = 0;
+ virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0;
+ virtual bool EndDependencyErrors() = 0;
+
+ virtual void DisallowedValue(const ValidateErrorCode code) = 0;
+ virtual void StartDisallowedType() = 0;
+ virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0;
+ virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
+ virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
+ virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
+ virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
+ virtual void MultipleOneOf(SizeType index1, SizeType index2) = 0;
+ virtual void Disallowed() = 0;
+ virtual void DisallowedWhenWriting() = 0;
+ virtual void DisallowedWhenReading() = 0;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
// Hasher
// For comparison of compound value
@@ -174,10 +345,10 @@ public:
bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
- bool Double(double d) {
- Number n;
+ bool Double(double d) {
+ Number n;
if (d < 0) n.u.i = static_cast<int64_t>(d);
- else n.u.u = static_cast<uint64_t>(d);
+ else n.u.u = static_cast<uint64_t>(d);
n.d = d;
return WriteNumber(n);
}
@@ -261,6 +432,7 @@ template <typename SchemaDocumentType>
struct SchemaValidationContext {
typedef Schema<SchemaDocumentType> SchemaType;
typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
+ typedef IValidationErrorHandler<SchemaType> ErrorHandlerType;
typedef typename SchemaType::ValueType ValueType;
typedef typename ValueType::Ch Ch;
@@ -270,11 +442,14 @@ struct SchemaValidationContext {
kPatternValidatorWithAdditionalProperty
};
- SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) :
+ SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s, unsigned fl = 0) :
factory(f),
+ error_handler(eh),
schema(s),
+ flags(fl),
valueSchema(),
invalidKeyword(),
+ invalidCode(),
hasher(),
arrayElementHashCodes(),
validators(),
@@ -295,13 +470,19 @@ struct SchemaValidationContext {
if (hasher)
factory.DestroryHasher(hasher);
if (validators) {
- for (SizeType i = 0; i < validatorCount; i++)
- factory.DestroySchemaValidator(validators[i]);
+ for (SizeType i = 0; i < validatorCount; i++) {
+ if (validators[i]) {
+ factory.DestroySchemaValidator(validators[i]);
+ }
+ }
factory.FreeState(validators);
}
if (patternPropertiesValidators) {
- for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)
- factory.DestroySchemaValidator(patternPropertiesValidators[i]);
+ for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) {
+ if (patternPropertiesValidators[i]) {
+ factory.DestroySchemaValidator(patternPropertiesValidators[i]);
+ }
+ }
factory.FreeState(patternPropertiesValidators);
}
if (patternPropertiesSchemas)
@@ -311,9 +492,12 @@ struct SchemaValidationContext {
}
SchemaValidatorFactoryType& factory;
+ ErrorHandlerType& error_handler;
const SchemaType* schema;
+ unsigned flags;
const SchemaType* valueSchema;
const Ch* invalidKeyword;
+ ValidateErrorCode invalidCode;
void* hasher; // Only validator access
void* arrayElementHashCodes; // Only validator access this
ISchemaValidator** validators;
@@ -345,15 +529,23 @@ public:
typedef SchemaValidationContext<SchemaDocumentType> Context;
typedef Schema<SchemaDocumentType> SchemaType;
typedef GenericValue<EncodingType, AllocatorType> SValue;
+ typedef IValidationErrorHandler<Schema> ErrorHandler;
+ typedef GenericUri<ValueType, AllocatorType> UriType;
friend class GenericSchemaDocument<ValueType, AllocatorType>;
- Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :
+ Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator, const UriType& id = UriType()) :
allocator_(allocator),
+ uri_(schemaDocument->GetURI(), *allocator),
+ id_(id, allocator),
+ spec_(schemaDocument->GetSpecification()),
+ pointer_(p, allocator),
+ typeless_(schemaDocument->GetTypeless()),
enum_(),
enumCount_(),
not_(),
type_((1 << kTotalSchemaType) - 1), // typeless
validatorCount_(),
+ notValidatorIndex_(),
properties_(),
additionalPropertiesSchema_(),
patternProperties_(),
@@ -377,15 +569,44 @@ public:
minLength_(0),
maxLength_(~SizeType(0)),
exclusiveMinimum_(false),
- exclusiveMaximum_(false)
+ exclusiveMaximum_(false),
+ defaultValueLength_(0),
+ readOnly_(false),
+ writeOnly_(false),
+ nullable_(false)
{
- typedef typename SchemaDocumentType::ValueType ValueType;
+ GenericStringBuffer<EncodingType> sb;
+ p.StringifyUriFragment(sb);
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Schema", sb.GetString(), id.GetString());
+
typedef typename ValueType::ConstValueIterator ConstValueIterator;
typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
+ // PR #1393
+ // Early add this Schema and its $ref(s) in schemaDocument's map to avoid infinite
+ // recursion (with recursive schemas), since schemaDocument->getSchema() is always
+ // checked before creating a new one. Don't cache typeless_, though.
+ if (this != typeless_) {
+ typedef typename SchemaDocumentType::SchemaEntry SchemaEntry;
+ SchemaEntry *entry = schemaDocument->schemaMap_.template Push<SchemaEntry>();
+ new (entry) SchemaEntry(pointer_, this, true, allocator_);
+ schemaDocument->AddSchemaRefs(this);
+ }
+
if (!value.IsObject())
return;
+ // If we have an id property, resolve it with the in-scope id
+ // Not supported for open api 2.0 or 3.0
+ if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
+ if (const ValueType* v = GetMember(value, GetIdString())) {
+ if (v->IsString()) {
+ UriType local(*v, allocator);
+ id_ = local.Resolve(id_, allocator);
+ RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), v->GetString(), id_.GetString());
+ }
+ }
+
if (const ValueType* v = GetMember(value, GetTypeString())) {
type_ = 0;
if (v->IsString())
@@ -395,29 +616,33 @@ public:
AddType(*itr);
}
- if (const ValueType* v = GetMember(value, GetEnumString()))
+ if (const ValueType* v = GetMember(value, GetEnumString())) {
if (v->IsArray() && v->Size() > 0) {
enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
- typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
- char buffer[256 + 24];
- MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
+ typedef Hasher<EncodingType, MemoryPoolAllocator<AllocatorType> > EnumHasherType;
+ char buffer[256u + 24];
+ MemoryPoolAllocator<AllocatorType> hasherAllocator(buffer, sizeof(buffer));
EnumHasherType h(&hasherAllocator, 256);
itr->Accept(h);
enum_[enumCount_++] = h.GetHashCode();
}
}
+ }
- if (schemaDocument) {
+ if (schemaDocument)
AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
+
+ // AnyOf, OneOf, Not not supported for open api 2.0
+ if (schemaDocument && spec_.oapi != kVersion20) {
AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
- }
- if (const ValueType* v = GetMember(value, GetNotString())) {
- schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
- notValidatorIndex_ = validatorCount_;
- validatorCount_++;
+ if (const ValueType* v = GetMember(value, GetNotString())) {
+ schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document, id_);
+ notValidatorIndex_ = validatorCount_;
+ validatorCount_++;
+ }
}
// Object
@@ -432,12 +657,14 @@ public:
if (properties && properties->IsObject())
for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
AddUniqueElement(allProperties, itr->name);
-
+
if (required && required->IsArray())
for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
if (itr->IsString())
AddUniqueElement(allProperties, *itr);
+ // Dependencies not supported for open api 2.0 and 3.0
+ if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
if (dependencies && dependencies->IsObject())
for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
AddUniqueElement(allProperties, itr->name);
@@ -453,7 +680,7 @@ public:
for (SizeType i = 0; i < propertyCount_; i++) {
new (&properties_[i]) Property();
properties_[i].name = allProperties[i];
- properties_[i].schema = GetTypeless();
+ properties_[i].schema = typeless_;
}
}
}
@@ -463,10 +690,12 @@ public:
for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
SizeType index;
if (FindPropertyIndex(itr->name, &index))
- schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
+ schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document, id_);
}
}
+ // PatternProperties not supported for open api 2.0 and 3.0
+ if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
@@ -474,8 +703,9 @@ public:
for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
new (&patternProperties_[patternPropertyCount_]) PatternProperty();
- patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
- schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
+ PointerType r = q.Append(itr->name, allocator_);
+ patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name, schemaDocument, r);
+ schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, r, itr->value, document, id_);
patternPropertyCount_++;
}
}
@@ -490,6 +720,8 @@ public:
}
}
+ // Dependencies not supported for open api 2.0 and 3.0
+ if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
if (dependencies && dependencies->IsObject()) {
PointerType q = p.Append(GetDependenciesString(), allocator_);
hasDependencies_ = true;
@@ -507,7 +739,7 @@ public:
}
else if (itr->value.IsObject()) {
hasSchemaDependencies_ = true;
- schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
+ schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document, id_);
properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
validatorCount_++;
}
@@ -519,7 +751,7 @@ public:
if (v->IsBool())
additionalProperties_ = v->GetBool();
else if (v->IsObject())
- schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
+ schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document, id_);
}
AssignIfExist(minProperties_, value, GetMinPropertiesString());
@@ -529,23 +761,25 @@ public:
if (const ValueType* v = GetMember(value, GetItemsString())) {
PointerType q = p.Append(GetItemsString(), allocator_);
if (v->IsObject()) // List validation
- schemaDocument->CreateSchema(&itemsList_, q, *v, document);
+ schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_);
else if (v->IsArray()) { // Tuple validation
itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
SizeType index = 0;
for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
- schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
+ schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document, id_);
}
}
AssignIfExist(minItems_, value, GetMinItemsString());
AssignIfExist(maxItems_, value, GetMaxItemsString());
+ // AdditionalItems not supported for openapi 2.0 and 3.0
+ if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
if (v->IsBool())
additionalItems_ = v->GetBool();
else if (v->IsObject())
- schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
+ schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document, id_);
}
AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
@@ -555,7 +789,7 @@ public:
AssignIfExist(maxLength_, value, GetMaxLengthString());
if (const ValueType* v = GetMember(value, GetPatternString()))
- pattern_ = CreatePattern(*v);
+ pattern_ = CreatePattern(*v, schemaDocument, p.Append(GetPatternString(), allocator_));
// Number
if (const ValueType* v = GetMember(value, GetMinimumString()))
@@ -572,12 +806,33 @@ public:
if (const ValueType* v = GetMember(value, GetMultipleOfString()))
if (v->IsNumber() && v->GetDouble() > 0.0)
multipleOf_.CopyFrom(*v, *allocator_);
+
+ // Default
+ if (const ValueType* v = GetMember(value, GetDefaultValueString()))
+ if (v->IsString())
+ defaultValueLength_ = v->GetStringLength();
+
+ // ReadOnly - open api only (until draft 7 supported)
+ // WriteOnly - open api 3 only (until draft 7 supported)
+ // Both can't be true
+ if (spec_.oapi != kVersionNone)
+ AssignIfExist(readOnly_, value, GetReadOnlyString());
+ if (spec_.oapi >= kVersion30)
+ AssignIfExist(writeOnly_, value, GetWriteOnlyString());
+ if (readOnly_ && writeOnly_)
+ schemaDocument->SchemaError(kSchemaErrorReadOnlyAndWriteOnly, p);
+
+ // Nullable - open api 3 only
+ // If true add 'null' as allowable type
+ if (spec_.oapi >= kVersion30) {
+ AssignIfExist(nullable_, value, GetNullableString());
+ if (nullable_)
+ AddType(GetNullString());
+ }
}
~Schema() {
- if (allocator_) {
- allocator_->Free(enum_);
- }
+ AllocatorType::Free(enum_);
if (properties_) {
for (SizeType i = 0; i < propertyCount_; i++)
properties_[i].~Property();
@@ -592,12 +847,29 @@ public:
#if RAPIDJSON_SCHEMA_HAS_REGEX
if (pattern_) {
pattern_->~RegexType();
- allocator_->Free(pattern_);
+ AllocatorType::Free(pattern_);
}
#endif
}
+ const SValue& GetURI() const {
+ return uri_;
+ }
+
+ const UriType& GetId() const {
+ return id_;
+ }
+
+ const Specification& GetSpecification() const {
+ return spec_;
+ }
+
+ const PointerType& GetPointer() const {
+ return pointer_;
+ }
+
bool BeginValue(Context& context) const {
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::BeginValue");
if (context.inArray) {
if (uniqueItems_)
context.valueUniqueness = true;
@@ -610,12 +882,18 @@ public:
else if (additionalItemsSchema_)
context.valueSchema = additionalItemsSchema_;
else if (additionalItems_)
- context.valueSchema = GetTypeless();
- else
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
+ context.valueSchema = typeless_;
+ else {
+ context.error_handler.DisallowedItem(context.arrayElementIndex);
+ // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
+ context.valueSchema = typeless_;
+ // Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set
+ context.arrayElementIndex++;
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalItems);
+ }
}
else
- context.valueSchema = GetTypeless();
+ context.valueSchema = typeless_;
context.arrayElementIndex++;
}
@@ -623,6 +901,8 @@ public:
}
RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndValue");
+ // Only check pattern properties if we have validators
if (context.patternPropertiesValidatorCount > 0) {
bool otherValid = false;
SizeType count = context.patternPropertiesValidatorCount;
@@ -637,133 +917,178 @@ public:
}
if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
- if (!patternValid)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+ if (!patternValid) {
+ context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
+ }
}
else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
- if (!patternValid || !otherValid)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+ if (!patternValid || !otherValid) {
+ context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
+ }
+ }
+ else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty)
+ context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
}
- else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
}
- if (enum_) {
+ // For enums only check if we have a hasher
+ if (enum_ && context.hasher) {
const uint64_t h = context.factory.GetHashCode(context.hasher);
for (SizeType i = 0; i < enumCount_; i++)
if (enum_[i] == h)
goto foundEnum;
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
+ context.error_handler.DisallowedValue(kValidateErrorEnum);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorEnum);
foundEnum:;
}
- if (allOf_.schemas)
- for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
- if (!context.validators[i]->IsValid())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
-
- if (anyOf_.schemas) {
- for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
- if (context.validators[i]->IsValid())
- goto foundAny;
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
- foundAny:;
- }
-
- if (oneOf_.schemas) {
- bool oneValid = false;
- for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
- if (context.validators[i]->IsValid()) {
- if (oneValid)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
- else
- oneValid = true;
+ // Only check allOf etc if we have validators
+ if (context.validatorCount > 0) {
+ if (allOf_.schemas)
+ for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
+ if (!context.validators[i]->IsValid()) {
+ context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf);
+ }
+
+ if (anyOf_.schemas) {
+ for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
+ if (context.validators[i]->IsValid())
+ goto foundAny;
+ context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf);
+ foundAny:;
+ }
+
+ if (oneOf_.schemas) {
+ bool oneValid = false;
+ SizeType firstMatch = 0;
+ for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
+ if (context.validators[i]->IsValid()) {
+ if (oneValid) {
+ context.error_handler.MultipleOneOf(firstMatch, i - oneOf_.begin);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch);
+ } else {
+ oneValid = true;
+ firstMatch = i - oneOf_.begin;
+ }
+ }
+ if (!oneValid) {
+ context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf);
}
- if (!oneValid)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
- }
+ }
- if (not_ && context.validators[notValidatorIndex_]->IsValid())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
+ if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
+ context.error_handler.Disallowed();
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot);
+ }
+ }
return true;
}
- bool Null(Context& context) const {
- if (!(type_ & (1 << kNullSchemaType)))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+ bool Null(Context& context) const {
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Null");
+ if (!(type_ & (1 << kNullSchemaType))) {
+ DisallowedType(context, GetNullString());
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
+ }
return CreateParallelValidator(context);
}
-
- bool Bool(Context& context, bool) const {
- if (!(type_ & (1 << kBooleanSchemaType)))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ bool Bool(Context& context, bool b) const {
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Bool", b);
+ if (!CheckBool(context, b))
+ return false;
return CreateParallelValidator(context);
}
bool Int(Context& context, int i) const {
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int", (int64_t)i);
if (!CheckInt(context, i))
return false;
return CreateParallelValidator(context);
}
bool Uint(Context& context, unsigned u) const {
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint", (uint64_t)u);
if (!CheckUint(context, u))
return false;
return CreateParallelValidator(context);
}
bool Int64(Context& context, int64_t i) const {
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int64", i);
if (!CheckInt(context, i))
return false;
return CreateParallelValidator(context);
}
bool Uint64(Context& context, uint64_t u) const {
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint64", u);
if (!CheckUint(context, u))
return false;
return CreateParallelValidator(context);
}
bool Double(Context& context, double d) const {
- if (!(type_ & (1 << kNumberSchemaType)))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Double", d);
+ if (!(type_ & (1 << kNumberSchemaType))) {
+ DisallowedType(context, GetNumberString());
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
+ }
if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
return false;
if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
return false;
-
+
if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
return false;
-
+
return CreateParallelValidator(context);
}
-
+
bool String(Context& context, const Ch* str, SizeType length, bool) const {
- if (!(type_ & (1 << kStringSchemaType)))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::String", str);
+ if (!(type_ & (1 << kStringSchemaType))) {
+ DisallowedType(context, GetStringString());
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
+ }
if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
SizeType count;
if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
- if (count < minLength_)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
- if (count > maxLength_)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
+ if (count < minLength_) {
+ context.error_handler.TooShort(str, length, minLength_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinLength);
+ }
+ if (count > maxLength_) {
+ context.error_handler.TooLong(str, length, maxLength_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxLength);
+ }
}
}
- if (pattern_ && !IsPatternMatch(pattern_, str, length))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
+ if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
+ context.error_handler.DoesNotMatch(str, length);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPattern);
+ }
return CreateParallelValidator(context);
}
- bool StartObject(Context& context) const {
- if (!(type_ & (1 << kObjectSchemaType)))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+ bool StartObject(Context& context) const {
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartObject");
+ if (!(type_ & (1 << kObjectSchemaType))) {
+ DisallowedType(context, GetObjectString());
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
+ }
if (hasDependencies_ || hasRequired_) {
context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
@@ -779,20 +1104,24 @@ public:
return CreateParallelValidator(context);
}
-
+
bool Key(Context& context, const Ch* str, SizeType len, bool) const {
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Key", str);
+
if (patternProperties_) {
context.patternPropertiesSchemaCount = 0;
for (SizeType i = 0; i < patternPropertyCount_; i++)
- if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len))
+ if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
+ context.valueSchema = typeless_;
+ }
}
- SizeType index;
+ SizeType index = 0;
if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
if (context.patternPropertiesSchemaCount > 0) {
context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
- context.valueSchema = GetTypeless();
+ context.valueSchema = typeless_;
context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
}
else
@@ -805,9 +1134,9 @@ public:
}
if (additionalPropertiesSchema_) {
- if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
+ if (context.patternPropertiesSchemaCount > 0) {
context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
- context.valueSchema = GetTypeless();
+ context.valueSchema = typeless_;
context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
}
else
@@ -815,73 +1144,144 @@ public:
return true;
}
else if (additionalProperties_) {
- context.valueSchema = GetTypeless();
+ context.valueSchema = typeless_;
return true;
}
- if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
+ if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties
+ // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
+ context.valueSchema = typeless_;
+ context.error_handler.DisallowedProperty(str, len);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalProperties);
+ }
return true;
}
bool EndObject(Context& context, SizeType memberCount) const {
- if (hasRequired_)
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndObject");
+ if (hasRequired_) {
+ context.error_handler.StartMissingProperties();
for (SizeType index = 0; index < propertyCount_; index++)
- if (properties_[index].required)
- if (!context.propertyExist[index])
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
+ if (properties_[index].required && !context.propertyExist[index])
+ if (properties_[index].schema->defaultValueLength_ == 0 )
+ context.error_handler.AddMissingProperty(properties_[index].name);
+ if (context.error_handler.EndMissingProperties())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorRequired);
+ }
- if (memberCount < minProperties_)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
+ if (memberCount < minProperties_) {
+ context.error_handler.TooFewProperties(memberCount, minProperties_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinProperties);
+ }
- if (memberCount > maxProperties_)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
+ if (memberCount > maxProperties_) {
+ context.error_handler.TooManyProperties(memberCount, maxProperties_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxProperties);
+ }
if (hasDependencies_) {
- for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
+ context.error_handler.StartDependencyErrors();
+ for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
+ const Property& source = properties_[sourceIndex];
if (context.propertyExist[sourceIndex]) {
- if (properties_[sourceIndex].dependencies) {
+ if (source.dependencies) {
+ context.error_handler.StartMissingDependentProperties();
for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
- if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex])
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
+ if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])
+ context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name);
+ context.error_handler.EndMissingDependentProperties(source.name);
+ }
+ else if (source.dependenciesSchema) {
+ ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex];
+ if (!dependenciesValidator->IsValid())
+ context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator);
}
- else if (properties_[sourceIndex].dependenciesSchema)
- if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
}
+ }
+ if (context.error_handler.EndDependencyErrors())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies);
}
return true;
}
- bool StartArray(Context& context) const {
- if (!(type_ & (1 << kArraySchemaType)))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
-
+ bool StartArray(Context& context) const {
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartArray");
context.arrayElementIndex = 0;
- context.inArray = true;
+ context.inArray = true; // Ensure we note that we are in an array
+
+ if (!(type_ & (1 << kArraySchemaType))) {
+ DisallowedType(context, GetArrayString());
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
+ }
return CreateParallelValidator(context);
}
- bool EndArray(Context& context, SizeType elementCount) const {
+ bool EndArray(Context& context, SizeType elementCount) const {
+ RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndArray");
context.inArray = false;
-
- if (elementCount < minItems_)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
-
- if (elementCount > maxItems_)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
+
+ if (elementCount < minItems_) {
+ context.error_handler.TooFewItems(elementCount, minItems_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems);
+ }
+
+ if (elementCount > maxItems_) {
+ context.error_handler.TooManyItems(elementCount, maxItems_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems);
+ }
return true;
}
+ static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode) {
+ switch (validateErrorCode) {
+ case kValidateErrorMultipleOf: return GetMultipleOfString();
+ case kValidateErrorMaximum: return GetMaximumString();
+ case kValidateErrorExclusiveMaximum: return GetMaximumString(); // Same
+ case kValidateErrorMinimum: return GetMinimumString();
+ case kValidateErrorExclusiveMinimum: return GetMinimumString(); // Same
+
+ case kValidateErrorMaxLength: return GetMaxLengthString();
+ case kValidateErrorMinLength: return GetMinLengthString();
+ case kValidateErrorPattern: return GetPatternString();
+
+ case kValidateErrorMaxItems: return GetMaxItemsString();
+ case kValidateErrorMinItems: return GetMinItemsString();
+ case kValidateErrorUniqueItems: return GetUniqueItemsString();
+ case kValidateErrorAdditionalItems: return GetAdditionalItemsString();
+
+ case kValidateErrorMaxProperties: return GetMaxPropertiesString();
+ case kValidateErrorMinProperties: return GetMinPropertiesString();
+ case kValidateErrorRequired: return GetRequiredString();
+ case kValidateErrorAdditionalProperties: return GetAdditionalPropertiesString();
+ case kValidateErrorPatternProperties: return GetPatternPropertiesString();
+ case kValidateErrorDependencies: return GetDependenciesString();
+
+ case kValidateErrorEnum: return GetEnumString();
+ case kValidateErrorType: return GetTypeString();
+
+ case kValidateErrorOneOf: return GetOneOfString();
+ case kValidateErrorOneOfMatch: return GetOneOfString(); // Same
+ case kValidateErrorAllOf: return GetAllOfString();
+ case kValidateErrorAnyOf: return GetAnyOfString();
+ case kValidateErrorNot: return GetNotString();
+
+ case kValidateErrorReadOnly: return GetReadOnlyString();
+ case kValidateErrorWriteOnly: return GetWriteOnlyString();
+
+ default: return GetNullString();
+ }
+ }
+
+
// Generate functions for string literal according to Ch
#define RAPIDJSON_STRING_(name, ...) \
static const ValueType& Get##name##String() {\
static const Ch s[] = { __VA_ARGS__, '\0' };\
- static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\
+ static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
return v;\
}
@@ -918,6 +1318,15 @@ public:
RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
+ RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')
+ RAPIDJSON_STRING_(Schema, '$', 's', 'c', 'h', 'e', 'm', 'a')
+ RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f')
+ RAPIDJSON_STRING_(Id, 'i', 'd')
+ RAPIDJSON_STRING_(Swagger, 's', 'w', 'a', 'g', 'g', 'e', 'r')
+ RAPIDJSON_STRING_(OpenApi, 'o', 'p', 'e', 'n', 'a', 'p', 'i')
+ RAPIDJSON_STRING_(ReadOnly, 'r', 'e', 'a', 'd', 'O', 'n', 'l', 'y')
+ RAPIDJSON_STRING_(WriteOnly, 'w', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y')
+ RAPIDJSON_STRING_(Nullable, 'n', 'u', 'l', 'l', 'a', 'b', 'l', 'e')
#undef RAPIDJSON_STRING_
@@ -934,7 +1343,7 @@ private:
};
#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
- typedef internal::GenericRegex<EncodingType> RegexType;
+ typedef internal::GenericRegex<EncodingType, AllocatorType> RegexType;
#elif RAPIDJSON_SCHEMA_USE_STDREGEX
typedef std::basic_regex<Ch> RegexType;
#else
@@ -949,11 +1358,6 @@ private:
SizeType count;
};
- static const SchemaType* GetTypeless() {
- static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0);
- return &typeless;
- }
-
template <typename V1, typename V2>
void AddUniqueElement(V1& a, const V2& v) {
for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
@@ -988,7 +1392,7 @@ private:
out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
memset(out.schemas, 0, sizeof(Schema*)* out.count);
for (SizeType i = 0; i < out.count; i++)
- schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
+ schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_);
out.begin = validatorCount_;
validatorCount_ += out.count;
}
@@ -997,10 +1401,11 @@ private:
#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
template <typename ValueType>
- RegexType* CreatePattern(const ValueType& value) {
+ RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p) {
if (value.IsString()) {
- RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString());
+ RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_);
if (!r->IsValid()) {
+ sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength());
r->~RegexType();
AllocatorType::Free(r);
r = 0;
@@ -1011,17 +1416,22 @@ private:
}
static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
- return pattern->Search(str);
+ GenericRegexSearch<RegexType> rs(*pattern);
+ return rs.Search(str);
}
#elif RAPIDJSON_SCHEMA_USE_STDREGEX
template <typename ValueType>
- RegexType* CreatePattern(const ValueType& value) {
- if (value.IsString())
+ RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p) {
+ if (value.IsString()) {
+ RegexType *r = static_cast<RegexType*>(allocator_->Malloc(sizeof(RegexType)));
try {
- return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
+ return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
}
- catch (const std::regex_error&) {
+ catch (const std::regex_error& e) {
+ sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength());
+ AllocatorType::Free(r);
}
+ }
return 0;
}
@@ -1031,7 +1441,9 @@ private:
}
#else
template <typename ValueType>
- RegexType* CreatePattern(const ValueType&) { return 0; }
+ RegexType* CreatePattern(const ValueType&) {
+ return 0;
+ }
static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
#endif // RAPIDJSON_SCHEMA_USE_STDREGEX
@@ -1046,6 +1458,9 @@ private:
else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
}
+ // Creates parallel validators for allOf, anyOf, oneOf, not and schema dependencies, if required.
+ // Also creates a hasher for enums and array uniqueness, if required.
+ // Also a useful place to add type-independent error checks.
bool CreateParallelValidator(Context& context) const {
if (enum_ || context.arrayUniqueness)
context.hasher = context.factory.CreateHasher();
@@ -1053,33 +1468,45 @@ private:
if (validatorCount_) {
RAPIDJSON_ASSERT(context.validators == 0);
context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
+ std::memset(context.validators, 0, sizeof(ISchemaValidator*) * validatorCount_);
context.validatorCount = validatorCount_;
+ // Always return after first failure for these sub-validators
if (allOf_.schemas)
- CreateSchemaValidators(context, allOf_);
+ CreateSchemaValidators(context, allOf_, false);
if (anyOf_.schemas)
- CreateSchemaValidators(context, anyOf_);
-
+ CreateSchemaValidators(context, anyOf_, false);
+
if (oneOf_.schemas)
- CreateSchemaValidators(context, oneOf_);
-
+ CreateSchemaValidators(context, oneOf_, false);
+
if (not_)
- context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
-
+ context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false);
+
if (hasSchemaDependencies_) {
for (SizeType i = 0; i < propertyCount_; i++)
if (properties_[i].dependenciesSchema)
- context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
+ context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema, false);
}
}
+ // Add any other type-independent checks here
+ if (readOnly_ && (context.flags & kValidateWriteFlag)) {
+ context.error_handler.DisallowedWhenWriting();
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorReadOnly);
+ }
+ if (writeOnly_ && (context.flags & kValidateReadFlag)) {
+ context.error_handler.DisallowedWhenReading();
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorWriteOnly);
+ }
+
return true;
}
- void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {
+ void CreateSchemaValidators(Context& context, const SchemaArray& schemas, const bool inheritContinueOnErrors) const {
for (SizeType i = 0; i < schemas.count; i++)
- context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
+ context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
}
// O(n)
@@ -1087,7 +1514,7 @@ private:
SizeType len = name.GetStringLength();
const Ch* str = name.GetString();
for (SizeType index = 0; index < propertyCount_; index++)
- if (properties_[index].name.GetStringLength() == len &&
+ if (properties_[index].name.GetStringLength() == len &&
(std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
{
*outIndex = index;
@@ -1096,17 +1523,30 @@ private:
return false;
}
+ bool CheckBool(Context& context, bool) const {
+ if (!(type_ & (1 << kBooleanSchemaType))) {
+ DisallowedType(context, GetBooleanString());
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
+ }
+ return true;
+ }
+
bool CheckInt(Context& context, int64_t i) const {
- if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+ if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
+ DisallowedType(context, GetIntegerString());
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
+ }
if (!minimum_.IsNull()) {
if (minimum_.IsInt64()) {
- if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+ if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
+ context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
+ }
}
else if (minimum_.IsUint64()) {
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
+ context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64()
}
else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
return false;
@@ -1114,19 +1554,23 @@ private:
if (!maximum_.IsNull()) {
if (maximum_.IsInt64()) {
- if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+ if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
+ context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
+ }
}
- else if (maximum_.IsUint64())
- /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64()
+ else if (maximum_.IsUint64()) { }
+ /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64()
else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
return false;
}
if (!multipleOf_.IsNull()) {
if (multipleOf_.IsUint64()) {
- if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+ if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
+ context.error_handler.NotMultipleOf(i, multipleOf_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
+ }
}
else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
return false;
@@ -1136,13 +1580,17 @@ private:
}
bool CheckUint(Context& context, uint64_t i) const {
- if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+ if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
+ DisallowedType(context, GetIntegerString());
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
+ }
if (!minimum_.IsNull()) {
if (minimum_.IsUint64()) {
- if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+ if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
+ context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
+ }
}
else if (minimum_.IsInt64())
/* do nothing */; // i >= 0 > minimum.Getint64()
@@ -1152,19 +1600,25 @@ private:
if (!maximum_.IsNull()) {
if (maximum_.IsUint64()) {
- if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+ if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
+ context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
+ }
+ }
+ else if (maximum_.IsInt64()) {
+ context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); // i >= 0 > maximum_
}
- else if (maximum_.IsInt64())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
return false;
}
if (!multipleOf_.IsNull()) {
if (multipleOf_.IsUint64()) {
- if (i % multipleOf_.GetUint64() != 0)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+ if (i % multipleOf_.GetUint64() != 0) {
+ context.error_handler.NotMultipleOf(i, multipleOf_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
+ }
}
else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
return false;
@@ -1174,14 +1628,18 @@ private:
}
bool CheckDoubleMinimum(Context& context, double d) const {
- if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+ if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
+ context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
+ }
return true;
}
bool CheckDoubleMaximum(Context& context, double d) const {
- if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+ if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
+ context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
+ }
return true;
}
@@ -1189,11 +1647,29 @@ private:
double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
double q = std::floor(a / b);
double r = a - q * b;
- if (r > 0.0)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+ if (r > 0.0) {
+ context.error_handler.NotMultipleOf(d, multipleOf_);
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
+ }
return true;
}
+ void DisallowedType(Context& context, const ValueType& actualType) const {
+ ErrorHandler& eh = context.error_handler;
+ eh.StartDisallowedType();
+
+ if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());
+ if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());
+ if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());
+ if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());
+ if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());
+
+ if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
+ else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
+
+ eh.EndDisallowedType(actualType);
+ }
+
struct Property {
Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
~Property() { AllocatorType::Free(dependencies); }
@@ -1207,7 +1683,7 @@ private:
struct PatternProperty {
PatternProperty() : schema(), pattern() {}
- ~PatternProperty() {
+ ~PatternProperty() {
if (pattern) {
pattern->~RegexType();
AllocatorType::Free(pattern);
@@ -1218,6 +1694,11 @@ private:
};
AllocatorType* allocator_;
+ SValue uri_;
+ UriType id_;
+ Specification spec_;
+ PointerType pointer_;
+ const SchemaType* typeless_;
uint64_t* enum_;
SizeType enumCount_;
SchemaArray allOf_;
@@ -1258,6 +1739,12 @@ private:
SValue multipleOf_;
bool exclusiveMinimum_;
bool exclusiveMaximum_;
+
+ SizeType defaultValueLength_;
+
+ bool readOnly_;
+ bool writeOnly_;
+ bool nullable_;
};
template<typename Stack, typename Ch>
@@ -1267,7 +1754,7 @@ struct TokenHelper {
char buffer[21];
size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
for (size_t i = 0; i < length; i++)
- *documentStack.template Push<Ch>() = buffer[i];
+ *documentStack.template Push<Ch>() = static_cast<Ch>(buffer[i]);
}
};
@@ -1299,9 +1786,18 @@ template <typename SchemaDocumentType>
class IGenericRemoteSchemaDocumentProvider {
public:
typedef typename SchemaDocumentType::Ch Ch;
+ typedef typename SchemaDocumentType::ValueType ValueType;
+ typedef typename SchemaDocumentType::AllocatorType AllocatorType;
virtual ~IGenericRemoteSchemaDocumentProvider() {}
virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
+ virtual const SchemaDocumentType* GetRemoteDocument(const GenericUri<ValueType, AllocatorType> uri, Specification& spec) {
+ // Default implementation just calls through for compatibility
+ // Following line suppresses unused parameter warning
+ (void)spec;
+ // printf("GetRemoteDocument: %d %d\n", spec.draft, spec.oapi);
+ return GetRemoteDocument(uri.GetBaseString(), uri.GetBaseStringLength());
+ }
};
///////////////////////////////////////////////////////////////////////////////
@@ -1326,6 +1822,9 @@ public:
typedef typename EncodingType::Ch Ch;
typedef internal::Schema<GenericSchemaDocument> SchemaType;
typedef GenericPointer<ValueType, Allocator> PointerType;
+ typedef GenericValue<EncodingType, AllocatorType> GValue;
+ typedef GenericUri<ValueType, Allocator> UriType;
+ typedef GenericStringRef<Ch> StringRefType;
friend class internal::Schema<GenericSchemaDocument>;
template <typename, typename, typename>
friend class GenericSchemaValidator;
@@ -1335,37 +1834,57 @@ public:
Compile a JSON document into schema document.
\param document A JSON document as source.
+ \param uri The base URI of this schema document for purposes of violation reporting.
+ \param uriLength Length of \c name, in code points.
\param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
\param allocator An optional allocator instance for allocating memory. Can be null.
+ \param pointer An optional JSON pointer to the start of the schema document
+ \param spec Optional schema draft or OpenAPI version. Used if no specification in document. Defaults to draft-04.
*/
- explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
+ explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0,
+ IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0,
+ const PointerType& pointer = PointerType(), // PR #1393
+ const Specification& spec = Specification(kDraft04)) :
remoteProvider_(remoteProvider),
allocator_(allocator),
ownAllocator_(),
root_(),
+ typeless_(),
schemaMap_(allocator, kInitialSchemaMapSize),
- schemaRef_(allocator, kInitialSchemaRefSize)
+ schemaRef_(allocator, kInitialSchemaRefSize),
+ spec_(spec),
+ error_(kObjectType),
+ currentError_()
{
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::GenericSchemaDocument");
if (!allocator_)
- ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
- // Generate root schema, it will call CreateSchema() to create sub-schemas,
- // And call AddRefSchema() if there are $ref.
- CreateSchemaRecursive(&root_, PointerType(), document, document);
+ Ch noUri[1] = {0};
+ uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
+ docId_ = UriType(uri_, allocator_);
- // Resolve $ref
- while (!schemaRef_.Empty()) {
- SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
- if (const SchemaType* s = GetSchema(refEntry->target)) {
- if (refEntry->schema)
- *refEntry->schema = s;
-
- // Create entry in map if not exist
- if (!GetSchema(refEntry->source)) {
- new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
- }
- }
- refEntry->~SchemaRefEntry();
+ typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
+ new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_, docId_);
+
+ // Establish the schema draft or open api version.
+ // We only ever look for '$schema' or 'swagger' or 'openapi' at the root of the document.
+ SetSchemaSpecification(document);
+
+ // Generate root schema, it will call CreateSchema() to create sub-schemas,
+ // And call HandleRefSchema() if there are $ref.
+ // PR #1393 use input pointer if supplied
+ root_ = typeless_;
+ if (pointer.GetTokenCount() == 0) {
+ CreateSchemaRecursive(&root_, pointer, document, document, docId_);
+ }
+ else if (const ValueType* v = pointer.Get(document)) {
+ CreateSchema(&root_, pointer, *v, document, docId_);
+ }
+ else {
+ GenericStringBuffer<EncodingType> sb;
+ pointer.StringifyUriFragment(sb);
+ SchemaErrorValue(kSchemaErrorStartUnknown, PointerType(), sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)));
}
RAPIDJSON_ASSERT(root_ != 0);
@@ -1380,12 +1899,19 @@ public:
allocator_(rhs.allocator_),
ownAllocator_(rhs.ownAllocator_),
root_(rhs.root_),
+ typeless_(rhs.typeless_),
schemaMap_(std::move(rhs.schemaMap_)),
- schemaRef_(std::move(rhs.schemaRef_))
+ schemaRef_(std::move(rhs.schemaRef_)),
+ uri_(std::move(rhs.uri_)),
+ docId_(std::move(rhs.docId_)),
+ spec_(rhs.spec_),
+ error_(std::move(rhs.error_)),
+ currentError_(std::move(rhs.currentError_))
{
rhs.remoteProvider_ = 0;
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
+ rhs.typeless_ = 0;
}
#endif
@@ -1394,24 +1920,92 @@ public:
while (!schemaMap_.Empty())
schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
+ if (typeless_) {
+ typeless_->~SchemaType();
+ Allocator::Free(typeless_);
+ }
+
+ // these may contain some allocator data so clear before deleting ownAllocator_
+ uri_.SetNull();
+ error_.SetNull();
+ currentError_.SetNull();
+
RAPIDJSON_DELETE(ownAllocator_);
}
+ const GValue& GetURI() const { return uri_; }
+
+ const Specification& GetSpecification() const { return spec_; }
+ bool IsSupportedSpecification() const { return spec_.IsSupported(); }
+
+ //! Static method to get the specification of any schema document
+ // Returns kDraftNone if document is silent
+ static const Specification GetSpecification(const ValueType& document) {
+ SchemaDraft draft = GetSchemaDraft(document);
+ if (draft != kDraftNone)
+ return Specification(draft);
+ else {
+ OpenApiVersion oapi = GetOpenApiVersion(document);
+ if (oapi != kVersionNone)
+ return Specification(oapi);
+ }
+ return Specification(kDraftNone);
+ }
+
//! Get the root schema.
const SchemaType& GetRoot() const { return *root_; }
-private:
+ //! Gets the error object.
+ GValue& GetError() { return error_; }
+ const GValue& GetError() const { return error_; }
+
+ static const StringRefType& GetSchemaErrorKeyword(SchemaErrorCode schemaErrorCode) {
+ switch (schemaErrorCode) {
+ case kSchemaErrorStartUnknown: return GetStartUnknownString();
+ case kSchemaErrorRefPlainName: return GetRefPlainNameString();
+ case kSchemaErrorRefInvalid: return GetRefInvalidString();
+ case kSchemaErrorRefPointerInvalid: return GetRefPointerInvalidString();
+ case kSchemaErrorRefUnknown: return GetRefUnknownString();
+ case kSchemaErrorRefCyclical: return GetRefCyclicalString();
+ case kSchemaErrorRefNoRemoteProvider: return GetRefNoRemoteProviderString();
+ case kSchemaErrorRefNoRemoteSchema: return GetRefNoRemoteSchemaString();
+ case kSchemaErrorRegexInvalid: return GetRegexInvalidString();
+ case kSchemaErrorSpecUnknown: return GetSpecUnknownString();
+ case kSchemaErrorSpecUnsupported: return GetSpecUnsupportedString();
+ case kSchemaErrorSpecIllegal: return GetSpecIllegalString();
+ case kSchemaErrorReadOnlyAndWriteOnly: return GetReadOnlyAndWriteOnlyString();
+ default: return GetNullString();
+ }
+ }
+
+ //! Default error method
+ void SchemaError(const SchemaErrorCode code, const PointerType& location) {
+ currentError_ = GValue(kObjectType);
+ AddCurrentError(code, location);
+ }
+
+ //! Method for error with single string value insert
+ void SchemaErrorValue(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length) {
+ currentError_ = GValue(kObjectType);
+ currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
+ AddCurrentError(code, location);
+ }
+
+ //! Method for error with invalid pointer
+ void SchemaErrorPointer(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length, const PointerType& pointer) {
+ currentError_ = GValue(kObjectType);
+ currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
+ currentError_.AddMember(GetOffsetString(), static_cast<SizeType>(pointer.GetParseErrorOffset() / sizeof(Ch)), *allocator_);
+ AddCurrentError(code, location);
+ }
+
+ private:
//! Prohibit copying
GenericSchemaDocument(const GenericSchemaDocument&);
//! Prohibit assignment
GenericSchemaDocument& operator=(const GenericSchemaDocument&);
- struct SchemaRefEntry {
- SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
- PointerType source;
- PointerType target;
- const SchemaType** schema;
- };
+ typedef const PointerType* SchemaRefPtr; // PR #1393
struct SchemaEntry {
SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
@@ -1426,78 +2020,361 @@ private:
bool owned;
};
- void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
- if (schema)
- *schema = SchemaType::GetTypeless();
+ void AddErrorInstanceLocation(GValue& result, const PointerType& location) {
+ GenericStringBuffer<EncodingType> sb;
+ location.StringifyUriFragment(sb);
+ GValue instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)), *allocator_);
+ result.AddMember(GetInstanceRefString(), instanceRef, *allocator_);
+ }
+
+ void AddError(GValue& keyword, GValue& error) {
+ typename GValue::MemberIterator member = error_.FindMember(keyword);
+ if (member == error_.MemberEnd())
+ error_.AddMember(keyword, error, *allocator_);
+ else {
+ if (member->value.IsObject()) {
+ GValue errors(kArrayType);
+ errors.PushBack(member->value, *allocator_);
+ member->value = errors;
+ }
+ member->value.PushBack(error, *allocator_);
+ }
+ }
+
+ void AddCurrentError(const SchemaErrorCode code, const PointerType& location) {
+ RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, GetSchemaErrorKeyword(code));
+ currentError_.AddMember(GetErrorCodeString(), code, *allocator_);
+ AddErrorInstanceLocation(currentError_, location);
+ AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_);
+ }
+
+#define RAPIDJSON_STRING_(name, ...) \
+ static const StringRefType& Get##name##String() {\
+ static const Ch s[] = { __VA_ARGS__, '\0' };\
+ static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
+ return v;\
+ }
+
+ RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')
+ RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
+ RAPIDJSON_STRING_(Value, 'v', 'a', 'l', 'u', 'e')
+ RAPIDJSON_STRING_(Offset, 'o', 'f', 'f', 's', 'e', 't')
+
+ RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
+ RAPIDJSON_STRING_(SpecUnknown, 'S', 'p', 'e', 'c', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
+ RAPIDJSON_STRING_(SpecUnsupported, 'S', 'p', 'e', 'c', 'U', 'n', 's', 'u', 'p', 'p', 'o', 'r', 't', 'e', 'd')
+ RAPIDJSON_STRING_(SpecIllegal, 'S', 'p', 'e', 'c', 'I', 'l', 'l', 'e', 'g', 'a', 'l')
+ RAPIDJSON_STRING_(StartUnknown, 'S', 't', 'a', 'r', 't', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
+ RAPIDJSON_STRING_(RefPlainName, 'R', 'e', 'f', 'P', 'l', 'a', 'i', 'n', 'N', 'a', 'm', 'e')
+ RAPIDJSON_STRING_(RefInvalid, 'R', 'e', 'f', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
+ RAPIDJSON_STRING_(RefPointerInvalid, 'R', 'e', 'f', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
+ RAPIDJSON_STRING_(RefUnknown, 'R', 'e', 'f', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
+ RAPIDJSON_STRING_(RefCyclical, 'R', 'e', 'f', 'C', 'y', 'c', 'l', 'i', 'c', 'a', 'l')
+ RAPIDJSON_STRING_(RefNoRemoteProvider, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r')
+ RAPIDJSON_STRING_(RefNoRemoteSchema, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'S', 'c', 'h', 'e', 'm', 'a')
+ RAPIDJSON_STRING_(ReadOnlyAndWriteOnly, 'R', 'e', 'a', 'd', 'O', 'n', 'l', 'y', 'A', 'n', 'd', 'W', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y')
+ RAPIDJSON_STRING_(RegexInvalid, 'R', 'e', 'g', 'e', 'x', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
+#undef RAPIDJSON_STRING_
+
+ // Static method to get schema draft of any schema document
+ static SchemaDraft GetSchemaDraft(const ValueType& document) {
+ static const Ch kDraft03String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '3', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
+ static const Ch kDraft04String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '4', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
+ static const Ch kDraft05String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '5', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
+ static const Ch kDraft06String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '6', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
+ static const Ch kDraft07String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '7', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
+ static const Ch kDraft2019_09String[] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/', '2', '0', '1', '9', '-', '0', '9', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0' };
+ static const Ch kDraft2020_12String[] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/', '2', '0', '2', '0', '-', '1', '2', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0' };
+
+ if (!document.IsObject()) {
+ return kDraftNone;
+ }
+
+ // Get the schema draft from the $schema keyword at the supplied location
+ typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSchemaString());
+ if (itr != document.MemberEnd()) {
+ if (!itr->value.IsString()) return kDraftUnknown;
+ const UriType draftUri(itr->value);
+ // Check base uri for match
+ if (draftUri.Match(UriType(kDraft04String), false)) return kDraft04;
+ if (draftUri.Match(UriType(kDraft05String), false)) return kDraft05;
+ if (draftUri.Match(UriType(kDraft06String), false)) return kDraft06;
+ if (draftUri.Match(UriType(kDraft07String), false)) return kDraft07;
+ if (draftUri.Match(UriType(kDraft03String), false)) return kDraft03;
+ if (draftUri.Match(UriType(kDraft2019_09String), false)) return kDraft2019_09;
+ if (draftUri.Match(UriType(kDraft2020_12String), false)) return kDraft2020_12;
+ return kDraftUnknown;
+ }
+ // $schema not found
+ return kDraftNone;
+ }
+
+
+ // Get open api version of any schema document
+ static OpenApiVersion GetOpenApiVersion(const ValueType& document) {
+ static const Ch kVersion20String[] = { '2', '.', '0', '\0' };
+ static const Ch kVersion30String[] = { '3', '.', '0', '.', '\0' }; // ignore patch level
+ static const Ch kVersion31String[] = { '3', '.', '1', '.', '\0' }; // ignore patch level
+ static SizeType len = internal::StrLen<Ch>(kVersion30String);
+
+ if (!document.IsObject()) {
+ return kVersionNone;
+ }
+
+ // Get the open api version from the swagger / openapi keyword at the supplied location
+ typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSwaggerString());
+ if (itr == document.MemberEnd()) itr = document.FindMember(SchemaType::GetOpenApiString());
+ if (itr != document.MemberEnd()) {
+ if (!itr->value.IsString()) return kVersionUnknown;
+ const ValueType kVersion20Value(kVersion20String);
+ if (kVersion20Value == itr->value) return kVersion20; // must match 2.0 exactly
+ const ValueType kVersion30Value(kVersion30String);
+ if (itr->value.GetStringLength() > len && kVersion30Value == ValueType(itr->value.GetString(), len)) return kVersion30; // must match 3.0.x
+ const ValueType kVersion31Value(kVersion31String);
+ if (itr->value.GetStringLength() > len && kVersion31Value == ValueType(itr->value.GetString(), len)) return kVersion31; // must match 3.1.x
+ return kVersionUnknown;
+ }
+ // swagger or openapi not found
+ return kVersionNone;
+ }
+
+ // Get the draft of the schema or the open api version (which implies the draft).
+ // Report an error if schema draft or open api version not supported or not recognized, or both in document, and carry on.
+ void SetSchemaSpecification(const ValueType& document) {
+ // Look for '$schema', 'swagger' or 'openapi' keyword at document root
+ SchemaDraft docDraft = GetSchemaDraft(document);
+ OpenApiVersion docOapi = GetOpenApiVersion(document);
+ // Error if both in document
+ if (docDraft != kDraftNone && docOapi != kVersionNone)
+ SchemaError(kSchemaErrorSpecIllegal, PointerType());
+ // Use document draft or open api version if present or use spec from constructor
+ if (docDraft != kDraftNone)
+ spec_ = Specification(docDraft);
+ else if (docOapi != kVersionNone)
+ spec_ = Specification(docOapi);
+ // Error if draft or version unknown
+ if (spec_.draft == kDraftUnknown || spec_.oapi == kVersionUnknown)
+ SchemaError(kSchemaErrorSpecUnknown, PointerType());
+ else if (!spec_.IsSupported())
+ SchemaError(kSchemaErrorSpecUnsupported, PointerType());
+ }
+
+ // Changed by PR #1393
+ void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
if (v.GetType() == kObjectType) {
- const SchemaType* s = GetSchema(pointer);
- if (!s)
- CreateSchema(schema, pointer, v, document);
+ UriType newid = UriType(CreateSchema(schema, pointer, v, document, id), allocator_);
for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
- CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
+ CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document, newid);
}
else if (v.GetType() == kArrayType)
for (SizeType i = 0; i < v.Size(); i++)
- CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
+ CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document, id);
}
- void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
+ // Changed by PR #1393
+ const UriType& CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
RAPIDJSON_ASSERT(pointer.IsValid());
+ GenericStringBuffer<EncodingType> sb;
+ pointer.StringifyUriFragment(sb);
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::CreateSchema", sb.GetString(), id.GetString());
if (v.IsObject()) {
- if (!HandleRefSchema(pointer, schema, v, document)) {
- SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_);
- new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_);
+ if (const SchemaType* sc = GetSchema(pointer)) {
+ if (schema)
+ *schema = sc;
+ AddSchemaRefs(const_cast<SchemaType*>(sc));
+ }
+ else if (!HandleRefSchema(pointer, schema, v, document, id)) {
+ // The new schema constructor adds itself and its $ref(s) to schemaMap_
+ SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_, id);
if (schema)
*schema = s;
+ return s->GetId();
}
}
+ else {
+ if (schema)
+ *schema = typeless_;
+ AddSchemaRefs(typeless_);
+ }
+ return id;
}
- bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) {
- static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' };
- static const ValueType kRefValue(kRefString, 4);
-
- typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
+ // Changed by PR #1393
+ // TODO should this return a UriType& ?
+ bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document, const UriType& id) {
+ typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString());
if (itr == v.MemberEnd())
return false;
+ GenericStringBuffer<EncodingType> sb;
+ source.StringifyUriFragment(sb);
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::HandleRefSchema", sb.GetString(), id.GetString());
+ // Resolve the source pointer to the $ref'ed schema (finally)
+ new (schemaRef_.template Push<SchemaRefPtr>()) SchemaRefPtr(&source);
+
if (itr->value.IsString()) {
SizeType len = itr->value.GetStringLength();
- if (len > 0) {
- const Ch* s = itr->value.GetString();
- SizeType i = 0;
- while (i < len && s[i] != '#') // Find the first #
- i++;
-
- if (i > 0) { // Remote reference, resolve immediately
- if (remoteProvider_) {
- if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) {
- PointerType pointer(&s[i], len - i, allocator_);
- if (pointer.IsValid()) {
- if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
- if (schema)
- *schema = sc;
+ if (len == 0)
+ SchemaError(kSchemaErrorRefInvalid, source);
+ else {
+ // First resolve $ref against the in-scope id
+ UriType scopeId = UriType(id, allocator_);
+ UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_);
+ RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), itr->value.GetString(), ref.GetString());
+ // See if the resolved $ref minus the fragment matches a resolved id in this document
+ // Search from the root. Returns the subschema in the document and its absolute JSON pointer.
+ PointerType basePointer = PointerType();
+ const ValueType *base = FindId(document, ref, basePointer, docId_, false);
+ if (!base) {
+ // Remote reference - call the remote document provider
+ if (!remoteProvider_)
+ SchemaError(kSchemaErrorRefNoRemoteProvider, source);
+ else {
+ if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref, spec_)) {
+ const Ch* s = ref.GetFragString();
+ len = ref.GetFragStringLength();
+ if (len <= 1 || s[1] == '/') {
+ // JSON pointer fragment, absolute in the remote schema
+ const PointerType pointer(s, len, allocator_);
+ if (!pointer.IsValid())
+ SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, pointer);
+ else {
+ // Get the subschema
+ if (const SchemaType *sc = remoteDocument->GetSchema(pointer)) {
+ if (schema)
+ *schema = sc;
+ AddSchemaRefs(const_cast<SchemaType *>(sc));
+ return true;
+ } else
+ SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
+ }
+ } else
+ // Plain name fragment, not allowed in remote schema
+ SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len);
+ } else
+ SchemaErrorValue(kSchemaErrorRefNoRemoteSchema, source, ref.GetString(), ref.GetStringLength());
+ }
+ }
+ else { // Local reference
+ const Ch* s = ref.GetFragString();
+ len = ref.GetFragStringLength();
+ if (len <= 1 || s[1] == '/') {
+ // JSON pointer fragment, relative to the resolved URI
+ const PointerType relPointer(s, len, allocator_);
+ if (!relPointer.IsValid())
+ SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, relPointer);
+ else {
+ // Get the subschema
+ if (const ValueType *pv = relPointer.Get(*base)) {
+ // Now get the absolute JSON pointer by adding relative to base
+ PointerType pointer(basePointer, allocator_);
+ for (SizeType i = 0; i < relPointer.GetTokenCount(); i++)
+ pointer = pointer.Append(relPointer.GetTokens()[i], allocator_);
+ if (IsCyclicRef(pointer))
+ SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength());
+ else {
+ // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there
+ // TODO: cache pointer <-> id mapping
+ size_t unresolvedTokenIndex;
+ scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
+ CreateSchema(schema, pointer, *pv, document, scopeId);
return true;
}
- }
+ } else
+ SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
}
+ } else {
+ // Plain name fragment, relative to the resolved URI
+ // Not supported in open api 2.0 and 3.0
+ PointerType pointer(allocator_);
+ if (spec_.oapi == kVersion20 || spec_.oapi == kVersion30)
+ SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len);
+ // See if the fragment matches an id in this document.
+ // Search from the base we just established. Returns the subschema in the document and its absolute JSON pointer.
+ else if (const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_), true, basePointer)) {
+ if (IsCyclicRef(pointer))
+ SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength());
+ else {
+ // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there
+ // TODO: cache pointer <-> id mapping
+ size_t unresolvedTokenIndex;
+ scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
+ CreateSchema(schema, pointer, *pv, document, scopeId);
+ return true;
+ }
+ } else
+ SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
}
}
- else if (s[i] == '#') { // Local reference, defer resolution
- PointerType pointer(&s[i], len - i, allocator_);
- if (pointer.IsValid()) {
- if (const ValueType* nv = pointer.Get(document))
- if (HandleRefSchema(source, schema, *nv, document))
- return true;
+ }
+ }
- new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
- return true;
- }
+ // Invalid/Unknown $ref
+ if (schema)
+ *schema = typeless_;
+ AddSchemaRefs(typeless_);
+ return true;
+ }
+
+ //! Find the first subschema with a resolved 'id' that matches the specified URI.
+ // If full specified use all URI else ignore fragment.
+ // If found, return a pointer to the subschema and its JSON pointer.
+ // TODO cache pointer <-> id mapping
+ ValueType* FindId(const ValueType& doc, const UriType& finduri, PointerType& resptr, const UriType& baseuri, bool full, const PointerType& here = PointerType()) const {
+ SizeType i = 0;
+ ValueType* resval = 0;
+ UriType tempuri = UriType(finduri, allocator_);
+ UriType localuri = UriType(baseuri, allocator_);
+ if (doc.GetType() == kObjectType) {
+ // Establish the base URI of this object
+ typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString());
+ if (m != doc.MemberEnd() && m->value.GetType() == kStringType) {
+ localuri = UriType(m->value, allocator_).Resolve(baseuri, allocator_);
+ }
+ // See if it matches
+ if (localuri.Match(finduri, full)) {
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::FindId (match)", full ? localuri.GetString() : localuri.GetBaseString());
+ resval = const_cast<ValueType *>(&doc);
+ resptr = here;
+ return resval;
+ }
+ // No match, continue looking
+ for (m = doc.MemberBegin(); m != doc.MemberEnd(); ++m) {
+ if (m->value.GetType() == kObjectType || m->value.GetType() == kArrayType) {
+ resval = FindId(m->value, finduri, resptr, localuri, full, here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_));
+ }
+ if (resval) break;
+ }
+ } else if (doc.GetType() == kArrayType) {
+ // Continue looking
+ for (typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v) {
+ if (v->GetType() == kObjectType || v->GetType() == kArrayType) {
+ resval = FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_));
}
+ if (resval) break;
+ i++;
}
}
+ return resval;
+ }
+
+ // Added by PR #1393
+ void AddSchemaRefs(SchemaType* schema) {
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::AddSchemaRefs");
+ while (!schemaRef_.Empty()) {
+ SchemaRefPtr *ref = schemaRef_.template Pop<SchemaRefPtr>(1);
+ SchemaEntry *entry = schemaMap_.template Push<SchemaEntry>();
+ new (entry) SchemaEntry(**ref, schema, false, allocator_);
+ }
+ }
+
+ // Added by PR #1393
+ bool IsCyclicRef(const PointerType& pointer) const {
+ for (const SchemaRefPtr* ref = schemaRef_.template Bottom<SchemaRefPtr>(); ref != schemaRef_.template End<SchemaRefPtr>(); ++ref)
+ if (pointer == **ref)
+ return true;
return false;
}
@@ -1515,6 +2392,8 @@ private:
return PointerType();
}
+ const SchemaType* GetTypeless() const { return typeless_; }
+
static const size_t kInitialSchemaMapSize = 64;
static const size_t kInitialSchemaRefSize = 64;
@@ -1522,8 +2401,14 @@ private:
Allocator *allocator_;
Allocator *ownAllocator_;
const SchemaType* root_; //!< Root schema.
+ SchemaType* typeless_;
internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
- internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref and schema which holds the $ref
+ internal::Stack<Allocator> schemaRef_; // Stores Pointer(s) from $ref(s) until resolved
+ GValue uri_; // Schema document URI
+ UriType docId_;
+ Specification spec_;
+ GValue error_;
+ GValue currentError_;
};
//! GenericSchemaDocument using Value type.
@@ -1552,13 +2437,16 @@ template <
typename StateAllocator = CrtAllocator>
class GenericSchemaValidator :
public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
- public internal::ISchemaValidator
-{
+ public internal::ISchemaValidator,
+ public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType> {
public:
typedef typename SchemaDocumentType::SchemaType SchemaType;
typedef typename SchemaDocumentType::PointerType PointerType;
typedef typename SchemaType::EncodingType EncodingType;
+ typedef typename SchemaType::SValue SValue;
typedef typename EncodingType::Ch Ch;
+ typedef GenericStringRef<Ch> StringRefType;
+ typedef GenericValue<EncodingType, StateAllocator> ValueType;
//! Constructor without output handler.
/*!
@@ -1575,16 +2463,19 @@ public:
:
schemaDocument_(&schemaDocument),
root_(schemaDocument.GetRoot()),
- outputHandler_(GetNullHandler()),
stateAllocator_(allocator),
ownStateAllocator_(0),
schemaStack_(allocator, schemaStackCapacity),
documentStack_(allocator, documentStackCapacity),
- valid_(true)
-#if RAPIDJSON_SCHEMA_VERBOSE
- , depth_(0)
-#endif
+ outputHandler_(0),
+ error_(kObjectType),
+ currentError_(),
+ missingDependents_(),
+ valid_(true),
+ flags_(kValidateDefaultFlags),
+ depth_(0)
{
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator");
}
//! Constructor with output handler.
@@ -1603,16 +2494,19 @@ public:
:
schemaDocument_(&schemaDocument),
root_(schemaDocument.GetRoot()),
- outputHandler_(outputHandler),
stateAllocator_(allocator),
ownStateAllocator_(0),
schemaStack_(allocator, schemaStackCapacity),
documentStack_(allocator, documentStackCapacity),
- valid_(true)
-#if RAPIDJSON_SCHEMA_VERBOSE
- , depth_(0)
-#endif
+ outputHandler_(&outputHandler),
+ error_(kObjectType),
+ currentError_(),
+ missingDependents_(),
+ valid_(true),
+ flags_(kValidateDefaultFlags),
+ depth_(0)
{
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (output handler)");
}
//! Destructor.
@@ -1626,44 +2520,291 @@ public:
while (!schemaStack_.Empty())
PopSchema();
documentStack_.Clear();
+ ResetError();
+ }
+
+ //! Reset the error state.
+ void ResetError() {
+ error_.SetObject();
+ currentError_.SetNull();
+ missingDependents_.SetNull();
valid_ = true;
}
- //! Checks whether the current state is valid.
- // Implementation of ISchemaValidator
- virtual bool IsValid() const { return valid_; }
+ //! Implementation of ISchemaValidator
+ void SetValidateFlags(unsigned flags) {
+ flags_ = flags;
+ }
+ virtual unsigned GetValidateFlags() const {
+ return flags_;
+ }
+
+ virtual bool IsValid() const {
+ if (!valid_) return false;
+ if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false;
+ return true;
+ }
+ //! End of Implementation of ISchemaValidator
+
+ //! Gets the error object.
+ ValueType& GetError() { return error_; }
+ const ValueType& GetError() const { return error_; }
//! Gets the JSON pointer pointed to the invalid schema.
+ // If reporting all errors, the stack will be empty.
PointerType GetInvalidSchemaPointer() const {
- return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
+ return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
}
//! Gets the keyword of invalid schema.
+ // If reporting all errors, the stack will be empty, so return "errors".
const Ch* GetInvalidSchemaKeyword() const {
- return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
+ if (!schemaStack_.Empty()) return CurrentContext().invalidKeyword;
+ if (GetContinueOnErrors() && !error_.ObjectEmpty()) return (const Ch*)GetErrorsString();
+ return 0;
+ }
+
+ //! Gets the error code of invalid schema.
+ // If reporting all errors, the stack will be empty, so return kValidateErrors.
+ ValidateErrorCode GetInvalidSchemaCode() const {
+ if (!schemaStack_.Empty()) return CurrentContext().invalidCode;
+ if (GetContinueOnErrors() && !error_.ObjectEmpty()) return kValidateErrors;
+ return kValidateErrorNone;
}
//! Gets the JSON pointer pointed to the invalid value.
+ // If reporting all errors, the stack will be empty.
PointerType GetInvalidDocumentPointer() const {
- return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
+ if (documentStack_.Empty()) {
+ return PointerType();
+ }
+ else {
+ return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
+ }
}
-#if RAPIDJSON_SCHEMA_VERBOSE
-#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
-RAPIDJSON_MULTILINEMACRO_BEGIN\
- *documentStack_.template Push<Ch>() = '\0';\
- documentStack_.template Pop<Ch>(1);\
- internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
-RAPIDJSON_MULTILINEMACRO_END
-#else
-#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
-#endif
+ void NotMultipleOf(int64_t actual, const SValue& expected) {
+ AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
+ }
+ void NotMultipleOf(uint64_t actual, const SValue& expected) {
+ AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
+ }
+ void NotMultipleOf(double actual, const SValue& expected) {
+ AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
+ }
+ void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) {
+ AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
+ exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
+ }
+ void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) {
+ AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
+ exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
+ }
+ void AboveMaximum(double actual, const SValue& expected, bool exclusive) {
+ AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
+ exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
+ }
+ void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) {
+ AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
+ exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
+ }
+ void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) {
+ AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
+ exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
+ }
+ void BelowMinimum(double actual, const SValue& expected, bool exclusive) {
+ AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
+ exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
+ }
+
+ void TooLong(const Ch* str, SizeType length, SizeType expected) {
+ AddNumberError(kValidateErrorMaxLength,
+ ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
+ }
+ void TooShort(const Ch* str, SizeType length, SizeType expected) {
+ AddNumberError(kValidateErrorMinLength,
+ ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
+ }
+ void DoesNotMatch(const Ch* str, SizeType length) {
+ currentError_.SetObject();
+ currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
+ AddCurrentError(kValidateErrorPattern);
+ }
+
+ void DisallowedItem(SizeType index) {
+ currentError_.SetObject();
+ currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
+ AddCurrentError(kValidateErrorAdditionalItems, true);
+ }
+ void TooFewItems(SizeType actualCount, SizeType expectedCount) {
+ AddNumberError(kValidateErrorMinItems,
+ ValueType(actualCount).Move(), SValue(expectedCount).Move());
+ }
+ void TooManyItems(SizeType actualCount, SizeType expectedCount) {
+ AddNumberError(kValidateErrorMaxItems,
+ ValueType(actualCount).Move(), SValue(expectedCount).Move());
+ }
+ void DuplicateItems(SizeType index1, SizeType index2) {
+ ValueType duplicates(kArrayType);
+ duplicates.PushBack(index1, GetStateAllocator());
+ duplicates.PushBack(index2, GetStateAllocator());
+ currentError_.SetObject();
+ currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
+ AddCurrentError(kValidateErrorUniqueItems, true);
+ }
+
+ void TooManyProperties(SizeType actualCount, SizeType expectedCount) {
+ AddNumberError(kValidateErrorMaxProperties,
+ ValueType(actualCount).Move(), SValue(expectedCount).Move());
+ }
+ void TooFewProperties(SizeType actualCount, SizeType expectedCount) {
+ AddNumberError(kValidateErrorMinProperties,
+ ValueType(actualCount).Move(), SValue(expectedCount).Move());
+ }
+ void StartMissingProperties() {
+ currentError_.SetArray();
+ }
+ void AddMissingProperty(const SValue& name) {
+ currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
+ }
+ bool EndMissingProperties() {
+ if (currentError_.Empty())
+ return false;
+ ValueType error(kObjectType);
+ error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
+ currentError_ = error;
+ AddCurrentError(kValidateErrorRequired);
+ return true;
+ }
+ void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) {
+ for (SizeType i = 0; i < count; ++i)
+ MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
+ }
+ void DisallowedProperty(const Ch* name, SizeType length) {
+ currentError_.SetObject();
+ currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
+ AddCurrentError(kValidateErrorAdditionalProperties, true);
+ }
+
+ void StartDependencyErrors() {
+ currentError_.SetObject();
+ }
+ void StartMissingDependentProperties() {
+ missingDependents_.SetArray();
+ }
+ void AddMissingDependentProperty(const SValue& targetName) {
+ missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
+ }
+ void EndMissingDependentProperties(const SValue& sourceName) {
+ if (!missingDependents_.Empty()) {
+ // Create equivalent 'required' error
+ ValueType error(kObjectType);
+ ValidateErrorCode code = kValidateErrorRequired;
+ error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
+ AddErrorCode(error, code);
+ AddErrorInstanceLocation(error, false);
+ // When appending to a pointer ensure its allocator is used
+ PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator());
+ AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator()));
+ ValueType wrapper(kObjectType);
+ wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator());
+ currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
+ }
+ }
+ void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) {
+ currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
+ static_cast<GenericSchemaValidator*>(subvalidator)->GetError(), GetStateAllocator());
+ }
+ bool EndDependencyErrors() {
+ if (currentError_.ObjectEmpty())
+ return false;
+ ValueType error(kObjectType);
+ error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
+ currentError_ = error;
+ AddCurrentError(kValidateErrorDependencies);
+ return true;
+ }
+
+ void DisallowedValue(const ValidateErrorCode code = kValidateErrorEnum) {
+ currentError_.SetObject();
+ AddCurrentError(code);
+ }
+ void StartDisallowedType() {
+ currentError_.SetArray();
+ }
+ void AddExpectedType(const typename SchemaType::ValueType& expectedType) {
+ currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
+ }
+ void EndDisallowedType(const typename SchemaType::ValueType& actualType) {
+ ValueType error(kObjectType);
+ error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
+ error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
+ currentError_ = error;
+ AddCurrentError(kValidateErrorType);
+ }
+ void NotAllOf(ISchemaValidator** subvalidators, SizeType count) {
+ // Treat allOf like oneOf and anyOf to match https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf
+ AddErrorArray(kValidateErrorAllOf, subvalidators, count);
+ //for (SizeType i = 0; i < count; ++i) {
+ // MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
+ //}
+ }
+ void NoneOf(ISchemaValidator** subvalidators, SizeType count) {
+ AddErrorArray(kValidateErrorAnyOf, subvalidators, count);
+ }
+ void NotOneOf(ISchemaValidator** subvalidators, SizeType count) {
+ AddErrorArray(kValidateErrorOneOf, subvalidators, count);
+ }
+ void MultipleOneOf(SizeType index1, SizeType index2) {
+ ValueType matches(kArrayType);
+ matches.PushBack(index1, GetStateAllocator());
+ matches.PushBack(index2, GetStateAllocator());
+ currentError_.SetObject();
+ currentError_.AddMember(GetMatchesString(), matches, GetStateAllocator());
+ AddCurrentError(kValidateErrorOneOfMatch);
+ }
+ void Disallowed() {
+ currentError_.SetObject();
+ AddCurrentError(kValidateErrorNot);
+ }
+ void DisallowedWhenWriting() {
+ currentError_.SetObject();
+ AddCurrentError(kValidateErrorReadOnly);
+ }
+ void DisallowedWhenReading() {
+ currentError_.SetObject();
+ AddCurrentError(kValidateErrorWriteOnly);
+ }
+
+#define RAPIDJSON_STRING_(name, ...) \
+ static const StringRefType& Get##name##String() {\
+ static const Ch s[] = { __VA_ARGS__, '\0' };\
+ static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
+ return v;\
+ }
+
+ RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')
+ RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f')
+ RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd')
+ RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l')
+ RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')
+ RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')
+ RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')
+ RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
+ RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e')
+ RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
+ RAPIDJSON_STRING_(Matches, 'm', 'a', 't', 'c', 'h', 'e', 's')
+
+#undef RAPIDJSON_STRING_
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
if (!valid_) return false; \
- if (!BeginValue() || !CurrentSchema().method arg1) {\
- RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
- return valid_ = false;\
+ if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\
+ *documentStack_.template Push<Ch>() = '\0';\
+ documentStack_.template Pop<Ch>(1);\
+ RAPIDJSON_SCHEMA_PRINT(InvalidDocument, documentStack_.template Bottom<Ch>());\
+ valid_ = false;\
+ return valid_;\
}
#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
@@ -1679,14 +2820,15 @@ RAPIDJSON_MULTILINEMACRO_END
}
#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
- return valid_ = EndValue() && outputHandler_.method arg2
+ valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\
+ return valid_;
#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
- bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); }
+ bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); }
bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
@@ -1699,51 +2841,69 @@ RAPIDJSON_MULTILINEMACRO_END
{ RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
bool StartObject() {
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartObject");
RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
- return valid_ = outputHandler_.StartObject();
+ valid_ = !outputHandler_ || outputHandler_->StartObject();
+ return valid_;
}
bool Key(const Ch* str, SizeType len, bool copy) {
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::Key", str);
if (!valid_) return false;
AppendToken(str, len);
- if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
+ if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) {
+ valid_ = false;
+ return valid_;
+ }
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
- return valid_ = outputHandler_.Key(str, len, copy);
+ valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
+ return valid_;
}
- bool EndObject(SizeType memberCount) {
+ bool EndObject(SizeType memberCount) {
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndObject");
if (!valid_) return false;
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
- if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
+ if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) {
+ valid_ = false;
+ return valid_;
+ }
RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
}
bool StartArray() {
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartArray");
RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
- return valid_ = outputHandler_.StartArray();
+ valid_ = !outputHandler_ || outputHandler_->StartArray();
+ return valid_;
}
bool EndArray(SizeType elementCount) {
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndArray");
if (!valid_) return false;
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
- if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
+ if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) {
+ valid_ = false;
+ return valid_;
+ }
RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
}
-#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
// Implementation of ISchemaStateFactory<SchemaType>
- virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
- return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root,
-#if RAPIDJSON_SCHEMA_VERBOSE
+ virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) {
+ *documentStack_.template Push<Ch>() = '\0';
+ documentStack_.template Pop<Ch>(1);
+ ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
depth_ + 1,
-#endif
&GetStateAllocator());
+ sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(unsigned)kValidateContinueOnErrorFlag);
+ return sv;
}
virtual void DestroySchemaValidator(ISchemaValidator* validator) {
@@ -1771,8 +2931,9 @@ RAPIDJSON_MULTILINEMACRO_END
}
virtual void FreeState(void* p) {
- return StateAllocator::Free(p);
+ StateAllocator::Free(p);
}
+ // End of implementation of ISchemaStateFactory<SchemaType>
private:
typedef typename SchemaType::Context Context;
@@ -1782,57 +2943,67 @@ private:
GenericSchemaValidator(
const SchemaDocumentType& schemaDocument,
const SchemaType& root,
-#if RAPIDJSON_SCHEMA_VERBOSE
+ const char* basePath, size_t basePathSize,
unsigned depth,
-#endif
StateAllocator* allocator = 0,
size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
size_t documentStackCapacity = kDefaultDocumentStackCapacity)
:
schemaDocument_(&schemaDocument),
root_(root),
- outputHandler_(GetNullHandler()),
stateAllocator_(allocator),
ownStateAllocator_(0),
schemaStack_(allocator, schemaStackCapacity),
documentStack_(allocator, documentStackCapacity),
- valid_(true)
-#if RAPIDJSON_SCHEMA_VERBOSE
- , depth_(depth)
-#endif
+ outputHandler_(0),
+ error_(kObjectType),
+ currentError_(),
+ missingDependents_(),
+ valid_(true),
+ flags_(kValidateDefaultFlags),
+ depth_(depth)
{
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (internal)", basePath && basePathSize ? basePath : "");
+ if (basePath && basePathSize)
+ memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
}
StateAllocator& GetStateAllocator() {
if (!stateAllocator_)
- stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator());
+ stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)();
return *stateAllocator_;
}
+ bool GetContinueOnErrors() const {
+ return flags_ & kValidateContinueOnErrorFlag;
+ }
+
bool BeginValue() {
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::BeginValue");
if (schemaStack_.Empty())
PushSchema(root_);
else {
if (CurrentContext().inArray)
internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
- if (!CurrentSchema().BeginValue(CurrentContext()))
+ if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
return false;
SizeType count = CurrentContext().patternPropertiesSchemaCount;
const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
bool valueUniqueness = CurrentContext().valueUniqueness;
- if (CurrentContext().valueSchema)
- PushSchema(*CurrentContext().valueSchema);
+ RAPIDJSON_ASSERT(CurrentContext().valueSchema);
+ PushSchema(*CurrentContext().valueSchema);
if (count > 0) {
CurrentContext().objectPatternValidatorType = patternValidatorType;
ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
+ std::memset(va, 0, sizeof(ISchemaValidator*) * count);
for (SizeType i = 0; i < count; i++)
- va[validatorCount++] = CreateSchemaValidator(*sa[i]);
+ va[validatorCount++] = CreateSchemaValidator(*sa[i], true); // Inherit continueOnError
}
CurrentContext().arrayUniqueness = valueUniqueness;
@@ -1841,31 +3012,37 @@ private:
}
bool EndValue() {
- if (!CurrentSchema().EndValue(CurrentContext()))
+ RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndValue");
+ if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
return false;
-#if RAPIDJSON_SCHEMA_VERBOSE
GenericStringBuffer<EncodingType> sb;
- schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
-
+ schemaDocument_->GetPointer(&CurrentSchema()).StringifyUriFragment(sb);
*documentStack_.template Push<Ch>() = '\0';
documentStack_.template Pop<Ch>(1);
- internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
-#endif
-
- uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;
+ RAPIDJSON_SCHEMA_PRINT(ValidatorPointers, sb.GetString(), documentStack_.template Bottom<Ch>(), depth_);
+ void* hasher = CurrentContext().hasher;
+ uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast<HasherType*>(hasher)->GetHashCode() : 0;
PopSchema();
if (!schemaStack_.Empty()) {
Context& context = CurrentContext();
- if (context.valueUniqueness) {
+ // Only check uniqueness if there is a hasher
+ if (hasher && context.valueUniqueness) {
HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
if (!a)
CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
- if (itr->GetUint64() == h)
- RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
+ if (itr->GetUint64() == h) {
+ DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());
+ // Cleanup before returning if continuing
+ if (GetContinueOnErrors()) {
+ a->PushBack(h, GetStateAllocator());
+ while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/');
+ }
+ RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorUniqueItems);
+ }
a->PushBack(h, GetStateAllocator());
}
}
@@ -1894,7 +3071,7 @@ private:
}
}
- RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, &schema); }
+ RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, *this, &schema, flags_); }
RAPIDJSON_FORCEINLINE void PopSchema() {
Context* c = schemaStack_.template Pop<Context>(1);
@@ -1905,28 +3082,98 @@ private:
c->~Context();
}
+ void AddErrorInstanceLocation(ValueType& result, bool parent) {
+ GenericStringBuffer<EncodingType> sb;
+ PointerType instancePointer = GetInvalidDocumentPointer();
+ ((parent && instancePointer.GetTokenCount() > 0)
+ ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
+ : instancePointer).StringifyUriFragment(sb);
+ ValueType instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
+ GetStateAllocator());
+ result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
+ }
+
+ void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) {
+ GenericStringBuffer<EncodingType> sb;
+ SizeType len = CurrentSchema().GetURI().GetStringLength();
+ if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch));
+ if (schema.GetTokenCount()) schema.StringifyUriFragment(sb);
+ else GetInvalidSchemaPointer().StringifyUriFragment(sb);
+ ValueType schemaRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
+ GetStateAllocator());
+ result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
+ }
+
+ void AddErrorCode(ValueType& result, const ValidateErrorCode code) {
+ result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
+ }
+
+ void AddError(ValueType& keyword, ValueType& error) {
+ typename ValueType::MemberIterator member = error_.FindMember(keyword);
+ if (member == error_.MemberEnd())
+ error_.AddMember(keyword, error, GetStateAllocator());
+ else {
+ if (member->value.IsObject()) {
+ ValueType errors(kArrayType);
+ errors.PushBack(member->value, GetStateAllocator());
+ member->value = errors;
+ }
+ member->value.PushBack(error, GetStateAllocator());
+ }
+ }
+
+ void AddCurrentError(const ValidateErrorCode code, bool parent = false) {
+ AddErrorCode(currentError_, code);
+ AddErrorInstanceLocation(currentError_, parent);
+ AddErrorSchemaLocation(currentError_);
+ AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(), false).Move(), currentError_);
+ }
+
+ void MergeError(ValueType& other) {
+ for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) {
+ AddError(it->name, it->value);
+ }
+ }
+
+ void AddNumberError(const ValidateErrorCode code, ValueType& actual, const SValue& expected,
+ const typename SchemaType::ValueType& (*exclusive)() = 0) {
+ currentError_.SetObject();
+ currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
+ currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
+ if (exclusive)
+ currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator());
+ AddCurrentError(code);
+ }
+
+ void AddErrorArray(const ValidateErrorCode code,
+ ISchemaValidator** subvalidators, SizeType count) {
+ ValueType errors(kArrayType);
+ for (SizeType i = 0; i < count; ++i)
+ errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator());
+ currentError_.SetObject();
+ currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
+ AddCurrentError(code);
+ }
+
const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
- static OutputHandler& GetNullHandler() {
- static OutputHandler nullHandler;
- return nullHandler;
- }
-
static const size_t kDefaultSchemaStackCapacity = 1024;
static const size_t kDefaultDocumentStackCapacity = 256;
const SchemaDocumentType* schemaDocument_;
const SchemaType& root_;
- OutputHandler& outputHandler_;
StateAllocator* stateAllocator_;
StateAllocator* ownStateAllocator_;
internal::Stack<StateAllocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *)
internal::Stack<StateAllocator> documentStack_; //!< stack to store the current path of validating document (Ch)
+ OutputHandler* outputHandler_;
+ ValueType error_;
+ ValueType currentError_;
+ ValueType missingDependents_;
bool valid_;
-#if RAPIDJSON_SCHEMA_VERBOSE
+ unsigned flags_;
unsigned depth_;
-#endif
};
typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
@@ -1954,13 +3201,14 @@ class SchemaValidatingReader {
public:
typedef typename SchemaDocumentType::PointerType PointerType;
typedef typename InputStream::Ch Ch;
+ typedef GenericValue<SourceEncoding, StackAllocator> ValueType;
//! Constructor
/*!
\param is Input stream.
\param sd Schema document.
*/
- SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}
+ SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), invalidSchemaCode_(kValidateErrorNone), error_(kObjectType), isValid_(true) {}
template <typename Handler>
bool operator()(Handler& handler) {
@@ -1973,11 +3221,14 @@ public:
invalidSchemaPointer_ = PointerType();
invalidSchemaKeyword_ = 0;
invalidDocumentPointer_ = PointerType();
+ error_.SetObject();
}
else {
invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
+ invalidSchemaCode_ = validator.GetInvalidSchemaCode();
invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
+ error_.CopyFrom(validator.GetError(), allocator_);
}
return parseResult_;
@@ -1988,6 +3239,8 @@ public:
const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
+ const ValueType& GetError() const { return error_; }
+ ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; }
private:
InputStream& is_;
@@ -1997,6 +3250,9 @@ private:
PointerType invalidSchemaPointer_;
const Ch* invalidSchemaKeyword_;
PointerType invalidDocumentPointer_;
+ ValidateErrorCode invalidSchemaCode_;
+ StackAllocator allocator_;
+ ValueType error_;
bool isValid_;
};
diff --git a/3rdparty/rapidjson/include/rapidjson/stream.h b/3rdparty/rapidjson/include/rapidjson/stream.h
index fef82c252ff..1fd70915c54 100644
--- a/3rdparty/rapidjson/include/rapidjson/stream.h
+++ b/3rdparty/rapidjson/include/rapidjson/stream.h
@@ -1,15 +1,15 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#include "rapidjson.h"
@@ -101,6 +101,50 @@ inline void PutN(Stream& stream, Ch c, size_t n) {
}
///////////////////////////////////////////////////////////////////////////////
+// GenericStreamWrapper
+
+//! A Stream Wrapper
+/*! \tThis string stream is a wrapper for any stream by just forwarding any
+ \treceived message to the origin stream.
+ \note implements Stream concept
+*/
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+template <typename InputStream, typename Encoding = UTF8<> >
+class GenericStreamWrapper {
+public:
+ typedef typename Encoding::Ch Ch;
+ GenericStreamWrapper(InputStream& is): is_(is) {}
+
+ Ch Peek() const { return is_.Peek(); }
+ Ch Take() { return is_.Take(); }
+ size_t Tell() { return is_.Tell(); }
+ Ch* PutBegin() { return is_.PutBegin(); }
+ void Put(Ch ch) { is_.Put(ch); }
+ void Flush() { is_.Flush(); }
+ size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); }
+
+ // wrapper for MemoryStream
+ const Ch* Peek4() const { return is_.Peek4(); }
+
+ // wrapper for AutoUTFInputStream
+ UTFType GetType() const { return is_.GetType(); }
+ bool HasBOM() const { return is_.HasBOM(); }
+
+protected:
+ InputStream& is_;
+};
+
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+RAPIDJSON_DIAG_POP
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
// StringStream
//! Read-only string stream.
diff --git a/3rdparty/rapidjson/include/rapidjson/stringbuffer.h b/3rdparty/rapidjson/include/rapidjson/stringbuffer.h
index 78f34d2098e..82ad3ca6bbf 100644
--- a/3rdparty/rapidjson/include/rapidjson/stringbuffer.h
+++ b/3rdparty/rapidjson/include/rapidjson/stringbuffer.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -78,8 +78,12 @@ public:
return stack_.template Bottom<Ch>();
}
+ //! Get the size of string in bytes in the string buffer.
size_t GetSize() const { return stack_.GetSize(); }
+ //! Get the length of string in Ch in the string buffer.
+ size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); }
+
static const size_t kDefaultCapacity = 256;
mutable internal::Stack<Allocator> stack_;
diff --git a/3rdparty/rapidjson/include/rapidjson/uri.h b/3rdparty/rapidjson/include/rapidjson/uri.h
new file mode 100644
index 00000000000..f93e508a4f4
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/uri.h
@@ -0,0 +1,481 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// (C) Copyright IBM Corporation 2021
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_URI_H_
+#define RAPIDJSON_URI_H_
+
+#include "internal/strfunc.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericUri
+
+template <typename ValueType, typename Allocator=CrtAllocator>
+class GenericUri {
+public:
+ typedef typename ValueType::Ch Ch;
+#if RAPIDJSON_HAS_STDSTRING
+ typedef std::basic_string<Ch> String;
+#endif
+
+ //! Constructors
+ GenericUri(Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
+ }
+
+ GenericUri(const Ch* uri, SizeType len, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
+ Parse(uri, len);
+ }
+
+ GenericUri(const Ch* uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
+ Parse(uri, internal::StrLen<Ch>(uri));
+ }
+
+ // Use with specializations of GenericValue
+ template<typename T> GenericUri(const T& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
+ const Ch* u = uri.template Get<const Ch*>(); // TypeHelper from document.h
+ Parse(u, internal::StrLen<Ch>(u));
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ GenericUri(const String& uri, Allocator* allocator = 0) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
+ Parse(uri.c_str(), internal::StrLen<Ch>(uri.c_str()));
+ }
+#endif
+
+ //! Copy constructor
+ GenericUri(const GenericUri& rhs) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(), ownAllocator_() {
+ *this = rhs;
+ }
+
+ //! Copy constructor
+ GenericUri(const GenericUri& rhs, Allocator* allocator) : uri_(), base_(), scheme_(), auth_(), path_(), query_(), frag_(), allocator_(allocator), ownAllocator_() {
+ *this = rhs;
+ }
+
+ //! Destructor.
+ ~GenericUri() {
+ Free();
+ RAPIDJSON_DELETE(ownAllocator_);
+ }
+
+ //! Assignment operator
+ GenericUri& operator=(const GenericUri& rhs) {
+ if (this != &rhs) {
+ // Do not delete ownAllocator
+ Free();
+ Allocate(rhs.GetStringLength());
+ auth_ = CopyPart(scheme_, rhs.scheme_, rhs.GetSchemeStringLength());
+ path_ = CopyPart(auth_, rhs.auth_, rhs.GetAuthStringLength());
+ query_ = CopyPart(path_, rhs.path_, rhs.GetPathStringLength());
+ frag_ = CopyPart(query_, rhs.query_, rhs.GetQueryStringLength());
+ base_ = CopyPart(frag_, rhs.frag_, rhs.GetFragStringLength());
+ uri_ = CopyPart(base_, rhs.base_, rhs.GetBaseStringLength());
+ CopyPart(uri_, rhs.uri_, rhs.GetStringLength());
+ }
+ return *this;
+ }
+
+ //! Getters
+ // Use with specializations of GenericValue
+ template<typename T> void Get(T& uri, Allocator& allocator) {
+ uri.template Set<const Ch*>(this->GetString(), allocator); // TypeHelper from document.h
+ }
+
+ const Ch* GetString() const { return uri_; }
+ SizeType GetStringLength() const { return uri_ == 0 ? 0 : internal::StrLen<Ch>(uri_); }
+ const Ch* GetBaseString() const { return base_; }
+ SizeType GetBaseStringLength() const { return base_ == 0 ? 0 : internal::StrLen<Ch>(base_); }
+ const Ch* GetSchemeString() const { return scheme_; }
+ SizeType GetSchemeStringLength() const { return scheme_ == 0 ? 0 : internal::StrLen<Ch>(scheme_); }
+ const Ch* GetAuthString() const { return auth_; }
+ SizeType GetAuthStringLength() const { return auth_ == 0 ? 0 : internal::StrLen<Ch>(auth_); }
+ const Ch* GetPathString() const { return path_; }
+ SizeType GetPathStringLength() const { return path_ == 0 ? 0 : internal::StrLen<Ch>(path_); }
+ const Ch* GetQueryString() const { return query_; }
+ SizeType GetQueryStringLength() const { return query_ == 0 ? 0 : internal::StrLen<Ch>(query_); }
+ const Ch* GetFragString() const { return frag_; }
+ SizeType GetFragStringLength() const { return frag_ == 0 ? 0 : internal::StrLen<Ch>(frag_); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ static String Get(const GenericUri& uri) { return String(uri.GetString(), uri.GetStringLength()); }
+ static String GetBase(const GenericUri& uri) { return String(uri.GetBaseString(), uri.GetBaseStringLength()); }
+ static String GetScheme(const GenericUri& uri) { return String(uri.GetSchemeString(), uri.GetSchemeStringLength()); }
+ static String GetAuth(const GenericUri& uri) { return String(uri.GetAuthString(), uri.GetAuthStringLength()); }
+ static String GetPath(const GenericUri& uri) { return String(uri.GetPathString(), uri.GetPathStringLength()); }
+ static String GetQuery(const GenericUri& uri) { return String(uri.GetQueryString(), uri.GetQueryStringLength()); }
+ static String GetFrag(const GenericUri& uri) { return String(uri.GetFragString(), uri.GetFragStringLength()); }
+#endif
+
+ //! Equality operators
+ bool operator==(const GenericUri& rhs) const {
+ return Match(rhs, true);
+ }
+
+ bool operator!=(const GenericUri& rhs) const {
+ return !Match(rhs, true);
+ }
+
+ bool Match(const GenericUri& uri, bool full = true) const {
+ Ch* s1;
+ Ch* s2;
+ if (full) {
+ s1 = uri_;
+ s2 = uri.uri_;
+ } else {
+ s1 = base_;
+ s2 = uri.base_;
+ }
+ if (s1 == s2) return true;
+ if (s1 == 0 || s2 == 0) return false;
+ return internal::StrCmp<Ch>(s1, s2) == 0;
+ }
+
+ //! Resolve this URI against another (base) URI in accordance with URI resolution rules.
+ // See https://tools.ietf.org/html/rfc3986
+ // Use for resolving an id or $ref with an in-scope id.
+ // Returns a new GenericUri for the resolved URI.
+ GenericUri Resolve(const GenericUri& baseuri, Allocator* allocator = 0) {
+ GenericUri resuri;
+ resuri.allocator_ = allocator;
+ // Ensure enough space for combining paths
+ resuri.Allocate(GetStringLength() + baseuri.GetStringLength() + 1); // + 1 for joining slash
+
+ if (!(GetSchemeStringLength() == 0)) {
+ // Use all of this URI
+ resuri.auth_ = CopyPart(resuri.scheme_, scheme_, GetSchemeStringLength());
+ resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength());
+ resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
+ resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
+ resuri.RemoveDotSegments();
+ } else {
+ // Use the base scheme
+ resuri.auth_ = CopyPart(resuri.scheme_, baseuri.scheme_, baseuri.GetSchemeStringLength());
+ if (!(GetAuthStringLength() == 0)) {
+ // Use this auth, path, query
+ resuri.path_ = CopyPart(resuri.auth_, auth_, GetAuthStringLength());
+ resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
+ resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
+ resuri.RemoveDotSegments();
+ } else {
+ // Use the base auth
+ resuri.path_ = CopyPart(resuri.auth_, baseuri.auth_, baseuri.GetAuthStringLength());
+ if (GetPathStringLength() == 0) {
+ // Use the base path
+ resuri.query_ = CopyPart(resuri.path_, baseuri.path_, baseuri.GetPathStringLength());
+ if (GetQueryStringLength() == 0) {
+ // Use the base query
+ resuri.frag_ = CopyPart(resuri.query_, baseuri.query_, baseuri.GetQueryStringLength());
+ } else {
+ // Use this query
+ resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
+ }
+ } else {
+ if (path_[0] == '/') {
+ // Absolute path - use all of this path
+ resuri.query_ = CopyPart(resuri.path_, path_, GetPathStringLength());
+ resuri.RemoveDotSegments();
+ } else {
+ // Relative path - append this path to base path after base path's last slash
+ size_t pos = 0;
+ if (!(baseuri.GetAuthStringLength() == 0) && baseuri.GetPathStringLength() == 0) {
+ resuri.path_[pos] = '/';
+ pos++;
+ }
+ size_t lastslashpos = baseuri.GetPathStringLength();
+ while (lastslashpos > 0) {
+ if (baseuri.path_[lastslashpos - 1] == '/') break;
+ lastslashpos--;
+ }
+ std::memcpy(&resuri.path_[pos], baseuri.path_, lastslashpos * sizeof(Ch));
+ pos += lastslashpos;
+ resuri.query_ = CopyPart(&resuri.path_[pos], path_, GetPathStringLength());
+ resuri.RemoveDotSegments();
+ }
+ // Use this query
+ resuri.frag_ = CopyPart(resuri.query_, query_, GetQueryStringLength());
+ }
+ }
+ }
+ // Always use this frag
+ resuri.base_ = CopyPart(resuri.frag_, frag_, GetFragStringLength());
+
+ // Re-constitute base_ and uri_
+ resuri.SetBase();
+ resuri.uri_ = resuri.base_ + resuri.GetBaseStringLength() + 1;
+ resuri.SetUri();
+ return resuri;
+ }
+
+ //! Get the allocator of this GenericUri.
+ Allocator& GetAllocator() { return *allocator_; }
+
+private:
+ // Allocate memory for a URI
+ // Returns total amount allocated
+ std::size_t Allocate(std::size_t len) {
+ // Create own allocator if user did not supply.
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
+
+ // Allocate one block containing each part of the URI (5) plus base plus full URI, all null terminated.
+ // Order: scheme, auth, path, query, frag, base, uri
+ // Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
+ size_t total = (3 * len + 7) * sizeof(Ch);
+ scheme_ = static_cast<Ch*>(allocator_->Malloc(total));
+ *scheme_ = '\0';
+ auth_ = scheme_;
+ auth_++;
+ *auth_ = '\0';
+ path_ = auth_;
+ path_++;
+ *path_ = '\0';
+ query_ = path_;
+ query_++;
+ *query_ = '\0';
+ frag_ = query_;
+ frag_++;
+ *frag_ = '\0';
+ base_ = frag_;
+ base_++;
+ *base_ = '\0';
+ uri_ = base_;
+ uri_++;
+ *uri_ = '\0';
+ return total;
+ }
+
+ // Free memory for a URI
+ void Free() {
+ if (scheme_) {
+ Allocator::Free(scheme_);
+ scheme_ = 0;
+ }
+ }
+
+ // Parse a URI into constituent scheme, authority, path, query, & fragment parts
+ // Supports URIs that match regex ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? as per
+ // https://tools.ietf.org/html/rfc3986
+ void Parse(const Ch* uri, std::size_t len) {
+ std::size_t start = 0, pos1 = 0, pos2 = 0;
+ Allocate(len);
+
+ // Look for scheme ([^:/?#]+):)?
+ if (start < len) {
+ while (pos1 < len) {
+ if (uri[pos1] == ':') break;
+ pos1++;
+ }
+ if (pos1 != len) {
+ while (pos2 < len) {
+ if (uri[pos2] == '/') break;
+ if (uri[pos2] == '?') break;
+ if (uri[pos2] == '#') break;
+ pos2++;
+ }
+ if (pos1 < pos2) {
+ pos1++;
+ std::memcpy(scheme_, &uri[start], pos1 * sizeof(Ch));
+ scheme_[pos1] = '\0';
+ start = pos1;
+ }
+ }
+ }
+ // Look for auth (//([^/?#]*))?
+ // Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
+ auth_ = scheme_ + GetSchemeStringLength();
+ auth_++;
+ *auth_ = '\0';
+ if (start < len - 1 && uri[start] == '/' && uri[start + 1] == '/') {
+ pos2 = start + 2;
+ while (pos2 < len) {
+ if (uri[pos2] == '/') break;
+ if (uri[pos2] == '?') break;
+ if (uri[pos2] == '#') break;
+ pos2++;
+ }
+ std::memcpy(auth_, &uri[start], (pos2 - start) * sizeof(Ch));
+ auth_[pos2 - start] = '\0';
+ start = pos2;
+ }
+ // Look for path ([^?#]*)
+ // Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
+ path_ = auth_ + GetAuthStringLength();
+ path_++;
+ *path_ = '\0';
+ if (start < len) {
+ pos2 = start;
+ while (pos2 < len) {
+ if (uri[pos2] == '?') break;
+ if (uri[pos2] == '#') break;
+ pos2++;
+ }
+ if (start != pos2) {
+ std::memcpy(path_, &uri[start], (pos2 - start) * sizeof(Ch));
+ path_[pos2 - start] = '\0';
+ if (path_[0] == '/')
+ RemoveDotSegments(); // absolute path - normalize
+ start = pos2;
+ }
+ }
+ // Look for query (\?([^#]*))?
+ // Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
+ query_ = path_ + GetPathStringLength();
+ query_++;
+ *query_ = '\0';
+ if (start < len && uri[start] == '?') {
+ pos2 = start + 1;
+ while (pos2 < len) {
+ if (uri[pos2] == '#') break;
+ pos2++;
+ }
+ if (start != pos2) {
+ std::memcpy(query_, &uri[start], (pos2 - start) * sizeof(Ch));
+ query_[pos2 - start] = '\0';
+ start = pos2;
+ }
+ }
+ // Look for fragment (#(.*))?
+ // Note need to set, increment, assign in 3 stages to avoid compiler warning bug.
+ frag_ = query_ + GetQueryStringLength();
+ frag_++;
+ *frag_ = '\0';
+ if (start < len && uri[start] == '#') {
+ std::memcpy(frag_, &uri[start], (len - start) * sizeof(Ch));
+ frag_[len - start] = '\0';
+ }
+
+ // Re-constitute base_ and uri_
+ base_ = frag_ + GetFragStringLength() + 1;
+ SetBase();
+ uri_ = base_ + GetBaseStringLength() + 1;
+ SetUri();
+ }
+
+ // Reconstitute base
+ void SetBase() {
+ Ch* next = base_;
+ std::memcpy(next, scheme_, GetSchemeStringLength() * sizeof(Ch));
+ next+= GetSchemeStringLength();
+ std::memcpy(next, auth_, GetAuthStringLength() * sizeof(Ch));
+ next+= GetAuthStringLength();
+ std::memcpy(next, path_, GetPathStringLength() * sizeof(Ch));
+ next+= GetPathStringLength();
+ std::memcpy(next, query_, GetQueryStringLength() * sizeof(Ch));
+ next+= GetQueryStringLength();
+ *next = '\0';
+ }
+
+ // Reconstitute uri
+ void SetUri() {
+ Ch* next = uri_;
+ std::memcpy(next, base_, GetBaseStringLength() * sizeof(Ch));
+ next+= GetBaseStringLength();
+ std::memcpy(next, frag_, GetFragStringLength() * sizeof(Ch));
+ next+= GetFragStringLength();
+ *next = '\0';
+ }
+
+ // Copy a part from one GenericUri to another
+ // Return the pointer to the next part to be copied to
+ Ch* CopyPart(Ch* to, Ch* from, std::size_t len) {
+ RAPIDJSON_ASSERT(to != 0);
+ RAPIDJSON_ASSERT(from != 0);
+ std::memcpy(to, from, len * sizeof(Ch));
+ to[len] = '\0';
+ Ch* next = to + len + 1;
+ return next;
+ }
+
+ // Remove . and .. segments from the path_ member.
+ // https://tools.ietf.org/html/rfc3986
+ // This is done in place as we are only removing segments.
+ void RemoveDotSegments() {
+ std::size_t pathlen = GetPathStringLength();
+ std::size_t pathpos = 0; // Position in path_
+ std::size_t newpos = 0; // Position in new path_
+
+ // Loop through each segment in original path_
+ while (pathpos < pathlen) {
+ // Get next segment, bounded by '/' or end
+ size_t slashpos = 0;
+ while ((pathpos + slashpos) < pathlen) {
+ if (path_[pathpos + slashpos] == '/') break;
+ slashpos++;
+ }
+ // Check for .. and . segments
+ if (slashpos == 2 && path_[pathpos] == '.' && path_[pathpos + 1] == '.') {
+ // Backup a .. segment in the new path_
+ // We expect to find a previously added slash at the end or nothing
+ RAPIDJSON_ASSERT(newpos == 0 || path_[newpos - 1] == '/');
+ size_t lastslashpos = newpos;
+ // Make sure we don't go beyond the start segment
+ if (lastslashpos > 1) {
+ // Find the next to last slash and back up to it
+ lastslashpos--;
+ while (lastslashpos > 0) {
+ if (path_[lastslashpos - 1] == '/') break;
+ lastslashpos--;
+ }
+ // Set the new path_ position
+ newpos = lastslashpos;
+ }
+ } else if (slashpos == 1 && path_[pathpos] == '.') {
+ // Discard . segment, leaves new path_ unchanged
+ } else {
+ // Move any other kind of segment to the new path_
+ RAPIDJSON_ASSERT(newpos <= pathpos);
+ std::memmove(&path_[newpos], &path_[pathpos], slashpos * sizeof(Ch));
+ newpos += slashpos;
+ // Add slash if not at end
+ if ((pathpos + slashpos) < pathlen) {
+ path_[newpos] = '/';
+ newpos++;
+ }
+ }
+ // Move to next segment
+ pathpos += slashpos + 1;
+ }
+ path_[newpos] = '\0';
+ }
+
+ Ch* uri_; // Everything
+ Ch* base_; // Everything except fragment
+ Ch* scheme_; // Includes the :
+ Ch* auth_; // Includes the //
+ Ch* path_; // Absolute if starts with /
+ Ch* query_; // Includes the ?
+ Ch* frag_; // Includes the #
+
+ Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_.
+ Allocator* ownAllocator_; //!< Allocator owned by this Uri.
+};
+
+//! GenericUri for Value (UTF-8, default allocator).
+typedef GenericUri<Value> Uri;
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_URI_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/writer.h b/3rdparty/rapidjson/include/rapidjson/writer.h
index 94f22dd5fce..8b389219ab9 100644
--- a/3rdparty/rapidjson/include/rapidjson/writer.h
+++ b/3rdparty/rapidjson/include/rapidjson/writer.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -16,6 +16,8 @@
#define RAPIDJSON_WRITER_H_
#include "stream.h"
+#include "internal/clzll.h"
+#include "internal/meta.h"
#include "internal/stack.h"
#include "internal/strfunc.h"
#include "internal/dtoa.h"
@@ -31,17 +33,18 @@
#include <nmmintrin.h>
#elif defined(RAPIDJSON_SSE2)
#include <emmintrin.h>
-#endif
-
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+#elif defined(RAPIDJSON_NEON)
+#include <arm_neon.h>
#endif
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(unreachable-code)
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
#endif
RAPIDJSON_NAMESPACE_BEGIN
@@ -103,6 +106,13 @@ public:
Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ Writer(Writer&& rhs) :
+ os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
+ rhs.os_ = 0;
+ }
+#endif
+
//! Reset the writer with a new stream.
/*!
This function reset the writer with a new stream and default settings,
@@ -184,12 +194,14 @@ public:
bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
+ RAPIDJSON_ASSERT(str != 0);
(void)copy;
Prefix(kNumberType);
return EndValue(WriteString(str, length));
}
bool String(const Ch* str, SizeType length, bool copy = false) {
+ RAPIDJSON_ASSERT(str != 0);
(void)copy;
Prefix(kStringType);
return EndValue(WriteString(str, length));
@@ -209,10 +221,18 @@ public:
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
+#if RAPIDJSON_HAS_STDSTRING
+ bool Key(const std::basic_string<Ch>& str)
+ {
+ return Key(str.data(), SizeType(str.size()));
+ }
+#endif
+
bool EndObject(SizeType memberCount = 0) {
(void)memberCount;
- RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
- RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
+ RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object
+ RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value
level_stack_.template Pop<Level>(1);
return EndValue(WriteEndObject());
}
@@ -236,9 +256,9 @@ public:
//@{
//! Simpler but slower overload.
- bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
- bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
-
+ bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); }
+ bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); }
+
//@}
//! Write a raw JSON value.
@@ -249,7 +269,21 @@ public:
\param length Length of the json.
\param type Type of the root of json.
*/
- bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); }
+ bool RawValue(const Ch* json, size_t length, Type type) {
+ RAPIDJSON_ASSERT(json != 0);
+ Prefix(type);
+ return EndValue(WriteRawValue(json, length));
+ }
+
+ //! Flush the output stream.
+ /*!
+ Allows the user to flush the output stream immediately.
+ */
+ void Flush() {
+ os_->Flush();
+ }
+
+ static const size_t kDefaultLevelDepth = 32;
protected:
//! Information for each nested level
@@ -259,8 +293,6 @@ protected:
bool inArray; //!< true if in array, otherwise in object
};
- static const size_t kDefaultLevelDepth = 32;
-
bool WriteNull() {
PutReserve(*os_, 4);
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
@@ -283,7 +315,7 @@ protected:
const char* end = internal::i32toa(i, buffer);
PutReserve(*os_, static_cast<size_t>(end - buffer));
for (const char* p = buffer; p != end; ++p)
- PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
return true;
}
@@ -292,7 +324,7 @@ protected:
const char* end = internal::u32toa(u, buffer);
PutReserve(*os_, static_cast<size_t>(end - buffer));
for (const char* p = buffer; p != end; ++p)
- PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
return true;
}
@@ -301,7 +333,7 @@ protected:
const char* end = internal::i64toa(i64, buffer);
PutReserve(*os_, static_cast<size_t>(end - buffer));
for (const char* p = buffer; p != end; ++p)
- PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
return true;
}
@@ -310,7 +342,7 @@ protected:
char* end = internal::u64toa(u64, buffer);
PutReserve(*os_, static_cast<size_t>(end - buffer));
for (char* p = buffer; p != end; ++p)
- PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
return true;
}
@@ -338,12 +370,12 @@ protected:
char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
PutReserve(*os_, static_cast<size_t>(end - buffer));
for (char* p = buffer; p != end; ++p)
- PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
return true;
}
bool WriteString(const Ch* str, SizeType length) {
- static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
static const char escape[256] = {
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
//0 1 2 3 4 5 6 7 8 9 A B C D E F
@@ -399,7 +431,7 @@ protected:
else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
is.Take();
PutUnsafe(*os_, '\\');
- PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
+ PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)]));
if (escape[static_cast<unsigned char>(c)] == 'u') {
PutUnsafe(*os_, '0');
PutUnsafe(*os_, '0');
@@ -427,9 +459,13 @@ protected:
bool WriteRawValue(const Ch* json, size_t length) {
PutReserve(*os_, length);
- for (size_t i = 0; i < length; i++) {
- RAPIDJSON_ASSERT(json[i] != '\0');
- PutUnsafe(*os_, json[i]);
+ GenericStringStream<SourceEncoding> is(json);
+ while (RAPIDJSON_LIKELY(is.Tell() < length)) {
+ RAPIDJSON_ASSERT(is.Peek() != '\0');
+ if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
+ Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
+ Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
+ return false;
}
return true;
}
@@ -457,7 +493,7 @@ protected:
// Flush the value if it is the top level one.
bool EndValue(bool ret) {
if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
- os_->Flush();
+ Flush();
return ret;
}
@@ -561,7 +597,7 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
// The rest of string using SIMD
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
- static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+ static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
@@ -570,7 +606,7 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
- const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
@@ -595,15 +631,79 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
is.src_ = p;
return RAPIDJSON_LIKELY(is.Tell() < length);
}
-#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+#elif defined(RAPIDJSON_NEON)
+template<>
+inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
+ if (length < 16)
+ return RAPIDJSON_LIKELY(is.Tell() < length);
-RAPIDJSON_NAMESPACE_END
+ if (!RAPIDJSON_LIKELY(is.Tell() < length))
+ return false;
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_POP
-#endif
+ const char* p = is.src_;
+ const char* end = is.head_ + length;
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
+ if (nextAligned > end)
+ return true;
-#ifdef __clang__
+ while (p != nextAligned)
+ if (*p < 0x20 || *p == '\"' || *p == '\\') {
+ is.src_ = p;
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+ }
+ else
+ os_->PutUnsafe(*p++);
+
+ // The rest of string using SIMD
+ const uint8x16_t s0 = vmovq_n_u8('"');
+ const uint8x16_t s1 = vmovq_n_u8('\\');
+ const uint8x16_t s2 = vmovq_n_u8('\b');
+ const uint8x16_t s3 = vmovq_n_u8(32);
+
+ for (; p != endAligned; p += 16) {
+ const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
+ uint8x16_t x = vceqq_u8(s, s0);
+ x = vorrq_u8(x, vceqq_u8(s, s1));
+ x = vorrq_u8(x, vceqq_u8(s, s2));
+ x = vorrq_u8(x, vcltq_u8(s, s3));
+
+ x = vrev64q_u8(x); // Rev in 64
+ uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
+ uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
+
+ SizeType len = 0;
+ bool escaped = false;
+ if (low == 0) {
+ if (high != 0) {
+ uint32_t lz = internal::clzll(high);
+ len = 8 + (lz >> 3);
+ escaped = true;
+ }
+ } else {
+ uint32_t lz = internal::clzll(low);
+ len = lz >> 3;
+ escaped = true;
+ }
+ if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
+ char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
+ for (size_t i = 0; i < len; i++)
+ q[i] = p[i];
+
+ p += len;
+ break;
+ }
+ vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s);
+ }
+
+ is.src_ = p;
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+}
+#endif // RAPIDJSON_NEON
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(_MSC_VER) || defined(__clang__)
RAPIDJSON_DIAG_POP
#endif
diff --git a/3rdparty/rapidjson/library.json b/3rdparty/rapidjson/library.json
index b59dabbc3d8..2210fcd6173 100644
--- a/3rdparty/rapidjson/library.json
+++ b/3rdparty/rapidjson/library.json
@@ -1,12 +1,15 @@
-{
- "name": "RapidJSON",
- "keywords": "json, sax, dom, parser, generator",
- "description": "A fast JSON parser/generator for C++ with both SAX/DOM style API",
- "include": "include",
- "examples": "example/*/*.cpp",
- "repository":
- {
- "type": "git",
- "url": "https://github.com/miloyip/rapidjson"
- }
-}
+{
+ "name": "RapidJSON",
+ "version": "1.1.0",
+ "keywords": "json, sax, dom, parser, generator",
+ "description": "A fast JSON parser/generator for C++ with both SAX/DOM style API",
+ "export": {
+ "include": "include"
+ },
+ "examples": "example/*/*.cpp",
+ "repository":
+ {
+ "type": "git",
+ "url": "https://github.com/Tencent/rapidjson"
+ }
+}
diff --git a/3rdparty/rapidjson/package.json b/3rdparty/rapidjson/package.json
index cc6087a5ca3..129581a6335 100644
--- a/3rdparty/rapidjson/package.json
+++ b/3rdparty/rapidjson/package.json
@@ -13,12 +13,12 @@
},
"repository": {
"type": "git",
- "url": "git+https://github.com/miloyip/rapidjson.git"
+ "url": "git+https://github.com/Tencent/rapidjson.git"
},
"author": "",
"license": "ISC",
"bugs": {
- "url": "https://github.com/miloyip/rapidjson/issues"
+ "url": "https://github.com/Tencent/rapidjson/issues"
},
- "homepage": "https://github.com/miloyip/rapidjson#readme"
+ "homepage": "https://github.com/Tencent/rapidjson#readme"
}
diff --git a/3rdparty/rapidjson/rapidjson.autopkg b/3rdparty/rapidjson/rapidjson.autopkg
index 70eb0d8a003..fe72030a9a4 100644
--- a/3rdparty/rapidjson/rapidjson.autopkg
+++ b/3rdparty/rapidjson/rapidjson.autopkg
@@ -5,10 +5,10 @@ nuget {
id = rapidjson;
version : ${MYVERSION};
title: "rapidjson";
- authors: {"https://github.com/miloyip/rapidjson/releases/tag/v1.1.0"};
+ authors: {"https://github.com/Tencent/rapidjson/releases/tag/v1.1.0"};
owners: {"@lsantos (github)"};
- licenseUrl: "https://github.com/miloyip/rapidjson/blob/master/license.txt";
- projectUrl: "https://github.com/miloyip/rapidjson/";
+ licenseUrl: "https://github.com/Tencent/rapidjson/blob/master/license.txt";
+ projectUrl: "https://github.com/Tencent/rapidjson/";
iconUrl: "https://cdn1.iconfinder.com/data/icons/fatcow/32x32/json.png";
requireLicenseAcceptance:false;
summary: @"A fast JSON parser/generator for C++ with both SAX/DOM style API";
@@ -48,7 +48,7 @@ Changed
dependencies {
packages : {
- //TODO: Add dependecies here in [pkg.name]/[version] form per newline
+ //TODO: Add dependencies here in [pkg.name]/[version] form per newline
//zlib/[1.2.8],
};
}
@@ -71,5 +71,7 @@ Changed
targets {
// We're trying to be standard about these sorts of thing. (Will help with config.h later :D)
//Defines += HAS_EQCORE;
+ // Fix creating the package with Raggles' fork of CoApp
+ Includes += "$(MSBuildThisFileDirectory)../..${d_include}";
};
} \ No newline at end of file
diff --git a/3rdparty/rapidjson/readme.md b/3rdparty/rapidjson/readme.md
index 4a1d64d0ade..ac683b05148 100644
--- a/3rdparty/rapidjson/readme.md
+++ b/3rdparty/rapidjson/readme.md
@@ -1,14 +1,14 @@
-![](doc/logo/rapidjson.png)
+![RapidJSON logo](doc/logo/rapidjson.png)
-![](https://img.shields.io/badge/release-v1.1.0-blue.png)
+![Release version](https://img.shields.io/badge/release-v1.1.0-blue.svg)
-## A fast JSON parser/generator for C++ with both SAX/DOM style API
+## A fast JSON parser/generator for C++ with both SAX/DOM style API
Tencent is pleased to support the open source community by making RapidJSON available.
-Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
-* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/)
+* [RapidJSON GitHub](https://github.com/Tencent/rapidjson/)
* RapidJSON Documentation
* [English](http://rapidjson.org/)
* [简体中文](http://rapidjson.org/zh-cn/)
@@ -20,12 +20,12 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
| :---------------: | :-----------------: | :-------------------: |
| ![lin-badge] | ![win-badge] | ![cov-badge] |
-[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status"
-[lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status"
-[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status"
-[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status"
-[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master
-[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master
+[lin-badge]: https://travis-ci.org/Tencent/rapidjson.svg?branch=master "Travis build status"
+[lin-link]: https://travis-ci.org/Tencent/rapidjson "Travis build status"
+[win-badge]: https://ci.appveyor.com/api/projects/status/l6qulgqahcayidrf/branch/master?svg=true "AppVeyor build status"
+[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson-0fdqj/branch/master "AppVeyor build status"
+[cov-badge]: https://coveralls.io/repos/Tencent/rapidjson/badge.svg?branch=master "Coveralls coverage"
+[cov-link]: https://coveralls.io/r/Tencent/rapidjson?branch=master "Coveralls coverage"
## Introduction
@@ -43,10 +43,10 @@ RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](
More features can be read [here](doc/features.md).
-JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at
+JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in full compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at
* [Introducing JSON](http://json.org/)
-* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](http://www.ietf.org/rfc/rfc7159.txt)
-* [Standard ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/standards/Ecma-404.htm)
+* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159)
+* [Standard ECMA-404: The JSON Data Interchange Format](https://www.ecma-international.org/publications/standards/Ecma-404.htm)
## Highlights in v1.1 (2016-8-25)
@@ -72,10 +72,13 @@ Users can build and run the unit tests on their platform/compiler.
RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder to system or project's include path.
+Alternatively, if you are using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager you can download and install rapidjson with CMake integration in a single command:
+* vcpkg install rapidjson
+
RapidJSON uses following software as its dependencies:
* [CMake](https://cmake.org/) as a general build tool
-* (optional)[Doxygen](http://www.doxygen.org) to build documentation
-* (optional)[googletest](https://github.com/google/googletest) for unit and performance testing
+* (optional) [Doxygen](http://www.doxygen.org) to build documentation
+* (optional) [googletest](https://github.com/google/googletest) for unit and performance testing
To generate user documentation and run tests please proceed with the steps below:
@@ -84,7 +87,7 @@ To generate user documentation and run tests please proceed with the steps below
3. Change to `build` directory and run `cmake ..` command to configure your build. Windows users can do the same with cmake-gui application.
4. On Windows, build the solution found in the build directory. On Linux, run `make` from the build directory.
-On successfull build you will find compiled test and example binaries in `bin`
+On successful build you will find compiled test and example binaries in `bin`
directory. The generated documentation will be available in `doc/html`
directory of the build tree. To run tests after finished build please run `make
test` or `ctest` from your build tree. You can get detailed output using `ctest
@@ -136,25 +139,72 @@ The following diagram shows the process.
![simpledom](doc/diagram/simpledom.png)
-More [examples](https://github.com/miloyip/rapidjson/tree/master/example) are available:
+More [examples](https://github.com/Tencent/rapidjson/tree/master/example) are available:
* DOM API
- * [tutorial](https://github.com/miloyip/rapidjson/blob/master/example/tutorial/tutorial.cpp): Basic usage of DOM API.
+ * [tutorial](https://github.com/Tencent/rapidjson/blob/master/example/tutorial/tutorial.cpp): Basic usage of DOM API.
* SAX API
- * [simplereader](https://github.com/miloyip/rapidjson/blob/master/example/simplereader/simplereader.cpp): Dumps all SAX events while parsing a JSON by `Reader`.
- * [condense](https://github.com/miloyip/rapidjson/blob/master/example/condense/condense.cpp): A command line tool to rewrite a JSON, with all whitespaces removed.
- * [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp): A command line tool to rewrite a JSON with indents and newlines by `PrettyWriter`.
- * [capitalize](https://github.com/miloyip/rapidjson/blob/master/example/capitalize/capitalize.cpp): A command line tool to capitalize strings in JSON.
- * [messagereader](https://github.com/miloyip/rapidjson/blob/master/example/messagereader/messagereader.cpp): Parse a JSON message with SAX API.
- * [serialize](https://github.com/miloyip/rapidjson/blob/master/example/serialize/serialize.cpp): Serialize a C++ object into JSON with SAX API.
- * [jsonx](https://github.com/miloyip/rapidjson/blob/master/example/jsonx/jsonx.cpp): Implements a `JsonxWriter` which stringify SAX events into [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html) (a kind of XML) format. The example is a command line tool which converts input JSON into JSONx format.
+ * [simplereader](https://github.com/Tencent/rapidjson/blob/master/example/simplereader/simplereader.cpp): Dumps all SAX events while parsing a JSON by `Reader`.
+ * [condense](https://github.com/Tencent/rapidjson/blob/master/example/condense/condense.cpp): A command line tool to rewrite a JSON, with all whitespaces removed.
+ * [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp): A command line tool to rewrite a JSON with indents and newlines by `PrettyWriter`.
+ * [capitalize](https://github.com/Tencent/rapidjson/blob/master/example/capitalize/capitalize.cpp): A command line tool to capitalize strings in JSON.
+ * [messagereader](https://github.com/Tencent/rapidjson/blob/master/example/messagereader/messagereader.cpp): Parse a JSON message with SAX API.
+ * [serialize](https://github.com/Tencent/rapidjson/blob/master/example/serialize/serialize.cpp): Serialize a C++ object into JSON with SAX API.
+ * [jsonx](https://github.com/Tencent/rapidjson/blob/master/example/jsonx/jsonx.cpp): Implements a `JsonxWriter` which stringify SAX events into [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html) (a kind of XML) format. The example is a command line tool which converts input JSON into JSONx format.
* Schema
- * [schemavalidator](https://github.com/miloyip/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp) : A command line tool to validate a JSON with a JSON schema.
-
+ * [schemavalidator](https://github.com/Tencent/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp) : A command line tool to validate a JSON with a JSON schema.
+
* Advanced
- * [prettyauto](https://github.com/miloyip/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): A modified version of [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp) to automatically handle JSON with any UTF encodings.
- * [parsebyparts](https://github.com/miloyip/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread.
- * [filterkey](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key.
- * [filterkeydom](https://github.com/miloyip/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`.
+ * [prettyauto](https://github.com/Tencent/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): A modified version of [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp) to automatically handle JSON with any UTF encodings.
+ * [parsebyparts](https://github.com/Tencent/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread.
+ * [filterkey](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key.
+ * [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`.
+
+## Contributing
+
+RapidJSON welcomes contributions. When contributing, please follow the code below.
+
+### Issues
+
+Feel free to submit issues and enhancement requests.
+
+Please help us by providing **minimal reproducible examples**, because source code is easier to let other people understand what happens.
+For crash problems on certain platforms, please bring stack dump content with the detail of the OS, compiler, etc.
+
+Please try breakpoint debugging first, tell us what you found, see if we can start exploring based on more information been prepared.
+
+### Workflow
+
+In general, we follow the "fork-and-pull" Git workflow.
+
+ 1. **Fork** the repo on GitHub
+ 2. **Clone** the project to your own machine
+ 3. **Checkout** a new branch on your fork, start developing on the branch
+ 4. **Test** the change before commit, Make sure the changes pass all the tests, including `unittest` and `preftest`, please add test case for each new feature or bug-fix if needed.
+ 5. **Commit** changes to your own branch
+ 6. **Push** your work back up to your fork
+ 7. Submit a **Pull request** so that we can review your changes
+
+NOTE: Be sure to merge the latest from "upstream" before making a pull request!
+
+### Copyright and Licensing
+
+You can copy and paste the license summary from below.
+
+```
+Tencent is pleased to support the open source community by making RapidJSON available.
+
+Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
+
+Licensed under the MIT License (the "License"); you may not use this file except
+in compliance with the License. You may obtain a copy of the License at
+
+http://opensource.org/licenses/MIT
+
+Unless required by applicable law or agreed to in writing, software distributed
+under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+CONDITIONS OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.
+```
diff --git a/3rdparty/rapidjson/readme.zh-cn.md b/3rdparty/rapidjson/readme.zh-cn.md
index b62b2e13252..216802e1b37 100644
--- a/3rdparty/rapidjson/readme.zh-cn.md
+++ b/3rdparty/rapidjson/readme.zh-cn.md
@@ -1,18 +1,18 @@
-![](doc/logo/rapidjson.png)
+![RapidJSON logo](doc/logo/rapidjson.png)
-![](https://img.shields.io/badge/release-v1.1.0-blue.png)
+![Release version](https://img.shields.io/badge/release-v1.1.0-blue.svg)
## 高效的 C++ JSON è§£æžï¼ç”Ÿæˆå™¨ï¼Œæä¾› SAX åŠ DOM 风格 API
Tencent is pleased to support the open source community by making RapidJSON available.
-Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
-* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/)
+* [RapidJSON GitHub](https://github.com/Tencent/rapidjson/)
* RapidJSON 文档
* [English](http://rapidjson.org/)
* [简体中文](http://rapidjson.org/zh-cn/)
- * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) å¯ä¸‹è½½ PDF/EPUB/MOBI,但ä¸å« API å‚考手册。
+ * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/details/zh-cn) å¯ä¸‹è½½ PDF/EPUB/MOBI,但ä¸å« API å‚考手册。
## Build 状æ€
@@ -20,12 +20,12 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights
| :---------------: | :-----------------: | :-------------------: |
| ![lin-badge] | ![win-badge] | ![cov-badge] |
-[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status"
-[lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status"
-[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status"
-[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status"
-[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master
-[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master
+[lin-badge]: https://travis-ci.org/Tencent/rapidjson.svg?branch=master "Travis build status"
+[lin-link]: https://travis-ci.org/Tencent/rapidjson "Travis build status"
+[win-badge]: https://ci.appveyor.com/api/projects/status/l6qulgqahcayidrf/branch/master?svg=true "AppVeyor build status"
+[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson-0fdqj/branch/master "AppVeyor build status"
+[cov-badge]: https://coveralls.io/repos/Tencent/rapidjson/badge.svg?branch=master "Coveralls coverage"
+[cov-link]: https://coveralls.io/r/Tencent/rapidjson?branch=master "Coveralls coverage"
## 简介
@@ -45,8 +45,8 @@ RapidJSON 是一个 C++ çš„ JSON è§£æžå™¨åŠç”Ÿæˆå™¨ã€‚å®ƒçš„çµæ„Ÿæ¥è‡ª [Rap
JSON(JavaScript Object Notation)是一个轻é‡çš„æ•°æ®äº¤æ¢æ ¼å¼ã€‚RapidJSON 应该完全éµä»Ž RFC7159/ECMA-404,并支æŒå¯é€‰çš„æ”¾å®½è¯­æ³•。 关于 JSON 的更多信æ¯å¯å‚考:
* [Introducing JSON](http://json.org/)
-* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](http://www.ietf.org/rfc/rfc7159.txt)
-* [Standard ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/standards/Ecma-404.htm)
+* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159)
+* [Standard ECMA-404: The JSON Data Interchange Format](https://www.ecma-international.org/publications/standards/Ecma-404.htm)
## v1.1 中的亮点 (2016-8-25)
@@ -73,9 +73,9 @@ RapidJSON 是跨平å°çš„。以下是一些曾测试的平å°ï¼ç¼–译器组åˆï
RapidJSON æ˜¯åªæœ‰å¤´æ–‡ä»¶çš„ C++ 库。åªéœ€æŠŠ `include/rapidjson` 目录å¤åˆ¶è‡³ç³»ç»Ÿæˆ–项目的 include 目录中。
RapidJSON ä¾èµ–于以下软件:
-* [CMake](http://www.cmake.org) 作为通用生æˆå·¥å…·
-* (optional)[Doxygen](http://www.doxygen.org) ç”¨äºŽç”Ÿæˆæ–‡æ¡£
-* (optional)[googletest](https://code.google.com/p/googletest/) 用于å•å…ƒåŠæ€§èƒ½æµ‹è¯•
+* [CMake](https://cmake.org/) 作为通用生æˆå·¥å…·
+* (optional) [Doxygen](http://www.doxygen.org) ç”¨äºŽç”Ÿæˆæ–‡æ¡£
+* (optional) [googletest](https://github.com/google/googletest) 用于å•å…ƒåŠæ€§èƒ½æµ‹è¯•
ç”Ÿæˆæµ‹è¯•åŠä¾‹å­çš„æ­¥éª¤ï¼š
@@ -128,25 +128,25 @@ int main() {
![simpledom](doc/diagram/simpledom.png)
-还有许多 [例å­](https://github.com/miloyip/rapidjson/tree/master/example) å¯ä¾›å‚考:
+还有许多 [例å­](https://github.com/Tencent/rapidjson/tree/master/example) å¯ä¾›å‚考:
* DOM API
- * [tutorial](https://github.com/miloyip/rapidjson/blob/master/example/tutorial/tutorial.cpp): DOM API 的基本使用方法。
+ * [tutorial](https://github.com/Tencent/rapidjson/blob/master/example/tutorial/tutorial.cpp): DOM API 的基本使用方法。
* SAX API
- * [simplereader](https://github.com/miloyip/rapidjson/blob/master/example/simplereader/simplereader.cpp): 使用 `Reader` è§£æž JSON æ—¶ï¼Œæ‰“å°æ‰€æœ‰ SAX 事件。
- * [condense](https://github.com/miloyip/rapidjson/blob/master/example/condense/condense.cpp): 移除 JSON 中所有空白符的命令行工具。
- * [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp): 为 JSON 加入缩进与æ¢è¡Œçš„命令行工具,当中使用了 `PrettyWriter`。
- * [capitalize](https://github.com/miloyip/rapidjson/blob/master/example/capitalize/capitalize.cpp): 把 JSON 中所有字符串改为大写的命令行工具。
- * [messagereader](https://github.com/miloyip/rapidjson/blob/master/example/messagereader/messagereader.cpp): 使用 SAX API 去解æžä¸€ä¸ª JSON 报文。
- * [serialize](https://github.com/miloyip/rapidjson/blob/master/example/serialize/serialize.cpp): 使用 SAX API 去åºåˆ—化 C++ å¯¹è±¡ï¼Œç”Ÿæˆ JSON。
- * [jsonx](https://github.com/miloyip/rapidjson/blob/master/example/jsonx/jsonx.cpp): 实现了一个 `JsonxWriter`,它能把 SAX äº‹ä»¶å†™æˆ [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html)ï¼ˆä¸€ç§ XML)格å¼ã€‚è¿™ä¸ªä¾‹å­æ˜¯æŠŠ JSON è¾“å…¥è½¬æ¢æˆ JSONx æ ¼å¼çš„命令行工具。
+ * [simplereader](https://github.com/Tencent/rapidjson/blob/master/example/simplereader/simplereader.cpp): 使用 `Reader` è§£æž JSON æ—¶ï¼Œæ‰“å°æ‰€æœ‰ SAX 事件。
+ * [condense](https://github.com/Tencent/rapidjson/blob/master/example/condense/condense.cpp): 移除 JSON 中所有空白符的命令行工具。
+ * [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp): 为 JSON 加入缩进与æ¢è¡Œçš„命令行工具,当中使用了 `PrettyWriter`。
+ * [capitalize](https://github.com/Tencent/rapidjson/blob/master/example/capitalize/capitalize.cpp): 把 JSON 中所有字符串改为大写的命令行工具。
+ * [messagereader](https://github.com/Tencent/rapidjson/blob/master/example/messagereader/messagereader.cpp): 使用 SAX API 去解æžä¸€ä¸ª JSON 报文。
+ * [serialize](https://github.com/Tencent/rapidjson/blob/master/example/serialize/serialize.cpp): 使用 SAX API 去åºåˆ—化 C++ å¯¹è±¡ï¼Œç”Ÿæˆ JSON。
+ * [jsonx](https://github.com/Tencent/rapidjson/blob/master/example/jsonx/jsonx.cpp): 实现了一个 `JsonxWriter`,它能把 SAX äº‹ä»¶å†™æˆ [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html)ï¼ˆä¸€ç§ XML)格å¼ã€‚è¿™ä¸ªä¾‹å­æ˜¯æŠŠ JSON è¾“å…¥è½¬æ¢æˆ JSONx æ ¼å¼çš„命令行工具。
* Schema API
- * [schemavalidator](https://github.com/miloyip/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp): 使用 JSON Schema 去校验 JSON 的命令行工具。
-
+ * [schemavalidator](https://github.com/Tencent/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp): 使用 JSON Schema 去校验 JSON 的命令行工具。
+
* 进阶
- * [prettyauto](https://github.com/miloyip/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp) 的修改版本,å¯è‡ªåЍ处ç†ä»»ä½• UTF ç¼–ç çš„ JSON。
- * [parsebyparts](https://github.com/miloyip/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): 这例å­ä¸­çš„ `AsyncDocumentParser` 类使用 C++ 线程æ¥é€æ®µè§£æž JSON。
- * [filterkey](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): ç§»å–使用者指定的键值的命令行工具。
- * [filterkeydom](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): 如上的工具,但展示如何使用生æˆå™¨ï¼ˆgenerator)去填充一个 `Document`。 \ No newline at end of file
+ * [prettyauto](https://github.com/Tencent/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp) 的修改版本,å¯è‡ªåЍ处ç†ä»»ä½• UTF ç¼–ç çš„ JSON。
+ * [parsebyparts](https://github.com/Tencent/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): 这例å­ä¸­çš„ `AsyncDocumentParser` 类使用 C++ 线程æ¥é€æ®µè§£æž JSON。
+ * [filterkey](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): ç§»å–使用者指定的键值的命令行工具。
+ * [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): 如上的工具,但展示如何使用生æˆå™¨ï¼ˆgenerator)去填充一个 `Document`。
diff --git a/3rdparty/rapidjson/test/perftest/CMakeLists.txt b/3rdparty/rapidjson/test/perftest/CMakeLists.txt
index c33aae469a3..035e544d919 100644
--- a/3rdparty/rapidjson/test/perftest/CMakeLists.txt
+++ b/3rdparty/rapidjson/test/perftest/CMakeLists.txt
@@ -19,6 +19,8 @@ if(CCACHE_FOUND)
endif()
endif(CCACHE_FOUND)
+set_property(DIRECTORY PROPERTY COMPILE_OPTIONS ${EXTRA_CXX_FLAGS})
+
IF(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug"))
add_test(NAME perftest
COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/perftest
diff --git a/3rdparty/rapidjson/test/perftest/misctest.cpp b/3rdparty/rapidjson/test/perftest/misctest.cpp
index aac84778429..f43b050181e 100644
--- a/3rdparty/rapidjson/test/perftest/misctest.cpp
+++ b/3rdparty/rapidjson/test/perftest/misctest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -432,7 +432,7 @@ bool Writer1<rapidjson::StringBuffer>::WriteUint(unsigned u) {
return true;
}
-// Using digits LUT to reduce divsion/modulo
+// Using digits LUT to reduce division/modulo
template<typename OutputStream>
class Writer2 {
public:
@@ -616,7 +616,7 @@ inline bool Writer3<rapidjson::InsituStringStream>::WriteUint64(uint64_t u) {
return true;
}
-// Using digits LUT to reduce divsion/modulo, two passes
+// Using digits LUT to reduce division/modulo, two passes
template<typename OutputStream>
class Writer4 {
public:
diff --git a/3rdparty/rapidjson/test/perftest/perftest.cpp b/3rdparty/rapidjson/test/perftest/perftest.cpp
index 4e79f1f5180..b149a4c12c8 100644
--- a/3rdparty/rapidjson/test/perftest/perftest.cpp
+++ b/3rdparty/rapidjson/test/perftest/perftest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
diff --git a/3rdparty/rapidjson/test/perftest/perftest.h b/3rdparty/rapidjson/test/perftest/perftest.h
index b098e414720..31e3ca63370 100644
--- a/3rdparty/rapidjson/test/perftest/perftest.h
+++ b/3rdparty/rapidjson/test/perftest/perftest.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -24,10 +24,13 @@
// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
+// Likewise, __ARM_NEON is used to detect Neon.
#if defined(__SSE4_2__)
# define RAPIDJSON_SSE42
#elif defined(__SSE2__)
# define RAPIDJSON_SSE2
+#elif defined(__ARM_NEON)
+# define RAPIDJSON_NEON
#endif
#define RAPIDJSON_HAS_STDSTRING 1
@@ -127,7 +130,8 @@ public:
"integers.json",
"mixed.json",
"nulls.json",
- "paragraphs.json"
+ "paragraphs.json",
+ "alotofkeys.json"
};
for (size_t j = 0; j < sizeof(typesfilenames) / sizeof(typesfilenames[0]); j++) {
@@ -155,7 +159,7 @@ public:
free(whitespace_);
json_ = 0;
whitespace_ = 0;
- for (size_t i = 0; i < 7; i++) {
+ for (size_t i = 0; i < 8; i++) {
free(types_[i]);
types_[i] = 0;
}
@@ -171,8 +175,8 @@ protected:
size_t length_;
char *whitespace_;
size_t whitespace_length_;
- char *types_[7];
- size_t typesLength_[7];
+ char *types_[8];
+ size_t typesLength_[8];
static const size_t kTrialCount = 1000;
};
diff --git a/3rdparty/rapidjson/test/perftest/platformtest.cpp b/3rdparty/rapidjson/test/perftest/platformtest.cpp
index bb905ca73be..c490da7a85e 100644
--- a/3rdparty/rapidjson/test/perftest/platformtest.cpp
+++ b/3rdparty/rapidjson/test/perftest/platformtest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -76,7 +76,7 @@ TEST_F(Platform, strlen) {
TEST_F(Platform, memcmp) {
for (int i = 0; i < kTrialCount; i++) {
- EXPECT_EQ(0, memcmp(temp_, json_, length_));
+ EXPECT_EQ(0u, memcmp(temp_, json_, length_));
}
}
diff --git a/3rdparty/rapidjson/test/perftest/rapidjsontest.cpp b/3rdparty/rapidjson/test/perftest/rapidjsontest.cpp
index 675db3182a5..ce41c109ab4 100644
--- a/3rdparty/rapidjson/test/perftest/rapidjsontest.cpp
+++ b/3rdparty/rapidjson/test/perftest/rapidjsontest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -21,13 +21,19 @@
#include "rapidjson/prettywriter.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/filereadstream.h"
+#include "rapidjson/istreamwrapper.h"
#include "rapidjson/encodedstream.h"
#include "rapidjson/memorystream.h"
+#include <fstream>
+#include <vector>
+
#ifdef RAPIDJSON_SSE2
#define SIMD_SUFFIX(name) name##_SSE2
#elif defined(RAPIDJSON_SSE42)
#define SIMD_SUFFIX(name) name##_SSE42
+#elif defined(RAPIDJSON_NEON)
+#define SIMD_SUFFIX(name) name##_NEON
#else
#define SIMD_SUFFIX(name) name
#endif
@@ -47,7 +53,7 @@ public:
// Parse as a document
EXPECT_FALSE(doc_.Parse(json_).HasParseError());
- for (size_t i = 0; i < 7; i++)
+ for (size_t i = 0; i < 8; i++)
EXPECT_FALSE(typesDoc_[i].Parse(types_[i]).HasParseError());
}
@@ -63,7 +69,7 @@ private:
protected:
char *temp_;
Document doc_;
- Document typesDoc_[7];
+ Document typesDoc_[8];
};
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler)) {
@@ -152,6 +158,35 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseIterativeInsitu_DummyHandler)) {
}
}
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseIterativePull_DummyHandler)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ StringStream s(json_);
+ BaseReaderHandler<> h;
+ Reader reader;
+ reader.IterativeParseInit();
+ while (!reader.IterativeParseComplete()) {
+ if (!reader.IterativeParseNext<kParseDefaultFlags>(s, h))
+ break;
+ }
+ EXPECT_FALSE(reader.HasParseError());
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseIterativePullInsitu_DummyHandler)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ memcpy(temp_, json_, length_ + 1);
+ InsituStringStream s(temp_);
+ BaseReaderHandler<> h;
+ Reader reader;
+ reader.IterativeParseInit();
+ while (!reader.IterativeParseComplete()) {
+ if (!reader.IterativeParseNext<kParseDefaultFlags|kParseInsituFlag>(s, h))
+ break;
+ }
+ EXPECT_FALSE(reader.HasParseError());
+ }
+}
+
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_ValidateEncoding)) {
for (size_t i = 0; i < kTrialCount; i++) {
StringStream s(json_);
@@ -301,6 +336,23 @@ TEST_F(RapidJson, DocumentAccept) {
}
}
+TEST_F(RapidJson, DocumentFind) {
+ typedef Document::ValueType ValueType;
+ typedef ValueType::ConstMemberIterator ConstMemberIterator;
+ const Document &doc = typesDoc_[7]; // alotofkeys.json
+ if (doc.IsObject()) {
+ std::vector<const ValueType*> keys;
+ for (ConstMemberIterator it = doc.MemberBegin(); it != doc.MemberEnd(); ++it) {
+ keys.push_back(&it->name);
+ }
+ for (size_t i = 0; i < kTrialCount; i++) {
+ for (size_t j = 0; j < keys.size(); j++) {
+ EXPECT_TRUE(doc.FindMember(*keys[j]) != doc.MemberEnd());
+ }
+ }
+ }
+}
+
struct NullStream {
typedef char Ch;
@@ -432,6 +484,77 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) {
}
}
+TEST_F(RapidJson, IStreamWrapper) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ std::ifstream is(filename_, std::ios::in | std::ios::binary);
+ char buffer[65536];
+ IStreamWrapper isw(is, buffer, sizeof(buffer));
+ while (isw.Take() != '\0')
+ ;
+ is.close();
+ }
+}
+
+TEST_F(RapidJson, IStreamWrapper_Unbuffered) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ std::ifstream is(filename_, std::ios::in | std::ios::binary);
+ IStreamWrapper isw(is);
+ while (isw.Take() != '\0')
+ ;
+ is.close();
+ }
+}
+
+TEST_F(RapidJson, IStreamWrapper_Setbuffered) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ std::ifstream is;
+ char buffer[65536];
+ is.rdbuf()->pubsetbuf(buffer, sizeof(buffer));
+ is.open(filename_, std::ios::in | std::ios::binary);
+ IStreamWrapper isw(is);
+ while (isw.Take() != '\0')
+ ;
+ is.close();
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_IStreamWrapper)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ std::ifstream is(filename_, std::ios::in | std::ios::binary);
+ char buffer[65536];
+ IStreamWrapper isw(is, buffer, sizeof(buffer));
+ BaseReaderHandler<> h;
+ Reader reader;
+ reader.Parse(isw, h);
+ is.close();
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_IStreamWrapper_Unbuffered)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ std::ifstream is(filename_, std::ios::in | std::ios::binary);
+ IStreamWrapper isw(is);
+ BaseReaderHandler<> h;
+ Reader reader;
+ reader.Parse(isw, h);
+ is.close();
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_IStreamWrapper_Setbuffered)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ std::ifstream is;
+ char buffer[65536];
+ is.rdbuf()->pubsetbuf(buffer, sizeof(buffer));
+ is.open(filename_, std::ios::in | std::ios::binary);
+ IStreamWrapper isw(is);
+ BaseReaderHandler<> h;
+ Reader reader;
+ reader.Parse(isw, h);
+ is.close();
+ }
+}
+
TEST_F(RapidJson, StringBuffer) {
StringBuffer sb;
for (int i = 0; i < 32 * 1024 * 1024; i++)
diff --git a/3rdparty/rapidjson/test/perftest/schematest.cpp b/3rdparty/rapidjson/test/perftest/schematest.cpp
index 468f5fe6f6a..7d27344b5c1 100644
--- a/3rdparty/rapidjson/test/perftest/schematest.cpp
+++ b/3rdparty/rapidjson/test/perftest/schematest.cpp
@@ -11,6 +11,11 @@
using namespace rapidjson;
+RAPIDJSON_DIAG_PUSH
+#if defined(__GNUC__) && __GNUC__ >= 7
+RAPIDJSON_DIAG_OFF(format-overflow)
+#endif
+
template <typename Allocator>
static char* ReadFile(const char* filename, Allocator& allocator) {
const char *paths[] = {
@@ -42,6 +47,8 @@ static char* ReadFile(const char* filename, Allocator& allocator) {
return json;
}
+RAPIDJSON_DIAG_POP
+
class Schema : public PerfTest {
public:
Schema() {}
diff --git a/3rdparty/rapidjson/test/unittest/CMakeLists.txt b/3rdparty/rapidjson/test/unittest/CMakeLists.txt
index b3204d6c8d6..565ed982397 100644
--- a/3rdparty/rapidjson/test/unittest/CMakeLists.txt
+++ b/3rdparty/rapidjson/test/unittest/CMakeLists.txt
@@ -3,6 +3,8 @@ include(CheckCXXCompilerFlag)
set(UNITTEST_SOURCES
allocatorstest.cpp
bigintegertest.cpp
+ clzlltest.cpp
+ cursorstreamwrappertest.cpp
documenttest.cpp
dtoatest.cpp
encodedstreamtest.cpp
@@ -14,6 +16,7 @@ set(UNITTEST_SOURCES
jsoncheckertest.cpp
namespacetest.cpp
pointertest.cpp
+ platformtest.cpp
prettywritertest.cpp
ostreamwrappertest.cpp
readertest.cpp
@@ -24,6 +27,7 @@ set(UNITTEST_SOURCES
stringbuffertest.cpp
strtodtest.cpp
unittest.cpp
+ uritest.cpp
valuetest.cpp
writertest.cpp)
@@ -36,10 +40,9 @@ if(CCACHE_FOUND)
endif()
endif(CCACHE_FOUND)
-if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal")
-elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything")
+set_property(DIRECTORY PROPERTY COMPILE_OPTIONS ${EXTRA_CXX_FLAGS})
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# If the user is running a newer version of Clang that includes the
# -Wdouble-promotion, we will ignore that warning.
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.7)
@@ -80,7 +83,7 @@ add_test(NAME unittest
if(NOT MSVC)
# Not running SIMD.* unit test cases for Valgrind
add_test(NAME valgrind_unittest
- COMMAND valgrind --leak-check=full --error-exitcode=1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest --gtest_filter=-SIMD.*
+ COMMAND valgrind --suppressions=${CMAKE_SOURCE_DIR}/test/valgrind.supp --leak-check=full --error-exitcode=1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest --gtest_filter=-SIMD.*
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
diff --git a/3rdparty/rapidjson/test/unittest/allocatorstest.cpp b/3rdparty/rapidjson/test/unittest/allocatorstest.cpp
index a5958de199e..2ffc3254265 100644
--- a/3rdparty/rapidjson/test/unittest/allocatorstest.cpp
+++ b/3rdparty/rapidjson/test/unittest/allocatorstest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -16,6 +16,11 @@
#include "rapidjson/allocators.h"
+#include <map>
+#include <string>
+#include <utility>
+#include <functional>
+
using namespace rapidjson;
template <typename Allocator>
@@ -47,39 +52,224 @@ void TestAllocator(Allocator& a) {
EXPECT_TRUE(a.Realloc(a.Malloc(1), 1, 0) == 0);
}
+struct TestStdAllocatorData {
+ TestStdAllocatorData(int &constructions, int &destructions) :
+ constructions_(&constructions),
+ destructions_(&destructions)
+ {
+ ++*constructions_;
+ }
+ TestStdAllocatorData(const TestStdAllocatorData& rhs) :
+ constructions_(rhs.constructions_),
+ destructions_(rhs.destructions_)
+ {
+ ++*constructions_;
+ }
+ TestStdAllocatorData& operator=(const TestStdAllocatorData& rhs)
+ {
+ this->~TestStdAllocatorData();
+ constructions_ = rhs.constructions_;
+ destructions_ = rhs.destructions_;
+ ++*constructions_;
+ return *this;
+ }
+ ~TestStdAllocatorData()
+ {
+ ++*destructions_;
+ }
+private:
+ TestStdAllocatorData();
+ int *constructions_,
+ *destructions_;
+};
+
+template <typename Allocator>
+void TestStdAllocator(const Allocator& a) {
+#if RAPIDJSON_HAS_CXX17
+ typedef StdAllocator<bool, Allocator> BoolAllocator;
+#else
+ typedef StdAllocator<void, Allocator> VoidAllocator;
+ typedef typename VoidAllocator::template rebind<bool>::other BoolAllocator;
+#endif
+ BoolAllocator ba(a), ba2(a);
+ EXPECT_TRUE(ba == ba2);
+ EXPECT_FALSE(ba!= ba2);
+ ba.deallocate(ba.allocate());
+ EXPECT_TRUE(ba == ba2);
+ EXPECT_FALSE(ba != ba2);
+
+ unsigned long long ll = 0, *llp = &ll;
+ const unsigned long long cll = 0, *cllp = &cll;
+ StdAllocator<unsigned long long, Allocator> lla(a);
+ EXPECT_EQ(lla.address(ll), llp);
+ EXPECT_EQ(lla.address(cll), cllp);
+ EXPECT_TRUE(lla.max_size() > 0 && lla.max_size() <= SIZE_MAX / sizeof(unsigned long long));
+
+ int *arr;
+ StdAllocator<int, Allocator> ia(a);
+ arr = ia.allocate(10 * sizeof(int));
+ EXPECT_TRUE(arr != 0);
+ for (int i = 0; i < 10; ++i) {
+ arr[i] = 0x0f0f0f0f;
+ }
+ ia.deallocate(arr, 10);
+ arr = Malloc<int>(ia, 10);
+ EXPECT_TRUE(arr != 0);
+ for (int i = 0; i < 10; ++i) {
+ arr[i] = 0x0f0f0f0f;
+ }
+ arr = Realloc<int>(ia, arr, 10, 20);
+ EXPECT_TRUE(arr != 0);
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(arr[i], 0x0f0f0f0f);
+ }
+ for (int i = 10; i < 20; i++) {
+ arr[i] = 0x0f0f0f0f;
+ }
+ Free<int>(ia, arr, 20);
+
+ int cons = 0, dest = 0;
+ StdAllocator<TestStdAllocatorData, Allocator> da(a);
+ for (int i = 1; i < 10; i++) {
+ TestStdAllocatorData *d = da.allocate();
+ EXPECT_TRUE(d != 0);
+
+ da.destroy(new(d) TestStdAllocatorData(cons, dest));
+ EXPECT_EQ(cons, i);
+ EXPECT_EQ(dest, i);
+
+ da.deallocate(d);
+ }
+
+ typedef StdAllocator<char, Allocator> CharAllocator;
+ typedef std::basic_string<char, std::char_traits<char>, CharAllocator> String;
+#if RAPIDJSON_HAS_CXX11
+ String s(CharAllocator{a});
+#else
+ CharAllocator ca(a);
+ String s(ca);
+#endif
+ for (int i = 0; i < 26; i++) {
+ s.push_back(static_cast<char>('A' + i));
+ }
+ EXPECT_TRUE(s == "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+ typedef StdAllocator<std::pair<const int, bool>, Allocator> MapAllocator;
+ typedef std::map<int, bool, std::less<int>, MapAllocator> Map;
+#if RAPIDJSON_HAS_CXX11
+ Map map(std::less<int>(), MapAllocator{a});
+#else
+ MapAllocator ma(a);
+ Map map(std::less<int>(), ma);
+#endif
+ for (int i = 0; i < 10; i++) {
+ map.insert(std::make_pair(i, (i % 2) == 0));
+ }
+ EXPECT_TRUE(map.size() == 10);
+ for (int i = 0; i < 10; i++) {
+ typename Map::iterator it = map.find(i);
+ EXPECT_TRUE(it != map.end());
+ EXPECT_TRUE(it->second == ((i % 2) == 0));
+ }
+}
+
TEST(Allocator, CrtAllocator) {
CrtAllocator a;
+
TestAllocator(a);
+ TestStdAllocator(a);
+
+ CrtAllocator a2;
+ EXPECT_TRUE(a == a2);
+ EXPECT_FALSE(a != a2);
+ a2.Free(a2.Malloc(1));
+ EXPECT_TRUE(a == a2);
+ EXPECT_FALSE(a != a2);
}
TEST(Allocator, MemoryPoolAllocator) {
- MemoryPoolAllocator<> a;
+ const size_t capacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY;
+ MemoryPoolAllocator<> a(capacity);
+
+ a.Clear(); // noop
+ EXPECT_EQ(a.Size(), 0u);
+ EXPECT_EQ(a.Capacity(), 0u);
+ EXPECT_EQ(a.Shared(), false);
+ {
+ MemoryPoolAllocator<> a2(a);
+ EXPECT_EQ(a2.Shared(), true);
+ EXPECT_EQ(a.Shared(), true);
+ EXPECT_TRUE(a == a2);
+ EXPECT_FALSE(a != a2);
+ a2.Free(a2.Malloc(1));
+ EXPECT_TRUE(a == a2);
+ EXPECT_FALSE(a != a2);
+ }
+ EXPECT_EQ(a.Shared(), false);
+ EXPECT_EQ(a.Capacity(), capacity);
+ EXPECT_EQ(a.Size(), 8u); // aligned
+ a.Clear();
+ EXPECT_EQ(a.Capacity(), 0u);
+ EXPECT_EQ(a.Size(), 0u);
+
TestAllocator(a);
+ TestStdAllocator(a);
for (size_t i = 1; i < 1000; i++) {
EXPECT_TRUE(a.Malloc(i) != 0);
EXPECT_LE(a.Size(), a.Capacity());
}
+
+ CrtAllocator baseAllocator;
+ a = MemoryPoolAllocator<>(capacity, &baseAllocator);
+ EXPECT_EQ(a.Capacity(), 0u);
+ EXPECT_EQ(a.Size(), 0u);
+ a.Free(a.Malloc(1));
+ EXPECT_EQ(a.Capacity(), capacity);
+ EXPECT_EQ(a.Size(), 8u); // aligned
+
+ {
+ a.Clear();
+ const size_t bufSize = 1024;
+ char *buffer = (char *)a.Malloc(bufSize);
+ MemoryPoolAllocator<> aligned_a(buffer, bufSize);
+ EXPECT_TRUE(aligned_a.Capacity() > 0 && aligned_a.Capacity() <= bufSize);
+ EXPECT_EQ(aligned_a.Size(), 0u);
+ aligned_a.Free(aligned_a.Malloc(1));
+ EXPECT_TRUE(aligned_a.Capacity() > 0 && aligned_a.Capacity() <= bufSize);
+ EXPECT_EQ(aligned_a.Size(), 8u); // aligned
+ }
+
+ {
+ a.Clear();
+ const size_t bufSize = 1024;
+ char *buffer = (char *)a.Malloc(bufSize);
+ RAPIDJSON_ASSERT(bufSize % sizeof(void*) == 0);
+ MemoryPoolAllocator<> unaligned_a(buffer + 1, bufSize - 1);
+ EXPECT_TRUE(unaligned_a.Capacity() > 0 && unaligned_a.Capacity() <= bufSize - sizeof(void*));
+ EXPECT_EQ(unaligned_a.Size(), 0u);
+ unaligned_a.Free(unaligned_a.Malloc(1));
+ EXPECT_TRUE(unaligned_a.Capacity() > 0 && unaligned_a.Capacity() <= bufSize - sizeof(void*));
+ EXPECT_EQ(unaligned_a.Size(), 8u); // aligned
+ }
}
TEST(Allocator, Alignment) {
-#if RAPIDJSON_64BIT == 1
- EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000000), RAPIDJSON_ALIGN(0));
- for (uint64_t i = 1; i < 8; i++) {
- EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000008), RAPIDJSON_ALIGN(i));
- EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000010), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0x00000000, 0x00000008) + i));
- EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000001, 0x00000000), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0x00000000, 0xFFFFFFF8) + i));
- EXPECT_EQ(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF8), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF0) + i));
+ if (sizeof(size_t) >= 8) {
+ EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000000), RAPIDJSON_ALIGN(0));
+ for (uint64_t i = 1; i < 8; i++) {
+ EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000008), RAPIDJSON_ALIGN(i));
+ EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000010), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0x00000000, 0x00000008) + i));
+ EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000001, 0x00000000), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0x00000000, 0xFFFFFFF8) + i));
+ EXPECT_EQ(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF8), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF0) + i));
+ }
}
-#else
+
EXPECT_EQ(0u, RAPIDJSON_ALIGN(0u));
- for (uint32_t i = 1; i < 4; i++) {
- EXPECT_EQ(4u, RAPIDJSON_ALIGN(i));
- EXPECT_EQ(8u, RAPIDJSON_ALIGN(4u + i));
- EXPECT_EQ(0xFFFFFFF8u, RAPIDJSON_ALIGN(0xFFFFFFF4u + i));
- EXPECT_EQ(0xFFFFFFFCu, RAPIDJSON_ALIGN(0xFFFFFFF8u + i));
+ for (uint32_t i = 1; i < 8; i++) {
+ EXPECT_EQ(8u, RAPIDJSON_ALIGN(i));
+ EXPECT_EQ(0xFFFFFFF8u, RAPIDJSON_ALIGN(0xFFFFFFF0u + i));
}
-#endif
}
TEST(Allocator, Issue399) {
diff --git a/3rdparty/rapidjson/test/unittest/bigintegertest.cpp b/3rdparty/rapidjson/test/unittest/bigintegertest.cpp
index a68e1444672..fad54382ca2 100644
--- a/3rdparty/rapidjson/test/unittest/bigintegertest.cpp
+++ b/3rdparty/rapidjson/test/unittest/bigintegertest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -120,6 +120,11 @@ TEST(BigInteger, LeftShift) {
EXPECT_TRUE(BIGINTEGER_LITERAL("4537899042132549697536") == a);
a <<= 99;
EXPECT_TRUE(BIGINTEGER_LITERAL("2876235222267216943024851750785644982682875244576768") == a);
+
+ a = 1;
+ a <<= 64; // a.count_ != 1
+ a <<= 256; // interShift == 0
+ EXPECT_TRUE(BIGINTEGER_LITERAL("2135987035920910082395021706169552114602704522356652769947041607822219725780640550022962086936576") == a);
}
TEST(BigInteger, Compare) {
diff --git a/3rdparty/rapidjson/test/unittest/clzlltest.cpp b/3rdparty/rapidjson/test/unittest/clzlltest.cpp
new file mode 100644
index 00000000000..ad465e1f319
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/clzlltest.cpp
@@ -0,0 +1,34 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/internal/clzll.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+#endif
+
+using namespace rapidjson::internal;
+
+TEST(clzll, normal) {
+ EXPECT_EQ(clzll(1), 63U);
+ EXPECT_EQ(clzll(2), 62U);
+ EXPECT_EQ(clzll(12), 60U);
+ EXPECT_EQ(clzll(0x0000000080000001UL), 32U);
+ EXPECT_EQ(clzll(0x8000000000000001UL), 0U);
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/cursorstreamwrappertest.cpp b/3rdparty/rapidjson/test/unittest/cursorstreamwrappertest.cpp
new file mode 100644
index 00000000000..dad3359459a
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/cursorstreamwrappertest.cpp
@@ -0,0 +1,115 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/document.h"
+#include "rapidjson/cursorstreamwrapper.h"
+
+using namespace rapidjson;
+
+// static const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}";
+
+bool testJson(const char *json, size_t &line, size_t &col) {
+ StringStream ss(json);
+ CursorStreamWrapper<StringStream> csw(ss);
+ Document document;
+ document.ParseStream(csw);
+ bool ret = document.HasParseError();
+ if (ret) {
+ col = csw.GetColumn();
+ line = csw.GetLine();
+ }
+ return ret;
+}
+
+TEST(CursorStreamWrapper, MissingFirstBracket) {
+ const char json[] = "\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}";
+ size_t col, line;
+ bool ret = testJson(json, line, col);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(line, 3u);
+ EXPECT_EQ(col, 0u);
+}
+
+TEST(CursorStreamWrapper, MissingQuotes) {
+ const char json[] = "{\"string\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}";
+ size_t col, line;
+ bool ret = testJson(json, line, col);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(line, 1u);
+ EXPECT_EQ(col, 8u);
+}
+
+TEST(CursorStreamWrapper, MissingColon) {
+ const char json[] = "{\"string\"\n\n\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}";
+ size_t col, line;
+ bool ret = testJson(json, line, col);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(line, 3u);
+ EXPECT_EQ(col, 0u);
+}
+
+TEST(CursorStreamWrapper, MissingSecondQuotes) {
+ const char json[] = "{\"string\"\n\n:my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}";
+ size_t col, line;
+ bool ret = testJson(json, line, col);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(line, 3u);
+ EXPECT_EQ(col, 1u);
+}
+
+TEST(CursorStreamWrapper, MissingComma) {
+ const char json[] = "{\"string\"\n\n:\"my string\"\"array\"\n:[\"1\", \"2\", \"3\"]}";
+ size_t col, line;
+ bool ret = testJson(json, line, col);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(line, 3u);
+ EXPECT_EQ(col, 12u);
+}
+
+TEST(CursorStreamWrapper, MissingArrayBracket) {
+ const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:\"1\", \"2\", \"3\"]}";
+ size_t col, line;
+ bool ret = testJson(json, line, col);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(line, 4u);
+ EXPECT_EQ(col, 9u);
+}
+
+TEST(CursorStreamWrapper, MissingArrayComma) {
+ const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\" \"2\", \"3\"]}";
+ size_t col, line;
+ bool ret = testJson(json, line, col);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(line, 4u);
+ EXPECT_EQ(col, 6u);
+}
+
+TEST(CursorStreamWrapper, MissingLastArrayBracket) {
+ const char json8[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"}";
+ size_t col, line;
+ bool ret = testJson(json8, line, col);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(line, 4u);
+ EXPECT_EQ(col, 15u);
+}
+
+TEST(CursorStreamWrapper, MissingLastBracket) {
+ const char json9[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]";
+ size_t col, line;
+ bool ret = testJson(json9, line, col);
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(line, 4u);
+ EXPECT_EQ(col, 16u);
+}
diff --git a/3rdparty/rapidjson/test/unittest/documenttest.cpp b/3rdparty/rapidjson/test/unittest/documenttest.cpp
index ecd4b79bc2a..c3d1e484dcc 100644
--- a/3rdparty/rapidjson/test/unittest/documenttest.cpp
+++ b/3rdparty/rapidjson/test/unittest/documenttest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -128,8 +128,14 @@ TEST(Document, UnchangedOnParseError) {
Document doc;
doc.SetArray().PushBack(0, doc.GetAllocator());
+ ParseResult noError;
+ EXPECT_TRUE(noError);
+
ParseResult err = doc.Parse("{]");
EXPECT_TRUE(doc.HasParseError());
+ EXPECT_NE(err, noError);
+ EXPECT_NE(err.Code(), noError);
+ EXPECT_NE(noError, doc.GetParseError());
EXPECT_EQ(err.Code(), doc.GetParseError());
EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
EXPECT_TRUE(doc.IsArray());
@@ -138,6 +144,9 @@ TEST(Document, UnchangedOnParseError) {
err = doc.Parse("{}");
EXPECT_FALSE(doc.HasParseError());
EXPECT_FALSE(err.IsError());
+ EXPECT_TRUE(err);
+ EXPECT_EQ(err, noError);
+ EXPECT_EQ(err.Code(), noError);
EXPECT_EQ(err.Code(), doc.GetParseError());
EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
EXPECT_TRUE(doc.IsObject());
@@ -291,7 +300,14 @@ TEST(Document, Swap) {
o.SetObject().AddMember("a", 1, a);
// Swap between Document and Value
- // d1.Swap(o); // doesn't compile
+ d1.Swap(o);
+ EXPECT_TRUE(d1.IsObject());
+ EXPECT_TRUE(o.IsArray());
+
+ d1.Swap(o);
+ EXPECT_TRUE(d1.IsArray());
+ EXPECT_TRUE(o.IsObject());
+
o.Swap(d1);
EXPECT_TRUE(d1.IsObject());
EXPECT_TRUE(o.IsArray());
@@ -309,6 +325,8 @@ TEST(Document, Swap) {
EXPECT_TRUE(d1.IsNull());
// reset document, including allocator
+ // so clear o before so that it doesnt contain dangling elements
+ o.Clear();
Document().Swap(d2);
EXPECT_TRUE(d2.IsNull());
EXPECT_NE(&d2.GetAllocator(), &a);
@@ -488,15 +506,19 @@ TYPED_TEST(DocumentMove, MoveConstructorParseError) {
a.Parse("{ 4 = 4]");
ParseResult error(a.GetParseError(), a.GetErrorOffset());
EXPECT_TRUE(a.HasParseError());
+ EXPECT_NE(error, noError);
+ EXPECT_NE(error.Code(), noError);
EXPECT_NE(error.Code(), noError.Code());
EXPECT_NE(error.Offset(), noError.Offset());
D b(std::move(a));
EXPECT_FALSE(a.HasParseError());
EXPECT_TRUE(b.HasParseError());
+ EXPECT_EQ(a.GetParseError(), noError);
EXPECT_EQ(a.GetParseError(), noError.Code());
- EXPECT_EQ(b.GetParseError(), error.Code());
EXPECT_EQ(a.GetErrorOffset(), noError.Offset());
+ EXPECT_EQ(b.GetParseError(), error);
+ EXPECT_EQ(b.GetParseError(), error.Code());
EXPECT_EQ(b.GetErrorOffset(), error.Offset());
D c(std::move(b));
diff --git a/3rdparty/rapidjson/test/unittest/dtoatest.cpp b/3rdparty/rapidjson/test/unittest/dtoatest.cpp
index afd76eb09ab..3ec89828986 100644
--- a/3rdparty/rapidjson/test/unittest/dtoatest.cpp
+++ b/3rdparty/rapidjson/test/unittest/dtoatest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -38,6 +38,7 @@ TEST(dtoa, normal) {
TEST_DTOA(0.123456789012, "0.123456789012");
TEST_DTOA(1234567.8, "1234567.8");
TEST_DTOA(-79.39773355813419, "-79.39773355813419");
+ TEST_DTOA(-36.973846435546875, "-36.973846435546875");
TEST_DTOA(0.000001, "0.000001");
TEST_DTOA(0.0000001, "1e-7");
TEST_DTOA(1e30, "1e30");
diff --git a/3rdparty/rapidjson/test/unittest/encodedstreamtest.cpp b/3rdparty/rapidjson/test/unittest/encodedstreamtest.cpp
index bc234d3ba76..1f0f0e7642f 100644
--- a/3rdparty/rapidjson/test/unittest/encodedstreamtest.cpp
+++ b/3rdparty/rapidjson/test/unittest/encodedstreamtest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -113,8 +113,8 @@ protected:
EXPECT_EQ(expected, actual);
}
EXPECT_EQ('\0', s.Peek());
- free(data);
EXPECT_EQ(size, eis.Tell());
+ free(data);
}
}
diff --git a/3rdparty/rapidjson/test/unittest/encodingstest.cpp b/3rdparty/rapidjson/test/unittest/encodingstest.cpp
index 67b0391ed06..455881e7e81 100644
--- a/3rdparty/rapidjson/test/unittest/encodingstest.cpp
+++ b/3rdparty/rapidjson/test/unittest/encodingstest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -267,7 +267,7 @@ static unsigned inline decode(unsigned* state, unsigned* codep, unsigned byte) {
*codep = (*state != UTF8_ACCEPT) ?
(byte & 0x3fu) | (*codep << 6) :
- (0xff >> type) & (byte);
+ (0xffu >> type) & (byte);
*state = utf8d[256 + *state + type];
return *state;
diff --git a/3rdparty/rapidjson/test/unittest/filestreamtest.cpp b/3rdparty/rapidjson/test/unittest/filestreamtest.cpp
index a38133fa7f6..de0b4d1a4aa 100644
--- a/3rdparty/rapidjson/test/unittest/filestreamtest.cpp
+++ b/3rdparty/rapidjson/test/unittest/filestreamtest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -21,7 +21,7 @@ using namespace rapidjson;
class FileStreamTest : public ::testing::Test {
public:
- FileStreamTest() : filename_(), json_(), length_() {}
+ FileStreamTest() : filename_(), json_(), length_(), abcde_() {}
virtual ~FileStreamTest();
virtual void SetUp() {
@@ -49,6 +49,24 @@ public:
size_t readLength = fread(json_, 1, length_, fp);
json_[readLength] = '\0';
fclose(fp);
+
+ const char *abcde_paths[] = {
+ "data/abcde.txt",
+ "bin/data/abcde.txt",
+ "../bin/data/abcde.txt",
+ "../../bin/data/abcde.txt",
+ "../../../bin/data/abcde.txt"
+ };
+ fp = 0;
+ for (size_t i = 0; i < sizeof(abcde_paths) / sizeof(abcde_paths[0]); i++) {
+ fp = fopen(abcde_paths[i], "rb");
+ if (fp) {
+ abcde_ = abcde_paths[i];
+ break;
+ }
+ }
+ ASSERT_TRUE(fp != 0);
+ fclose(fp);
}
virtual void TearDown() {
@@ -64,6 +82,7 @@ protected:
const char* filename_;
char *json_;
size_t length_;
+ const char* abcde_;
};
FileStreamTest::~FileStreamTest() {}
@@ -86,6 +105,30 @@ TEST_F(FileStreamTest, FileReadStream) {
fclose(fp);
}
+TEST_F(FileStreamTest, FileReadStream_Peek4) {
+ FILE *fp = fopen(abcde_, "rb");
+ ASSERT_TRUE(fp != 0);
+ char buffer[4];
+ FileReadStream s(fp, buffer, sizeof(buffer));
+
+ const char* c = s.Peek4();
+ for (int i = 0; i < 4; i++)
+ EXPECT_EQ('a' + i, c[i]);
+ EXPECT_EQ(0u, s.Tell());
+
+ for (int i = 0; i < 5; i++) {
+ EXPECT_EQ(static_cast<size_t>(i), s.Tell());
+ EXPECT_EQ('a' + i, s.Peek());
+ EXPECT_EQ('a' + i, s.Peek());
+ EXPECT_EQ('a' + i, s.Take());
+ }
+ EXPECT_EQ(5u, s.Tell());
+ EXPECT_EQ(0, s.Peek());
+ EXPECT_EQ(0, s.Take());
+
+ fclose(fp);
+}
+
TEST_F(FileStreamTest, FileWriteStream) {
char filename[L_tmpnam];
FILE* fp = TempFile(filename);
diff --git a/3rdparty/rapidjson/test/unittest/fwdtest.cpp b/3rdparty/rapidjson/test/unittest/fwdtest.cpp
index 4f326846116..e9c707805a5 100644
--- a/3rdparty/rapidjson/test/unittest/fwdtest.cpp
+++ b/3rdparty/rapidjson/test/unittest/fwdtest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -100,6 +100,9 @@ struct Foo {
#include "rapidjson/prettywriter.h"
#include "rapidjson/schema.h" // -> pointer.h
+typedef Transcoder<UTF8<>, UTF8<> > TranscoderUtf8ToUtf8;
+typedef BaseReaderHandler<UTF8<>, void> BaseReaderHandlerUtf8Void;
+
Foo::Foo() :
// encodings.h
utf8(RAPIDJSON_NEW(UTF8<>)),
@@ -111,40 +114,40 @@ Foo::Foo() :
utf32le(RAPIDJSON_NEW(UTF32LE<>)),
ascii(RAPIDJSON_NEW(ASCII<>)),
autoutf(RAPIDJSON_NEW(AutoUTF<unsigned>)),
- transcoder(RAPIDJSON_NEW((Transcoder<UTF8<>, UTF8<> >))),
+ transcoder(RAPIDJSON_NEW(TranscoderUtf8ToUtf8)),
// allocators.h
crtallocator(RAPIDJSON_NEW(CrtAllocator)),
memorypoolallocator(RAPIDJSON_NEW(MemoryPoolAllocator<>)),
// stream.h
- stringstream(RAPIDJSON_NEW(StringStream(0))),
- insitustringstream(RAPIDJSON_NEW(InsituStringStream(0))),
+ stringstream(RAPIDJSON_NEW(StringStream)(NULL)),
+ insitustringstream(RAPIDJSON_NEW(InsituStringStream)(NULL)),
// stringbuffer.h
stringbuffer(RAPIDJSON_NEW(StringBuffer)),
// // filereadstream.h
- // filereadstream(RAPIDJSON_NEW(FileReadStream(stdout, buffer, sizeof(buffer)))),
+ // filereadstream(RAPIDJSON_NEW(FileReadStream)(stdout, buffer, sizeof(buffer))),
// // filewritestream.h
- // filewritestream(RAPIDJSON_NEW(FileWriteStream(stdout, buffer, sizeof(buffer)))),
+ // filewritestream(RAPIDJSON_NEW(FileWriteStream)(stdout, buffer, sizeof(buffer))),
// memorybuffer.h
memorybuffer(RAPIDJSON_NEW(MemoryBuffer)),
// memorystream.h
- memorystream(RAPIDJSON_NEW(MemoryStream(0, 0))),
+ memorystream(RAPIDJSON_NEW(MemoryStream)(NULL, 0)),
// reader.h
- basereaderhandler(RAPIDJSON_NEW((BaseReaderHandler<UTF8<>, void>))),
+ basereaderhandler(RAPIDJSON_NEW(BaseReaderHandlerUtf8Void)),
reader(RAPIDJSON_NEW(Reader)),
// writer.h
- writer(RAPIDJSON_NEW((Writer<StringBuffer>))),
+ writer(RAPIDJSON_NEW(Writer<StringBuffer>)),
// prettywriter.h
- prettywriter(RAPIDJSON_NEW((PrettyWriter<StringBuffer>))),
+ prettywriter(RAPIDJSON_NEW(PrettyWriter<StringBuffer>)),
// document.h
value(RAPIDJSON_NEW(Value)),
@@ -154,8 +157,8 @@ Foo::Foo() :
pointer(RAPIDJSON_NEW(Pointer)),
// schema.h
- schemadocument(RAPIDJSON_NEW(SchemaDocument(*document))),
- schemavalidator(RAPIDJSON_NEW(SchemaValidator(*schemadocument)))
+ schemadocument(RAPIDJSON_NEW(SchemaDocument)(*document)),
+ schemavalidator(RAPIDJSON_NEW(SchemaValidator)(*schemadocument))
{
}
diff --git a/3rdparty/rapidjson/test/unittest/istreamwrappertest.cpp b/3rdparty/rapidjson/test/unittest/istreamwrappertest.cpp
index 9d6fbcff0de..f0cdb2d38c4 100644
--- a/3rdparty/rapidjson/test/unittest/istreamwrappertest.cpp
+++ b/3rdparty/rapidjson/test/unittest/istreamwrappertest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -20,7 +20,7 @@
#include <sstream>
#include <fstream>
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__clang__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4702) // unreachable code
#endif
@@ -35,21 +35,21 @@ static void TestStringStream() {
{
StringStreamType iss;
BasicIStreamWrapper<StringStreamType> is(iss);
- EXPECT_EQ(0, is.Tell());
+ EXPECT_EQ(0u, is.Tell());
if (sizeof(Ch) == 1) {
EXPECT_EQ(0, is.Peek4());
- EXPECT_EQ(0, is.Tell());
+ EXPECT_EQ(0u, is.Tell());
}
EXPECT_EQ(0, is.Peek());
EXPECT_EQ(0, is.Take());
- EXPECT_EQ(0, is.Tell());
+ EXPECT_EQ(0u, is.Tell());
}
{
Ch s[] = { 'A', 'B', 'C', '\0' };
StringStreamType iss(s);
BasicIStreamWrapper<StringStreamType> is(iss);
- EXPECT_EQ(0, is.Tell());
+ EXPECT_EQ(0u, is.Tell());
if (sizeof(Ch) == 1) {
EXPECT_EQ(0, is.Peek4()); // less than 4 bytes
}
@@ -59,7 +59,7 @@ static void TestStringStream() {
EXPECT_EQ('A' + i, is.Peek());
EXPECT_EQ('A' + i, is.Take());
}
- EXPECT_EQ(3, is.Tell());
+ EXPECT_EQ(3u, is.Tell());
EXPECT_EQ(0, is.Peek());
EXPECT_EQ(0, is.Take());
}
@@ -72,7 +72,7 @@ static void TestStringStream() {
const Ch* c = is.Peek4();
for (int i = 0; i < 4; i++)
EXPECT_EQ('A' + i, c[i]);
- EXPECT_EQ(0, is.Tell());
+ EXPECT_EQ(0u, is.Tell());
}
for (int i = 0; i < 5; i++) {
EXPECT_EQ(static_cast<size_t>(i), is.Tell());
@@ -80,7 +80,7 @@ static void TestStringStream() {
EXPECT_EQ('A' + i, is.Peek());
EXPECT_EQ('A' + i, is.Take());
}
- EXPECT_EQ(5, is.Tell());
+ EXPECT_EQ(5u, is.Tell());
EXPECT_EQ(0, is.Peek());
EXPECT_EQ(0, is.Take());
}
@@ -129,7 +129,7 @@ TEST(IStreamWrapper, ifstream) {
Document d;
EXPECT_TRUE(!d.ParseStream(eis).HasParseError());
EXPECT_TRUE(d.IsObject());
- EXPECT_EQ(5, d.MemberCount());
+ EXPECT_EQ(5u, d.MemberCount());
}
TEST(IStreamWrapper, fstream) {
@@ -140,7 +140,7 @@ TEST(IStreamWrapper, fstream) {
Document d;
EXPECT_TRUE(!d.ParseStream(eis).HasParseError());
EXPECT_TRUE(d.IsObject());
- EXPECT_EQ(5, d.MemberCount());
+ EXPECT_EQ(5u, d.MemberCount());
}
// wifstream/wfstream only works on C++11 with codecvt_utf16
@@ -176,6 +176,6 @@ TEST(IStreamWrapper, wfstream) {
#endif
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__clang__)
RAPIDJSON_DIAG_POP
#endif
diff --git a/3rdparty/rapidjson/test/unittest/itoatest.cpp b/3rdparty/rapidjson/test/unittest/itoatest.cpp
index b752a6a26ee..4c834de3734 100644
--- a/3rdparty/rapidjson/test/unittest/itoatest.cpp
+++ b/3rdparty/rapidjson/test/unittest/itoatest.cpp
@@ -1,15 +1,15 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#include "unittest.h"
@@ -61,7 +61,7 @@ static void VerifyValue(T value, void(*f)(T, char*), char* (*g)(T, char*)) {
f(value, buffer1);
*g(value, buffer2) = '\0';
-
+
EXPECT_STREQ(buffer1, buffer2);
}
@@ -70,23 +70,23 @@ template <typename T>
static void Verify(void(*f)(T, char*), char* (*g)(T, char*)) {
// Boundary cases
VerifyValue<T>(0, f, g);
- VerifyValue<T>(std::numeric_limits<T>::min(), f, g);
- VerifyValue<T>(std::numeric_limits<T>::max(), f, g);
+ VerifyValue<T>((std::numeric_limits<T>::min)(), f, g);
+ VerifyValue<T>((std::numeric_limits<T>::max)(), f, g);
// 2^n - 1, 2^n, 10^n - 1, 10^n until overflow
- for (uint32_t power = 2; power <= 10; power += 8) {
+ for (int power = 2; power <= 10; power += 8) {
T i = 1, last;
do {
VerifyValue<T>(i - 1, f, g);
VerifyValue<T>(i, f, g);
- if (std::numeric_limits<T>::min() < 0) {
+ if ((std::numeric_limits<T>::min)() < 0) {
VerifyValue<T>(Traits<T>::Negate(i), f, g);
VerifyValue<T>(Traits<T>::Negate(i + 1), f, g);
}
last = i;
- if (i > static_cast<T>(std::numeric_limits<T>::max() / static_cast<T>(power)))
+ if (i > static_cast<T>((std::numeric_limits<T>::max)() / static_cast<T>(power)))
break;
- i *= power;
+ i *= static_cast<T>(power);
} while (last < i);
}
}
diff --git a/3rdparty/rapidjson/test/unittest/jsoncheckertest.cpp b/3rdparty/rapidjson/test/unittest/jsoncheckertest.cpp
index bea788d26e3..19e1f1c47a2 100644
--- a/3rdparty/rapidjson/test/unittest/jsoncheckertest.cpp
+++ b/3rdparty/rapidjson/test/unittest/jsoncheckertest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -48,6 +48,24 @@ static char* ReadFile(const char* filename, size_t& length) {
return json;
}
+struct NoOpHandler {
+ bool Null() { return true; }
+ bool Bool(bool) { return true; }
+ bool Int(int) { return true; }
+ bool Uint(unsigned) { return true; }
+ bool Int64(int64_t) { return true; }
+ bool Uint64(uint64_t) { return true; }
+ bool Double(double) { return true; }
+ bool RawNumber(const char*, SizeType, bool) { return true; }
+ bool String(const char*, SizeType, bool) { return true; }
+ bool StartObject() { return true; }
+ bool Key(const char*, SizeType, bool) { return true; }
+ bool EndObject(SizeType) { return true; }
+ bool StartArray() { return true; }
+ bool EndArray(SizeType) { return true; }
+};
+
+
TEST(JsonChecker, Reader) {
char filename[256];
@@ -67,13 +85,26 @@ TEST(JsonChecker, Reader) {
continue;
}
+ // Test stack-based parsing.
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
document.Parse(json);
- EXPECT_TRUE(document.HasParseError());
+ EXPECT_TRUE(document.HasParseError()) << filename;
+ // Test iterative parsing.
document.Parse<kParseIterativeFlag>(json);
- EXPECT_TRUE(document.HasParseError());
-
+ EXPECT_TRUE(document.HasParseError()) << filename;
+
+ // Test iterative pull-parsing.
+ Reader reader;
+ StringStream ss(json);
+ NoOpHandler h;
+ reader.IterativeParseInit();
+ while (!reader.IterativeParseComplete()) {
+ if (!reader.IterativeParseNext<kParseDefaultFlags>(ss, h))
+ break;
+ }
+ EXPECT_TRUE(reader.HasParseError()) << filename;
+
free(json);
}
@@ -87,12 +118,25 @@ TEST(JsonChecker, Reader) {
continue;
}
+ // Test stack-based parsing.
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
document.Parse(json);
- EXPECT_FALSE(document.HasParseError());
+ EXPECT_FALSE(document.HasParseError()) << filename;
+ // Test iterative parsing.
document.Parse<kParseIterativeFlag>(json);
- EXPECT_FALSE(document.HasParseError());
+ EXPECT_FALSE(document.HasParseError()) << filename;
+
+ // Test iterative pull-parsing.
+ Reader reader;
+ StringStream ss(json);
+ NoOpHandler h;
+ reader.IterativeParseInit();
+ while (!reader.IterativeParseComplete()) {
+ if (!reader.IterativeParseNext<kParseDefaultFlags>(ss, h))
+ break;
+ }
+ EXPECT_FALSE(reader.HasParseError()) << filename;
free(json);
}
diff --git a/3rdparty/rapidjson/test/unittest/namespacetest.cpp b/3rdparty/rapidjson/test/unittest/namespacetest.cpp
index 1814724aec6..e33e6d5f54c 100644
--- a/3rdparty/rapidjson/test/unittest/namespacetest.cpp
+++ b/3rdparty/rapidjson/test/unittest/namespacetest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
diff --git a/3rdparty/rapidjson/test/unittest/ostreamwrappertest.cpp b/3rdparty/rapidjson/test/unittest/ostreamwrappertest.cpp
index b1d1cd827fc..be9e429cadc 100644
--- a/3rdparty/rapidjson/test/unittest/ostreamwrappertest.cpp
+++ b/3rdparty/rapidjson/test/unittest/ostreamwrappertest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -69,14 +69,15 @@ static void TestFileStream() {
const char* s = "Hello World!\n";
{
- ofstream ofs(filename, ios::out | ios::binary);
- BasicOStreamWrapper<ofstream> osw(ofs);
+ FileStreamType ofs(filename, ios::out | ios::binary);
+ BasicOStreamWrapper<FileStreamType> osw(ofs);
for (const char* p = s; *p; p++)
osw.Put(*p);
osw.Flush();
}
fp = fopen(filename, "r");
+ ASSERT_TRUE( fp != NULL );
for (const char* p = s; *p; p++)
EXPECT_EQ(*p, static_cast<char>(fgetc(fp)));
fclose(fp);
diff --git a/3rdparty/rapidjson/test/unittest/platformtest.cpp b/3rdparty/rapidjson/test/unittest/platformtest.cpp
new file mode 100644
index 00000000000..05eba3f5bdc
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/platformtest.cpp
@@ -0,0 +1,40 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2021 THL A29 Limited, a Tencent company, and Milo Yip.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+
+// see https://github.com/Tencent/rapidjson/issues/1448
+// including windows.h on purpose to provoke a compile time problem as GetObject is a
+// macro that gets defined when windows.h is included
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include "rapidjson/document.h"
+#undef GetObject
+
+using namespace rapidjson;
+
+TEST(Platform, GetObject) {
+ Document doc;
+ doc.Parse(" { \"object\" : { \"pi\": 3.1416} } ");
+ EXPECT_TRUE(doc.IsObject());
+ EXPECT_TRUE(doc.HasMember("object"));
+ const Document::ValueType& o = doc["object"];
+ EXPECT_TRUE(o.IsObject());
+ Value::ConstObject sub = o.GetObject();
+ EXPECT_TRUE(sub.HasMember("pi"));
+ Value::ConstObject sub2 = o.GetObj();
+ EXPECT_TRUE(sub2.HasMember("pi"));
+}
diff --git a/3rdparty/rapidjson/test/unittest/pointertest.cpp b/3rdparty/rapidjson/test/unittest/pointertest.cpp
index dbddbedee25..c35fa8f5374 100644
--- a/3rdparty/rapidjson/test/unittest/pointertest.cpp
+++ b/3rdparty/rapidjson/test/unittest/pointertest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -15,7 +15,10 @@
#include "unittest.h"
#include "rapidjson/pointer.h"
#include "rapidjson/stringbuffer.h"
+#include "rapidjson/ostreamwrapper.h"
#include <sstream>
+#include <map>
+#include <algorithm>
using namespace rapidjson;
@@ -300,7 +303,7 @@ TEST(Pointer, Parse_URIFragment) {
}
{
- // Decode UTF-8 perecent encoding to UTF-8
+ // Decode UTF-8 percent encoding to UTF-8
Pointer p("#/%C2%A2");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
@@ -308,7 +311,7 @@ TEST(Pointer, Parse_URIFragment) {
}
{
- // Decode UTF-8 perecent encoding to UTF-16
+ // Decode UTF-8 percent encoding to UTF-16
GenericPointer<GenericValue<UTF16<> > > p(L"#/%C2%A2");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
@@ -317,7 +320,7 @@ TEST(Pointer, Parse_URIFragment) {
}
{
- // Decode UTF-8 perecent encoding to UTF-16
+ // Decode UTF-8 percent encoding to UTF-16
GenericPointer<GenericValue<UTF16<> > > p(L"#/%E2%82%AC");
EXPECT_TRUE(p.IsValid());
EXPECT_EQ(1u, p.GetTokenCount());
@@ -441,8 +444,8 @@ TEST(Pointer, Stringify) {
}
// Construct a Pointer with static tokens, no dynamic allocation involved.
-#define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
-#define INDEX(i) { #i, sizeof(#i) - 1, i }
+#define NAME(s) { s, static_cast<SizeType>(sizeof(s) / sizeof(s[0]) - 1), kPointerInvalidIndex }
+#define INDEX(i) { #i, static_cast<SizeType>(sizeof(#i) - 1), i }
static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(0) }; // equivalent to "/foo/0"
@@ -462,7 +465,8 @@ TEST(Pointer, ConstructorWithToken) {
TEST(Pointer, CopyConstructor) {
{
- Pointer p("/foo/0");
+ CrtAllocator allocator;
+ Pointer p("/foo/0", &allocator);
Pointer q(p);
EXPECT_TRUE(q.IsValid());
EXPECT_EQ(2u, q.GetTokenCount());
@@ -471,6 +475,9 @@ TEST(Pointer, CopyConstructor) {
EXPECT_EQ(1u, q.GetTokens()[1].length);
EXPECT_STREQ("0", q.GetTokens()[1].name);
EXPECT_EQ(0u, q.GetTokens()[1].index);
+
+ // Copied pointer needs to have its own allocator
+ EXPECT_NE(&p.GetAllocator(), &q.GetAllocator());
}
// Static tokens
@@ -489,7 +496,8 @@ TEST(Pointer, CopyConstructor) {
TEST(Pointer, Assignment) {
{
- Pointer p("/foo/0");
+ CrtAllocator allocator;
+ Pointer p("/foo/0", &allocator);
Pointer q;
q = p;
EXPECT_TRUE(q.IsValid());
@@ -499,7 +507,8 @@ TEST(Pointer, Assignment) {
EXPECT_EQ(1u, q.GetTokens()[1].length);
EXPECT_STREQ("0", q.GetTokens()[1].name);
EXPECT_EQ(0u, q.GetTokens()[1].index);
- q = q;
+ EXPECT_NE(&p.GetAllocator(), &q.GetAllocator());
+ q = static_cast<const Pointer &>(q);
EXPECT_TRUE(q.IsValid());
EXPECT_EQ(2u, q.GetTokenCount());
EXPECT_EQ(3u, q.GetTokens()[0].length);
@@ -507,6 +516,7 @@ TEST(Pointer, Assignment) {
EXPECT_EQ(1u, q.GetTokens()[1].length);
EXPECT_STREQ("0", q.GetTokens()[1].name);
EXPECT_EQ(0u, q.GetTokens()[1].index);
+ EXPECT_NE(&p.GetAllocator(), &q.GetAllocator());
}
// Static tokens
@@ -524,6 +534,36 @@ TEST(Pointer, Assignment) {
}
}
+TEST(Pointer, Swap) {
+ Pointer p("/foo/0");
+ Pointer q(&p.GetAllocator());
+
+ q.Swap(p);
+ EXPECT_EQ(&q.GetAllocator(), &p.GetAllocator());
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_TRUE(q.IsValid());
+ EXPECT_EQ(0u, p.GetTokenCount());
+ EXPECT_EQ(2u, q.GetTokenCount());
+ EXPECT_EQ(3u, q.GetTokens()[0].length);
+ EXPECT_STREQ("foo", q.GetTokens()[0].name);
+ EXPECT_EQ(1u, q.GetTokens()[1].length);
+ EXPECT_STREQ("0", q.GetTokens()[1].name);
+ EXPECT_EQ(0u, q.GetTokens()[1].index);
+
+ // std::swap compatibility
+ std::swap(p, q);
+ EXPECT_EQ(&p.GetAllocator(), &q.GetAllocator());
+ EXPECT_TRUE(q.IsValid());
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(0u, q.GetTokenCount());
+ EXPECT_EQ(2u, p.GetTokenCount());
+ EXPECT_EQ(3u, p.GetTokens()[0].length);
+ EXPECT_STREQ("foo", p.GetTokens()[0].name);
+ EXPECT_EQ(1u, p.GetTokens()[1].length);
+ EXPECT_STREQ("0", p.GetTokens()[1].name);
+ EXPECT_EQ(0u, p.GetTokens()[1].index);
+}
+
TEST(Pointer, Append) {
{
Pointer p;
@@ -610,6 +650,52 @@ TEST(Pointer, Create) {
}
}
+static const char kJsonIds[] = "{\n"
+ " \"id\": \"/root/\","
+ " \"foo\":[\"bar\", \"baz\", {\"id\": \"inarray\", \"child\": 1}],\n"
+ " \"int\" : 2,\n"
+ " \"str\" : \"val\",\n"
+ " \"obj\": {\"id\": \"inobj\", \"child\": 3},\n"
+ " \"jbo\": {\"id\": true, \"child\": 4}\n"
+ "}";
+
+
+TEST(Pointer, GetUri) {
+ CrtAllocator allocator;
+ Document d;
+ d.Parse(kJsonIds);
+ Pointer::UriType doc("http://doc");
+ Pointer::UriType root("http://doc/root/");
+ Pointer::UriType empty = Pointer::UriType();
+
+ EXPECT_TRUE(Pointer("").GetUri(d, doc) == doc);
+ EXPECT_TRUE(Pointer("/foo").GetUri(d, doc) == root);
+ EXPECT_TRUE(Pointer("/foo/0").GetUri(d, doc) == root);
+ EXPECT_TRUE(Pointer("/foo/2").GetUri(d, doc) == root);
+ EXPECT_TRUE(Pointer("/foo/2/child").GetUri(d, doc) == Pointer::UriType("http://doc/root/inarray"));
+ EXPECT_TRUE(Pointer("/int").GetUri(d, doc) == root);
+ EXPECT_TRUE(Pointer("/str").GetUri(d, doc) == root);
+ EXPECT_TRUE(Pointer("/obj").GetUri(d, doc) == root);
+ EXPECT_TRUE(Pointer("/obj/child").GetUri(d, doc) == Pointer::UriType("http://doc/root/inobj"));
+ EXPECT_TRUE(Pointer("/jbo").GetUri(d, doc) == root);
+ EXPECT_TRUE(Pointer("/jbo/child").GetUri(d, doc) == root); // id not string
+
+ size_t unresolvedTokenIndex;
+ EXPECT_TRUE(Pointer("/abc").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // Out of boundary
+ EXPECT_EQ(0u, unresolvedTokenIndex);
+ EXPECT_TRUE(Pointer("/foo/3").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // Out of boundary
+ EXPECT_EQ(1u, unresolvedTokenIndex);
+ EXPECT_TRUE(Pointer("/foo/a").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // "/foo" is an array, cannot query by "a"
+ EXPECT_EQ(1u, unresolvedTokenIndex);
+ EXPECT_TRUE(Pointer("/foo/0/0").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // "/foo/0" is an string, cannot further query
+ EXPECT_EQ(2u, unresolvedTokenIndex);
+ EXPECT_TRUE(Pointer("/foo/0/a").GetUri(d, doc, &unresolvedTokenIndex, &allocator) == empty); // "/foo/0" is an string, cannot further query
+ EXPECT_EQ(2u, unresolvedTokenIndex);
+
+ Pointer::Token tokens[] = { { "foo ...", 3, kPointerInvalidIndex } };
+ EXPECT_TRUE(Pointer(tokens, 1).GetUri(d, doc) == root);
+}
+
TEST(Pointer, Get) {
Document d;
d.Parse(kJson);
@@ -626,16 +712,20 @@ TEST(Pointer, Get) {
EXPECT_EQ(&d["k\"l"], Pointer("/k\"l").Get(d));
EXPECT_EQ(&d[" "], Pointer("/ ").Get(d));
EXPECT_EQ(&d["m~n"], Pointer("/m~0n").Get(d));
- EXPECT_TRUE(Pointer("/abc").Get(d) == 0);
+
+ EXPECT_TRUE(Pointer("/abc").Get(d) == 0); // Out of boundary
size_t unresolvedTokenIndex;
EXPECT_TRUE(Pointer("/foo/2").Get(d, &unresolvedTokenIndex) == 0); // Out of boundary
- EXPECT_EQ(1, unresolvedTokenIndex);
+ EXPECT_EQ(1u, unresolvedTokenIndex);
EXPECT_TRUE(Pointer("/foo/a").Get(d, &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a"
- EXPECT_EQ(1, unresolvedTokenIndex);
+ EXPECT_EQ(1u, unresolvedTokenIndex);
EXPECT_TRUE(Pointer("/foo/0/0").Get(d, &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
- EXPECT_EQ(2, unresolvedTokenIndex);
+ EXPECT_EQ(2u, unresolvedTokenIndex);
EXPECT_TRUE(Pointer("/foo/0/a").Get(d, &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
- EXPECT_EQ(2, unresolvedTokenIndex);
+ EXPECT_EQ(2u, unresolvedTokenIndex);
+
+ Pointer::Token tokens[] = { { "foo ...", 3, kPointerInvalidIndex } };
+ EXPECT_EQ(&d["foo"], Pointer(tokens, 1).Get(d));
}
TEST(Pointer, GetWithDefault) {
@@ -862,7 +952,7 @@ TEST(Pointer, Set_NoAllocator) {
#endif
}
-TEST(Pointer, Swap) {
+TEST(Pointer, Swap_Value) {
Document d;
d.Parse(kJson);
Document::AllocatorType& a = d.GetAllocator();
@@ -871,7 +961,7 @@ TEST(Pointer, Swap) {
EXPECT_STREQ("bar", d["foo"][1].GetString());
}
-TEST(Pointer, Swap_NoAllocator) {
+TEST(Pointer, Swap_Value_NoAllocator) {
Document d;
d.Parse(kJson);
Pointer("/foo/0").Swap(d, *Pointer("/foo/1").Get(d));
@@ -954,13 +1044,13 @@ TEST(Pointer, GetValueByPointer) {
size_t unresolvedTokenIndex;
EXPECT_TRUE(GetValueByPointer(d, "/foo/2", &unresolvedTokenIndex) == 0); // Out of boundary
- EXPECT_EQ(1, unresolvedTokenIndex);
+ EXPECT_EQ(1u, unresolvedTokenIndex);
EXPECT_TRUE(GetValueByPointer(d, "/foo/a", &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a"
- EXPECT_EQ(1, unresolvedTokenIndex);
+ EXPECT_EQ(1u, unresolvedTokenIndex);
EXPECT_TRUE(GetValueByPointer(d, "/foo/0/0", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
- EXPECT_EQ(2, unresolvedTokenIndex);
+ EXPECT_EQ(2u, unresolvedTokenIndex);
EXPECT_TRUE(GetValueByPointer(d, "/foo/0/a", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
- EXPECT_EQ(2, unresolvedTokenIndex);
+ EXPECT_EQ(2u, unresolvedTokenIndex);
// const version
const Value& v = d;
@@ -968,13 +1058,13 @@ TEST(Pointer, GetValueByPointer) {
EXPECT_EQ(&d["foo"][0], GetValueByPointer(v, "/foo/0"));
EXPECT_TRUE(GetValueByPointer(v, "/foo/2", &unresolvedTokenIndex) == 0); // Out of boundary
- EXPECT_EQ(1, unresolvedTokenIndex);
+ EXPECT_EQ(1u, unresolvedTokenIndex);
EXPECT_TRUE(GetValueByPointer(v, "/foo/a", &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a"
- EXPECT_EQ(1, unresolvedTokenIndex);
+ EXPECT_EQ(1u, unresolvedTokenIndex);
EXPECT_TRUE(GetValueByPointer(v, "/foo/0/0", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
- EXPECT_EQ(2, unresolvedTokenIndex);
+ EXPECT_EQ(2u, unresolvedTokenIndex);
EXPECT_TRUE(GetValueByPointer(v, "/foo/0/a", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
- EXPECT_EQ(2, unresolvedTokenIndex);
+ EXPECT_EQ(2u, unresolvedTokenIndex);
}
@@ -1488,7 +1578,112 @@ TEST(Pointer, Ambiguity) {
}
}
-// https://github.com/miloyip/rapidjson/issues/483
+TEST(Pointer, ResolveOnObject) {
+ Document d;
+ EXPECT_FALSE(d.Parse("{\"a\": 123}").HasParseError());
+
+ {
+ Value::ConstObject o = static_cast<const Document&>(d).GetObject();
+ EXPECT_EQ(123, Pointer("/a").Get(o)->GetInt());
+ }
+
+ {
+ Value::Object o = d.GetObject();
+ Pointer("/a").Set(o, 456, d.GetAllocator());
+ EXPECT_EQ(456, Pointer("/a").Get(o)->GetInt());
+ }
+}
+
+TEST(Pointer, ResolveOnArray) {
+ Document d;
+ EXPECT_FALSE(d.Parse("[1, 2, 3]").HasParseError());
+
+ {
+ Value::ConstArray a = static_cast<const Document&>(d).GetArray();
+ EXPECT_EQ(2, Pointer("/1").Get(a)->GetInt());
+ }
+
+ {
+ Value::Array a = d.GetArray();
+ Pointer("/1").Set(a, 123, d.GetAllocator());
+ EXPECT_EQ(123, Pointer("/1").Get(a)->GetInt());
+ }
+}
+
+TEST(Pointer, LessThan) {
+ static const struct {
+ const char *str;
+ bool valid;
+ } pointers[] = {
+ { "/a/b", true },
+ { "/a", true },
+ { "/d/1", true },
+ { "/d/2/z", true },
+ { "/d/2/3", true },
+ { "/d/2", true },
+ { "/a/c", true },
+ { "/e/f~g", false },
+ { "/d/2/zz", true },
+ { "/d/1", true },
+ { "/d/2/z", true },
+ { "/e/f~~g", false },
+ { "/e/f~0g", true },
+ { "/e/f~1g", true },
+ { "/e/f.g", true },
+ { "", true }
+ };
+ static const char *ordered_pointers[] = {
+ "",
+ "/a",
+ "/a/b",
+ "/a/c",
+ "/d/1",
+ "/d/1",
+ "/d/2",
+ "/e/f.g",
+ "/e/f~1g",
+ "/e/f~0g",
+ "/d/2/3",
+ "/d/2/z",
+ "/d/2/z",
+ "/d/2/zz",
+ NULL, // was invalid "/e/f~g"
+ NULL // was invalid "/e/f~~g"
+ };
+ typedef MemoryPoolAllocator<> AllocatorType;
+ typedef GenericPointer<Value, AllocatorType> PointerType;
+ typedef std::multimap<PointerType, size_t> PointerMap;
+ PointerMap map;
+ PointerMap::iterator it;
+ AllocatorType allocator;
+ size_t i;
+
+ EXPECT_EQ(sizeof(pointers) / sizeof(pointers[0]),
+ sizeof(ordered_pointers) / sizeof(ordered_pointers[0]));
+
+ for (i = 0; i < sizeof(pointers) / sizeof(pointers[0]); ++i) {
+ it = map.insert(PointerMap::value_type(PointerType(pointers[i].str, &allocator), i));
+ if (!it->first.IsValid()) {
+ EXPECT_EQ(++it, map.end());
+ }
+ }
+
+ for (i = 0, it = map.begin(); it != map.end(); ++it, ++i) {
+ EXPECT_TRUE(it->second < sizeof(pointers) / sizeof(pointers[0]));
+ EXPECT_EQ(it->first.IsValid(), pointers[it->second].valid);
+ EXPECT_TRUE(i < sizeof(ordered_pointers) / sizeof(ordered_pointers[0]));
+ EXPECT_EQ(it->first.IsValid(), !!ordered_pointers[i]);
+ if (it->first.IsValid()) {
+ std::stringstream ss;
+ OStreamWrapper os(ss);
+ EXPECT_TRUE(it->first.Stringify(os));
+ EXPECT_EQ(ss.str(), pointers[it->second].str);
+ EXPECT_EQ(ss.str(), ordered_pointers[i]);
+ }
+ }
+}
+
+// https://github.com/Tencent/rapidjson/issues/483
namespace myjson {
class MyAllocator
@@ -1522,3 +1717,14 @@ TEST(Pointer, Issue483) {
value.SetString(mystr.c_str(), static_cast<SizeType>(mystr.length()), document.GetAllocator());
myjson::Pointer(path.c_str()).Set(document, value, document.GetAllocator());
}
+
+TEST(Pointer, Issue1899) {
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ PointerType p;
+ PointerType q = p.Append("foo");
+ EXPECT_TRUE(PointerType("/foo") == q);
+ q = q.Append(1234);
+ EXPECT_TRUE(PointerType("/foo/1234") == q);
+ q = q.Append("");
+ EXPECT_TRUE(PointerType("/foo/1234/") == q);
+}
diff --git a/3rdparty/rapidjson/test/unittest/prettywritertest.cpp b/3rdparty/rapidjson/test/unittest/prettywritertest.cpp
index a372f7986f8..0b7feef3b25 100644
--- a/3rdparty/rapidjson/test/unittest/prettywritertest.cpp
+++ b/3rdparty/rapidjson/test/unittest/prettywritertest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -18,6 +18,11 @@
#include "rapidjson/stringbuffer.h"
#include "rapidjson/filewritestream.h"
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
using namespace rapidjson;
static const char kJson[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,-1],\"u64\":1234567890123456789,\"i64\":-1234567890123456789}";
@@ -162,6 +167,7 @@ TEST(PrettyWriter, OStreamWrapper) {
TEST(PrettyWriter, FileWriteStream) {
char filename[L_tmpnam];
FILE* fp = TempFile(filename);
+ ASSERT_TRUE(fp!=NULL);
char buffer[16];
FileWriteStream os(fp, buffer, sizeof(buffer));
PrettyWriter<FileWriteStream> writer(os);
@@ -201,3 +207,167 @@ TEST(PrettyWriter, RawValue) {
"}",
buffer.GetString());
}
+
+TEST(PrettyWriter, InvalidEventSequence) {
+ // {]
+ {
+ StringBuffer buffer;
+ PrettyWriter<StringBuffer> writer(buffer);
+ writer.StartObject();
+ EXPECT_THROW(writer.EndArray(), AssertException);
+ EXPECT_FALSE(writer.IsComplete());
+ }
+
+ // [}
+ {
+ StringBuffer buffer;
+ PrettyWriter<StringBuffer> writer(buffer);
+ writer.StartArray();
+ EXPECT_THROW(writer.EndObject(), AssertException);
+ EXPECT_FALSE(writer.IsComplete());
+ }
+
+ // { 1:
+ {
+ StringBuffer buffer;
+ PrettyWriter<StringBuffer> writer(buffer);
+ writer.StartObject();
+ EXPECT_THROW(writer.Int(1), AssertException);
+ EXPECT_FALSE(writer.IsComplete());
+ }
+
+ // { 'a' }
+ {
+ StringBuffer buffer;
+ PrettyWriter<StringBuffer> writer(buffer);
+ writer.StartObject();
+ writer.Key("a");
+ EXPECT_THROW(writer.EndObject(), AssertException);
+ EXPECT_FALSE(writer.IsComplete());
+ }
+
+ // { 'a':'b','c' }
+ {
+ StringBuffer buffer;
+ PrettyWriter<StringBuffer> writer(buffer);
+ writer.StartObject();
+ writer.Key("a");
+ writer.String("b");
+ writer.Key("c");
+ EXPECT_THROW(writer.EndObject(), AssertException);
+ EXPECT_FALSE(writer.IsComplete());
+ }
+}
+
+TEST(PrettyWriter, NaN) {
+ double nan = std::numeric_limits<double>::quiet_NaN();
+
+ EXPECT_TRUE(internal::Double(nan).IsNan());
+ StringBuffer buffer;
+ {
+ PrettyWriter<StringBuffer> writer(buffer);
+ EXPECT_FALSE(writer.Double(nan));
+ }
+ {
+ PrettyWriter<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> writer(buffer);
+ EXPECT_TRUE(writer.Double(nan));
+ EXPECT_STREQ("NaN", buffer.GetString());
+ }
+ GenericStringBuffer<UTF16<> > buffer2;
+ PrettyWriter<GenericStringBuffer<UTF16<> > > writer2(buffer2);
+ EXPECT_FALSE(writer2.Double(nan));
+}
+
+TEST(PrettyWriter, Inf) {
+ double inf = std::numeric_limits<double>::infinity();
+
+ EXPECT_TRUE(internal::Double(inf).IsInf());
+ StringBuffer buffer;
+ {
+ PrettyWriter<StringBuffer> writer(buffer);
+ EXPECT_FALSE(writer.Double(inf));
+ }
+ {
+ PrettyWriter<StringBuffer> writer(buffer);
+ EXPECT_FALSE(writer.Double(-inf));
+ }
+ {
+ PrettyWriter<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> writer(buffer);
+ EXPECT_TRUE(writer.Double(inf));
+ }
+ {
+ PrettyWriter<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> writer(buffer);
+ EXPECT_TRUE(writer.Double(-inf));
+ }
+ EXPECT_STREQ("Infinity-Infinity", buffer.GetString());
+}
+
+TEST(PrettyWriter, Issue_889) {
+ char buf[100] = "Hello";
+
+ StringBuffer buffer;
+ PrettyWriter<StringBuffer> writer(buffer);
+ writer.StartArray();
+ writer.String(buf);
+ writer.EndArray();
+
+ EXPECT_STREQ("[\n \"Hello\"\n]", buffer.GetString());
+ EXPECT_TRUE(writer.IsComplete()); \
+}
+
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+static PrettyWriter<StringBuffer> WriterGen(StringBuffer &target) {
+ PrettyWriter<StringBuffer> writer(target);
+ writer.StartObject();
+ writer.Key("a");
+ writer.Int(1);
+ return writer;
+}
+
+TEST(PrettyWriter, MoveCtor) {
+ StringBuffer buffer;
+ PrettyWriter<StringBuffer> writer(WriterGen(buffer));
+ writer.EndObject();
+ EXPECT_TRUE(writer.IsComplete());
+ EXPECT_STREQ(
+ "{\n"
+ " \"a\": 1\n"
+ "}",
+ buffer.GetString());
+}
+#endif
+
+TEST(PrettyWriter, Issue_1336) {
+#define T(meth, val, expected) \
+ { \
+ StringBuffer buffer; \
+ PrettyWriter<StringBuffer> writer(buffer); \
+ writer.meth(val); \
+ \
+ EXPECT_STREQ(expected, buffer.GetString()); \
+ EXPECT_TRUE(writer.IsComplete()); \
+ }
+
+ T(Bool, false, "false");
+ T(Bool, true, "true");
+ T(Int, 0, "0");
+ T(Uint, 0, "0");
+ T(Int64, 0, "0");
+ T(Uint64, 0, "0");
+ T(Double, 0, "0.0");
+ T(String, "Hello", "\"Hello\"");
+#undef T
+
+ StringBuffer buffer;
+ PrettyWriter<StringBuffer> writer(buffer);
+ writer.Null();
+
+ EXPECT_STREQ("null", buffer.GetString());
+ EXPECT_TRUE(writer.IsComplete());
+}
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/readertest.cpp b/3rdparty/rapidjson/test/unittest/readertest.cpp
index 64a1f9c3cf4..f828dbbe258 100644
--- a/3rdparty/rapidjson/test/unittest/readertest.cpp
+++ b/3rdparty/rapidjson/test/unittest/readertest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -207,6 +207,7 @@ static void TestParseDouble() {
TEST_DOUBLE(fullPrecision, "0.0", 0.0);
TEST_DOUBLE(fullPrecision, "-0.0", -0.0); // For checking issue #289
+ TEST_DOUBLE(fullPrecision, "0e100", 0.0); // For checking issue #1249
TEST_DOUBLE(fullPrecision, "1.0", 1.0);
TEST_DOUBLE(fullPrecision, "-1.0", -1.0);
TEST_DOUBLE(fullPrecision, "1.5", 1.5);
@@ -233,7 +234,7 @@ static void TestParseDouble() {
TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow
TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double)
TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double)
- TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120
+ TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/Tencent/rapidjson/issues/120
TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise
TEST_DOUBLE(fullPrecision, "45913141877270640000.0", 45913141877270640000.0);
TEST_DOUBLE(fullPrecision, "2.2250738585072011e-308", 2.2250738585072011e-308); // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
@@ -242,16 +243,18 @@ static void TestParseDouble() {
TEST_DOUBLE(fullPrecision, "1e-214748363", 0.0); // Maximum supported negative exponent
TEST_DOUBLE(fullPrecision, "1e-214748364", 0.0);
TEST_DOUBLE(fullPrecision, "1e-21474836311", 0.0);
+ TEST_DOUBLE(fullPrecision, "1.00000000001e-2147483638", 0.0);
TEST_DOUBLE(fullPrecision, "0.017976931348623157e+310", 1.7976931348623157e+308); // Max double in another form
+ TEST_DOUBLE(fullPrecision, "128.74836467836484838364836483643636483648e-336", 0.0); // Issue #1251
// Since
- // abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... �� 10^-324
- // abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... �� 10 ^ -324
+ // abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... x 10^-324
+ // abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... x 10 ^ -324
// So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e-308
TEST_DOUBLE(fullPrecision, "2.2250738585072012e-308", 2.2250738585072014e-308); // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
// More closer to normal/subnormal boundary
- // boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... �� 10^-308
+ // boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... x 10^-308
TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164564e-308", 2.2250738585072009e-308);
TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164565e-308", 2.2250738585072014e-308);
@@ -376,6 +379,208 @@ static void TestParseDouble() {
d = d.Value() * 0.5;
}
}
+
+ // Issue 1249
+ TEST_DOUBLE(fullPrecision, "0e100", 0.0);
+
+ // Issue 1251
+ TEST_DOUBLE(fullPrecision, "128.74836467836484838364836483643636483648e-336", 0.0);
+
+ // Issue 1256
+ TEST_DOUBLE(fullPrecision,
+ "6223372036854775296.1701512723685473547372536854755293372036854685477"
+ "529752233737201701512337200972013723685473123372036872036854236854737"
+ "247372368372367752975258547752975254729752547372368737201701512354737"
+ "83723677529752585477247372368372368547354737253685475529752",
+ 6223372036854775808.0);
+
+#if 0
+ // Test (length + exponent) overflow
+ TEST_DOUBLE(fullPrecision, "0e+2147483647", 0.0);
+ TEST_DOUBLE(fullPrecision, "0e-2147483648", 0.0);
+ TEST_DOUBLE(fullPrecision, "1e-2147483648", 0.0);
+ TEST_DOUBLE(fullPrecision, "0e+9223372036854775807", 0.0);
+ TEST_DOUBLE(fullPrecision, "0e-9223372036854775808", 0.0);
+#endif
+
+ if (fullPrecision)
+ {
+ TEST_DOUBLE(fullPrecision, "1e-325", 0.0);
+ TEST_DOUBLE(fullPrecision, "1e-324", 0.0);
+ TEST_DOUBLE(fullPrecision, "2e-324", 0.0);
+ TEST_DOUBLE(fullPrecision, "2.4703282292062327e-324", 0.0);
+ TEST_DOUBLE(fullPrecision, "2.4703282292062328e-324", 5e-324);
+ TEST_DOUBLE(fullPrecision, "2.48e-324",5e-324);
+ TEST_DOUBLE(fullPrecision, "2.5e-324", 5e-324);
+
+ // Slightly above max-normal
+ TEST_DOUBLE(fullPrecision, "1.7976931348623158e+308", 1.7976931348623158e+308);
+
+ TEST_DOUBLE(fullPrecision,
+ "17976931348623157081452742373170435679807056752584499659891747680315726"
+ "07800285387605895586327668781715404589535143824642343213268894641827684"
+ "67546703537516986049910576551282076245490090389328944075868508455133942"
+ "30458323690322294816580855933212334827479782620414472316873817718091929"
+ "9881250404026184124858368",
+ (std::numeric_limits<double>::max)());
+
+ TEST_DOUBLE(fullPrecision,
+ "243546080556034731077856379609316893158278902575447060151047"
+ "212703405344938119816206067372775299130836050315842578309818"
+ "316450894337978612745889730079163798234256495613858256849283"
+ "467066859489192118352020514036083287319232435355752493038825"
+ "828481044358810649108367633313557305310641892225870327827273"
+ "41408256.000000",
+ 2.4354608055603473e+307);
+ // 9007199254740991 * 2^971 (max normal)
+ TEST_DOUBLE(fullPrecision,
+ "1.797693134862315708145274237317043567980705675258449965989174768031572607800285"
+ "38760589558632766878171540458953514382464234321326889464182768467546703537516986"
+ "04991057655128207624549009038932894407586850845513394230458323690322294816580855"
+ "9332123348274797826204144723168738177180919299881250404026184124858368e+308",
+ 1.797693134862315708e+308 // 0x1.fffffffffffffp1023
+ );
+#if 0
+ // TODO:
+ // Should work at least in full-precision mode...
+ TEST_DOUBLE(fullPrecision,
+ "0.00000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000024703282292062327208828439643411068618252"
+ "9901307162382212792841250337753635104375932649918180817996189"
+ "8982823477228588654633283551779698981993873980053909390631503"
+ "5659515570226392290858392449105184435931802849936536152500319"
+ "3704576782492193656236698636584807570015857692699037063119282"
+ "7955855133292783433840935197801553124659726357957462276646527"
+ "2827220056374006485499977096599470454020828166226237857393450"
+ "7363390079677619305775067401763246736009689513405355374585166"
+ "6113422376667860416215968046191446729184030053005753084904876"
+ "5391711386591646239524912623653881879636239373280423891018672"
+ "3484976682350898633885879256283027559956575244555072551893136"
+ "9083625477918694866799496832404970582102851318545139621383772"
+ "2826145437693412532098591327667236328125",
+ 0.0);
+#endif
+ // 9007199254740991 * 2^-1074 = (2^53 - 1) * 2^-1074
+ TEST_DOUBLE(fullPrecision,
+ "4.450147717014402272114819593418263951869639092703291296046852219449644444042153"
+ "89103305904781627017582829831782607924221374017287738918929105531441481564124348"
+ "67599762821265346585071045737627442980259622449029037796981144446145705102663115"
+ "10031828794952795966823603998647925096578034214163701381261333311989876551545144"
+ "03152612538132666529513060001849177663286607555958373922409899478075565940981010"
+ "21612198814605258742579179000071675999344145086087205681577915435923018910334964"
+ "86942061405218289243144579760516365090360651414037721744226256159024466852576737"
+ "24464300755133324500796506867194913776884780053099639677097589658441378944337966"
+ "21993967316936280457084866613206797017728916080020698679408551343728867675409720"
+ "757232455434770912461317493580281734466552734375e-308",
+ 4.450147717014402272e-308 // 0x1.fffffffffffffp-1022
+ );
+ // 9007199254740990 * 2^-1074
+ TEST_DOUBLE(fullPrecision,
+ "4.450147717014401778049173752171719775300846224481918930987049605124880018456471"
+ "39035755177760751831052846195619008686241717547743167145836439860405887584484471"
+ "19639655002484083577939142623582164522087943959208000909794783876158397872163051"
+ "22622675229968408654350206725478309956546318828765627255022767720818849892988457"
+ "26333908582101604036318532842699932130356061901518261174396928478121372742040102"
+ "17446565569357687263889031732270082446958029584739170416643195242132750803227473"
+ "16608838720742955671061336566907126801014814608027120593609275183716632624844904"
+ "31985250929886016737037234388448352929102742708402644340627409931664203093081360"
+ "70794835812045179006047003875039546061891526346421705014598610179523165038319441"
+ "51446491086954182492263498716056346893310546875e-308",
+ 4.450147717014401778e-308 // 0x1.ffffffffffffep-1022
+ );
+ // half way between the two numbers above.
+ // round to nearest even.
+ TEST_DOUBLE(fullPrecision,
+ "4.450147717014402025081996672794991863585242658592605113516950912287262231249312"
+ "64069530541271189424317838013700808305231545782515453032382772695923684574304409"
+ "93619708911874715081505094180604803751173783204118519353387964161152051487413083"
+ "16327252012460602310586905362063117526562176521464664318142050516404363222266800"
+ "64743260560117135282915796422274554896821334728738317548403413978098469341510556"
+ "19529382191981473003234105366170879223151087335413188049110555339027884856781219"
+ "01775450062980622457102958163711745945687733011032421168917765671370549738710820"
+ "78224775842509670618916870627821633352993761380751142008862499795052791018709663"
+ "46394401564490729731565935244123171539810221213221201847003580761626016356864581"
+ "1358486831521563686919762403704226016998291015625e-308",
+ 4.450147717014401778e-308 // 0x1.ffffffffffffep-1022
+ );
+ TEST_DOUBLE(fullPrecision,
+ "4.450147717014402025081996672794991863585242658592605113516950912287262231249312"
+ "64069530541271189424317838013700808305231545782515453032382772695923684574304409"
+ "93619708911874715081505094180604803751173783204118519353387964161152051487413083"
+ "16327252012460602310586905362063117526562176521464664318142050516404363222266800"
+ "64743260560117135282915796422274554896821334728738317548403413978098469341510556"
+ "19529382191981473003234105366170879223151087335413188049110555339027884856781219"
+ "01775450062980622457102958163711745945687733011032421168917765671370549738710820"
+ "78224775842509670618916870627821633352993761380751142008862499795052791018709663"
+ "46394401564490729731565935244123171539810221213221201847003580761626016356864581"
+ "13584868315215636869197624037042260169982910156250000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000e-308",
+ 4.450147717014401778e-308 // 0x1.ffffffffffffep-1022
+ );
+#if 0
+ // ... round up
+ // TODO:
+ // Should work at least in full-precision mode...
+ TEST_DOUBLE(fullPrecision,
+ "4.450147717014402025081996672794991863585242658592605113516950912287262231249312"
+ "64069530541271189424317838013700808305231545782515453032382772695923684574304409"
+ "93619708911874715081505094180604803751173783204118519353387964161152051487413083"
+ "16327252012460602310586905362063117526562176521464664318142050516404363222266800"
+ "64743260560117135282915796422274554896821334728738317548403413978098469341510556"
+ "19529382191981473003234105366170879223151087335413188049110555339027884856781219"
+ "01775450062980622457102958163711745945687733011032421168917765671370549738710820"
+ "78224775842509670618916870627821633352993761380751142008862499795052791018709663"
+ "46394401564490729731565935244123171539810221213221201847003580761626016356864581"
+ "13584868315215636869197624037042260169982910156250000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000001e-308",
+ 4.450147717014402272e-308 // 0x1.fffffffffffffp-1022
+ );
+#endif
+ // ... round down
+ TEST_DOUBLE(fullPrecision,
+ "4.450147717014402025081996672794991863585242658592605113516950912287262231249312"
+ "64069530541271189424317838013700808305231545782515453032382772695923684574304409"
+ "93619708911874715081505094180604803751173783204118519353387964161152051487413083"
+ "16327252012460602310586905362063117526562176521464664318142050516404363222266800"
+ "64743260560117135282915796422274554896821334728738317548403413978098469341510556"
+ "19529382191981473003234105366170879223151087335413188049110555339027884856781219"
+ "01775450062980622457102958163711745945687733011032421168917765671370549738710820"
+ "78224775842509670618916870627821633352993761380751142008862499795052791018709663"
+ "46394401564490729731565935244123171539810221213221201847003580761626016356864581"
+ "13584868315215636869197624037042260169982910156249999999999999999999999999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999e-308",
+ 4.450147717014401778e-308 // 0x1.ffffffffffffep-1022
+ );
+ // Slightly below half way between max-normal and infinity.
+ // Should round down.
+ TEST_DOUBLE(fullPrecision,
+ "1.797693134862315807937289714053034150799341327100378269361737789804449682927647"
+ "50946649017977587207096330286416692887910946555547851940402630657488671505820681"
+ "90890200070838367627385484581771153176447573027006985557136695962284291481986083"
+ "49364752927190741684443655107043427115596995080930428801779041744977919999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999"
+ "99999999999999999999999999999999999999999999999999999999999999999999999999999999e+308",
+ 1.797693134862315708e+308 // 0x1.fffffffffffffp1023
+ );
+ }
+
#undef TEST_DOUBLE
}
@@ -415,21 +620,23 @@ TEST(Reader, ParseNumber_NormalPrecisionError) {
uint64_t bias1 = e.ToBias();
uint64_t bias2 = a.ToBias();
double ulp = static_cast<double>(bias1 >= bias2 ? bias1 - bias2 : bias2 - bias1);
- ulpMax = std::max(ulpMax, ulp);
+ ulpMax = (std::max)(ulpMax, ulp);
ulpSum += ulp;
}
printf("ULP Average = %g, Max = %g \n", ulpSum / count, ulpMax);
}
-TEST(Reader, ParseNumber_Error) {
+template<bool fullPrecision>
+static void TestParseNumberError() {
#define TEST_NUMBER_ERROR(errorCode, str, errorOffset, streamPos) \
{ \
- char buffer[1001]; \
+ char buffer[2048]; \
+ ASSERT_LT(std::strlen(str), 2048u); \
sprintf(buffer, "%s", str); \
InsituStringStream s(buffer); \
BaseReaderHandler<> h; \
Reader reader; \
- EXPECT_FALSE(reader.Parse(s, h)); \
+ EXPECT_FALSE(reader.Parse<fullPrecision ? kParseFullPrecisionFlag : 0>(s, h)); \
EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
EXPECT_EQ(streamPos, s.Tell());\
@@ -442,21 +649,109 @@ TEST(Reader, ParseNumber_Error) {
for (int i = 1; i < 310; i++)
n1e309[i] = '0';
n1e309[310] = '\0';
- TEST_NUMBER_ERROR(kParseErrorNumberTooBig, n1e309, 0, 309);
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, n1e309, 0u, 310u);
}
- TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e309", 0, 5);
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e309", 0u, 5u);
// Miss fraction part in number.
- TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.", 2, 2);
- TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.a", 2, 2);
+ TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.", 2u, 2u);
+ TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.a", 2u, 2u);
// Miss exponent in number.
- TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e", 2, 2);
- TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e_", 2, 2);
+ TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e", 2u, 2u);
+ TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e_", 2u, 2u);
+
+ // Issue 849
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1.8e308", 0u, 7u);
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "5e308", 0u, 5u);
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e309", 0u, 5u);
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1.0e310", 0u, 7u);
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1.00e310", 0u, 8u);
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "-1.8e308", 0u, 8u);
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "-1e309", 0u, 6u);
+
+ // Issue 1253
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "2e308", 0u, 5u);
+
+ // Issue 1259
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig,
+ "88474320368547737236837236775298547354737253685475547552933720368546854775297525"
+ "29337203685468547770151233720097201372368547312337203687203685423685123372036872"
+ "03685473724737236837236775297525854775297525472975254737236873720170151235473783"
+ "7236737247372368772473723683723456789012E66", 0u, 283u);
+
+#if 0
+ // Test (length + exponent) overflow
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e+2147483647", 0u, 13u);
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e+9223372036854775807", 0u, 22u);
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e+10000", 0u, 8u);
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e+50000", 0u, 8u);
+#endif
+
+ // 9007199254740992 * 2^971 ("infinity")
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig,
+ "1.797693134862315907729305190789024733617976978942306572734300811577326758055009"
+ "63132708477322407536021120113879871393357658789768814416622492847430639474124377"
+ "76789342486548527630221960124609411945308295208500576883815068234246288147391311"
+ "0540827237163350510684586298239947245938479716304835356329624224137216e+308", 0u, 315u);
+
+ // TODO:
+ // These tests (currently) fail in normal-precision mode
+ if (fullPrecision)
+ {
+ // Half way between max-normal and infinity
+ // Should round to infinity in nearest-even mode.
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig,
+ "1.797693134862315807937289714053034150799341327100378269361737789804449682927647"
+ "50946649017977587207096330286416692887910946555547851940402630657488671505820681"
+ "90890200070838367627385484581771153176447573027006985557136695962284291481986083"
+ "49364752927190741684443655107043427115596995080930428801779041744977920000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000e+308", 0u, 1125u);
+ // ...round up
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig,
+ "1.797693134862315807937289714053034150799341327100378269361737789804449682927647"
+ "50946649017977587207096330286416692887910946555547851940402630657488671505820681"
+ "90890200070838367627385484581771153176447573027006985557136695962284291481986083"
+ "49364752927190741684443655107043427115596995080930428801779041744977920000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000001e+308", 0u, 1205u);
+ }
+
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig,
+ "10000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "0000000000000000000000000000000000000000000000000000000000000000000001", 0u, 310u);
#undef TEST_NUMBER_ERROR
}
+TEST(Reader, ParseNumberError_NormalPrecisionDouble) {
+ TestParseNumberError<false>();
+}
+
+TEST(Reader, ParseNumberError_FullPrecisionDouble) {
+ TestParseNumberError<true>();
+}
+
template <typename Encoding>
struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encoding> > {
ParseStringHandler() : str_(0), length_(0), copy_() {}
@@ -636,21 +931,24 @@ TEST(Reader, ParseString_Error) {
}
// Invalid escape character in string.
- TEST_STRING_ERROR(kParseErrorStringEscapeInvalid, "[\"\\a\"]", 2, 3);
+ TEST_STRING_ERROR(kParseErrorStringEscapeInvalid, "[\"\\a\"]", 2u, 3u);
// Incorrect hex digit after \\u escape in string.
- TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]", 2, 7);
+ TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]", 2u, 7u);
// Quotation in \\u escape in string (Issue #288)
- TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uaaa\"]", 2, 7);
- TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uD800\\uFFF\"]", 2, 13);
+ TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uaaa\"]", 2u, 7u);
+ TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uD800\\uFFF\"]", 2u, 13u);
// The surrogate pair in string is invalid.
- TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]", 2, 8);
- TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFFFF\"]", 2, 14);
+ TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]", 2u, 8u);
+ TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFFFF\"]", 2u, 14u);
+
+ // Single low surrogate pair in string is invalid.
+ TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\udc4d\"]", 2u, 8u);
// Missing a closing quotation mark in string.
- TEST_STRING_ERROR(kParseErrorStringMissQuotationMark, "[\"Test]", 7, 7);
+ TEST_STRING_ERROR(kParseErrorStringMissQuotationMark, "[\"Test]", 7u, 7u);
// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
@@ -673,7 +971,7 @@ TEST(Reader, ParseString_Error) {
char e[] = { '[', '\"', 0, ' ', '\"', ']', '\0' };
for (unsigned c = 0xC0u; c <= 0xFFu; c++) {
e[2] = static_cast<char>(c);
- int streamPos;
+ unsigned streamPos;
if (c <= 0xC1u)
streamPos = 3; // 0xC0 - 0xC1
else if (c <= 0xDFu)
@@ -684,7 +982,7 @@ TEST(Reader, ParseString_Error) {
streamPos = 6; // 0xF0 - 0xF4
else
streamPos = 3; // 0xF5 - 0xFF
- TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e, 2, streamPos);
+ TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e, 2u, streamPos);
}
}
@@ -725,6 +1023,8 @@ TEST(Reader, ParseString_Error) {
// Malform ASCII sequence
TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x80u), '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x01u), '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x1Cu), '\"', ']', '\0'));
#undef ARRAY
#undef TEST_STRINGARRAY_ERROR
@@ -765,7 +1065,7 @@ TEST(Reader, ParseArray) {
TEST(Reader, ParseArray_Error) {
#define TEST_ARRAY_ERROR(errorCode, str, errorOffset) \
{ \
- int streamPos = errorOffset; \
+ unsigned streamPos = errorOffset; \
char buffer[1001]; \
strncpy(buffer, str, 1000); \
InsituStringStream s(buffer); \
@@ -778,13 +1078,13 @@ TEST(Reader, ParseArray_Error) {
}
// Missing a comma or ']' after an array element.
- TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1", 2);
- TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1}", 2);
- TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1 2]", 3);
+ TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1", 2u);
+ TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1}", 2u);
+ TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1 2]", 3u);
// Array cannot have a trailing comma (without kParseTrailingCommasFlag);
// a value must follow a comma
- TEST_ARRAY_ERROR(kParseErrorValueInvalid, "[1,]", 3);
+ TEST_ARRAY_ERROR(kParseErrorValueInvalid, "[1,]", 3u);
#undef TEST_ARRAY_ERROR
}
@@ -933,7 +1233,7 @@ TEST(Reader, ParseInsituIterative_MultipleRoot) {
#define TEST_ERROR(errorCode, str, errorOffset) \
{ \
- int streamPos = errorOffset; \
+ unsigned streamPos = errorOffset; \
char buffer[1001]; \
strncpy(buffer, str, 1000); \
InsituStringStream s(buffer); \
@@ -947,48 +1247,48 @@ TEST(Reader, ParseInsituIterative_MultipleRoot) {
TEST(Reader, ParseDocument_Error) {
// The document is empty.
- TEST_ERROR(kParseErrorDocumentEmpty, "", 0);
- TEST_ERROR(kParseErrorDocumentEmpty, " ", 1);
- TEST_ERROR(kParseErrorDocumentEmpty, " \n", 2);
+ TEST_ERROR(kParseErrorDocumentEmpty, "", 0u);
+ TEST_ERROR(kParseErrorDocumentEmpty, " ", 1u);
+ TEST_ERROR(kParseErrorDocumentEmpty, " \n", 2u);
// The document root must not follow by other values.
- TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0", 3);
- TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0", 3);
- TEST_ERROR(kParseErrorDocumentRootNotSingular, "null []", 5);
- TEST_ERROR(kParseErrorDocumentRootNotSingular, "0 {}", 2);
+ TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0", 3u);
+ TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0", 3u);
+ TEST_ERROR(kParseErrorDocumentRootNotSingular, "null []", 5u);
+ TEST_ERROR(kParseErrorDocumentRootNotSingular, "0 {}", 2u);
}
TEST(Reader, ParseValue_Error) {
// Invalid value.
- TEST_ERROR(kParseErrorValueInvalid, "nulL", 3);
- TEST_ERROR(kParseErrorValueInvalid, "truE", 3);
- TEST_ERROR(kParseErrorValueInvalid, "falsE", 4);
- TEST_ERROR(kParseErrorValueInvalid, "a]", 0);
- TEST_ERROR(kParseErrorValueInvalid, ".1", 0);
+ TEST_ERROR(kParseErrorValueInvalid, "nulL", 3u);
+ TEST_ERROR(kParseErrorValueInvalid, "truE", 3u);
+ TEST_ERROR(kParseErrorValueInvalid, "falsE", 4u);
+ TEST_ERROR(kParseErrorValueInvalid, "a]", 0u);
+ TEST_ERROR(kParseErrorValueInvalid, ".1", 0u);
}
TEST(Reader, ParseObject_Error) {
// Missing a name for object member.
- TEST_ERROR(kParseErrorObjectMissName, "{1}", 1);
- TEST_ERROR(kParseErrorObjectMissName, "{:1}", 1);
- TEST_ERROR(kParseErrorObjectMissName, "{null:1}", 1);
- TEST_ERROR(kParseErrorObjectMissName, "{true:1}", 1);
- TEST_ERROR(kParseErrorObjectMissName, "{false:1}", 1);
- TEST_ERROR(kParseErrorObjectMissName, "{1:1}", 1);
- TEST_ERROR(kParseErrorObjectMissName, "{[]:1}", 1);
- TEST_ERROR(kParseErrorObjectMissName, "{{}:1}", 1);
- TEST_ERROR(kParseErrorObjectMissName, "{xyz:1}", 1);
+ TEST_ERROR(kParseErrorObjectMissName, "{1}", 1u);
+ TEST_ERROR(kParseErrorObjectMissName, "{:1}", 1u);
+ TEST_ERROR(kParseErrorObjectMissName, "{null:1}", 1u);
+ TEST_ERROR(kParseErrorObjectMissName, "{true:1}", 1u);
+ TEST_ERROR(kParseErrorObjectMissName, "{false:1}", 1u);
+ TEST_ERROR(kParseErrorObjectMissName, "{1:1}", 1u);
+ TEST_ERROR(kParseErrorObjectMissName, "{[]:1}", 1u);
+ TEST_ERROR(kParseErrorObjectMissName, "{{}:1}", 1u);
+ TEST_ERROR(kParseErrorObjectMissName, "{xyz:1}", 1u);
// Missing a colon after a name of object member.
- TEST_ERROR(kParseErrorObjectMissColon, "{\"a\" 1}", 5);
- TEST_ERROR(kParseErrorObjectMissColon, "{\"a\",1}", 4);
+ TEST_ERROR(kParseErrorObjectMissColon, "{\"a\" 1}", 5u);
+ TEST_ERROR(kParseErrorObjectMissColon, "{\"a\",1}", 4u);
// Must be a comma or '}' after an object member
- TEST_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, "{\"a\":1]", 6);
+ TEST_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, "{\"a\":1]", 6u);
// Object cannot have a trailing comma (without kParseTrailingCommasFlag);
// an object member name must follow a comma
- TEST_ERROR(kParseErrorObjectMissName, "{\"a\":1,}", 7);
+ TEST_ERROR(kParseErrorObjectMissName, "{\"a\":1,}", 7u);
// This tests that MemoryStream is checking the length in Peek().
{
@@ -1092,6 +1392,36 @@ private:
std::istream& is_;
};
+class WIStreamWrapper {
+public:
+ typedef wchar_t Ch;
+
+ WIStreamWrapper(std::wistream& is) : is_(is) {}
+
+ Ch Peek() const {
+ unsigned c = is_.peek();
+ return c == std::char_traits<wchar_t>::eof() ? Ch('\0') : static_cast<Ch>(c);
+ }
+
+ Ch Take() {
+ unsigned c = is_.get();
+ return c == std::char_traits<wchar_t>::eof() ? Ch('\0') : static_cast<Ch>(c);
+ }
+
+ size_t Tell() const { return static_cast<size_t>(is_.tellg()); }
+
+ Ch* PutBegin() { assert(false); return 0; }
+ void Put(Ch) { assert(false); }
+ void Flush() { assert(false); }
+ size_t PutEnd(Ch*) { assert(false); return 0; }
+
+private:
+ WIStreamWrapper(const WIStreamWrapper&);
+ WIStreamWrapper& operator=(const WIStreamWrapper&);
+
+ std::wistream& is_;
+};
+
TEST(Reader, Parse_IStreamWrapper_StringStream) {
const char* json = "[1,2,3,4]";
@@ -1108,7 +1438,7 @@ TEST(Reader, Parse_IStreamWrapper_StringStream) {
#define TESTERRORHANDLING(text, errorCode, offset)\
{\
- int streamPos = offset; \
+ unsigned streamPos = offset; \
StringStream json(text); \
BaseReaderHandler<> handler; \
Reader reader; \
@@ -1157,22 +1487,22 @@ template<typename Encoding = UTF8<> >
struct IterativeParsingReaderHandler {
typedef typename Encoding::Ch Ch;
- const static int LOG_NULL = -1;
- const static int LOG_BOOL = -2;
- const static int LOG_INT = -3;
- const static int LOG_UINT = -4;
- const static int LOG_INT64 = -5;
- const static int LOG_UINT64 = -6;
- const static int LOG_DOUBLE = -7;
- const static int LOG_STRING = -8;
- const static int LOG_STARTOBJECT = -9;
- const static int LOG_KEY = -10;
- const static int LOG_ENDOBJECT = -11;
- const static int LOG_STARTARRAY = -12;
- const static int LOG_ENDARRAY = -13;
+ const static uint32_t LOG_NULL = 0x10000000;
+ const static uint32_t LOG_BOOL = 0x20000000;
+ const static uint32_t LOG_INT = 0x30000000;
+ const static uint32_t LOG_UINT = 0x40000000;
+ const static uint32_t LOG_INT64 = 0x50000000;
+ const static uint32_t LOG_UINT64 = 0x60000000;
+ const static uint32_t LOG_DOUBLE = 0x70000000;
+ const static uint32_t LOG_STRING = 0x80000000;
+ const static uint32_t LOG_STARTOBJECT = 0x90000000;
+ const static uint32_t LOG_KEY = 0xA0000000;
+ const static uint32_t LOG_ENDOBJECT = 0xB0000000;
+ const static uint32_t LOG_STARTARRAY = 0xC0000000;
+ const static uint32_t LOG_ENDARRAY = 0xD0000000;
const static size_t LogCapacity = 256;
- int Logs[LogCapacity];
+ uint32_t Logs[LogCapacity];
size_t LogCount;
IterativeParsingReaderHandler() : LogCount(0) {
@@ -1202,8 +1532,8 @@ struct IterativeParsingReaderHandler {
bool EndObject(SizeType c) {
RAPIDJSON_ASSERT(LogCount < LogCapacity);
- Logs[LogCount++] = LOG_ENDOBJECT;
- Logs[LogCount++] = static_cast<int>(c);
+ RAPIDJSON_ASSERT((static_cast<uint32_t>(c) & 0xF0000000) == 0);
+ Logs[LogCount++] = LOG_ENDOBJECT | static_cast<uint32_t>(c);
return true;
}
@@ -1211,8 +1541,8 @@ struct IterativeParsingReaderHandler {
bool EndArray(SizeType c) {
RAPIDJSON_ASSERT(LogCount < LogCapacity);
- Logs[LogCount++] = LOG_ENDARRAY;
- Logs[LogCount++] = static_cast<int>(c);
+ RAPIDJSON_ASSERT((static_cast<uint32_t>(c) & 0xF0000000) == 0);
+ Logs[LogCount++] = LOG_ENDARRAY | static_cast<uint32_t>(c);
return true;
}
};
@@ -1228,7 +1558,7 @@ TEST(Reader, IterativeParsing_General) {
EXPECT_FALSE(r.IsError());
EXPECT_FALSE(reader.HasParseError());
- int e[] = {
+ uint32_t e[] = {
handler.LOG_STARTARRAY,
handler.LOG_INT,
handler.LOG_STARTOBJECT,
@@ -1236,14 +1566,14 @@ TEST(Reader, IterativeParsing_General) {
handler.LOG_STARTARRAY,
handler.LOG_INT,
handler.LOG_INT,
- handler.LOG_ENDARRAY, 2,
- handler.LOG_ENDOBJECT, 1,
+ handler.LOG_ENDARRAY | 2,
+ handler.LOG_ENDOBJECT | 1,
handler.LOG_NULL,
handler.LOG_BOOL,
handler.LOG_BOOL,
handler.LOG_STRING,
handler.LOG_DOUBLE,
- handler.LOG_ENDARRAY, 7
+ handler.LOG_ENDARRAY | 7
};
EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount);
@@ -1265,20 +1595,20 @@ TEST(Reader, IterativeParsing_Count) {
EXPECT_FALSE(r.IsError());
EXPECT_FALSE(reader.HasParseError());
- int e[] = {
+ uint32_t e[] = {
handler.LOG_STARTARRAY,
handler.LOG_STARTOBJECT,
- handler.LOG_ENDOBJECT, 0,
+ handler.LOG_ENDOBJECT | 0,
handler.LOG_STARTOBJECT,
handler.LOG_KEY,
handler.LOG_INT,
- handler.LOG_ENDOBJECT, 1,
+ handler.LOG_ENDOBJECT | 1,
handler.LOG_STARTARRAY,
handler.LOG_INT,
- handler.LOG_ENDARRAY, 1,
+ handler.LOG_ENDARRAY | 1,
handler.LOG_STARTARRAY,
- handler.LOG_ENDARRAY, 0,
- handler.LOG_ENDARRAY, 4
+ handler.LOG_ENDARRAY | 0,
+ handler.LOG_ENDARRAY | 4
};
EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount);
@@ -1289,6 +1619,51 @@ TEST(Reader, IterativeParsing_Count) {
}
}
+TEST(Reader, IterativePullParsing_General) {
+ {
+ IterativeParsingReaderHandler<> handler;
+ uint32_t e[] = {
+ handler.LOG_STARTARRAY,
+ handler.LOG_INT,
+ handler.LOG_STARTOBJECT,
+ handler.LOG_KEY,
+ handler.LOG_STARTARRAY,
+ handler.LOG_INT,
+ handler.LOG_INT,
+ handler.LOG_ENDARRAY | 2,
+ handler.LOG_ENDOBJECT | 1,
+ handler.LOG_NULL,
+ handler.LOG_BOOL,
+ handler.LOG_BOOL,
+ handler.LOG_STRING,
+ handler.LOG_DOUBLE,
+ handler.LOG_ENDARRAY | 7
+ };
+
+ StringStream is("[1, {\"k\": [1, 2]}, null, false, true, \"string\", 1.2]");
+ Reader reader;
+
+ reader.IterativeParseInit();
+ while (!reader.IterativeParseComplete()) {
+ size_t oldLogCount = handler.LogCount;
+ EXPECT_TRUE(oldLogCount < sizeof(e) / sizeof(int)) << "overrun";
+
+ EXPECT_TRUE(reader.IterativeParseNext<kParseDefaultFlags>(is, handler)) << "parse fail";
+ EXPECT_EQ(handler.LogCount, oldLogCount + 1) << "handler should be invoked exactly once each time";
+ EXPECT_EQ(e[oldLogCount], handler.Logs[oldLogCount]) << "wrong event returned";
+ }
+
+ EXPECT_FALSE(reader.HasParseError());
+ EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount) << "handler invoked wrong number of times";
+
+ // The handler should not be invoked when the JSON has been fully read, but it should not fail
+ size_t oldLogCount = handler.LogCount;
+ EXPECT_TRUE(reader.IterativeParseNext<kParseDefaultFlags>(is, handler)) << "parse-next past complete is allowed";
+ EXPECT_EQ(handler.LogCount, oldLogCount) << "parse-next past complete should not invoke handler";
+ EXPECT_FALSE(reader.HasParseError()) << "parse-next past complete should not generate parse error";
+ }
+}
+
// Test iterative parsing on kParseErrorTermination.
struct HandlerTerminateAtStartObject : public IterativeParsingReaderHandler<> {
bool StartObject() { return false; }
@@ -1633,6 +2008,129 @@ TEST(Reader, NumbersAsStrings) {
Reader reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
}
+ {
+ char n1e319[321]; // '1' followed by 319 '0'
+ n1e319[0] = '1';
+ for (int i = 1; i < 320; i++)
+ n1e319[i] = '0';
+ n1e319[320] = '\0';
+ StringStream s(n1e319);
+ NumbersAsStringsHandler h(n1e319);
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
+ }
+}
+
+struct NumbersAsStringsHandlerWChar_t {
+ bool Null() { return true; }
+ bool Bool(bool) { return true; }
+ bool Int(int) { return true; }
+ bool Uint(unsigned) { return true; }
+ bool Int64(int64_t) { return true; }
+ bool Uint64(uint64_t) { return true; }
+ bool Double(double) { return true; }
+ // 'str' is not null-terminated
+ bool RawNumber(const wchar_t* str, SizeType length, bool) {
+ EXPECT_TRUE(str != 0);
+ EXPECT_TRUE(expected_len_ == length);
+ EXPECT_TRUE(wcsncmp(str, expected_, length) == 0);
+ return true;
+ }
+ bool String(const wchar_t*, SizeType, bool) { return true; }
+ bool StartObject() { return true; }
+ bool Key(const wchar_t*, SizeType, bool) { return true; }
+ bool EndObject(SizeType) { return true; }
+ bool StartArray() { return true; }
+ bool EndArray(SizeType) { return true; }
+
+ NumbersAsStringsHandlerWChar_t(const wchar_t* expected)
+ : expected_(expected)
+ , expected_len_(wcslen(expected)) {}
+
+ const wchar_t* expected_;
+ size_t expected_len_;
+};
+
+TEST(Reader, NumbersAsStringsWChar_t) {
+ {
+ const wchar_t* json = L"{ \"pi\": 3.1416 } ";
+ GenericStringStream<UTF16<> > s(json);
+ NumbersAsStringsHandlerWChar_t h(L"3.1416");
+ GenericReader<UTF16<>, UTF16<> > reader;
+ EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
+ }
+ {
+ wchar_t* json = StrDup(L"{ \"pi\": 3.1416 } ");
+ GenericInsituStringStream<UTF16<> > s(json);
+ NumbersAsStringsHandlerWChar_t h(L"3.1416");
+ GenericReader<UTF16<>, UTF16<> > reader;
+ EXPECT_TRUE(reader.Parse<kParseInsituFlag | kParseNumbersAsStringsFlag>(s, h));
+ free(json);
+ }
+ {
+ const wchar_t* json = L"{ \"gigabyte\": 1.0e9 } ";
+ GenericStringStream<UTF16<> > s(json);
+ NumbersAsStringsHandlerWChar_t h(L"1.0e9");
+ GenericReader<UTF16<>, UTF16<> > reader;
+ EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
+ }
+ {
+ wchar_t* json = StrDup(L"{ \"gigabyte\": 1.0e9 } ");
+ GenericInsituStringStream<UTF16<> > s(json);
+ NumbersAsStringsHandlerWChar_t h(L"1.0e9");
+ GenericReader<UTF16<>, UTF16<> > reader;
+ EXPECT_TRUE(reader.Parse<kParseInsituFlag | kParseNumbersAsStringsFlag>(s, h));
+ free(json);
+ }
+ {
+ const wchar_t* json = L"{ \"pi\": 314.159e-2 } ";
+ GenericStringStream<UTF16<> > s(json);
+ NumbersAsStringsHandlerWChar_t h(L"314.159e-2");
+ GenericReader<UTF16<>, UTF16<> > reader;
+ EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
+ }
+ {
+ wchar_t* json = StrDup(L"{ \"gigabyte\": 314.159e-2 } ");
+ GenericInsituStringStream<UTF16<> > s(json);
+ NumbersAsStringsHandlerWChar_t h(L"314.159e-2");
+ GenericReader<UTF16<>, UTF16<> > reader;
+ EXPECT_TRUE(reader.Parse<kParseInsituFlag | kParseNumbersAsStringsFlag>(s, h));
+ free(json);
+ }
+ {
+ const wchar_t* json = L"{ \"negative\": -1.54321 } ";
+ GenericStringStream<UTF16<> > s(json);
+ NumbersAsStringsHandlerWChar_t h(L"-1.54321");
+ GenericReader<UTF16<>, UTF16<> > reader;
+ EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
+ }
+ {
+ wchar_t* json = StrDup(L"{ \"negative\": -1.54321 } ");
+ GenericInsituStringStream<UTF16<> > s(json);
+ NumbersAsStringsHandlerWChar_t h(L"-1.54321");
+ GenericReader<UTF16<>, UTF16<> > reader;
+ EXPECT_TRUE(reader.Parse<kParseInsituFlag | kParseNumbersAsStringsFlag>(s, h));
+ free(json);
+ }
+ {
+ const wchar_t* json = L"{ \"pi\": 314.159e-2 } ";
+ std::wstringstream ss(json);
+ WIStreamWrapper s(ss);
+ NumbersAsStringsHandlerWChar_t h(L"314.159e-2");
+ GenericReader<UTF16<>, UTF16<> > reader;
+ EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
+ }
+ {
+ wchar_t n1e319[321]; // '1' followed by 319 '0'
+ n1e319[0] = L'1';
+ for(int i = 1; i < 320; i++)
+ n1e319[i] = L'0';
+ n1e319[320] = L'\0';
+ GenericStringStream<UTF16<> > s(n1e319);
+ NumbersAsStringsHandlerWChar_t h(n1e319);
+ GenericReader<UTF16<>, UTF16<> > reader;
+ EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
+ }
}
template <unsigned extraFlags>
@@ -1811,7 +2309,7 @@ TEST(Reader, ParseNanAndInfinity) {
}
#define TEST_NAN_INF_ERROR(errorCode, str, errorOffset) \
{ \
- int streamPos = errorOffset; \
+ unsigned streamPos = errorOffset; \
char buffer[1001]; \
strncpy(buffer, str, 1000); \
InsituStringStream s(buffer); \
@@ -1832,13 +2330,41 @@ TEST(Reader, ParseNanAndInfinity) {
TEST_NAN_INF("Infinity", inf);
TEST_NAN_INF("-Inf", -inf);
TEST_NAN_INF("-Infinity", -inf);
- TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "nan", 1);
- TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "-nan", 1);
- TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NAN", 1);
- TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "-Infinty", 6);
+ TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NInf", 1u);
+ TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NaInf", 2u);
+ TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "INan", 1u);
+ TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "InNan", 2u);
+ TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "nan", 1u);
+ TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "-nan", 1u);
+ TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NAN", 1u);
+ TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "-Infinty", 6u);
#undef TEST_NAN_INF_ERROR
#undef TEST_NAN_INF
}
+TEST(Reader, EscapedApostrophe) {
+ const char json[] = " { \"foo\": \"bar\\'buzz\" } ";
+
+ BaseReaderHandler<> h;
+
+ {
+ StringStream s(json);
+ Reader reader;
+ ParseResult r = reader.Parse<kParseNoFlags>(s, h);
+ EXPECT_TRUE(reader.HasParseError());
+ EXPECT_EQ(kParseErrorStringEscapeInvalid, r.Code());
+ EXPECT_EQ(14u, r.Offset());
+ }
+
+ {
+ StringStream s(json);
+ Reader reader;
+ ParseResult r = reader.Parse<kParseEscapedApostropheFlag>(s, h);
+ EXPECT_FALSE(reader.HasParseError());
+ EXPECT_EQ(kParseErrorNone, r.Code());
+ EXPECT_EQ(0u, r.Offset());
+ }
+}
+
RAPIDJSON_DIAG_POP
diff --git a/3rdparty/rapidjson/test/unittest/regextest.cpp b/3rdparty/rapidjson/test/unittest/regextest.cpp
index 4fb5b222e44..a288622bc7b 100644
--- a/3rdparty/rapidjson/test/unittest/regextest.cpp
+++ b/3rdparty/rapidjson/test/unittest/regextest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -20,523 +20,569 @@ using namespace rapidjson::internal;
TEST(Regex, Single) {
Regex re("a");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("a"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("b"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("a"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("b"));
}
TEST(Regex, Concatenation) {
Regex re("abc");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("abc"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("a"));
- EXPECT_FALSE(re.Match("b"));
- EXPECT_FALSE(re.Match("ab"));
- EXPECT_FALSE(re.Match("abcd"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("abc"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("a"));
+ EXPECT_FALSE(rs.Match("b"));
+ EXPECT_FALSE(rs.Match("ab"));
+ EXPECT_FALSE(rs.Match("abcd"));
}
TEST(Regex, Alternation1) {
Regex re("abab|abbb");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("abab"));
- EXPECT_TRUE(re.Match("abbb"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("ab"));
- EXPECT_FALSE(re.Match("ababa"));
- EXPECT_FALSE(re.Match("abb"));
- EXPECT_FALSE(re.Match("abbbb"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("abab"));
+ EXPECT_TRUE(rs.Match("abbb"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("ab"));
+ EXPECT_FALSE(rs.Match("ababa"));
+ EXPECT_FALSE(rs.Match("abb"));
+ EXPECT_FALSE(rs.Match("abbbb"));
}
TEST(Regex, Alternation2) {
Regex re("a|b|c");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("a"));
- EXPECT_TRUE(re.Match("b"));
- EXPECT_TRUE(re.Match("c"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("aa"));
- EXPECT_FALSE(re.Match("ab"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("a"));
+ EXPECT_TRUE(rs.Match("b"));
+ EXPECT_TRUE(rs.Match("c"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("aa"));
+ EXPECT_FALSE(rs.Match("ab"));
}
TEST(Regex, Parenthesis1) {
Regex re("(ab)c");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("abc"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("a"));
- EXPECT_FALSE(re.Match("b"));
- EXPECT_FALSE(re.Match("ab"));
- EXPECT_FALSE(re.Match("abcd"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("abc"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("a"));
+ EXPECT_FALSE(rs.Match("b"));
+ EXPECT_FALSE(rs.Match("ab"));
+ EXPECT_FALSE(rs.Match("abcd"));
}
TEST(Regex, Parenthesis2) {
Regex re("a(bc)");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("abc"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("a"));
- EXPECT_FALSE(re.Match("b"));
- EXPECT_FALSE(re.Match("ab"));
- EXPECT_FALSE(re.Match("abcd"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("abc"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("a"));
+ EXPECT_FALSE(rs.Match("b"));
+ EXPECT_FALSE(rs.Match("ab"));
+ EXPECT_FALSE(rs.Match("abcd"));
}
TEST(Regex, Parenthesis3) {
Regex re("(a|b)(c|d)");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("ac"));
- EXPECT_TRUE(re.Match("ad"));
- EXPECT_TRUE(re.Match("bc"));
- EXPECT_TRUE(re.Match("bd"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("ab"));
- EXPECT_FALSE(re.Match("cd"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("ac"));
+ EXPECT_TRUE(rs.Match("ad"));
+ EXPECT_TRUE(rs.Match("bc"));
+ EXPECT_TRUE(rs.Match("bd"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("ab"));
+ EXPECT_FALSE(rs.Match("cd"));
}
TEST(Regex, ZeroOrOne1) {
Regex re("a?");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match(""));
- EXPECT_TRUE(re.Match("a"));
- EXPECT_FALSE(re.Match("aa"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match(""));
+ EXPECT_TRUE(rs.Match("a"));
+ EXPECT_FALSE(rs.Match("aa"));
}
TEST(Regex, ZeroOrOne2) {
Regex re("a?b");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("b"));
- EXPECT_TRUE(re.Match("ab"));
- EXPECT_FALSE(re.Match("a"));
- EXPECT_FALSE(re.Match("aa"));
- EXPECT_FALSE(re.Match("bb"));
- EXPECT_FALSE(re.Match("ba"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("b"));
+ EXPECT_TRUE(rs.Match("ab"));
+ EXPECT_FALSE(rs.Match("a"));
+ EXPECT_FALSE(rs.Match("aa"));
+ EXPECT_FALSE(rs.Match("bb"));
+ EXPECT_FALSE(rs.Match("ba"));
}
TEST(Regex, ZeroOrOne3) {
Regex re("ab?");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("a"));
- EXPECT_TRUE(re.Match("ab"));
- EXPECT_FALSE(re.Match("b"));
- EXPECT_FALSE(re.Match("aa"));
- EXPECT_FALSE(re.Match("bb"));
- EXPECT_FALSE(re.Match("ba"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("a"));
+ EXPECT_TRUE(rs.Match("ab"));
+ EXPECT_FALSE(rs.Match("b"));
+ EXPECT_FALSE(rs.Match("aa"));
+ EXPECT_FALSE(rs.Match("bb"));
+ EXPECT_FALSE(rs.Match("ba"));
}
TEST(Regex, ZeroOrOne4) {
Regex re("a?b?");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match(""));
- EXPECT_TRUE(re.Match("a"));
- EXPECT_TRUE(re.Match("b"));
- EXPECT_TRUE(re.Match("ab"));
- EXPECT_FALSE(re.Match("aa"));
- EXPECT_FALSE(re.Match("bb"));
- EXPECT_FALSE(re.Match("ba"));
- EXPECT_FALSE(re.Match("abc"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match(""));
+ EXPECT_TRUE(rs.Match("a"));
+ EXPECT_TRUE(rs.Match("b"));
+ EXPECT_TRUE(rs.Match("ab"));
+ EXPECT_FALSE(rs.Match("aa"));
+ EXPECT_FALSE(rs.Match("bb"));
+ EXPECT_FALSE(rs.Match("ba"));
+ EXPECT_FALSE(rs.Match("abc"));
}
TEST(Regex, ZeroOrOne5) {
Regex re("a(ab)?b");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("ab"));
- EXPECT_TRUE(re.Match("aabb"));
- EXPECT_FALSE(re.Match("aab"));
- EXPECT_FALSE(re.Match("abb"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("ab"));
+ EXPECT_TRUE(rs.Match("aabb"));
+ EXPECT_FALSE(rs.Match("aab"));
+ EXPECT_FALSE(rs.Match("abb"));
}
TEST(Regex, ZeroOrMore1) {
Regex re("a*");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match(""));
- EXPECT_TRUE(re.Match("a"));
- EXPECT_TRUE(re.Match("aa"));
- EXPECT_FALSE(re.Match("b"));
- EXPECT_FALSE(re.Match("ab"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match(""));
+ EXPECT_TRUE(rs.Match("a"));
+ EXPECT_TRUE(rs.Match("aa"));
+ EXPECT_FALSE(rs.Match("b"));
+ EXPECT_FALSE(rs.Match("ab"));
}
TEST(Regex, ZeroOrMore2) {
Regex re("a*b");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("b"));
- EXPECT_TRUE(re.Match("ab"));
- EXPECT_TRUE(re.Match("aab"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("bb"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("b"));
+ EXPECT_TRUE(rs.Match("ab"));
+ EXPECT_TRUE(rs.Match("aab"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("bb"));
}
TEST(Regex, ZeroOrMore3) {
Regex re("a*b*");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match(""));
- EXPECT_TRUE(re.Match("a"));
- EXPECT_TRUE(re.Match("aa"));
- EXPECT_TRUE(re.Match("b"));
- EXPECT_TRUE(re.Match("bb"));
- EXPECT_TRUE(re.Match("ab"));
- EXPECT_TRUE(re.Match("aabb"));
- EXPECT_FALSE(re.Match("ba"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match(""));
+ EXPECT_TRUE(rs.Match("a"));
+ EXPECT_TRUE(rs.Match("aa"));
+ EXPECT_TRUE(rs.Match("b"));
+ EXPECT_TRUE(rs.Match("bb"));
+ EXPECT_TRUE(rs.Match("ab"));
+ EXPECT_TRUE(rs.Match("aabb"));
+ EXPECT_FALSE(rs.Match("ba"));
}
TEST(Regex, ZeroOrMore4) {
Regex re("a(ab)*b");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("ab"));
- EXPECT_TRUE(re.Match("aabb"));
- EXPECT_TRUE(re.Match("aababb"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("aa"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("ab"));
+ EXPECT_TRUE(rs.Match("aabb"));
+ EXPECT_TRUE(rs.Match("aababb"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("aa"));
}
TEST(Regex, OneOrMore1) {
Regex re("a+");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("a"));
- EXPECT_TRUE(re.Match("aa"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("b"));
- EXPECT_FALSE(re.Match("ab"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("a"));
+ EXPECT_TRUE(rs.Match("aa"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("b"));
+ EXPECT_FALSE(rs.Match("ab"));
}
TEST(Regex, OneOrMore2) {
Regex re("a+b");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("ab"));
- EXPECT_TRUE(re.Match("aab"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("b"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("ab"));
+ EXPECT_TRUE(rs.Match("aab"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("b"));
}
TEST(Regex, OneOrMore3) {
Regex re("a+b+");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("ab"));
- EXPECT_TRUE(re.Match("aab"));
- EXPECT_TRUE(re.Match("abb"));
- EXPECT_TRUE(re.Match("aabb"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("b"));
- EXPECT_FALSE(re.Match("ba"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("ab"));
+ EXPECT_TRUE(rs.Match("aab"));
+ EXPECT_TRUE(rs.Match("abb"));
+ EXPECT_TRUE(rs.Match("aabb"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("b"));
+ EXPECT_FALSE(rs.Match("ba"));
}
TEST(Regex, OneOrMore4) {
Regex re("a(ab)+b");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("aabb"));
- EXPECT_TRUE(re.Match("aababb"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("ab"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("aabb"));
+ EXPECT_TRUE(rs.Match("aababb"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("ab"));
}
TEST(Regex, QuantifierExact1) {
Regex re("ab{3}c");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("abbbc"));
- EXPECT_FALSE(re.Match("ac"));
- EXPECT_FALSE(re.Match("abc"));
- EXPECT_FALSE(re.Match("abbc"));
- EXPECT_FALSE(re.Match("abbbbc"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("abbbc"));
+ EXPECT_FALSE(rs.Match("ac"));
+ EXPECT_FALSE(rs.Match("abc"));
+ EXPECT_FALSE(rs.Match("abbc"));
+ EXPECT_FALSE(rs.Match("abbbbc"));
}
TEST(Regex, QuantifierExact2) {
Regex re("a(bc){3}d");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("abcbcbcd"));
- EXPECT_FALSE(re.Match("ad"));
- EXPECT_FALSE(re.Match("abcd"));
- EXPECT_FALSE(re.Match("abcbcd"));
- EXPECT_FALSE(re.Match("abcbcbcbcd"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("abcbcbcd"));
+ EXPECT_FALSE(rs.Match("ad"));
+ EXPECT_FALSE(rs.Match("abcd"));
+ EXPECT_FALSE(rs.Match("abcbcd"));
+ EXPECT_FALSE(rs.Match("abcbcbcbcd"));
}
TEST(Regex, QuantifierExact3) {
Regex re("a(b|c){3}d");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("abbbd"));
- EXPECT_TRUE(re.Match("acccd"));
- EXPECT_TRUE(re.Match("abcbd"));
- EXPECT_FALSE(re.Match("ad"));
- EXPECT_FALSE(re.Match("abbd"));
- EXPECT_FALSE(re.Match("accccd"));
- EXPECT_FALSE(re.Match("abbbbd"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("abbbd"));
+ EXPECT_TRUE(rs.Match("acccd"));
+ EXPECT_TRUE(rs.Match("abcbd"));
+ EXPECT_FALSE(rs.Match("ad"));
+ EXPECT_FALSE(rs.Match("abbd"));
+ EXPECT_FALSE(rs.Match("accccd"));
+ EXPECT_FALSE(rs.Match("abbbbd"));
}
TEST(Regex, QuantifierMin1) {
Regex re("ab{3,}c");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("abbbc"));
- EXPECT_TRUE(re.Match("abbbbc"));
- EXPECT_TRUE(re.Match("abbbbbc"));
- EXPECT_FALSE(re.Match("ac"));
- EXPECT_FALSE(re.Match("abc"));
- EXPECT_FALSE(re.Match("abbc"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("abbbc"));
+ EXPECT_TRUE(rs.Match("abbbbc"));
+ EXPECT_TRUE(rs.Match("abbbbbc"));
+ EXPECT_FALSE(rs.Match("ac"));
+ EXPECT_FALSE(rs.Match("abc"));
+ EXPECT_FALSE(rs.Match("abbc"));
}
TEST(Regex, QuantifierMin2) {
Regex re("a(bc){3,}d");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("abcbcbcd"));
- EXPECT_TRUE(re.Match("abcbcbcbcd"));
- EXPECT_FALSE(re.Match("ad"));
- EXPECT_FALSE(re.Match("abcd"));
- EXPECT_FALSE(re.Match("abcbcd"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("abcbcbcd"));
+ EXPECT_TRUE(rs.Match("abcbcbcbcd"));
+ EXPECT_FALSE(rs.Match("ad"));
+ EXPECT_FALSE(rs.Match("abcd"));
+ EXPECT_FALSE(rs.Match("abcbcd"));
}
TEST(Regex, QuantifierMin3) {
Regex re("a(b|c){3,}d");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("abbbd"));
- EXPECT_TRUE(re.Match("acccd"));
- EXPECT_TRUE(re.Match("abcbd"));
- EXPECT_TRUE(re.Match("accccd"));
- EXPECT_TRUE(re.Match("abbbbd"));
- EXPECT_FALSE(re.Match("ad"));
- EXPECT_FALSE(re.Match("abbd"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("abbbd"));
+ EXPECT_TRUE(rs.Match("acccd"));
+ EXPECT_TRUE(rs.Match("abcbd"));
+ EXPECT_TRUE(rs.Match("accccd"));
+ EXPECT_TRUE(rs.Match("abbbbd"));
+ EXPECT_FALSE(rs.Match("ad"));
+ EXPECT_FALSE(rs.Match("abbd"));
}
TEST(Regex, QuantifierMinMax1) {
Regex re("ab{3,5}c");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("abbbc"));
- EXPECT_TRUE(re.Match("abbbbc"));
- EXPECT_TRUE(re.Match("abbbbbc"));
- EXPECT_FALSE(re.Match("ac"));
- EXPECT_FALSE(re.Match("abc"));
- EXPECT_FALSE(re.Match("abbc"));
- EXPECT_FALSE(re.Match("abbbbbbc"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("abbbc"));
+ EXPECT_TRUE(rs.Match("abbbbc"));
+ EXPECT_TRUE(rs.Match("abbbbbc"));
+ EXPECT_FALSE(rs.Match("ac"));
+ EXPECT_FALSE(rs.Match("abc"));
+ EXPECT_FALSE(rs.Match("abbc"));
+ EXPECT_FALSE(rs.Match("abbbbbbc"));
}
TEST(Regex, QuantifierMinMax2) {
Regex re("a(bc){3,5}d");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("abcbcbcd"));
- EXPECT_TRUE(re.Match("abcbcbcbcd"));
- EXPECT_TRUE(re.Match("abcbcbcbcbcd"));
- EXPECT_FALSE(re.Match("ad"));
- EXPECT_FALSE(re.Match("abcd"));
- EXPECT_FALSE(re.Match("abcbcd"));
- EXPECT_FALSE(re.Match("abcbcbcbcbcbcd"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("abcbcbcd"));
+ EXPECT_TRUE(rs.Match("abcbcbcbcd"));
+ EXPECT_TRUE(rs.Match("abcbcbcbcbcd"));
+ EXPECT_FALSE(rs.Match("ad"));
+ EXPECT_FALSE(rs.Match("abcd"));
+ EXPECT_FALSE(rs.Match("abcbcd"));
+ EXPECT_FALSE(rs.Match("abcbcbcbcbcbcd"));
}
TEST(Regex, QuantifierMinMax3) {
Regex re("a(b|c){3,5}d");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("abbbd"));
- EXPECT_TRUE(re.Match("acccd"));
- EXPECT_TRUE(re.Match("abcbd"));
- EXPECT_TRUE(re.Match("accccd"));
- EXPECT_TRUE(re.Match("abbbbd"));
- EXPECT_TRUE(re.Match("acccccd"));
- EXPECT_TRUE(re.Match("abbbbbd"));
- EXPECT_FALSE(re.Match("ad"));
- EXPECT_FALSE(re.Match("abbd"));
- EXPECT_FALSE(re.Match("accccccd"));
- EXPECT_FALSE(re.Match("abbbbbbd"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("abbbd"));
+ EXPECT_TRUE(rs.Match("acccd"));
+ EXPECT_TRUE(rs.Match("abcbd"));
+ EXPECT_TRUE(rs.Match("accccd"));
+ EXPECT_TRUE(rs.Match("abbbbd"));
+ EXPECT_TRUE(rs.Match("acccccd"));
+ EXPECT_TRUE(rs.Match("abbbbbd"));
+ EXPECT_FALSE(rs.Match("ad"));
+ EXPECT_FALSE(rs.Match("abbd"));
+ EXPECT_FALSE(rs.Match("accccccd"));
+ EXPECT_FALSE(rs.Match("abbbbbbd"));
}
// Issue538
TEST(Regex, QuantifierMinMax4) {
Regex re("a(b|c){0,3}d");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("ad"));
- EXPECT_TRUE(re.Match("abd"));
- EXPECT_TRUE(re.Match("acd"));
- EXPECT_TRUE(re.Match("abbd"));
- EXPECT_TRUE(re.Match("accd"));
- EXPECT_TRUE(re.Match("abcd"));
- EXPECT_TRUE(re.Match("abbbd"));
- EXPECT_TRUE(re.Match("acccd"));
- EXPECT_FALSE(re.Match("abbbbd"));
- EXPECT_FALSE(re.Match("add"));
- EXPECT_FALSE(re.Match("accccd"));
- EXPECT_FALSE(re.Match("abcbcd"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("ad"));
+ EXPECT_TRUE(rs.Match("abd"));
+ EXPECT_TRUE(rs.Match("acd"));
+ EXPECT_TRUE(rs.Match("abbd"));
+ EXPECT_TRUE(rs.Match("accd"));
+ EXPECT_TRUE(rs.Match("abcd"));
+ EXPECT_TRUE(rs.Match("abbbd"));
+ EXPECT_TRUE(rs.Match("acccd"));
+ EXPECT_FALSE(rs.Match("abbbbd"));
+ EXPECT_FALSE(rs.Match("add"));
+ EXPECT_FALSE(rs.Match("accccd"));
+ EXPECT_FALSE(rs.Match("abcbcd"));
}
// Issue538
TEST(Regex, QuantifierMinMax5) {
Regex re("a(b|c){0,}d");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("ad"));
- EXPECT_TRUE(re.Match("abd"));
- EXPECT_TRUE(re.Match("acd"));
- EXPECT_TRUE(re.Match("abbd"));
- EXPECT_TRUE(re.Match("accd"));
- EXPECT_TRUE(re.Match("abcd"));
- EXPECT_TRUE(re.Match("abbbd"));
- EXPECT_TRUE(re.Match("acccd"));
- EXPECT_TRUE(re.Match("abbbbd"));
- EXPECT_TRUE(re.Match("accccd"));
- EXPECT_TRUE(re.Match("abcbcd"));
- EXPECT_FALSE(re.Match("add"));
- EXPECT_FALSE(re.Match("aad"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("ad"));
+ EXPECT_TRUE(rs.Match("abd"));
+ EXPECT_TRUE(rs.Match("acd"));
+ EXPECT_TRUE(rs.Match("abbd"));
+ EXPECT_TRUE(rs.Match("accd"));
+ EXPECT_TRUE(rs.Match("abcd"));
+ EXPECT_TRUE(rs.Match("abbbd"));
+ EXPECT_TRUE(rs.Match("acccd"));
+ EXPECT_TRUE(rs.Match("abbbbd"));
+ EXPECT_TRUE(rs.Match("accccd"));
+ EXPECT_TRUE(rs.Match("abcbcd"));
+ EXPECT_FALSE(rs.Match("add"));
+ EXPECT_FALSE(rs.Match("aad"));
}
-#define EURO "\xE2\x82\xAC" // "\xE2\x82\xAC" is UTF-8 sequence of Euro sign U+20AC
+#define EURO "\xE2\x82\xAC" // "\xE2\x82\xAC" is UTF-8 rsquence of Euro sign U+20AC
TEST(Regex, Unicode) {
Regex re("a" EURO "+b");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("a" EURO "b"));
- EXPECT_TRUE(re.Match("a" EURO EURO "b"));
- EXPECT_FALSE(re.Match("a?b"));
- EXPECT_FALSE(re.Match("a" EURO "\xAC" "b")); // unaware of UTF-8 will match
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("a" EURO "b"));
+ EXPECT_TRUE(rs.Match("a" EURO EURO "b"));
+ EXPECT_FALSE(rs.Match("a?b"));
+ EXPECT_FALSE(rs.Match("a" EURO "\xAC" "b")); // unaware of UTF-8 will match
}
TEST(Regex, AnyCharacter) {
Regex re(".");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("a"));
- EXPECT_TRUE(re.Match("b"));
- EXPECT_TRUE(re.Match(EURO));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("aa"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("a"));
+ EXPECT_TRUE(rs.Match("b"));
+ EXPECT_TRUE(rs.Match(EURO));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("aa"));
}
TEST(Regex, CharacterRange1) {
Regex re("[abc]");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("a"));
- EXPECT_TRUE(re.Match("b"));
- EXPECT_TRUE(re.Match("c"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("`"));
- EXPECT_FALSE(re.Match("d"));
- EXPECT_FALSE(re.Match("aa"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("a"));
+ EXPECT_TRUE(rs.Match("b"));
+ EXPECT_TRUE(rs.Match("c"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("`"));
+ EXPECT_FALSE(rs.Match("d"));
+ EXPECT_FALSE(rs.Match("aa"));
}
TEST(Regex, CharacterRange2) {
Regex re("[^abc]");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("`"));
- EXPECT_TRUE(re.Match("d"));
- EXPECT_FALSE(re.Match("a"));
- EXPECT_FALSE(re.Match("b"));
- EXPECT_FALSE(re.Match("c"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("aa"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("`"));
+ EXPECT_TRUE(rs.Match("d"));
+ EXPECT_FALSE(rs.Match("a"));
+ EXPECT_FALSE(rs.Match("b"));
+ EXPECT_FALSE(rs.Match("c"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("aa"));
}
TEST(Regex, CharacterRange3) {
Regex re("[a-c]");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("a"));
- EXPECT_TRUE(re.Match("b"));
- EXPECT_TRUE(re.Match("c"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("`"));
- EXPECT_FALSE(re.Match("d"));
- EXPECT_FALSE(re.Match("aa"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("a"));
+ EXPECT_TRUE(rs.Match("b"));
+ EXPECT_TRUE(rs.Match("c"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("`"));
+ EXPECT_FALSE(rs.Match("d"));
+ EXPECT_FALSE(rs.Match("aa"));
}
TEST(Regex, CharacterRange4) {
Regex re("[^a-c]");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("`"));
- EXPECT_TRUE(re.Match("d"));
- EXPECT_FALSE(re.Match("a"));
- EXPECT_FALSE(re.Match("b"));
- EXPECT_FALSE(re.Match("c"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("aa"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("`"));
+ EXPECT_TRUE(rs.Match("d"));
+ EXPECT_FALSE(rs.Match("a"));
+ EXPECT_FALSE(rs.Match("b"));
+ EXPECT_FALSE(rs.Match("c"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("aa"));
}
TEST(Regex, CharacterRange5) {
Regex re("[-]");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("-"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("a"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("-"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("a"));
}
TEST(Regex, CharacterRange6) {
Regex re("[a-]");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("a"));
- EXPECT_TRUE(re.Match("-"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("`"));
- EXPECT_FALSE(re.Match("b"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("a"));
+ EXPECT_TRUE(rs.Match("-"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("`"));
+ EXPECT_FALSE(rs.Match("b"));
}
TEST(Regex, CharacterRange7) {
Regex re("[-a]");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("a"));
- EXPECT_TRUE(re.Match("-"));
- EXPECT_FALSE(re.Match(""));
- EXPECT_FALSE(re.Match("`"));
- EXPECT_FALSE(re.Match("b"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("a"));
+ EXPECT_TRUE(rs.Match("-"));
+ EXPECT_FALSE(rs.Match(""));
+ EXPECT_FALSE(rs.Match("`"));
+ EXPECT_FALSE(rs.Match("b"));
}
TEST(Regex, CharacterRange8) {
Regex re("[a-zA-Z0-9]*");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("Milo"));
- EXPECT_TRUE(re.Match("MT19937"));
- EXPECT_TRUE(re.Match("43"));
- EXPECT_FALSE(re.Match("a_b"));
- EXPECT_FALSE(re.Match("!"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("Milo"));
+ EXPECT_TRUE(rs.Match("MT19937"));
+ EXPECT_TRUE(rs.Match("43"));
+ EXPECT_FALSE(rs.Match("a_b"));
+ EXPECT_FALSE(rs.Match("!"));
}
TEST(Regex, Search) {
Regex re("abc");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Search("abc"));
- EXPECT_TRUE(re.Search("_abc"));
- EXPECT_TRUE(re.Search("abc_"));
- EXPECT_TRUE(re.Search("_abc_"));
- EXPECT_TRUE(re.Search("__abc__"));
- EXPECT_TRUE(re.Search("abcabc"));
- EXPECT_FALSE(re.Search("a"));
- EXPECT_FALSE(re.Search("ab"));
- EXPECT_FALSE(re.Search("bc"));
- EXPECT_FALSE(re.Search("cba"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Search("abc"));
+ EXPECT_TRUE(rs.Search("_abc"));
+ EXPECT_TRUE(rs.Search("abc_"));
+ EXPECT_TRUE(rs.Search("_abc_"));
+ EXPECT_TRUE(rs.Search("__abc__"));
+ EXPECT_TRUE(rs.Search("abcabc"));
+ EXPECT_FALSE(rs.Search("a"));
+ EXPECT_FALSE(rs.Search("ab"));
+ EXPECT_FALSE(rs.Search("bc"));
+ EXPECT_FALSE(rs.Search("cba"));
}
TEST(Regex, Search_BeginAnchor) {
Regex re("^abc");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Search("abc"));
- EXPECT_TRUE(re.Search("abc_"));
- EXPECT_TRUE(re.Search("abcabc"));
- EXPECT_FALSE(re.Search("_abc"));
- EXPECT_FALSE(re.Search("_abc_"));
- EXPECT_FALSE(re.Search("a"));
- EXPECT_FALSE(re.Search("ab"));
- EXPECT_FALSE(re.Search("bc"));
- EXPECT_FALSE(re.Search("cba"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Search("abc"));
+ EXPECT_TRUE(rs.Search("abc_"));
+ EXPECT_TRUE(rs.Search("abcabc"));
+ EXPECT_FALSE(rs.Search("_abc"));
+ EXPECT_FALSE(rs.Search("_abc_"));
+ EXPECT_FALSE(rs.Search("a"));
+ EXPECT_FALSE(rs.Search("ab"));
+ EXPECT_FALSE(rs.Search("bc"));
+ EXPECT_FALSE(rs.Search("cba"));
}
TEST(Regex, Search_EndAnchor) {
Regex re("abc$");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Search("abc"));
- EXPECT_TRUE(re.Search("_abc"));
- EXPECT_TRUE(re.Search("abcabc"));
- EXPECT_FALSE(re.Search("abc_"));
- EXPECT_FALSE(re.Search("_abc_"));
- EXPECT_FALSE(re.Search("a"));
- EXPECT_FALSE(re.Search("ab"));
- EXPECT_FALSE(re.Search("bc"));
- EXPECT_FALSE(re.Search("cba"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Search("abc"));
+ EXPECT_TRUE(rs.Search("_abc"));
+ EXPECT_TRUE(rs.Search("abcabc"));
+ EXPECT_FALSE(rs.Search("abc_"));
+ EXPECT_FALSE(rs.Search("_abc_"));
+ EXPECT_FALSE(rs.Search("a"));
+ EXPECT_FALSE(rs.Search("ab"));
+ EXPECT_FALSE(rs.Search("bc"));
+ EXPECT_FALSE(rs.Search("cba"));
}
TEST(Regex, Search_BothAnchor) {
Regex re("^abc$");
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Search("abc"));
- EXPECT_FALSE(re.Search(""));
- EXPECT_FALSE(re.Search("a"));
- EXPECT_FALSE(re.Search("b"));
- EXPECT_FALSE(re.Search("ab"));
- EXPECT_FALSE(re.Search("abcd"));
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Search("abc"));
+ EXPECT_FALSE(rs.Search(""));
+ EXPECT_FALSE(rs.Search("a"));
+ EXPECT_FALSE(rs.Search("b"));
+ EXPECT_FALSE(rs.Search("ab"));
+ EXPECT_FALSE(rs.Search("abcd"));
}
TEST(Regex, Escape) {
const char* s = "\\^\\$\\|\\(\\)\\?\\*\\+\\.\\[\\]\\{\\}\\\\\\f\\n\\r\\t\\v[\\b][\\[][\\]]";
Regex re(s);
ASSERT_TRUE(re.IsValid());
- EXPECT_TRUE(re.Match("^$|()?*+.[]{}\\\x0C\n\r\t\x0B\b[]"));
- EXPECT_FALSE(re.Match(s)); // Not escaping
+ RegexSearch rs(re);
+ EXPECT_TRUE(rs.Match("^$|()?*+.[]{}\\\x0C\n\r\t\x0B\b[]"));
+ EXPECT_FALSE(rs.Match(s)); // Not escaping
}
TEST(Regex, Invalid) {
@@ -549,6 +595,7 @@ TEST(Regex, Invalid) {
TEST_INVALID("");
TEST_INVALID("a|");
TEST_INVALID("()");
+ TEST_INVALID("(");
TEST_INVALID(")");
TEST_INVALID("(a))");
TEST_INVALID("(a|)");
diff --git a/3rdparty/rapidjson/test/unittest/schematest.cpp b/3rdparty/rapidjson/test/unittest/schematest.cpp
index 6a8b685f454..7387c08961e 100644
--- a/3rdparty/rapidjson/test/unittest/schematest.cpp
+++ b/3rdparty/rapidjson/test/unittest/schematest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -12,14 +12,22 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
+#define RAPIDJSON_SCHEMA_VERBOSE 0
+#define RAPIDJSON_HAS_STDSTRING 1
+
#include "unittest.h"
#include "rapidjson/schema.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
+#include "rapidjson/error/error.h"
+#include "rapidjson/error/en.h"
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(variadic-macros)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4822) // local class member function does not have a body
#endif
using namespace rapidjson;
@@ -104,6 +112,13 @@ TEST(SchemaValidator, Hasher) {
#define VALIDATE(schema, json, expected) \
{\
+ VALIDATE_(schema, json, expected, true) \
+}
+
+#define VALIDATE_(schema, json, expected, expected2) \
+{\
+ EXPECT_TRUE(expected2 == schema.GetError().ObjectEmpty());\
+ EXPECT_TRUE(schema.IsSupportedSpecification());\
SchemaValidator validator(schema);\
Document d;\
/*printf("\n%s\n", json);*/\
@@ -111,27 +126,50 @@ TEST(SchemaValidator, Hasher) {
EXPECT_FALSE(d.HasParseError());\
EXPECT_TRUE(expected == d.Accept(validator));\
EXPECT_TRUE(expected == validator.IsValid());\
+ ValidateErrorCode code = validator.GetInvalidSchemaCode();\
+ if (expected) {\
+ EXPECT_TRUE(code == kValidateErrorNone);\
+ EXPECT_TRUE(validator.GetInvalidSchemaKeyword() == 0);\
+ }\
if ((expected) && !validator.IsValid()) {\
StringBuffer sb;\
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);\
printf("Invalid schema: %s\n", sb.GetString());\
printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());\
+ printf("Invalid code: %d\n", code);\
+ printf("Invalid message: %s\n", GetValidateError_En(code));\
sb.Clear();\
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);\
printf("Invalid document: %s\n", sb.GetString());\
+ sb.Clear();\
+ Writer<StringBuffer> w(sb);\
+ validator.GetError().Accept(w);\
+ printf("Validation error: %s\n", sb.GetString());\
}\
}
-#define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer) \
+#define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error) \
{\
- SchemaValidator validator(schema);\
+ INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, kValidateDefaultFlags, SchemaValidator, Pointer) \
+}
+
+#define INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, \
+ flags, SchemaValidatorType, PointerType) \
+{\
+ EXPECT_TRUE(schema.GetError().ObjectEmpty());\
+ EXPECT_TRUE(schema.IsSupportedSpecification());\
+ SchemaValidatorType validator(schema);\
+ validator.SetValidateFlags(flags);\
Document d;\
/*printf("\n%s\n", json);*/\
d.Parse(json);\
EXPECT_FALSE(d.HasParseError());\
- EXPECT_FALSE(d.Accept(validator));\
+ d.Accept(validator);\
EXPECT_FALSE(validator.IsValid());\
- if (validator.GetInvalidSchemaPointer() != Pointer(invalidSchemaPointer)) {\
+ ValidateErrorCode code = validator.GetInvalidSchemaCode();\
+ ASSERT_TRUE(code != kValidateErrorNone);\
+ ASSERT_TRUE(strcmp(GetValidateError_En(code), "Unknown error.") != 0);\
+ if (validator.GetInvalidSchemaPointer() != PointerType(invalidSchemaPointer)) {\
StringBuffer sb;\
validator.GetInvalidSchemaPointer().Stringify(sb);\
printf("GetInvalidSchemaPointer() Expected: %s Actual: %s\n", invalidSchemaPointer, sb.GetString());\
@@ -142,12 +180,35 @@ TEST(SchemaValidator, Hasher) {
printf("GetInvalidSchemaKeyword() Expected: %s Actual %s\n", invalidSchemaKeyword, validator.GetInvalidSchemaKeyword());\
ADD_FAILURE();\
}\
- if (validator.GetInvalidDocumentPointer() != Pointer(invalidDocumentPointer)) {\
+ if (validator.GetInvalidDocumentPointer() != PointerType(invalidDocumentPointer)) {\
StringBuffer sb;\
validator.GetInvalidDocumentPointer().Stringify(sb);\
printf("GetInvalidDocumentPointer() Expected: %s Actual: %s\n", invalidDocumentPointer, sb.GetString());\
ADD_FAILURE();\
}\
+ Document e;\
+ e.Parse(error);\
+ if (validator.GetError() != e) {\
+ StringBuffer sb;\
+ Writer<StringBuffer> w(sb);\
+ validator.GetError().Accept(w);\
+ printf("GetError() Expected: %s Actual: %s\n", error, sb.GetString());\
+ ADD_FAILURE();\
+ }\
+}
+
+// Use for checking whether a compiled schema document contains errors
+#define SCHEMAERROR(schema, error) \
+{\
+ Document e;\
+ e.Parse(error);\
+ if (schema.GetError() != e) {\
+ StringBuffer sb;\
+ Writer<StringBuffer> w(sb);\
+ schema.GetError().Accept(w);\
+ printf("GetError() Expected: %s Actual: %s\n", error, sb.GetString());\
+ ADD_FAILURE();\
+ }\
}
TEST(SchemaValidator, Typeless) {
@@ -167,7 +228,12 @@ TEST(SchemaValidator, MultiType) {
VALIDATE(s, "42", true);
VALIDATE(s, "\"Life, the universe, and everything\"", true);
- INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "");
+ INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\", \"number\"], \"actual\": \"array\""
+ "}}");
}
TEST(SchemaValidator, Enum_Typed) {
@@ -176,10 +242,11 @@ TEST(SchemaValidator, Enum_Typed) {
SchemaDocument s(sd);
VALIDATE(s, "\"red\"", true);
- INVALIDATE(s, "\"blue\"", "", "enum", "");
+ INVALIDATE(s, "\"blue\"", "", "enum", "",
+ "{ \"enum\": { \"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
}
-TEST(SchemaValidator, Enum_Typless) {
+TEST(SchemaValidator, Enum_Typeless) {
Document sd;
sd.Parse("{ \"enum\": [\"red\", \"amber\", \"green\", null, 42] }");
SchemaDocument s(sd);
@@ -187,7 +254,8 @@ TEST(SchemaValidator, Enum_Typless) {
VALIDATE(s, "\"red\"", true);
VALIDATE(s, "null", true);
VALIDATE(s, "42", true);
- INVALIDATE(s, "0", "", "enum", "");
+ INVALIDATE(s, "0", "", "enum", "",
+ "{ \"enum\": { \"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
}
TEST(SchemaValidator, Enum_InvalidType) {
@@ -196,7 +264,12 @@ TEST(SchemaValidator, Enum_InvalidType) {
SchemaDocument s(sd);
VALIDATE(s, "\"red\"", true);
- INVALIDATE(s, "null", "", "type", "");
+ INVALIDATE(s, "null", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"null\""
+ "}}");
}
TEST(SchemaValidator, AllOf) {
@@ -206,7 +279,14 @@ TEST(SchemaValidator, AllOf) {
SchemaDocument s(sd);
VALIDATE(s, "\"ok\"", true);
- INVALIDATE(s, "\"too long\"", "", "allOf", "");
+ INVALIDATE(s, "\"too long\"", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " {},"
+ " {\"maxLength\": {\"errorCode\": 6, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\", \"expected\": 5, \"actual\": \"too long\"}}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ "}}");
}
{
Document sd;
@@ -214,7 +294,14 @@ TEST(SchemaValidator, AllOf) {
SchemaDocument s(sd);
VALIDATE(s, "\"No way\"", false);
- INVALIDATE(s, "-1", "", "allOf", "");
+ INVALIDATE(s, "-1", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " {\"type\": { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\", \"errorCode\": 20, \"expected\": [\"string\"], \"actual\": \"integer\"}},"
+ " {}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ "}}");
}
}
@@ -225,7 +312,23 @@ TEST(SchemaValidator, AnyOf) {
VALIDATE(s, "\"Yes\"", true);
VALIDATE(s, "42", true);
- INVALIDATE(s, "{ \"Not a\": \"string or number\" }", "", "anyOf", "");
+ INVALIDATE(s, "{ \"Not a\": \"string or number\" }", "", "anyOf", "",
+ "{ \"anyOf\": {"
+ " \"errorCode\": 24,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\", "
+ " \"errors\": ["
+ " { \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/0\","
+ " \"expected\": [\"string\"], \"actual\": \"object\""
+ " }},"
+ " { \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/1\","
+ " \"expected\": [\"number\"], \"actual\": \"object\""
+ " }}"
+ " ]"
+ "}}");
}
TEST(SchemaValidator, OneOf) {
@@ -235,8 +338,25 @@ TEST(SchemaValidator, OneOf) {
VALIDATE(s, "10", true);
VALIDATE(s, "9", true);
- INVALIDATE(s, "2", "", "oneOf", "");
- INVALIDATE(s, "15", "", "oneOf", "");
+ INVALIDATE(s, "2", "", "oneOf", "",
+ "{ \"oneOf\": {"
+ " \"errorCode\": 21,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"errors\": ["
+ " { \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#/oneOf/0\","
+ " \"expected\": 5, \"actual\": 2"
+ " }},"
+ " { \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#/oneOf/1\","
+ " \"expected\": 3, \"actual\": 2"
+ " }}"
+ " ]"
+ "}}");
+ INVALIDATE(s, "15", "", "oneOf", "",
+ "{ \"oneOf\": { \"errorCode\": 22, \"instanceRef\": \"#\", \"schemaRef\": \"#\", \"matches\": [0,1]}}");
}
TEST(SchemaValidator, Not) {
@@ -246,7 +366,8 @@ TEST(SchemaValidator, Not) {
VALIDATE(s, "42", true);
VALIDATE(s, "{ \"key\": \"value\" }", true);
- INVALIDATE(s, "\"I am a string\"", "", "not", "");
+ INVALIDATE(s, "\"I am a string\"", "", "not", "",
+ "{ \"not\": { \"errorCode\": 25, \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}");
}
TEST(SchemaValidator, Ref) {
@@ -310,7 +431,14 @@ TEST(SchemaValidator, Ref_AllOf) {
"}");
SchemaDocument s(sd);
- INVALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"} }", "/properties/shipping_address", "allOf", "/shipping_address");
+ INVALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"} }", "/properties/shipping_address", "allOf", "/shipping_address",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " {},"
+ " {\"required\": {\"errorCode\": 15, \"instanceRef\": \"#/shipping_address\", \"schemaRef\": \"#/properties/shipping_address/allOf/1\", \"missing\": [\"type\"]}}"
+ " ],"
+ " \"errorCode\":23,\"instanceRef\":\"#/shipping_address\",\"schemaRef\":\"#/properties/shipping_address\""
+ "}}");
VALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\", \"type\": \"business\"} }", true);
}
@@ -320,11 +448,36 @@ TEST(SchemaValidator, String) {
SchemaDocument s(sd);
VALIDATE(s, "\"I'm a string\"", true);
- INVALIDATE(s, "42", "", "type", "");
- INVALIDATE(s, "2147483648", "", "type", ""); // 2^31 can only be fit in unsigned
- INVALIDATE(s, "-2147483649", "", "type", ""); // -2^31 - 1 can only be fit in int64_t
- INVALIDATE(s, "4294967296", "", "type", ""); // 2^32 can only be fit in int64_t
- INVALIDATE(s, "3.1415926", "", "type", "");
+ INVALIDATE(s, "42", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}");
+ INVALIDATE(s, "2147483648", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}"); // 2^31 can only be fit in unsigned
+ INVALIDATE(s, "-2147483649", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}"); // -2^31 - 1 can only be fit in int64_t
+ INVALIDATE(s, "4294967296", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}"); // 2^32 can only be fit in int64_t
+ INVALIDATE(s, "3.1415926", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"number\""
+ "}}");
}
TEST(SchemaValidator, String_LengthRange) {
@@ -332,10 +485,20 @@ TEST(SchemaValidator, String_LengthRange) {
sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
SchemaDocument s(sd);
- INVALIDATE(s, "\"A\"", "", "minLength", "");
+ INVALIDATE(s, "\"A\"", "", "minLength", "",
+ "{ \"minLength\": {"
+ " \"errorCode\": 7,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 2, \"actual\": \"A\""
+ "}}");
VALIDATE(s, "\"AB\"", true);
VALIDATE(s, "\"ABC\"", true);
- INVALIDATE(s, "\"ABCD\"", "", "maxLength", "");
+ INVALIDATE(s, "\"ABCD\"", "", "maxLength", "",
+ "{ \"maxLength\": {"
+ " \"errorCode\": 6,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 3, \"actual\": \"ABCD\""
+ "}}");
}
#if RAPIDJSON_SCHEMA_HAS_REGEX
@@ -346,18 +509,29 @@ TEST(SchemaValidator, String_Pattern) {
VALIDATE(s, "\"555-1212\"", true);
VALIDATE(s, "\"(888)555-1212\"", true);
- INVALIDATE(s, "\"(888)555-1212 ext. 532\"", "", "pattern", "");
- INVALIDATE(s, "\"(800)FLOWERS\"", "", "pattern", "");
+ INVALIDATE(s, "\"(888)555-1212 ext. 532\"", "", "pattern", "",
+ "{ \"pattern\": {"
+ " \"errorCode\": 8,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"actual\": \"(888)555-1212 ext. 532\""
+ "}}");
+ INVALIDATE(s, "\"(800)FLOWERS\"", "", "pattern", "",
+ "{ \"pattern\": {"
+ " \"errorCode\": 8,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"actual\": \"(800)FLOWERS\""
+ "}}");
}
TEST(SchemaValidator, String_Pattern_Invalid) {
Document sd;
- sd.Parse("{\"type\":\"string\",\"pattern\":\"a{0}\"}"); // TODO: report regex is invalid somehow
+ sd.Parse("{\"type\":\"string\",\"pattern\":\"a{0}\"}");
SchemaDocument s(sd);
+ SCHEMAERROR(s, "{\"RegexInvalid\":{\"errorCode\":9,\"instanceRef\":\"#/pattern\",\"value\":\"a{0}\"}}");
- VALIDATE(s, "\"\"", true);
- VALIDATE(s, "\"a\"", true);
- VALIDATE(s, "\"aa\"", true);
+ VALIDATE_(s, "\"\"", true, false);
+ VALIDATE_(s, "\"a\"", true, false);
+ VALIDATE_(s, "\"aa\"", true, false);
}
#endif
@@ -372,8 +546,18 @@ TEST(SchemaValidator, Integer) {
VALIDATE(s, "-2147483649", true); // -2^31 - 1 can only be fit in int64_t
VALIDATE(s, "2147483648", true); // 2^31 can only be fit in unsigned
VALIDATE(s, "4294967296", true); // 2^32 can only be fit in int64_t
- INVALIDATE(s, "3.1415926", "", "type", "");
- INVALIDATE(s, "\"42\"", "", "type", "");
+ INVALIDATE(s, "3.1415926", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"integer\"], \"actual\": \"number\""
+ "}}");
+ INVALIDATE(s, "\"42\"", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"integer\"], \"actual\": \"string\""
+ "}}");
}
TEST(SchemaValidator, Integer_Range) {
@@ -381,12 +565,27 @@ TEST(SchemaValidator, Integer_Range) {
sd.Parse("{\"type\":\"integer\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
SchemaDocument s(sd);
- INVALIDATE(s, "-1", "", "minimum", "");
+ INVALIDATE(s, "-1", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 0, \"actual\": -1"
+ "}}");
VALIDATE(s, "0", true);
VALIDATE(s, "10", true);
VALIDATE(s, "99", true);
- INVALIDATE(s, "100", "", "maximum", "");
- INVALIDATE(s, "101", "", "maximum", "");
+ INVALIDATE(s, "100", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100"
+ "}}");
+ INVALIDATE(s, "101", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 101"
+ "}}");
}
TEST(SchemaValidator, Integer_Range64Boundary) {
@@ -394,7 +593,12 @@ TEST(SchemaValidator, Integer_Range64Boundary) {
sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775807,\"maximum\":9223372036854775806}");
SchemaDocument s(sd);
- INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
+ INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -9223372036854775807, \"actual\": -9223372036854775808"
+ "}}");
VALIDATE(s, "-9223372036854775807", true);
VALIDATE(s, "-2147483648", true); // int min
VALIDATE(s, "0", true);
@@ -402,8 +606,18 @@ TEST(SchemaValidator, Integer_Range64Boundary) {
VALIDATE(s, "2147483648", true); // unsigned first
VALIDATE(s, "4294967295", true); // unsigned max
VALIDATE(s, "9223372036854775806", true);
- INVALIDATE(s, "9223372036854775807", "", "maximum", "");
- INVALIDATE(s, "18446744073709551615", "", "maximum", ""); // uint64_t max
+ INVALIDATE(s, "9223372036854775807", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 2,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775806, \"actual\": 9223372036854775807"
+ "}}");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 2,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775806, \"actual\": 18446744073709551615"
+ "}}"); // uint64_t max
}
TEST(SchemaValidator, Integer_RangeU64Boundary) {
@@ -411,16 +625,56 @@ TEST(SchemaValidator, Integer_RangeU64Boundary) {
sd.Parse("{\"type\":\"integer\",\"minimum\":9223372036854775808,\"maximum\":18446744073709551614}");
SchemaDocument s(sd);
- INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
- INVALIDATE(s, "9223372036854775807", "", "minimum", "");
- INVALIDATE(s, "-2147483648", "", "minimum", ""); // int min
- INVALIDATE(s, "0", "", "minimum", "");
- INVALIDATE(s, "2147483647", "", "minimum", ""); // int max
- INVALIDATE(s, "2147483648", "", "minimum", ""); // unsigned first
- INVALIDATE(s, "4294967295", "", "minimum", ""); // unsigned max
+ INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": -9223372036854775808"
+ "}}");
+ INVALIDATE(s, "9223372036854775807", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": 9223372036854775807"
+ "}}");
+ INVALIDATE(s, "-2147483648", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": -2147483648"
+ "}}"); // int min
+ INVALIDATE(s, "0", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": 0"
+ "}}");
+ INVALIDATE(s, "2147483647", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": 2147483647"
+ "}}"); // int max
+ INVALIDATE(s, "2147483648", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": 2147483648"
+ "}}"); // unsigned first
+ INVALIDATE(s, "4294967295", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808, \"actual\": 4294967295"
+ "}}"); // unsigned max
VALIDATE(s, "9223372036854775808", true);
VALIDATE(s, "18446744073709551614", true);
- INVALIDATE(s, "18446744073709551615", "", "maximum", "");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 2,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 18446744073709551614, \"actual\": 18446744073709551615"
+ "}}");
}
TEST(SchemaValidator, Integer_Range64BoundaryExclusive) {
@@ -428,10 +682,22 @@ TEST(SchemaValidator, Integer_Range64BoundaryExclusive) {
sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775808,\"maximum\":18446744073709551615,\"exclusiveMinimum\":true,\"exclusiveMaximum\":true}");
SchemaDocument s(sd);
- INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
+ INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 5,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -9223372036854775808, \"exclusiveMinimum\": true, "
+ " \"actual\": -9223372036854775808"
+ "}}");
VALIDATE(s, "-9223372036854775807", true);
VALIDATE(s, "18446744073709551614", true);
- INVALIDATE(s, "18446744073709551615", "", "maximum", "");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 18446744073709551615, \"exclusiveMaximum\": true, "
+ " \"actual\": 18446744073709551615"
+ "}}");
}
TEST(SchemaValidator, Integer_MultipleOf) {
@@ -443,8 +709,18 @@ TEST(SchemaValidator, Integer_MultipleOf) {
VALIDATE(s, "10", true);
VALIDATE(s, "-10", true);
VALIDATE(s, "20", true);
- INVALIDATE(s, "23", "", "multipleOf", "");
- INVALIDATE(s, "-23", "", "multipleOf", "");
+ INVALIDATE(s, "23", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10, \"actual\": 23"
+ "}}");
+ INVALIDATE(s, "-23", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10, \"actual\": -23"
+ "}}");
}
TEST(SchemaValidator, Integer_MultipleOf64Boundary) {
@@ -454,7 +730,12 @@ TEST(SchemaValidator, Integer_MultipleOf64Boundary) {
VALIDATE(s, "0", true);
VALIDATE(s, "18446744073709551615", true);
- INVALIDATE(s, "18446744073709551614", "", "multipleOf", "");
+ INVALIDATE(s, "18446744073709551614", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 18446744073709551615, \"actual\": 18446744073709551614"
+ "}}");
}
TEST(SchemaValidator, Number_Range) {
@@ -462,15 +743,35 @@ TEST(SchemaValidator, Number_Range) {
sd.Parse("{\"type\":\"number\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
SchemaDocument s(sd);
- INVALIDATE(s, "-1", "", "minimum", "");
+ INVALIDATE(s, "-1", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 0, \"actual\": -1"
+ "}}");
VALIDATE(s, "0", true);
VALIDATE(s, "0.1", true);
VALIDATE(s, "10", true);
VALIDATE(s, "99", true);
VALIDATE(s, "99.9", true);
- INVALIDATE(s, "100", "", "maximum", "");
- INVALIDATE(s, "100.0", "", "maximum", "");
- INVALIDATE(s, "101.5", "", "maximum", "");
+ INVALIDATE(s, "100", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100"
+ "}}");
+ INVALIDATE(s, "100.0", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100.0"
+ "}}");
+ INVALIDATE(s, "101.5", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 101.5"
+ "}}");
}
TEST(SchemaValidator, Number_RangeInt) {
@@ -478,19 +779,74 @@ TEST(SchemaValidator, Number_RangeInt) {
sd.Parse("{\"type\":\"number\",\"minimum\":-100,\"maximum\":-1,\"exclusiveMaximum\":true}");
SchemaDocument s(sd);
- INVALIDATE(s, "-101", "", "minimum", "");
- INVALIDATE(s, "-100.1", "", "minimum", "");
+ INVALIDATE(s, "-101", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -100, \"actual\": -101"
+ "}}");
+ INVALIDATE(s, "-100.1", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -100, \"actual\": -100.1"
+ "}}");
VALIDATE(s, "-100", true);
VALIDATE(s, "-2", true);
- INVALIDATE(s, "-1", "", "maximum", "");
- INVALIDATE(s, "-0.9", "", "maximum", "");
- INVALIDATE(s, "0", "", "maximum", "");
- INVALIDATE(s, "2147483647", "", "maximum", ""); // int max
- INVALIDATE(s, "2147483648", "", "maximum", ""); // unsigned first
- INVALIDATE(s, "4294967295", "", "maximum", ""); // unsigned max
- INVALIDATE(s, "9223372036854775808", "", "maximum", "");
- INVALIDATE(s, "18446744073709551614", "", "maximum", "");
- INVALIDATE(s, "18446744073709551615", "", "maximum", "");
+ INVALIDATE(s, "-1", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": -1"
+ "}}");
+ INVALIDATE(s, "-0.9", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": -0.9"
+ "}}");
+ INVALIDATE(s, "0", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 0"
+ "}}");
+ INVALIDATE(s, "2147483647", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 2147483647"
+ "}}"); // int max
+ INVALIDATE(s, "2147483648", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 2147483648"
+ "}}"); // unsigned first
+ INVALIDATE(s, "4294967295", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 4294967295"
+ "}}"); // unsigned max
+ INVALIDATE(s, "9223372036854775808", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 9223372036854775808"
+ "}}");
+ INVALIDATE(s, "18446744073709551614", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
+ "}}");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
+ "}}");
}
TEST(SchemaValidator, Number_RangeDouble) {
@@ -498,23 +854,88 @@ TEST(SchemaValidator, Number_RangeDouble) {
sd.Parse("{\"type\":\"number\",\"minimum\":0.1,\"maximum\":100.1,\"exclusiveMaximum\":true}");
SchemaDocument s(sd);
- INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
- INVALIDATE(s, "-2147483648", "", "minimum", ""); // int min
- INVALIDATE(s, "-1", "", "minimum", "");
+ INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 0.1, \"actual\": -9223372036854775808"
+ "}}");
+ INVALIDATE(s, "-2147483648", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 0.1, \"actual\": -2147483648"
+ "}}"); // int min
+ INVALIDATE(s, "-1", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 0.1, \"actual\": -1"
+ "}}");
VALIDATE(s, "0.1", true);
VALIDATE(s, "10", true);
VALIDATE(s, "99", true);
VALIDATE(s, "100", true);
- INVALIDATE(s, "101", "", "maximum", "");
- INVALIDATE(s, "101.5", "", "maximum", "");
- INVALIDATE(s, "18446744073709551614", "", "maximum", "");
- INVALIDATE(s, "18446744073709551615", "", "maximum", "");
- INVALIDATE(s, "2147483647", "", "maximum", ""); // int max
- INVALIDATE(s, "2147483648", "", "maximum", ""); // unsigned first
- INVALIDATE(s, "4294967295", "", "maximum", ""); // unsigned max
- INVALIDATE(s, "9223372036854775808", "", "maximum", "");
- INVALIDATE(s, "18446744073709551614", "", "maximum", "");
- INVALIDATE(s, "18446744073709551615", "", "maximum", "");
+ INVALIDATE(s, "101", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 101"
+ "}}");
+ INVALIDATE(s, "101.5", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 101.5"
+ "}}");
+ INVALIDATE(s, "18446744073709551614", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
+ "}}");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
+ "}}");
+ INVALIDATE(s, "2147483647", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 2147483647"
+ "}}"); // int max
+ INVALIDATE(s, "2147483648", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 2147483648"
+ "}}"); // unsigned first
+ INVALIDATE(s, "4294967295", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 4294967295"
+ "}}"); // unsigned max
+ INVALIDATE(s, "9223372036854775808", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 9223372036854775808"
+ "}}");
+ INVALIDATE(s, "18446744073709551614", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614"
+ "}}");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615"
+ "}}");
}
TEST(SchemaValidator, Number_RangeDoubleU64Boundary) {
@@ -522,15 +943,50 @@ TEST(SchemaValidator, Number_RangeDoubleU64Boundary) {
sd.Parse("{\"type\":\"number\",\"minimum\":9223372036854775808.0,\"maximum\":18446744073709550000.0}");
SchemaDocument s(sd);
- INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
- INVALIDATE(s, "-2147483648", "", "minimum", ""); // int min
- INVALIDATE(s, "0", "", "minimum", "");
- INVALIDATE(s, "2147483647", "", "minimum", ""); // int max
- INVALIDATE(s, "2147483648", "", "minimum", ""); // unsigned first
- INVALIDATE(s, "4294967295", "", "minimum", ""); // unsigned max
+ INVALIDATE(s, "-9223372036854775808", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808.0, \"actual\": -9223372036854775808"
+ "}}");
+ INVALIDATE(s, "-2147483648", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808.0, \"actual\": -2147483648"
+ "}}"); // int min
+ INVALIDATE(s, "0", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808.0, \"actual\": 0"
+ "}}");
+ INVALIDATE(s, "2147483647", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808.0, \"actual\": 2147483647"
+ "}}"); // int max
+ INVALIDATE(s, "2147483648", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808.0, \"actual\": 2147483648"
+ "}}"); // unsigned first
+ INVALIDATE(s, "4294967295", "", "minimum", "",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 9223372036854775808.0, \"actual\": 4294967295"
+ "}}"); // unsigned max
VALIDATE(s, "9223372036854775808", true);
VALIDATE(s, "18446744073709540000", true);
- INVALIDATE(s, "18446744073709551615", "", "maximum", "");
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "",
+ "{ \"maximum\": {"
+ " \"errorCode\": 2,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 18446744073709550000.0, \"actual\": 18446744073709551615"
+ "}}");
}
TEST(SchemaValidator, Number_MultipleOf) {
@@ -542,13 +998,38 @@ TEST(SchemaValidator, Number_MultipleOf) {
VALIDATE(s, "10", true);
VALIDATE(s, "-10", true);
VALIDATE(s, "20", true);
- INVALIDATE(s, "23", "", "multipleOf", "");
- INVALIDATE(s, "-2147483648", "", "multipleOf", ""); // int min
+ INVALIDATE(s, "23", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10.0, \"actual\": 23"
+ "}}");
+ INVALIDATE(s, "-2147483648", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10.0, \"actual\": -2147483648"
+ "}}"); // int min
VALIDATE(s, "-2147483640", true);
- INVALIDATE(s, "2147483647", "", "multipleOf", ""); // int max
- INVALIDATE(s, "2147483648", "", "multipleOf", ""); // unsigned first
+ INVALIDATE(s, "2147483647", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10.0, \"actual\": 2147483647"
+ "}}"); // int max
+ INVALIDATE(s, "2147483648", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10.0, \"actual\": 2147483648"
+ "}}"); // unsigned first
VALIDATE(s, "2147483650", true);
- INVALIDATE(s, "4294967295", "", "multipleOf", ""); // unsigned max
+ INVALIDATE(s, "4294967295", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 10.0, \"actual\": 4294967295"
+ "}}"); // unsigned max
VALIDATE(s, "4294967300", true);
}
@@ -559,7 +1040,12 @@ TEST(SchemaValidator, Number_MultipleOfOne) {
VALIDATE(s, "42", true);
VALIDATE(s, "42.0", true);
- INVALIDATE(s, "3.1415926", "", "multipleOf", "");
+ INVALIDATE(s, "3.1415926", "", "multipleOf", "",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 1, \"actual\": 3.1415926"
+ "}}");
}
TEST(SchemaValidator, Object) {
@@ -569,8 +1055,18 @@ TEST(SchemaValidator, Object) {
VALIDATE(s, "{\"key\":\"value\",\"another_key\":\"another_value\"}", true);
VALIDATE(s, "{\"Sun\":1.9891e30,\"Jupiter\":1.8986e27,\"Saturn\":5.6846e26,\"Neptune\":10.243e25,\"Uranus\":8.6810e25,\"Earth\":5.9736e24,\"Venus\":4.8685e24,\"Mars\":6.4185e23,\"Mercury\":3.3022e23,\"Moon\":7.349e22,\"Pluto\":1.25e22}", true);
- INVALIDATE(s, "[\"An\", \"array\", \"not\", \"an\", \"object\"]", "", "type", "");
- INVALIDATE(s, "\"Not an object\"", "", "type", "");
+ INVALIDATE(s, "[\"An\", \"array\", \"not\", \"an\", \"object\"]", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"object\"], \"actual\": \"array\""
+ "}}");
+ INVALIDATE(s, "\"Not an object\"", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"object\"], \"actual\": \"string\""
+ "}}");
}
TEST(SchemaValidator, Object_Properties) {
@@ -588,7 +1084,19 @@ TEST(SchemaValidator, Object_Properties) {
SchemaDocument s(sd);
VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
- INVALIDATE(s, "{ \"number\": \"1600\", \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", "/properties/number", "type", "/number");
+ INVALIDATE(s, "{ \"number\": \"1600\", \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", "/properties/number", "type", "/number",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/number\", \"schemaRef\": \"#/properties/number\","
+ " \"expected\": [\"number\"], \"actual\": \"string\""
+ "}}");
+ INVALIDATE(s, "{ \"number\": \"One\", \"street_name\": \"Microsoft\", \"street_type\": \"Way\" }",
+ "/properties/number", "type", "/number",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/number\", \"schemaRef\": \"#/properties/number\","
+ " \"expected\": [\"number\"], \"actual\": \"string\""
+ "}}"); // fail fast
VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\" }", true);
VALIDATE(s, "{}", true);
VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
@@ -612,7 +1120,12 @@ TEST(SchemaValidator, Object_AdditionalPropertiesBoolean) {
SchemaDocument s(sd);
VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
- INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", "", "additionalProperties", "/direction");
+ INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", "", "additionalProperties", "/direction",
+ "{ \"additionalProperties\": {"
+ " \"errorCode\": 16,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"disallowed\": \"direction\""
+ "}}");
}
TEST(SchemaValidator, Object_AdditionalPropertiesObject) {
@@ -633,7 +1146,12 @@ TEST(SchemaValidator, Object_AdditionalPropertiesObject) {
VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
- INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"office_number\": 201 }", "/additionalProperties", "type", "/office_number");
+ INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"office_number\": 201 }", "/additionalProperties", "type", "/office_number",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/office_number\", \"schemaRef\": \"#/additionalProperties\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}");
}
TEST(SchemaValidator, Object_Required) {
@@ -653,20 +1171,75 @@ TEST(SchemaValidator, Object_Required) {
VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\" }", true);
VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true);
- INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "");
-}
+ INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "",
+ "{ \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"missing\": [\"email\"]"
+ "}}");
+ INVALIDATE(s, "{}", "", "required", "",
+ "{ \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"missing\": [\"name\", \"email\"]"
+ "}}");
+}
+
+TEST(SchemaValidator, Object_Required_PassWithDefault) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"properties\" : {"
+ " \"name\": { \"type\": \"string\", \"default\": \"William Shakespeare\" },"
+ " \"email\" : { \"type\": \"string\", \"default\": \"\" },"
+ " \"address\" : { \"type\": \"string\" },"
+ " \"telephone\" : { \"type\": \"string\" }"
+ " },"
+ " \"required\":[\"name\", \"email\"]"
+ "}");
+ SchemaDocument s(sd);
+ VALIDATE(s, "{ \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true);
+ INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "",
+ "{ \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"missing\": [\"email\"]"
+ "}}");
+ INVALIDATE(s, "{}", "", "required", "",
+ "{ \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"missing\": [\"email\"]"
+ "}}");
+}
TEST(SchemaValidator, Object_PropertiesRange) {
Document sd;
sd.Parse("{\"type\":\"object\", \"minProperties\":2, \"maxProperties\":3}");
SchemaDocument s(sd);
- INVALIDATE(s, "{}", "", "minProperties", "");
- INVALIDATE(s, "{\"a\":0}", "", "minProperties", "");
+ INVALIDATE(s, "{}", "", "minProperties", "",
+ "{ \"minProperties\": {"
+ " \"errorCode\": 14,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 2, \"actual\": 0"
+ "}}");
+ INVALIDATE(s, "{\"a\":0}", "", "minProperties", "",
+ "{ \"minProperties\": {"
+ " \"errorCode\": 14,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 2, \"actual\": 1"
+ "}}");
VALIDATE(s, "{\"a\":0,\"b\":1}", true);
VALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2}", true);
- INVALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", "", "maxProperties", "");
+ INVALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", "", "maxProperties", "",
+ "{ \"maxProperties\": {"
+ " \"errorCode\": 13,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\", "
+ " \"expected\": 3, \"actual\": 4"
+ "}}");
}
TEST(SchemaValidator, Object_PropertyDependencies) {
@@ -677,19 +1250,32 @@ TEST(SchemaValidator, Object_PropertyDependencies) {
" \"properties\": {"
" \"name\": { \"type\": \"string\" },"
" \"credit_card\": { \"type\": \"number\" },"
+ " \"cvv_code\": { \"type\": \"number\" },"
" \"billing_address\": { \"type\": \"string\" }"
" },"
" \"required\": [\"name\"],"
" \"dependencies\": {"
- " \"credit_card\": [\"billing_address\"]"
+ " \"credit_card\": [\"cvv_code\", \"billing_address\"]"
" }"
"}");
SchemaDocument s(sd);
- VALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555, \"billing_address\": \"555 Debtor's Lane\" }", true);
- INVALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555 }", "", "dependencies", "");
+ VALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555, \"cvv_code\": 777, "
+ "\"billing_address\": \"555 Debtor's Lane\" }", true);
+ INVALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555 }", "", "dependencies", "",
+ "{ \"dependencies\": {"
+ " \"errorCode\": 18,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"errors\": {"
+ " \"credit_card\": {"
+ " \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/credit_card\","
+ " \"missing\": [\"cvv_code\", \"billing_address\"]"
+ " } } }"
+ "}}");
VALIDATE(s, "{ \"name\": \"John Doe\"}", true);
- VALIDATE(s, "{ \"name\": \"John Doe\", \"billing_address\": \"555 Debtor's Lane\" }", true);
+ VALIDATE(s, "{ \"name\": \"John Doe\", \"cvv_code\": 777, \"billing_address\": \"555 Debtor's Lane\" }", true);
}
TEST(SchemaValidator, Object_SchemaDependencies) {
@@ -714,7 +1300,18 @@ TEST(SchemaValidator, Object_SchemaDependencies) {
SchemaDocument s(sd);
VALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555,\"billing_address\" : \"555 Debtor's Lane\"}", true);
- INVALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555 }", "", "dependencies", "");
+ INVALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555 }", "", "dependencies", "",
+ "{ \"dependencies\": {"
+ " \"errorCode\": 18,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"errors\": {"
+ " \"credit_card\": {"
+ " \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/credit_card\","
+ " \"missing\": [\"billing_address\"]"
+ " } } }"
+ "}}");
VALIDATE(s, "{\"name\": \"John Doe\", \"billing_address\" : \"555 Debtor's Lane\"}", true);
}
@@ -733,12 +1330,85 @@ TEST(SchemaValidator, Object_PatternProperties) {
VALIDATE(s, "{ \"S_25\": \"This is a string\" }", true);
VALIDATE(s, "{ \"I_0\": 42 }", true);
- INVALIDATE(s, "{ \"S_0\": 42 }", "", "patternProperties", "/S_0");
- INVALIDATE(s, "{ \"I_42\": \"This is a string\" }", "", "patternProperties", "/I_42");
+ INVALIDATE(s, "{ \"S_0\": 42 }", "", "patternProperties", "/S_0",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/S_0\", \"schemaRef\": \"#/patternProperties/%5ES_\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}");
+ INVALIDATE(s, "{ \"I_42\": \"This is a string\" }", "", "patternProperties", "/I_42",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/patternProperties/%5EI_\","
+ " \"expected\": [\"integer\"], \"actual\": \"string\""
+ "}}");
VALIDATE(s, "{ \"keyword\": \"value\" }", true);
}
-TEST(SchemaValidator, Object_PatternProperties_AdditionalProperties) {
+TEST(SchemaValidator, Object_PatternProperties_ErrorConflict) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"patternProperties\": {"
+ " \"^I_\": { \"multipleOf\": 5 },"
+ " \"30$\": { \"multipleOf\": 6 }"
+ " }"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"I_30\": 30 }", true);
+ INVALIDATE(s, "{ \"I_30\": 7 }", "", "patternProperties", "/I_30",
+ "{ \"multipleOf\": ["
+ " {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#/I_30\", \"schemaRef\": \"#/patternProperties/%5EI_\","
+ " \"expected\": 5, \"actual\": 7"
+ " }, {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#/I_30\", \"schemaRef\": \"#/patternProperties/30%24\","
+ " \"expected\": 6, \"actual\": 7"
+ " }"
+ "]}");
+}
+
+TEST(SchemaValidator, Object_Properties_PatternProperties) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"I_42\": { \"type\": \"integer\", \"minimum\": 73 }"
+ " },"
+ " \"patternProperties\": {"
+ " \"^I_\": { \"type\": \"integer\", \"multipleOf\": 6 }"
+ " }"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"I_6\": 6 }", true);
+ VALIDATE(s, "{ \"I_42\": 78 }", true);
+ INVALIDATE(s, "{ \"I_42\": 42 }", "", "patternProperties", "/I_42",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/properties/I_42\","
+ " \"expected\": 73, \"actual\": 42"
+ "}}");
+ INVALIDATE(s, "{ \"I_42\": 7 }", "", "patternProperties", "/I_42",
+ "{ \"minimum\": {"
+ " \"errorCode\": 4,"
+ " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/properties/I_42\","
+ " \"expected\": 73, \"actual\": 7"
+ " },"
+ " \"multipleOf\": {"
+ " \"errorCode\": 1,"
+ " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/patternProperties/%5EI_\","
+ " \"expected\": 6, \"actual\": 7"
+ " }"
+ "}");
+}
+
+TEST(SchemaValidator, Object_PatternProperties_AdditionalPropertiesObject) {
Document sd;
sd.Parse(
"{"
@@ -756,7 +1426,36 @@ TEST(SchemaValidator, Object_PatternProperties_AdditionalProperties) {
VALIDATE(s, "{ \"builtin\": 42 }", true);
VALIDATE(s, "{ \"keyword\": \"value\" }", true);
- INVALIDATE(s, "{ \"keyword\": 42 }", "/additionalProperties", "type", "/keyword");
+ INVALIDATE(s, "{ \"keyword\": 42 }", "/additionalProperties", "type", "/keyword",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/keyword\", \"schemaRef\": \"#/additionalProperties\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}");
+}
+
+// Replaces test Issue285 and tests failure as well as success
+TEST(SchemaValidator, Object_PatternProperties_AdditionalPropertiesBoolean) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"patternProperties\": {"
+ " \"^S_\": { \"type\": \"string\" },"
+ " \"^I_\": { \"type\": \"integer\" }"
+ " },"
+ " \"additionalProperties\": false"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"S_25\": \"This is a string\" }", true);
+ VALIDATE(s, "{ \"I_0\": 42 }", true);
+ INVALIDATE(s, "{ \"keyword\": \"value\" }", "", "additionalProperties", "/keyword",
+ "{ \"additionalProperties\": {"
+ " \"errorCode\": 16,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"disallowed\": \"keyword\""
+ "}}");
}
#endif
@@ -767,7 +1466,12 @@ TEST(SchemaValidator, Array) {
VALIDATE(s, "[1, 2, 3, 4, 5]", true);
VALIDATE(s, "[3, \"different\", { \"types\" : \"of values\" }]", true);
- INVALIDATE(s, "{\"Not\": \"an array\"}", "", "type", "");
+ INVALIDATE(s, "{\"Not\": \"an array\"}", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"array\"], \"actual\": \"object\""
+ "}}");
}
TEST(SchemaValidator, Array_ItemsList) {
@@ -782,7 +1486,12 @@ TEST(SchemaValidator, Array_ItemsList) {
SchemaDocument s(sd);
VALIDATE(s, "[1, 2, 3, 4, 5]", true);
- INVALIDATE(s, "[1, 2, \"3\", 4, 5]", "/items", "type", "/2");
+ INVALIDATE(s, "[1, 2, \"3\", 4, 5]", "/items", "type", "/2",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/2\", \"schemaRef\": \"#/items\","
+ " \"expected\": [\"number\"], \"actual\": \"string\""
+ "}}");
VALIDATE(s, "[]", true);
}
@@ -811,13 +1520,25 @@ TEST(SchemaValidator, Array_ItemsTuple) {
SchemaDocument s(sd);
VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
- INVALIDATE(s, "[24, \"Sussex\", \"Drive\"]", "/items/2", "enum", "/2");
- INVALIDATE(s, "[\"Palais de l'Elysee\"]", "/items/0", "type", "/0");
+ INVALIDATE(s, "[24, \"Sussex\", \"Drive\"]", "/items/2", "enum", "/2",
+ "{ \"enum\": { \"errorCode\": 19, \"instanceRef\": \"#/2\", \"schemaRef\": \"#/items/2\" }}");
+ INVALIDATE(s, "[\"Palais de l'Elysee\"]", "/items/0", "type", "/0",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items/0\","
+ " \"expected\": [\"number\"], \"actual\": \"string\""
+ "}}");
+ INVALIDATE(s, "[\"Twenty-four\", \"Sussex\", \"Drive\"]", "/items/0", "type", "/0",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items/0\","
+ " \"expected\": [\"number\"], \"actual\": \"string\""
+ "}}"); // fail fast
VALIDATE(s, "[10, \"Downing\", \"Street\"]", true);
VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", true);
}
-TEST(SchemaValidator, Array_AdditionalItmes) {
+TEST(SchemaValidator, Array_AdditionalItems) {
Document sd;
sd.Parse(
"{"
@@ -844,7 +1565,12 @@ TEST(SchemaValidator, Array_AdditionalItmes) {
VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\"]", true);
- INVALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", "", "items", "/4");
+ INVALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", "", "additionalItems", "/4",
+ "{ \"additionalItems\": {"
+ " \"errorCode\": 12,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"disallowed\": 4"
+ "}}");
}
TEST(SchemaValidator, Array_ItemsRange) {
@@ -852,11 +1578,26 @@ TEST(SchemaValidator, Array_ItemsRange) {
sd.Parse("{\"type\": \"array\",\"minItems\": 2,\"maxItems\" : 3}");
SchemaDocument s(sd);
- INVALIDATE(s, "[]", "", "minItems", "");
- INVALIDATE(s, "[1]", "", "minItems", "");
+ INVALIDATE(s, "[]", "", "minItems", "",
+ "{ \"minItems\": {"
+ " \"errorCode\": 10,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 2, \"actual\": 0"
+ "}}");
+ INVALIDATE(s, "[1]", "", "minItems", "",
+ "{ \"minItems\": {"
+ " \"errorCode\": 10,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 2, \"actual\": 1"
+ "}}");
VALIDATE(s, "[1, 2]", true);
VALIDATE(s, "[1, 2, 3]", true);
- INVALIDATE(s, "[1, 2, 3, 4]", "", "maxItems", "");
+ INVALIDATE(s, "[1, 2, 3, 4]", "", "maxItems", "",
+ "{ \"maxItems\": {"
+ " \"errorCode\": 9,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 3, \"actual\": 4"
+ "}}");
}
TEST(SchemaValidator, Array_UniqueItems) {
@@ -865,7 +1606,18 @@ TEST(SchemaValidator, Array_UniqueItems) {
SchemaDocument s(sd);
VALIDATE(s, "[1, 2, 3, 4, 5]", true);
- INVALIDATE(s, "[1, 2, 3, 3, 4]", "", "uniqueItems", "/3");
+ INVALIDATE(s, "[1, 2, 3, 3, 4]", "", "uniqueItems", "/3",
+ "{ \"uniqueItems\": {"
+ " \"errorCode\": 11,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"duplicates\": [2, 3]"
+ "}}");
+ INVALIDATE(s, "[1, 2, 3, 3, 3]", "", "uniqueItems", "/3",
+ "{ \"uniqueItems\": {"
+ " \"errorCode\": 11,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"duplicates\": [2, 3]"
+ "}}"); // fail fast
VALIDATE(s, "[]", true);
}
@@ -876,8 +1628,18 @@ TEST(SchemaValidator, Boolean) {
VALIDATE(s, "true", true);
VALIDATE(s, "false", true);
- INVALIDATE(s, "\"true\"", "", "type", "");
- INVALIDATE(s, "0", "", "type", "");
+ INVALIDATE(s, "\"true\"", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"boolean\"], \"actual\": \"string\""
+ "}}");
+ INVALIDATE(s, "0", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"boolean\"], \"actual\": \"integer\""
+ "}}");
}
TEST(SchemaValidator, Null) {
@@ -886,9 +1648,24 @@ TEST(SchemaValidator, Null) {
SchemaDocument s(sd);
VALIDATE(s, "null", true);
- INVALIDATE(s, "false", "", "type", "");
- INVALIDATE(s, "0", "", "type", "");
- INVALIDATE(s, "\"\"", "", "type", "");
+ INVALIDATE(s, "false", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"null\"], \"actual\": \"boolean\""
+ "}}");
+ INVALIDATE(s, "0", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"null\"], \"actual\": \"integer\""
+ "}}");
+ INVALIDATE(s, "\"\"", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"null\"], \"actual\": \"string\""
+ "}}");
}
// Additional tests
@@ -899,8 +1676,18 @@ TEST(SchemaValidator, ObjectInArray) {
SchemaDocument s(sd);
VALIDATE(s, "[\"a\"]", true);
- INVALIDATE(s, "[1]", "/items", "type", "/0");
- INVALIDATE(s, "[{}]", "/items", "type", "/0");
+ INVALIDATE(s, "[1]", "/items", "type", "/0",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items\","
+ " \"expected\": [\"string\"], \"actual\": \"integer\""
+ "}}");
+ INVALIDATE(s, "[{}]", "/items", "type", "/0",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items\","
+ " \"expected\": [\"string\"], \"actual\": \"object\""
+ "}}");
}
TEST(SchemaValidator, MultiTypeInObject) {
@@ -918,7 +1705,12 @@ TEST(SchemaValidator, MultiTypeInObject) {
VALIDATE(s, "{ \"tel\": 999 }", true);
VALIDATE(s, "{ \"tel\": \"123-456\" }", true);
- INVALIDATE(s, "{ \"tel\": true }", "/properties/tel", "type", "/tel");
+ INVALIDATE(s, "{ \"tel\": true }", "/properties/tel", "type", "/tel",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/tel\", \"schemaRef\": \"#/properties/tel\","
+ " \"expected\": [\"string\", \"integer\"], \"actual\": \"boolean\""
+ "}}");
}
TEST(SchemaValidator, MultiTypeWithObject) {
@@ -936,7 +1728,12 @@ TEST(SchemaValidator, MultiTypeWithObject) {
VALIDATE(s, "\"Hello\"", true);
VALIDATE(s, "{ \"tel\": 999 }", true);
- INVALIDATE(s, "{ \"tel\": \"fail\" }", "/properties/tel", "type", "/tel");
+ INVALIDATE(s, "{ \"tel\": \"fail\" }", "/properties/tel", "type", "/tel",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/tel\", \"schemaRef\": \"#/properties/tel\","
+ " \"expected\": [\"integer\"], \"actual\": \"string\""
+ "}}");
}
TEST(SchemaValidator, AllOf_Nested) {
@@ -953,11 +1750,72 @@ TEST(SchemaValidator, AllOf_Nested) {
VALIDATE(s, "\"ok\"", true);
VALIDATE(s, "\"OK\"", true);
- INVALIDATE(s, "\"okay\"", "", "allOf", "");
- INVALIDATE(s, "\"o\"", "", "allOf", "");
- INVALIDATE(s, "\"n\"", "", "allOf", "");
- INVALIDATE(s, "\"too long\"", "", "allOf", "");
- INVALIDATE(s, "123", "", "allOf", "");
+ INVALIDATE(s, "\"okay\"", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " {},{},"
+ " { \"allOf\": {"
+ " \"errors\": ["
+ " {},"
+ " { \"enum\": {\"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\" }}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\""
+ " }}],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ "}}");
+ INVALIDATE(s, "\"o\"", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " { \"minLength\": {\"actual\": \"o\", \"expected\": 2, \"errorCode\": 7, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\" }},"
+ " {},{}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ "}}");
+ INVALIDATE(s, "\"n\"", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " { \"minLength\": {\"actual\": \"n\", \"expected\": 2, \"errorCode\": 7, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\" }},"
+ " {},"
+ " { \"allOf\": {"
+ " \"errors\": ["
+ " { \"enum\": {\"errorCode\": 19 ,\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"}},"
+ " { \"enum\": {\"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\""
+ " }}"
+ " ],"
+ " \"errorCode\":23,\"instanceRef\":\"#\",\"schemaRef\":\"#\""
+ "}}");
+ INVALIDATE(s, "\"too long\"", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " {},"
+ " { \"maxLength\": {\"actual\": \"too long\", \"expected\": 5, \"errorCode\": 6, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\" }},"
+ " { \"allOf\": {"
+ " \"errors\": ["
+ " { \"enum\": {\"errorCode\": 19 ,\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"}},"
+ " { \"enum\": {\"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\""
+ " }}"
+ " ],"
+ " \"errorCode\":23,\"instanceRef\":\"#\",\"schemaRef\":\"#\""
+ "}}");
+ INVALIDATE(s, "123", "", "allOf", "",
+ "{ \"allOf\": {"
+ " \"errors\": ["
+ " {\"type\": {\"expected\": [\"string\"], \"actual\": \"integer\", \"errorCode\": 20, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"}},"
+ " {\"type\": {\"expected\": [\"string\"], \"actual\": \"integer\", \"errorCode\": 20, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\"}},"
+ " { \"allOf\": {"
+ " \"errors\": ["
+ " { \"enum\": {\"errorCode\": 19 ,\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"}},"
+ " { \"enum\": {\"errorCode\": 19, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}}"
+ " ],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\""
+ " }}"
+ " ],"
+ " \"errorCode\":23,\"instanceRef\":\"#\",\"schemaRef\":\"#\""
+ "}}");
}
TEST(SchemaValidator, EscapedPointer) {
@@ -970,7 +1828,189 @@ TEST(SchemaValidator, EscapedPointer) {
" }"
"}");
SchemaDocument s(sd);
- INVALIDATE(s, "{\"~/\":true}", "/properties/~0~1", "type", "/~0~1");
+ INVALIDATE(s, "{\"~/\":true}", "/properties/~0~1", "type", "/~0~1",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/~0~1\", \"schemaRef\": \"#/properties/~0~1\","
+ " \"expected\": [\"number\"], \"actual\": \"boolean\""
+ "}}");
+}
+
+TEST(SchemaValidator, SchemaPointer) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"swagger\": \"2.0\","
+ " \"paths\": {"
+ " \"/some/path\": {"
+ " \"post\": {"
+ " \"parameters\": ["
+ " {"
+ " \"in\": \"body\","
+ " \"name\": \"body\","
+ " \"schema\": {"
+ " \"properties\": {"
+ " \"a\": {"
+ " \"$ref\": \"#/definitions/Prop_a\""
+ " },"
+ " \"b\": {"
+ " \"type\": \"integer\""
+ " }"
+ " },"
+ " \"type\": \"object\""
+ " }"
+ " }"
+ " ],"
+ " \"responses\": {"
+ " \"200\": {"
+ " \"schema\": {"
+ " \"$ref\": \"#/definitions/Resp_200\""
+ " }"
+ " }"
+ " }"
+ " }"
+ " }"
+ " },"
+ " \"definitions\": {"
+ " \"Prop_a\": {"
+ " \"properties\": {"
+ " \"c\": {"
+ " \"enum\": ["
+ " \"C1\","
+ " \"C2\","
+ " \"C3\""
+ " ],"
+ " \"type\": \"string\""
+ " },"
+ " \"d\": {"
+ " \"$ref\": \"#/definitions/Prop_d\""
+ " },"
+ " \"s\": {"
+ " \"type\": \"string\""
+ " }"
+ " },"
+ " \"required\": [\"c\"],"
+ " \"type\": \"object\""
+ " },"
+ " \"Prop_d\": {"
+ " \"properties\": {"
+ " \"a\": {"
+ " \"$ref\": \"#/definitions/Prop_a\""
+ " },"
+ " \"c\": {"
+ " \"$ref\": \"#/definitions/Prop_a/properties/c\""
+ " }"
+ " },"
+ " \"type\": \"object\""
+ " },"
+ " \"Resp_200\": {"
+ " \"properties\": {"
+ " \"e\": {"
+ " \"type\": \"string\""
+ " },"
+ " \"f\": {"
+ " \"type\": \"boolean\""
+ " }"
+ " },"
+ " \"type\": \"object\""
+ " }"
+ " }"
+ "}");
+ SchemaDocument s1(sd, NULL, 0, NULL, NULL, Pointer("#/paths/~1some~1path/post/parameters/0/schema"));
+ VALIDATE(s1,
+ "{"
+ " \"a\": {"
+ " \"c\": \"C1\","
+ " \"d\": {"
+ " \"a\": {"
+ " \"c\": \"C2\""
+ " },"
+ " \"c\": \"C3\""
+ " }"
+ " },"
+ " \"b\": 123"
+ "}",
+ true);
+ INVALIDATE(s1,
+ "{"
+ " \"a\": {"
+ " \"c\": \"C1\","
+ " \"d\": {"
+ " \"a\": {"
+ " \"c\": \"C2\""
+ " },"
+ " \"c\": \"C3\""
+ " }"
+ " },"
+ " \"b\": \"should be an int\""
+ "}",
+ "#/paths/~1some~1path/post/parameters/0/schema/properties/b", "type", "#/b",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\":\"#/b\","
+ " \"schemaRef\":\"#/paths/~1some~1path/post/parameters/0/schema/properties/b\","
+ " \"expected\": [\"integer\"], \"actual\":\"string\""
+ "}}");
+ INVALIDATE(s1,
+ "{"
+ " \"a\": {"
+ " \"c\": \"C1\","
+ " \"d\": {"
+ " \"a\": {"
+ " \"c\": \"should be within enum\""
+ " },"
+ " \"c\": \"C3\""
+ " }"
+ " },"
+ " \"b\": 123"
+ "}",
+ "#/definitions/Prop_a/properties/c", "enum", "#/a/d/a/c",
+ "{ \"enum\": {"
+ " \"errorCode\": 19,"
+ " \"instanceRef\":\"#/a/d/a/c\","
+ " \"schemaRef\":\"#/definitions/Prop_a/properties/c\""
+ "}}");
+ INVALIDATE(s1,
+ "{"
+ " \"a\": {"
+ " \"c\": \"C1\","
+ " \"d\": {"
+ " \"a\": {"
+ " \"s\": \"required 'c' is missing\""
+ " }"
+ " }"
+ " },"
+ " \"b\": 123"
+ "}",
+ "#/definitions/Prop_a", "required", "#/a/d/a",
+ "{ \"required\": {"
+ " \"errorCode\": 15,"
+ " \"missing\":[\"c\"],"
+ " \"instanceRef\":\"#/a/d/a\","
+ " \"schemaRef\":\"#/definitions/Prop_a\""
+ "}}");
+ SchemaDocument s2(sd, NULL, 0, NULL, NULL, Pointer("#/paths/~1some~1path/post/responses/200/schema"));
+ VALIDATE(s2,
+ "{ \"e\": \"some string\", \"f\": false }",
+ true);
+ INVALIDATE(s2,
+ "{ \"e\": true, \"f\": false }",
+ "#/definitions/Resp_200/properties/e", "type", "#/e",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\":\"#/e\","
+ " \"schemaRef\":\"#/definitions/Resp_200/properties/e\","
+ " \"expected\": [\"string\"], \"actual\":\"boolean\""
+ "}}");
+ INVALIDATE(s2,
+ "{ \"e\": \"some string\", \"f\": 123 }",
+ "#/definitions/Resp_200/properties/f", "type", "#/f",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\":\"#/f\","
+ " \"schemaRef\":\"#/definitions/Resp_200/properties/f\","
+ " \"expected\": [\"boolean\"], \"actual\":\"integer\""
+ "}}");
}
template <typename Allocator>
@@ -1012,14 +2052,21 @@ TEST(SchemaValidator, ValidateMetaSchema) {
ASSERT_FALSE(d.HasParseError());
SchemaDocument sd(d);
SchemaValidator validator(sd);
- if (!d.Accept(validator)) {
+ d.Accept(validator);
+ if (!validator.IsValid()) {
StringBuffer sb;
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
printf("Invalid schema: %s\n", sb.GetString());
printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
+ printf("Invalid code: %d\n", validator.GetInvalidSchemaCode());
+ printf("Invalid message: %s\n", GetValidateError_En(validator.GetInvalidSchemaCode()));
sb.Clear();
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
printf("Invalid document: %s\n", sb.GetString());
+ sb.Clear();
+ Writer<StringBuffer> w(sb);
+ validator.GetError().Accept(w);
+ printf("Validation error: %s\n", sb.GetString());
ADD_FAILURE();
}
CrtAllocator::Free(json);
@@ -1039,7 +2086,8 @@ TEST(SchemaValidator, ValidateMetaSchema_UTF16) {
ASSERT_FALSE(d.HasParseError());
SD sd(d);
SV validator(sd);
- if (!d.Accept(validator)) {
+ d.Accept(validator);
+ if (!validator.IsValid()) {
GenericStringBuffer<UTF16<> > sb;
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
wprintf(L"Invalid schema: %ls\n", sb.GetString());
@@ -1047,6 +2095,10 @@ TEST(SchemaValidator, ValidateMetaSchema_UTF16) {
sb.Clear();
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
wprintf(L"Invalid document: %ls\n", sb.GetString());
+ sb.Clear();
+ Writer<GenericStringBuffer<UTF16<> >, UTF16<> > w(sb);
+ validator.GetError().Accept(w);
+ printf("Validation error: %ls\n", sb.GetString());
ADD_FAILURE();
}
CrtAllocator::Free(json);
@@ -1063,7 +2115,15 @@ public:
"jsonschema/remotes/integer.json",
"jsonschema/remotes/subSchemas.json",
"jsonschema/remotes/folder/folderInteger.json",
- "draft-04/schema"
+ "draft-04/schema",
+ "unittestschema/address.json"
+ };
+ const char* uris[kCount] = {
+ "http://localhost:1234/integer.json",
+ "http://localhost:1234/subSchemas.json",
+ "http://localhost:1234/folder/folderInteger.json",
+ "http://json-schema.org/draft-04/schema",
+ "http://localhost:1234/address.json"
};
for (size_t i = 0; i < kCount; i++) {
@@ -1081,7 +2141,7 @@ public:
MemoryPoolAllocator<> stackAllocator(stackBuffer, sizeof(stackBuffer));
DocumentType d(&documentAllocator_, 1024, &stackAllocator);
d.Parse(json);
- sd_[i] = new SchemaDocumentType(d, 0, &schemaAllocator_);
+ sd_[i] = new SchemaDocumentType(d, uris[i], static_cast<SizeType>(strlen(uris[i])), 0, &schemaAllocator_);
MemoryPoolAllocator<>::Free(json);
}
};
@@ -1093,16 +2153,13 @@ public:
}
virtual const SchemaDocumentType* GetRemoteDocument(const char* uri, SizeType length) {
- const char* uris[kCount] = {
- "http://localhost:1234/integer.json",
- "http://localhost:1234/subSchemas.json",
- "http://localhost:1234/folder/folderInteger.json",
- "http://json-schema.org/draft-04/schema"
- };
-
+ //printf("GetRemoteDocument : %s\n", uri);
for (size_t i = 0; i < kCount; i++)
- if (strncmp(uri, uris[i], length) == 0 && strlen(uris[i]) == length)
+ if (typename SchemaDocumentType::GValue(uri, length) == sd_[i]->GetURI()) {
+ //printf("Matched document");
return sd_[i];
+ }
+ //printf("No matched document");
return 0;
}
@@ -1112,12 +2169,12 @@ private:
RemoteSchemaDocumentProvider(const RemoteSchemaDocumentProvider&);
RemoteSchemaDocumentProvider& operator=(const RemoteSchemaDocumentProvider&);
- static const size_t kCount = 4;
+ static const size_t kCount = 5;
SchemaDocumentType* sd_[kCount];
typename DocumentType::AllocatorType documentAllocator_;
typename SchemaDocumentType::AllocatorType schemaAllocator_;
char documentBuffer_[16384];
- char schemaBuffer_[128 * 1024];
+ char schemaBuffer_[128u * 1024];
};
TEST(SchemaValidator, TestSuite) {
@@ -1181,6 +2238,7 @@ TEST(SchemaValidator, TestSuite) {
ADD_FAILURE();
}
else {
+ //printf("\njson test suite file %s parsed ok\n", filename);
GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<> > d(&documentAllocator, 1024, &documentStackAllocator);
d.Parse(json);
if (d.HasParseError()) {
@@ -1190,22 +2248,27 @@ TEST(SchemaValidator, TestSuite) {
else {
for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
{
- SchemaDocumentType schema((*schemaItr)["schema"], &provider, &schemaAllocator);
- GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > validator(schema, &validatorAllocator);
const char* description1 = (*schemaItr)["description"].GetString();
+ //printf("\ncompiling schema for json test %s \n", description1);
+ SchemaDocumentType schema((*schemaItr)["schema"], filenames[i], static_cast<SizeType>(strlen(filenames[i])), &provider, &schemaAllocator);
+ GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > validator(schema, &validatorAllocator);
const Value& tests = (*schemaItr)["tests"];
for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
const char* description2 = (*testItr)["description"].GetString();
+ //printf("running json test %s \n", description2);
if (!onlyRunDescription || strcmp(description2, onlyRunDescription) == 0) {
const Value& data = (*testItr)["data"];
bool expected = (*testItr)["valid"].GetBool();
testCount++;
validator.Reset();
- bool actual = data.Accept(validator);
+ data.Accept(validator);
+ bool actual = validator.IsValid();
if (expected != actual)
printf("Fail: %30s \"%s\" \"%s\"\n", filename, description1, description2);
- else
+ else {
+ //printf("Passed: %30s \"%s\" \"%s\"\n", filename, description1, description2);
passCount++;
+ }
}
}
//printf("%zu %zu %zu\n", documentAllocator.Size(), schemaAllocator.Size(), validatorAllocator.Size());
@@ -1220,8 +2283,8 @@ TEST(SchemaValidator, TestSuite) {
jsonAllocator.Clear();
}
printf("%d / %d passed (%2d%%)\n", passCount, testCount, passCount * 100 / testCount);
- // if (passCount != testCount)
- // ADD_FAILURE();
+ if (passCount != testCount)
+ ADD_FAILURE();
}
TEST(SchemaValidatingReader, Simple) {
@@ -1252,9 +2315,20 @@ TEST(SchemaValidatingReader, Invalid) {
EXPECT_FALSE(reader.IsValid());
EXPECT_EQ(kParseErrorTermination, reader.GetParseResult().Code());
EXPECT_STREQ("maxLength", reader.GetInvalidSchemaKeyword());
+ EXPECT_TRUE(reader.GetInvalidSchemaCode() == kValidateErrorMaxLength);
EXPECT_TRUE(reader.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
EXPECT_TRUE(reader.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
EXPECT_TRUE(d.IsNull());
+ Document e;
+ e.Parse(
+ "{ \"maxLength\": {"
+ " \"errorCode\": 6,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 3, \"actual\": \"ABCD\""
+ "}}");
+ if (e != reader.GetError()) {
+ ADD_FAILURE();
+ }
}
TEST(SchemaValidatingWriter, Simple) {
@@ -1279,6 +2353,21 @@ TEST(SchemaValidatingWriter, Simple) {
EXPECT_FALSE(validator.IsValid());
EXPECT_TRUE(validator.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
EXPECT_TRUE(validator.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
+ EXPECT_TRUE(validator.GetInvalidSchemaCode() == kValidateErrorMaxLength);
+ Document e;
+ e.Parse(
+ "{ \"maxLength\": {"
+" \"errorCode\": 6,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": 3, \"actual\": \"ABCD\""
+ "}}");
+ EXPECT_EQ(e, validator.GetError());
+}
+
+TEST(Schema, Issue848) {
+ rapidjson::Document d;
+ rapidjson::SchemaDocument s(d);
+ rapidjson::GenericSchemaValidator<rapidjson::SchemaDocument, rapidjson::Document> v(s);
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
@@ -1294,7 +2383,12 @@ TEST(Schema, Issue552) {
SchemaDocument s = ReturnSchemaDocument();
VALIDATE(s, "42", true);
VALIDATE(s, "\"Life, the universe, and everything\"", true);
- INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "");
+ INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\", \"number\"], \"actual\": \"array\""
+ "}}");
}
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
@@ -1305,9 +2399,1177 @@ TEST(SchemaValidator, Issue608) {
SchemaDocument s(sd);
VALIDATE(s, "{\"a\" : null, \"b\": null}", true);
- INVALIDATE(s, "{\"a\" : null, \"a\" : null}", "", "required", "");
+ INVALIDATE(s, "{\"a\" : null, \"a\" : null}", "", "required", "",
+ "{ \"required\": {"
+ " \"errorCode\": 15,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"missing\": [\"b\"]"
+ "}}");
}
-#ifdef __clang__
+// Fail to resolve $ref in allOf causes crash in SchemaValidator::StartObject()
+TEST(SchemaValidator, Issue728_AllOfRef) {
+ Document sd;
+ sd.Parse("{\"allOf\": [{\"$ref\": \"#/abc\"}]}");
+ SchemaDocument s(sd);
+ SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/allOf/0\",\"value\":\"#/abc\"}}");
+
+ VALIDATE_(s, "{\"key1\": \"abc\", \"key2\": \"def\"}", true, false);
+}
+
+TEST(SchemaValidator, Issue1017_allOfHandler) {
+ Document sd;
+ sd.Parse("{\"allOf\": [{\"type\": \"object\",\"properties\": {\"cyanArray2\": {\"type\": \"array\",\"items\": { \"type\": \"string\" }}}},{\"type\": \"object\",\"properties\": {\"blackArray\": {\"type\": \"array\",\"items\": { \"type\": \"string\" }}},\"required\": [ \"blackArray\" ]}]}");
+ SchemaDocument s(sd);
+ StringBuffer sb;
+ Writer<StringBuffer> writer(sb);
+ GenericSchemaValidator<SchemaDocument, Writer<StringBuffer> > validator(s, writer);
+ EXPECT_TRUE(validator.StartObject());
+ EXPECT_TRUE(validator.Key("cyanArray2", 10, false));
+ EXPECT_TRUE(validator.StartArray());
+ EXPECT_TRUE(validator.EndArray(0));
+ EXPECT_TRUE(validator.Key("blackArray", 10, false));
+ EXPECT_TRUE(validator.StartArray());
+ EXPECT_TRUE(validator.EndArray(0));
+ EXPECT_TRUE(validator.EndObject(0));
+ EXPECT_TRUE(validator.IsValid());
+ EXPECT_STREQ("{\"cyanArray2\":[],\"blackArray\":[]}", sb.GetString());
+}
+
+TEST(SchemaValidator, Ref_remote) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"$ref\": \"http://localhost:1234/subSchemas.json#/integer\"}");
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "null", "/integer", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\","
+ " \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// Merge with id where $ref is full URI
+TEST(SchemaValidator, Ref_remote_change_resolution_scope_uri) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"id\": \"http://ignore/blah#/ref\", \"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"http://localhost:1234/subSchemas.json#/integer\"}}}");
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt\": null}", "/integer", "type", "/myInt",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt\","
+ " \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// Merge with id where $ref is a relative path
+TEST(SchemaValidator, Ref_remote_change_resolution_scope_relative_path) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"id\": \"http://localhost:1234/\", \"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"subSchemas.json#/integer\"}}}");
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt\": null}", "/integer", "type", "/myInt",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt\","
+ " \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// Merge with id where $ref is an absolute path
+TEST(SchemaValidator, Ref_remote_change_resolution_scope_absolute_path) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"id\": \"http://localhost:1234/xxxx\", \"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#/integer\"}}}");
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt\": null}", "/integer", "type", "/myInt",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt\","
+ " \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// Merge with id where $ref is an absolute path, and the document has a base URI
+TEST(SchemaValidator, Ref_remote_change_resolution_scope_absolute_path_document) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#/integer\"}}}");
+ SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt\": null}", "/integer", "type", "/myInt",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt\","
+ " \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// $ref is a non-JSON pointer fragment and there a matching id
+TEST(SchemaValidator, Ref_internal_id_1) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"#myId\"}, \"myStr\": {\"type\": \"string\", \"id\": \"#myStrId\"}, \"myInt2\": {\"type\": \"integer\", \"id\": \"#myId\"}}}");
+ SchemaDocumentType s(sd);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt1\": null}", "/properties/myInt2", "type", "/myInt1",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt1\","
+ " \"schemaRef\": \"#/properties/myInt2\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// $ref is a non-JSON pointer fragment and there are two matching ids so we take the first
+TEST(SchemaValidator, Ref_internal_id_2) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"#myId\"}, \"myInt2\": {\"type\": \"integer\", \"id\": \"#myId\"}, \"myStr\": {\"type\": \"string\", \"id\": \"#myId\"}}}");
+ SchemaDocumentType s(sd);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt1\": null}", "/properties/myInt2", "type", "/myInt1",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt1\","
+ " \"schemaRef\": \"#/properties/myInt2\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// $ref is a non-JSON pointer fragment and there is a matching id within array
+TEST(SchemaValidator, Ref_internal_id_in_array) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"#myId\"}, \"myInt2\": {\"anyOf\": [{\"type\": \"string\", \"id\": \"#myStrId\"}, {\"type\": \"integer\", \"id\": \"#myId\"}]}}}");
+ SchemaDocumentType s(sd);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"myInt1\": null}", "/properties/myInt2/anyOf/1", "type", "/myInt1",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt1\","
+ " \"schemaRef\": \"#/properties/myInt2/anyOf/1\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// $ref is a non-JSON pointer fragment and there is a matching id, and the schema is embedded in the document
+TEST(SchemaValidator, Ref_internal_id_and_schema_pointer) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{ \"schema\": {\"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"#myId\"}, \"myInt2\": {\"anyOf\": [{\"type\": \"integer\", \"id\": \"#myId\"}]}}}}");
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ SchemaDocumentType s(sd, 0, 0, 0, 0, PointerType("/schema"));
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ INVALIDATE_(s, "{\"myInt1\": null}", "/schema/properties/myInt2/anyOf/0", "type", "/myInt1",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#/myInt1\","
+ " \"schemaRef\": \"#/schema/properties/myInt2/anyOf/0\","
+ " \"expected\": [\"integer\"], \"actual\": \"null\""
+ "}}",
+ kValidateDefaultFlags, SchemaValidatorType, PointerType);
+}
+
+// Test that $refs are correctly resolved when intermediate multiple ids are present
+// Includes $ref to a part of the document with a different in-scope id, which also contains $ref..
+TEST(SchemaValidator, Ref_internal_multiple_ids) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ //RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/idandref.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocumentType s(sd, "http://xyz", 10/*, &provider*/);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"PA1\": \"s\", \"PA2\": \"t\", \"PA3\": \"r\", \"PX1\": 1, \"PX2Y\": 2, \"PX3Z\": 3, \"PX4\": 4, \"PX5\": 5, \"PX6\": 6, \"PX7W\": 7, \"PX8N\": { \"NX\": 8}}", "#", "errors", "#",
+ "{ \"type\": ["
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PA1\", \"schemaRef\": \"http://xyz#/definitions/A\", \"expected\": [\"integer\"], \"actual\": \"string\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PA2\", \"schemaRef\": \"http://xyz#/definitions/A\", \"expected\": [\"integer\"], \"actual\": \"string\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PA3\", \"schemaRef\": \"http://xyz#/definitions/A\", \"expected\": [\"integer\"], \"actual\": \"string\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX1\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX2Y\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX3Z\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX4\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX5\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX6\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX7W\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"},"
+ " {\"errorCode\": 20, \"instanceRef\": \"#/PX8N/NX\", \"schemaRef\": \"http://xyz#/definitions/B/definitions/X\", \"expected\": [\"boolean\"], \"actual\": \"integer\"}"
+ "]}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidatorType, PointerType);
+ CrtAllocator::Free(schema);
+}
+
+TEST(SchemaValidator, Ref_remote_issue1210) {
+ class SchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
+ SchemaDocument** collection;
+
+ // Dummy private copy constructor & assignment operator.
+ // Function bodies added so that they compile in MSVC 2019.
+ SchemaDocumentProvider(const SchemaDocumentProvider&) : collection(NULL) {
+ }
+ SchemaDocumentProvider& operator=(const SchemaDocumentProvider&) {
+ return *this;
+ }
+
+ public:
+ SchemaDocumentProvider(SchemaDocument** collection) : collection(collection) { }
+ virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) {
+ int i = 0;
+ while (collection[i] && SchemaDocument::GValue(uri, length) != collection[i]->GetURI()) ++i;
+ return collection[i];
+ }
+ };
+ SchemaDocument* collection[] = { 0, 0, 0 };
+ SchemaDocumentProvider provider(collection);
+
+ Document x, y, z;
+ x.Parse("{\"properties\":{\"country\":{\"$ref\":\"y.json#/definitions/country_remote\"}},\"type\":\"object\"}");
+ y.Parse("{\"definitions\":{\"country_remote\":{\"$ref\":\"z.json#/definitions/country_list\"}}}");
+ z.Parse("{\"definitions\":{\"country_list\":{\"enum\":[\"US\"]}}}");
+
+ SchemaDocument sz(z, "z.json", 6, &provider);
+ collection[0] = &sz;
+ SchemaDocument sy(y, "y.json", 6, &provider);
+ collection[1] = &sy;
+ SchemaDocument sx(x, "x.json", 6, &provider);
+
+ VALIDATE(sx, "{\"country\":\"UK\"}", false);
+ VALIDATE(sx, "{\"country\":\"US\"}", true);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, all errors are reported.
+TEST(SchemaValidator, ContinueOnErrors) {
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ VALIDATE(s, "{\"version\": 1.0, \"address\": {\"number\": 24, \"street1\": \"The Woodlands\", \"street3\": \"Ham\", \"city\": \"Romsey\", \"area\": \"Kent\", \"country\": \"UK\", \"postcode\": \"SO51 0GP\"}, \"phones\": [\"0111-222333\", \"0777-666888\"], \"names\": [\"Fred\", \"Bloggs\"]}", true);
+ INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false, \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"Narnia\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#",
+ "{ \"multipleOf\": {"
+ " \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01"
+ " },"
+ " \"minimum\": {"
+ " \"errorCode\": 5, \"instanceRef\": \"#/address/number\", \"schemaRef\": \"#/definitions/positiveInt_type\", \"expected\": 0, \"actual\": 0, \"exclusiveMinimum\": true"
+ " },"
+ " \"type\": ["
+ " {\"expected\": [\"null\", \"string\"], \"actual\": \"boolean\", \"errorCode\": 20, \"instanceRef\": \"#/address/street2\", \"schemaRef\": \"#/definitions/address_type/properties/street2\"},"
+ " {\"expected\": [\"string\"], \"actual\": \"integer\", \"errorCode\": 20, \"instanceRef\": \"#/extra/S_xxx\", \"schemaRef\": \"#/properties/extra/patternProperties/%5ES_\"}"
+ " ],"
+ " \"maxLength\": {"
+ " \"actual\": \"RomseyTownFC\", \"expected\": 10, \"errorCode\": 6, \"instanceRef\": \"#/address/city\", \"schemaRef\": \"#/definitions/address_type/properties/city\""
+ " },"
+ " \"anyOf\": {"
+ " \"errors\":["
+ " {\"pattern\": {\"actual\": \"999ABC\", \"errorCode\": 8, \"instanceRef\": \"#/address/postcode\", \"schemaRef\": \"#/definitions/address_type/properties/postcode/anyOf/0\"}},"
+ " {\"pattern\": {\"actual\": \"999ABC\", \"errorCode\": 8, \"instanceRef\": \"#/address/postcode\", \"schemaRef\": \"#/definitions/address_type/properties/postcode/anyOf/1\"}}"
+ " ],"
+ " \"errorCode\": 24, \"instanceRef\": \"#/address/postcode\", \"schemaRef\": \"#/definitions/address_type/properties/postcode\""
+ " },"
+ " \"allOf\": {"
+ " \"errors\":["
+ " {\"enum\":{\"errorCode\":19,\"instanceRef\":\"#/address/country\",\"schemaRef\":\"#/definitions/country_type\"}}"
+ " ],"
+ " \"errorCode\":23,\"instanceRef\":\"#/address/country\",\"schemaRef\":\"#/definitions/address_type/properties/country\""
+ " },"
+ " \"minItems\": {"
+ " \"actual\": 0, \"expected\": 1, \"errorCode\": 10, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\""
+ " },"
+ " \"additionalProperties\": {"
+ " \"disallowed\": \"planet\", \"errorCode\": 16, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ " },"
+ " \"required\": {"
+ " \"missing\": [\"street1\"], \"errorCode\": 15, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\""
+ " },"
+ " \"oneOf\": {"
+ " \"matches\": [0, 1], \"errorCode\": 22, \"instanceRef\": \"#/address/area\", \"schemaRef\": \"#/definitions/address_type/properties/area\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ INVALIDATE_(s, "{\"address\": {\"number\": 200, \"street1\": {}, \"street3\": null, \"city\": \"Rom\", \"area\": \"Dorset\", \"postcode\": \"SO51 0GP\"}, \"phones\": [\"0111-222333\", \"0777-666888\", \"0777-666888\"], \"names\": [\"Fred\", \"S\", \"M\", \"Bloggs\"]}", "#", "errors", "#",
+ "{ \"maximum\": {"
+ " \"errorCode\": 3, \"instanceRef\": \"#/address/number\", \"schemaRef\": \"#/definitions/positiveInt_type\", \"expected\": 100, \"actual\": 200, \"exclusiveMaximum\": true"
+ " },"
+ " \"type\": {"
+ " \"expected\": [\"string\"], \"actual\": \"object\", \"errorCode\": 20, \"instanceRef\": \"#/address/street1\", \"schemaRef\": \"#/definitions/address_type/properties/street1\""
+ " },"
+ " \"not\": {"
+ " \"errorCode\": 25, \"instanceRef\": \"#/address/street3\", \"schemaRef\": \"#/definitions/address_type/properties/street3\""
+ " },"
+ " \"minLength\": {"
+ " \"actual\": \"Rom\", \"expected\": 4, \"errorCode\": 7, \"instanceRef\": \"#/address/city\", \"schemaRef\": \"#/definitions/address_type/properties/city\""
+ " },"
+ " \"maxItems\": {"
+ " \"actual\": 3, \"expected\": 2, \"errorCode\": 9, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\""
+ " },"
+ " \"uniqueItems\": {"
+ " \"duplicates\": [1, 2], \"errorCode\": 11, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\""
+ " },"
+ " \"minProperties\": {\"actual\": 6, \"expected\": 7, \"errorCode\": 14, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\""
+ " },"
+ " \"additionalItems\": ["
+ " {\"disallowed\": 2, \"errorCode\": 12, \"instanceRef\": \"#/names\", \"schemaRef\": \"#/properties/names\"},"
+ " {\"disallowed\": 3, \"errorCode\": 12, \"instanceRef\": \"#/names\", \"schemaRef\": \"#/properties/names\"}"
+ " ],"
+ " \"dependencies\": {"
+ " \"errors\": {"
+ " \"address\": {\"required\": {\"missing\": [\"version\"], \"errorCode\": 15, \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/address\"}},"
+ " \"names\": {\"required\": {\"missing\": [\"version\"], \"errorCode\": 15, \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/names\"}}"
+ " },"
+ " \"errorCode\": 18, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ " },"
+ " \"oneOf\": {"
+ " \"errors\": ["
+ " {\"enum\": {\"errorCode\": 19, \"instanceRef\": \"#/address/area\", \"schemaRef\": \"#/definitions/county_type\"}},"
+ " {\"enum\": {\"errorCode\": 19, \"instanceRef\": \"#/address/area\", \"schemaRef\": \"#/definitions/province_type\"}}"
+ " ],"
+ " \"errorCode\": 21, \"instanceRef\": \"#/address/area\", \"schemaRef\": \"#/definitions/address_type/properties/area\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, it is not propagated to oneOf sub-validator so we only get the first error.
+TEST(SchemaValidator, ContinueOnErrors_OneOf) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/oneOf_address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false, \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"BC\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#",
+ "{ \"oneOf\": {"
+ " \"errors\": [{"
+ " \"multipleOf\": {"
+ " \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"http://localhost:1234/address.json#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01"
+ " }"
+ " }],"
+ " \"errorCode\": 21, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidatorType, PointerType);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, it is not propagated to allOf sub-validator so we only get the first error.
+TEST(SchemaValidator, ContinueOnErrors_AllOf) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/allOf_address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false, \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"BC\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#",
+ "{ \"allOf\": {"
+ " \"errors\": [{"
+ " \"multipleOf\": {"
+ " \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"http://localhost:1234/address.json#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01"
+ " }"
+ " }],"
+ " \"errorCode\": 23, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidatorType, PointerType);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, it is not propagated to anyOf sub-validator so we only get the first error.
+TEST(SchemaValidator, ContinueOnErrors_AnyOf) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/anyOf_address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocumentType s(sd, 0, 0, &provider);
+ typedef GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > SchemaValidatorType;
+ typedef GenericPointer<Value, MemoryPoolAllocator<> > PointerType;
+ INVALIDATE_(s, "{\"version\": 1.01, \"address\": {\"number\": 0, \"street2\": false, \"street3\": \"Ham\", \"city\": \"RomseyTownFC\", \"area\": \"BC\", \"country\": \"USA\", \"postcode\": \"999ABC\"}, \"phones\": [], \"planet\": \"Earth\", \"extra\": {\"S_xxx\": 123}}", "#", "errors", "#",
+ "{ \"anyOf\": {"
+ " \"errors\": [{"
+ " \"multipleOf\": {"
+ " \"errorCode\": 1, \"instanceRef\": \"#/version\", \"schemaRef\": \"http://localhost:1234/address.json#/definitions/decimal_type\", \"expected\": 1.0, \"actual\": 1.01"
+ " }"
+ " }],"
+ " \"errorCode\": 24, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidatorType, PointerType);
+
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, arrays with uniqueItems:true are correctly processed when an item is invalid.
+// This tests that we don't blow up if a hasher does not get created.
+TEST(SchemaValidator, ContinueOnErrors_UniqueItems) {
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ VALIDATE(s, "{\"phones\":[\"12-34\",\"56-78\"]}", true);
+ INVALIDATE_(s, "{\"phones\":[\"12-34\",\"12-34\"]}", "#", "errors", "#",
+ "{\"uniqueItems\": {\"duplicates\": [0,1], \"errorCode\": 11, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ INVALIDATE_(s, "{\"phones\":[\"ab-34\",\"cd-78\"]}", "#", "errors", "#",
+ "{\"pattern\": ["
+ " {\"actual\": \"ab-34\", \"errorCode\": 8, \"instanceRef\": \"#/phones/0\", \"schemaRef\": \"#/definitions/phone_type\"},"
+ " {\"actual\": \"cd-78\", \"errorCode\": 8, \"instanceRef\": \"#/phones/1\", \"schemaRef\": \"#/definitions/phone_type\"}"
+ "]}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, an enum field is correctly processed when it has an invalid value.
+// This tests that we don't blow up if a hasher does not get created.
+TEST(SchemaValidator, ContinueOnErrors_Enum) {
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ VALIDATE(s, "{\"gender\":\"M\"}", true);
+ INVALIDATE_(s, "{\"gender\":\"X\"}", "#", "errors", "#",
+ "{\"enum\": {\"errorCode\": 19, \"instanceRef\": \"#/gender\", \"schemaRef\": \"#/properties/gender\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ INVALIDATE_(s, "{\"gender\":1}", "#", "errors", "#",
+ "{\"type\": {\"expected\":[\"string\"], \"actual\": \"integer\", \"errorCode\": 20, \"instanceRef\": \"#/gender\", \"schemaRef\": \"#/properties/gender\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, an array appearing for an object property is handled
+// This tests that we don't blow up when there is a type mismatch.
+TEST(SchemaValidator, ContinueOnErrors_RogueArray) {
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ INVALIDATE_(s, "{\"address\":[{\"number\": 0}]}", "#", "errors", "#",
+ "{\"type\": {\"expected\":[\"object\"], \"actual\": \"array\", \"errorCode\": 20, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\"},"
+ " \"dependencies\": {"
+ " \"errors\": {"
+ " \"address\": {\"required\": {\"missing\": [\"version\"], \"errorCode\": 15, \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/address\"}}"
+ " },\"errorCode\": 18, \"instanceRef\": \"#\", \"schemaRef\": \"#\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, an object appearing for an array property is handled
+// This tests that we don't blow up when there is a type mismatch.
+TEST(SchemaValidator, ContinueOnErrors_RogueObject) {
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ INVALIDATE_(s, "{\"phones\":{\"number\": 0}}", "#", "errors", "#",
+ "{\"type\": {\"expected\":[\"array\"], \"actual\": \"object\", \"errorCode\": 20, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, a string appearing for an array or object property is handled
+// This tests that we don't blow up when there is a type mismatch.
+TEST(SchemaValidator, ContinueOnErrors_RogueString) {
+ CrtAllocator allocator;
+ char* schema = ReadFile("unittestschema/address.json", allocator);
+ Document sd;
+ sd.Parse(schema);
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ INVALIDATE_(s, "{\"address\":\"number\"}", "#", "errors", "#",
+ "{\"type\": {\"expected\":[\"object\"], \"actual\": \"string\", \"errorCode\": 20, \"instanceRef\": \"#/address\", \"schemaRef\": \"#/definitions/address_type\"},"
+ " \"dependencies\": {"
+ " \"errors\": {"
+ " \"address\": {\"required\": {\"missing\": [\"version\"], \"errorCode\": 15, \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/address\"}}"
+ " },\"errorCode\": 18, \"instanceRef\": \"#\", \"schemaRef\": \"#\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ INVALIDATE_(s, "{\"phones\":\"number\"}", "#", "errors", "#",
+ "{\"type\": {\"expected\":[\"array\"], \"actual\": \"string\", \"errorCode\": 20, \"instanceRef\": \"#/phones\", \"schemaRef\": \"#/properties/phones\"}}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ CrtAllocator::Free(schema);
+}
+
+// Test that when kValidateContinueOnErrorFlag is set, an incorrect simple type with a sub-schema is handled correctly.
+// This tests that we don't blow up when there is a type mismatch but there is a sub-schema present
+TEST(SchemaValidator, ContinueOnErrors_BadSimpleType) {
+ Document sd;
+ sd.Parse("{\"type\":\"string\", \"anyOf\":[{\"maxLength\":2}]}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ VALIDATE(s, "\"AB\"", true);
+ INVALIDATE_(s, "\"ABC\"", "#", "errors", "#",
+ "{ \"anyOf\": {"
+ " \"errors\": [{"
+ " \"maxLength\": {"
+ " \"errorCode\": 6, \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/0\", \"expected\": 2, \"actual\": \"ABC\""
+ " }"
+ " }],"
+ " \"errorCode\": 24, \"instanceRef\": \"#\", \"schemaRef\": \"#\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+ // Invalid type
+ INVALIDATE_(s, "333", "#", "errors", "#",
+ "{ \"type\": {"
+ " \"errorCode\": 20, \"instanceRef\": \"#\", \"schemaRef\": \"#\", \"expected\": [\"string\"], \"actual\": \"integer\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateContinueOnErrorFlag, SchemaValidator, Pointer);
+}
+
+
+TEST(SchemaValidator, UnknownValidationError) {
+ ASSERT_TRUE(SchemaValidator::SchemaType::GetValidateErrorKeyword(kValidateErrors).GetString() == std::string("null"));
+}
+
+// The first occurrence of a duplicate keyword is taken
+TEST(SchemaValidator, DuplicateKeyword) {
+ Document sd;
+ sd.Parse("{ \"title\": \"test\",\"type\": \"number\", \"type\": \"string\" }");
+ EXPECT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ VALIDATE(s, "42", true);
+ INVALIDATE(s, "\"Life, the universe, and everything\"", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"number\"], \"actual\": \"string\""
+ "}}");
+}
+
+
+// SchemaDocument tests
+
+// Specification (schema draft, open api version)
+TEST(SchemaValidator, Schema_SupportedNotObject) {
+ Document sd;
+ sd.Parse("true");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedNoSpec) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedNoSpecStatic) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ Specification spec = SchemaDocumentType::GetSpecification(sd);
+ ASSERT_FALSE(spec.IsSupported());
+ ASSERT_TRUE(spec.draft == kDraftNone);
+ ASSERT_TRUE(spec.oapi == kVersionNone);
+}
+
+TEST(SchemaValidator, Schema_SupportedDraft5Static) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-05/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ Specification spec = SchemaDocumentType::GetSpecification(sd);
+ ASSERT_TRUE(spec.IsSupported());
+ ASSERT_TRUE(spec.draft == kDraft05);
+ ASSERT_TRUE(spec.oapi == kVersionNone);
+}
+
+TEST(SchemaValidator, Schema_SupportedDraft4) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-04/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedDraft4NoFrag) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-04/schema\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedDraft5) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-05/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft05);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedDraft5NoFrag) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-05/schema\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft05);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_IgnoreDraftEmbedded) {
+ Document sd;
+ sd.Parse("{\"root\": {\"$schema\":\"http://json-schema.org/draft-05/schema#\", \"type\": \"integer\"}}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, SchemaDocument::PointerType("/root"));
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedDraftOverride) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kDraft04));
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_UnknownDraftOverride) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kDraftUnknown));
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraftUnknown);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedDraftOverride) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kDraft03));
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft03);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnknownDraft) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-xxx/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraftUnknown);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnknownDraftNotString) {
+ Document sd;
+ sd.Parse("{\"$schema\": 4, \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraftUnknown);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedDraft3) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-03/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft03);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedDraft6) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-06/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft06);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedDraft7) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"http://json-schema.org/draft-07/schema#\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft07);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedDraft2019_09) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"https://json-schema.org/draft/2019-09/schema\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft2019_09);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedDraft2020_12) {
+ Document sd;
+ sd.Parse("{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\", \"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft2020_12);
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionNone);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_SupportedVersion20Static) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"swagger\":\"2.0\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ Specification spec = SchemaDocumentType::GetSpecification(sd);
+ ASSERT_TRUE(spec.IsSupported());
+ ASSERT_TRUE(spec.draft == kDraft04);
+ ASSERT_TRUE(spec.oapi == kVersion20);
+}
+
+TEST(SchemaValidator, Schema_SupportedVersion20) {
+ Document sd;
+ sd.Parse("{\"swagger\":\"2.0\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersion20);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedVersion30x) {
+ Document sd;
+ sd.Parse("{\"openapi\":\"3.0.0\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersion30);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft05);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_SupportedVersionOverride) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersion20));
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersion20);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ EXPECT_TRUE(s.GetError().ObjectEmpty());
+}
+
+TEST(SchemaValidator, Schema_UnknownVersionOverride) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersionUnknown));
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionUnknown);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedVersionOverride) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersion31));
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersion31);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft2020_12);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnknownVersion) {
+ Document sd;
+ sd.Parse("{\"openapi\":\"1.0\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionUnknown);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnknownVersionShort) {
+ Document sd;
+ sd.Parse("{\"openapi\":\"3.0.\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionUnknown);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnknownVersionNotString) {
+ Document sd;
+ sd.Parse("{\"swagger\": 2}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersionUnknown);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft04);
+ SCHEMAERROR(s, "{\"SpecUnknown\":{\"errorCode\":10,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_UnsupportedVersion31) {
+ Document sd;
+ sd.Parse("{\"openapi\":\"3.1.0\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_FALSE(s.IsSupportedSpecification());
+ ASSERT_TRUE(s.GetSpecification().oapi == kVersion31);
+ ASSERT_TRUE(s.GetSpecification().draft == kDraft2020_12);
+ SCHEMAERROR(s, "{\"SpecUnsupported\":{\"errorCode\":11,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_DraftAndVersion) {
+ Document sd;
+ sd.Parse("{\"swagger\": \"2.0\", \"$schema\": \"http://json-schema.org/draft-04/schema#\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ ASSERT_TRUE(s.IsSupportedSpecification());
+ SCHEMAERROR(s, "{\"SpecIllegal\":{\"errorCode\":12,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, Schema_StartUnknown) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd, 0, 0, 0, 0, SchemaDocument::PointerType("/nowhere"));
+ SCHEMAERROR(s, "{\"StartUnknown\":{\"errorCode\":1,\"instanceRef\":\"#\", \"value\":\"#/nowhere\"}}");
+}
+
+TEST(SchemaValidator, Schema_MultipleErrors) {
+ Document sd;
+ sd.Parse("{\"swagger\": \"foo\", \"$schema\": \"bar\"}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s(sd);
+ SCHEMAERROR(s, "{ \"SpecUnknown\": {\"errorCode\":10,\"instanceRef\":\"#\"},"
+ " \"SpecIllegal\": {\"errorCode\":12,\"instanceRef\":\"#\"}"
+ "}");
+}
+
+// $ref is a non-JSON pointer fragment - not allowed when OpenAPI
+TEST(SchemaValidator, Schema_RefPlainNameOpenApi) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"swagger\": \"2.0\", \"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"#myId\"}, \"myStr\": {\"type\": \"string\", \"id\": \"#myStrId\"}, \"myInt2\": {\"type\": \"integer\", \"id\": \"#myId\"}}}");
+ SchemaDocumentType s(sd);
+ SCHEMAERROR(s, "{\"RefPlainName\":{\"errorCode\":2,\"instanceRef\":\"#/properties/myInt1\",\"value\":\"#myId\"}}");
+}
+
+// $ref is a non-JSON pointer fragment - not allowed when remote document
+TEST(SchemaValidator, Schema_RefPlainNameRemote) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#plainname\"}}}");
+ SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
+ SCHEMAERROR(s, "{\"RefPlainName\":{\"errorCode\":2,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#plainname\"}}");
+}
+
+// $ref is an empty string
+TEST(SchemaValidator, Schema_RefEmptyString) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt1\": {\"$ref\": \"\"}}}");
+ SchemaDocumentType s(sd);
+ SCHEMAERROR(s, "{\"RefInvalid\":{\"errorCode\":3,\"instanceRef\":\"#/properties/myInt1\"}}");
+}
+
+// $ref is remote but no provider
+TEST(SchemaValidator, Schema_RefNoRemoteProvider) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#plainname\"}}}");
+ SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, 0);
+ SCHEMAERROR(s, "{\"RefNoRemoteProvider\":{\"errorCode\":7,\"instanceRef\":\"#/properties/myInt\"}}");
+}
+
+// $ref is remote but no schema returned
+TEST(SchemaValidator, Schema_RefNoRemoteSchema) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/will-not-resolve.json\"}}}");
+ SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
+ SCHEMAERROR(s, "{\"RefNoRemoteSchema\":{\"errorCode\":8,\"instanceRef\":\"#/properties/myInt\",\"value\":\"http://localhost:1234/will-not-resolve.json\"}}");
+}
+
+// $ref pointer is invalid
+TEST(SchemaValidator, Schema_RefPointerInvalid) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#/&&&&&\"}}}");
+ SchemaDocumentType s(sd);
+ SCHEMAERROR(s, "{\"RefPointerInvalid\":{\"errorCode\":4,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#/&&&&&\",\"offset\":2}}");
+}
+
+// $ref is remote and pointer is invalid
+TEST(SchemaValidator, Schema_RefPointerInvalidRemote) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#/abc&&&&&\"}}}");
+ SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
+ SCHEMAERROR(s, "{\"RefPointerInvalid\":{\"errorCode\":4,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#/abc&&&&&\",\"offset\":5}}");
+}
+
+// $ref is unknown non-pointer
+TEST(SchemaValidator, Schema_RefUnknownPlainName) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#plainname\"}}}");
+ SchemaDocumentType s(sd);
+ SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#plainname\"}}");
+}
+
+/// $ref is unknown pointer
+TEST(SchemaValidator, Schema_RefUnknownPointer) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"#/a/b\"}}}");
+ SchemaDocumentType s(sd);
+ SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/properties/myInt\",\"value\":\"#/a/b\"}}");
+}
+
+// $ref is remote and unknown pointer
+TEST(SchemaValidator, Schema_RefUnknownPointerRemote) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {\"myInt\": {\"$ref\": \"/subSchemas.json#/a/b\"}}}");
+ SchemaDocumentType s(sd, "http://localhost:1234/xxxx", 26, &provider);
+ SCHEMAERROR(s, "{\"RefUnknown\":{\"errorCode\":5,\"instanceRef\":\"#/properties/myInt\",\"value\":\"http://localhost:1234/subSchemas.json#/a/b\"}}");
+}
+
+// $ref is cyclical
+TEST(SchemaValidator, Schema_RefCyclical) {
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ Document sd;
+ sd.Parse("{\"type\": \"object\", \"properties\": {"
+ " \"cyclic_source\": {"
+ " \"$ref\": \"#/properties/cyclic_target\""
+ " },"
+ " \"cyclic_target\": {"
+ " \"$ref\": \"#/properties/cyclic_source\""
+ " }"
+ "}}");
+ SchemaDocumentType s(sd);
+ SCHEMAERROR(s, "{\"RefCyclical\":{\"errorCode\":6,\"instanceRef\":\"#/properties/cyclic_target\",\"value\":\"#/properties/cyclic_source\"}}");
+}
+
+TEST(SchemaValidator, Schema_ReadOnlyAndWriteOnly) {
+ Document sd;
+ sd.Parse("{\"type\": \"integer\", \"readOnly\": true, \"writeOnly\": true}");
+ ASSERT_FALSE(sd.HasParseError());
+ SchemaDocument s1(sd, 0, 0, 0, 0, 0, Specification(kDraft04));
+ EXPECT_TRUE(s1.GetError().ObjectEmpty());
+ SchemaDocument s2(sd, 0, 0, 0, 0, 0, Specification(kVersion30));
+ SCHEMAERROR(s2, "{\"ReadOnlyAndWriteOnly\":{\"errorCode\":13,\"instanceRef\":\"#\"}}");
+}
+
+TEST(SchemaValidator, ReadOnlyWhenWriting) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\":\"object\","
+ " \"properties\": {"
+ " \"rprop\" : {"
+ " \"type\": \"string\","
+ " \"readOnly\": true"
+ " }"
+ " }"
+ "}");
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersion20));
+ VALIDATE(s, "{ \"rprop\": \"hello\" }", true);
+ INVALIDATE_(s, "{ \"rprop\": \"hello\" }", "/properties/rprop", "readOnly", "/rprop",
+ "{ \"readOnly\": {"
+ " \"errorCode\": 26, \"instanceRef\": \"#/rprop\", \"schemaRef\": \"#/properties/rprop\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateWriteFlag, SchemaValidator, Pointer);
+}
+
+TEST(SchemaValidator, WriteOnlyWhenReading) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\":\"object\","
+ " \"properties\": {"
+ " \"wprop\" : {"
+ " \"type\": \"boolean\","
+ " \"writeOnly\": true"
+ " }"
+ " }"
+ "}");
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, Specification(kVersion30));
+ VALIDATE(s, "{ \"wprop\": true }", true);
+ INVALIDATE_(s, "{ \"wprop\": true }", "/properties/wprop", "writeOnly", "/wprop",
+ "{ \"writeOnly\": {"
+ " \"errorCode\": 27, \"instanceRef\": \"#/wprop\", \"schemaRef\": \"#/properties/wprop\""
+ " }"
+ "}",
+ kValidateDefaultFlags | kValidateReadFlag, SchemaValidator, Pointer);
+}
+
+TEST(SchemaValidator, NullableTrue) {
+ Document sd;
+ sd.Parse("{\"type\": \"string\", \"nullable\": true}");
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, kVersion20);
+
+ VALIDATE(s, "\"hello\"", true);
+ INVALIDATE(s, "null", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"null\""
+ "}}");
+ INVALIDATE(s, "false", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"boolean\""
+ "}}");
+
+ SchemaDocument s30(sd, 0, 0, 0, 0, 0, kVersion30);
+
+ VALIDATE(s30, "\"hello\"", true);
+ VALIDATE(s30, "null", true);
+ INVALIDATE(s30, "false", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"null\", \"string\"], \"actual\": \"boolean\""
+ "}}");
+}
+
+TEST(SchemaValidator, NullableFalse) {
+ Document sd;
+ sd.Parse("{\"type\": \"string\", \"nullable\": false}");
+ SchemaDocument s(sd, 0, 0, 0, 0, 0, kVersion20);
+
+ VALIDATE(s, "\"hello\"", true);
+ INVALIDATE(s, "null", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"null\""
+ "}}");
+ INVALIDATE(s, "false", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"boolean\""
+ "}}");
+
+ SchemaDocument s30(sd, 0, 0, 0, 0, 0, kVersion30);
+
+ VALIDATE(s30, "\"hello\"", true);
+ INVALIDATE(s, "null", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"null\""
+ "}}");
+ INVALIDATE(s30, "false", "", "type", "",
+ "{ \"type\": {"
+ " \"errorCode\": 20,"
+ " \"instanceRef\": \"#\", \"schemaRef\": \"#\","
+ " \"expected\": [\"string\"], \"actual\": \"boolean\""
+ "}}");
+}
+
+#if defined(_MSC_VER) || defined(__clang__)
RAPIDJSON_DIAG_POP
#endif
diff --git a/3rdparty/rapidjson/test/unittest/simdtest.cpp b/3rdparty/rapidjson/test/unittest/simdtest.cpp
index b01b559f42b..570b0836436 100644
--- a/3rdparty/rapidjson/test/unittest/simdtest.cpp
+++ b/3rdparty/rapidjson/test/unittest/simdtest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -21,6 +21,8 @@
# define RAPIDJSON_SSE42
#elif defined(__SSE2__)
# define RAPIDJSON_SSE2
+#elif defined(__ARM_NEON)
+# define RAPIDJSON_NEON
#endif
#define RAPIDJSON_NAMESPACE rapidjson_simd
@@ -41,14 +43,18 @@ using namespace rapidjson_simd;
#define SIMD_SUFFIX(name) name##_SSE2
#elif defined(RAPIDJSON_SSE42)
#define SIMD_SUFFIX(name) name##_SSE42
+#elif defined(RAPIDJSON_NEON)
+#define SIMD_SUFFIX(name) name##_NEON
#else
#define SIMD_SUFFIX(name) name
#endif
+#define SIMD_SIZE_ALIGN(n) ((size_t(n) + 15) & ~size_t(15))
+
template <typename StreamType>
void TestSkipWhitespace() {
for (size_t step = 1; step < 32; step++) {
- char buffer[1025];
+ char buffer[SIMD_SIZE_ALIGN(1025)];
for (size_t i = 0; i < 1024; i++)
buffer[i] = " \t\r\n"[i % 4];
for (size_t i = 0; i < 1024; i += step)
@@ -75,7 +81,7 @@ TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) {
TEST(SIMD, SIMD_SUFFIX(SkipWhitespace_EncodedMemoryStream)) {
for (size_t step = 1; step < 32; step++) {
- char buffer[1024];
+ char buffer[SIMD_SIZE_ALIGN(1024)];
for (size_t i = 0; i < 1024; i++)
buffer[i] = " \t\r\n"[i % 4];
for (size_t i = 0; i < 1024; i += step)
@@ -83,14 +89,12 @@ TEST(SIMD, SIMD_SUFFIX(SkipWhitespace_EncodedMemoryStream)) {
MemoryStream ms(buffer, 1024);
EncodedInputStream<UTF8<>, MemoryStream> s(ms);
- size_t i = 0;
for (;;) {
SkipWhitespace(s);
if (s.Peek() == '\0')
break;
//EXPECT_EQ(i, s.Tell());
EXPECT_EQ('X', s.Take());
- i += step;
}
}
}
@@ -105,8 +109,8 @@ struct ScanCopyUnescapedStringHandler : BaseReaderHandler<UTF8<>, ScanCopyUnesca
template <unsigned parseFlags, typename StreamType>
void TestScanCopyUnescapedString() {
- char buffer[1024 + 5 + 32];
- char backup[1024 + 5 + 32];
+ char buffer[SIMD_SIZE_ALIGN(1024u + 5 + 32)];
+ char backup[SIMD_SIZE_ALIGN(1024u + 5 + 32)];
// Test "ABCDABCD...\\"
for (size_t offset = 0; offset < 32; offset++) {
@@ -163,7 +167,7 @@ TEST(SIMD, SIMD_SUFFIX(ScanCopyUnescapedString)) {
}
TEST(SIMD, SIMD_SUFFIX(ScanWriteUnescapedString)) {
- char buffer[2048 + 1 + 32];
+ char buffer[SIMD_SIZE_ALIGN(2048 + 1 + 32)];
for (size_t offset = 0; offset < 32; offset++) {
for (size_t step = 0; step < 1024; step++) {
char* s = buffer + offset;
diff --git a/3rdparty/rapidjson/test/unittest/strfunctest.cpp b/3rdparty/rapidjson/test/unittest/strfunctest.cpp
index cc1bb22f0e9..411269396a0 100644
--- a/3rdparty/rapidjson/test/unittest/strfunctest.cpp
+++ b/3rdparty/rapidjson/test/unittest/strfunctest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
diff --git a/3rdparty/rapidjson/test/unittest/stringbuffertest.cpp b/3rdparty/rapidjson/test/unittest/stringbuffertest.cpp
index ded513cddcf..eaa29e715e1 100644
--- a/3rdparty/rapidjson/test/unittest/stringbuffertest.cpp
+++ b/3rdparty/rapidjson/test/unittest/stringbuffertest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -26,6 +26,7 @@ using namespace rapidjson;
TEST(StringBuffer, InitialSize) {
StringBuffer buffer;
EXPECT_EQ(0u, buffer.GetSize());
+ EXPECT_EQ(0u, buffer.GetLength());
EXPECT_STREQ("", buffer.GetString());
}
@@ -34,14 +35,17 @@ TEST(StringBuffer, Put) {
buffer.Put('A');
EXPECT_EQ(1u, buffer.GetSize());
+ EXPECT_EQ(1u, buffer.GetLength());
EXPECT_STREQ("A", buffer.GetString());
}
TEST(StringBuffer, PutN_Issue672) {
GenericStringBuffer<UTF8<>, MemoryPoolAllocator<> > buffer;
- EXPECT_EQ(0, buffer.GetSize());
+ EXPECT_EQ(0u, buffer.GetSize());
+ EXPECT_EQ(0u, buffer.GetLength());
rapidjson::PutN(buffer, ' ', 1);
- EXPECT_EQ(1, buffer.GetSize());
+ EXPECT_EQ(1u, buffer.GetSize());
+ EXPECT_EQ(1u, buffer.GetLength());
}
TEST(StringBuffer, Clear) {
@@ -52,6 +56,7 @@ TEST(StringBuffer, Clear) {
buffer.Clear();
EXPECT_EQ(0u, buffer.GetSize());
+ EXPECT_EQ(0u, buffer.GetLength());
EXPECT_STREQ("", buffer.GetString());
}
@@ -60,6 +65,7 @@ TEST(StringBuffer, Push) {
buffer.Push(5);
EXPECT_EQ(5u, buffer.GetSize());
+ EXPECT_EQ(5u, buffer.GetLength());
// Causes sudden expansion to make the stack's capacity equal to size
buffer.Push(65536u);
@@ -76,9 +82,19 @@ TEST(StringBuffer, Pop) {
buffer.Pop(3);
EXPECT_EQ(2u, buffer.GetSize());
+ EXPECT_EQ(2u, buffer.GetLength());
EXPECT_STREQ("AB", buffer.GetString());
}
+TEST(StringBuffer, GetLength_Issue744) {
+ GenericStringBuffer<UTF16<wchar_t> > buffer;
+ buffer.Put('A');
+ buffer.Put('B');
+ buffer.Put('C');
+ EXPECT_EQ(3u * sizeof(wchar_t), buffer.GetSize());
+ EXPECT_EQ(3u, buffer.GetLength());
+}
+
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
#if 0 // Many old compiler does not support these. Turn it off temporaily.
@@ -130,18 +146,23 @@ TEST(StringBuffer, MoveConstructor) {
x.Put('D');
EXPECT_EQ(4u, x.GetSize());
+ EXPECT_EQ(4u, x.GetLength());
EXPECT_STREQ("ABCD", x.GetString());
// StringBuffer y(x); // does not compile (!is_copy_constructible)
StringBuffer y(std::move(x));
EXPECT_EQ(0u, x.GetSize());
+ EXPECT_EQ(0u, x.GetLength());
EXPECT_EQ(4u, y.GetSize());
+ EXPECT_EQ(4u, y.GetLength());
EXPECT_STREQ("ABCD", y.GetString());
// StringBuffer z = y; // does not compile (!is_copy_assignable)
StringBuffer z = std::move(y);
EXPECT_EQ(0u, y.GetSize());
+ EXPECT_EQ(0u, y.GetLength());
EXPECT_EQ(4u, z.GetSize());
+ EXPECT_EQ(4u, z.GetLength());
EXPECT_STREQ("ABCD", z.GetString());
}
@@ -153,13 +174,14 @@ TEST(StringBuffer, MoveAssignment) {
x.Put('D');
EXPECT_EQ(4u, x.GetSize());
+ EXPECT_EQ(4u, x.GetLength());
EXPECT_STREQ("ABCD", x.GetString());
StringBuffer y;
// y = x; // does not compile (!is_copy_assignable)
y = std::move(x);
EXPECT_EQ(0u, x.GetSize());
- EXPECT_EQ(4u, y.GetSize());
+ EXPECT_EQ(4u, y.GetLength());
EXPECT_STREQ("ABCD", y.GetString());
}
diff --git a/3rdparty/rapidjson/test/unittest/strtodtest.cpp b/3rdparty/rapidjson/test/unittest/strtodtest.cpp
index cde836c7eb7..66167a4a35c 100644
--- a/3rdparty/rapidjson/test/unittest/strtodtest.cpp
+++ b/3rdparty/rapidjson/test/unittest/strtodtest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -91,7 +91,7 @@ TEST(Strtod, CheckApproximationCase) {
}
// Remove common power of two factor from all three scaled values
- int common_Exp2 = std::min(dS_Exp2, std::min(bS_Exp2, hS_Exp2));
+ int common_Exp2 = (std::min)(dS_Exp2, (std::min)(bS_Exp2, hS_Exp2));
dS_Exp2 -= common_Exp2;
bS_Exp2 -= common_Exp2;
hS_Exp2 -= common_Exp2;
diff --git a/3rdparty/rapidjson/test/unittest/unittest.cpp b/3rdparty/rapidjson/test/unittest/unittest.cpp
index b754563ea2b..879976a782f 100644
--- a/3rdparty/rapidjson/test/unittest/unittest.cpp
+++ b/3rdparty/rapidjson/test/unittest/unittest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
diff --git a/3rdparty/rapidjson/test/unittest/unittest.h b/3rdparty/rapidjson/test/unittest/unittest.h
index e125bf88dc3..0e64d3970b7 100644
--- a/3rdparty/rapidjson/test/unittest/unittest.h
+++ b/3rdparty/rapidjson/test/unittest/unittest.h
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -78,7 +78,7 @@ inline Ch* StrDup(const Ch* str) {
}
inline FILE* TempFile(char *filename) {
-#ifdef _MSC_VER
+#if defined(__WIN32__) || defined(_MSC_VER)
filename = tmpnam(filename);
// For Visual Studio, tmpnam() adds a backslash in front. Remove it.
@@ -117,7 +117,15 @@ public:
#pragma GCC diagnostic pop
#endif
-#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
+// Not using noexcept for testing RAPIDJSON_ASSERT()
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
+
+#ifndef RAPIDJSON_ASSERT
+#define RAPIDJSON_ASSERT(x) (!(x) ? throw AssertException(RAPIDJSON_STRINGIFY(x)) : (void)0u)
+#ifndef RAPIDJSON_ASSERT_THROWS
+#define RAPIDJSON_ASSERT_THROWS
+#endif
+#endif
class Random {
public:
diff --git a/3rdparty/rapidjson/test/unittest/uritest.cpp b/3rdparty/rapidjson/test/unittest/uritest.cpp
new file mode 100644
index 00000000000..789c9dd828b
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/uritest.cpp
@@ -0,0 +1,725 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// (C) Copyright IBM Corporation 2021
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#define RAPIDJSON_SCHEMA_VERBOSE 0
+#define RAPIDJSON_HAS_STDSTRING 1
+
+#include "unittest.h"
+#include "rapidjson/document.h"
+#include "rapidjson/uri.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(variadic-macros)
+#elif defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4822) // local class member function does not have a body
+#endif
+
+using namespace rapidjson;
+
+TEST(Uri, DefaultConstructor) {
+ typedef GenericUri<Value> UriType;
+ UriType u;
+ EXPECT_TRUE(u.GetSchemeString() == 0);
+ EXPECT_TRUE(u.GetAuthString() == 0);
+ EXPECT_TRUE(u.GetPathString() == 0);
+ EXPECT_TRUE(u.GetBaseString() == 0);
+ EXPECT_TRUE(u.GetQueryString() == 0);
+ EXPECT_TRUE(u.GetFragString() == 0);
+ EXPECT_TRUE(u.GetString() == 0);
+ EXPECT_TRUE(u.GetSchemeStringLength() == 0);
+ EXPECT_TRUE(u.GetAuthStringLength() == 0);
+ EXPECT_TRUE(u.GetPathStringLength() == 0);
+ EXPECT_TRUE(u.GetBaseStringLength() == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == 0);
+ EXPECT_TRUE(u.GetStringLength() == 0);
+}
+
+TEST(Uri, Parse) {
+ typedef GenericUri<Value, MemoryPoolAllocator<> > UriType;
+ MemoryPoolAllocator<CrtAllocator> allocator;
+ Value v;
+ Value w;
+
+ v.SetString("http://auth/path/xxx?query#frag", allocator);
+ UriType u = UriType(v, &allocator);
+ EXPECT_TRUE(StrCmp(u.GetSchemeString(), "http:") == 0);
+ EXPECT_TRUE(StrCmp(u.GetAuthString(), "//auth") == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), "/path/xxx") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), "http://auth/path/xxx?query") == 0);
+ EXPECT_TRUE(StrCmp(u.GetQueryString(), "?query") == 0);
+ EXPECT_TRUE(StrCmp(u.GetFragString(), "#frag") == 0);
+ u.Get(w, allocator);
+ EXPECT_TRUE(*w.GetString() == *v.GetString());
+
+ v.SetString("urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f", allocator);
+ u = UriType(v, &allocator);
+ EXPECT_TRUE(StrCmp(u.GetSchemeString(), "urn:") == 0);
+ EXPECT_TRUE(u.GetAuthStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), "uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), "urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f") == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == 0);
+ u.Get(w, allocator);
+ EXPECT_TRUE(*w.GetString() == *v.GetString());
+
+ v.SetString("", allocator);
+ u = UriType(v, &allocator);
+ EXPECT_TRUE(u.GetSchemeStringLength() == 0);
+ EXPECT_TRUE(u.GetAuthStringLength() == 0);
+ EXPECT_TRUE(u.GetPathStringLength() == 0);
+ EXPECT_TRUE(u.GetBaseStringLength() == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == 0);
+
+ v.SetString("http://auth/", allocator);
+ u = UriType(v, &allocator);
+ EXPECT_TRUE(StrCmp(u.GetSchemeString(), "http:") == 0);
+ EXPECT_TRUE(StrCmp(u.GetAuthString(), "//auth") == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), "/") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), "http://auth/") == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == 0);
+
+ u = UriType("/path/sub");
+ EXPECT_TRUE(u.GetSchemeStringLength() == 0);
+ EXPECT_TRUE(u.GetAuthStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), "/path/sub") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), "/path/sub") == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == 0);
+
+ // absolute path gets normalized
+ u = UriType("/path/../sub/");
+ EXPECT_TRUE(u.GetSchemeStringLength() == 0);
+ EXPECT_TRUE(u.GetAuthStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), "/sub/") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), "/sub/") == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == 0);
+
+ // relative path does not
+ u = UriType("path/../sub");
+ EXPECT_TRUE(u.GetSchemeStringLength() == 0);
+ EXPECT_TRUE(u.GetAuthStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), "path/../sub") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), "path/../sub") == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == 0);
+
+ u = UriType("http://auth#frag/stuff");
+ EXPECT_TRUE(StrCmp(u.GetSchemeString(), "http:") == 0);
+ EXPECT_TRUE(StrCmp(u.GetAuthString(), "//auth") == 0);
+ EXPECT_TRUE(u.GetPathStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), "http://auth") == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetFragString(), "#frag/stuff") == 0);
+ EXPECT_TRUE(StrCmp(u.GetString(), "http://auth#frag/stuff") == 0);
+
+ const Value::Ch c[] = { '#', 'f', 'r', 'a', 'g', '/', 's', 't', 'u', 'f', 'f', '\0'};
+ SizeType len = internal::StrLen<Value::Ch>(c);
+ u = UriType(c, len);
+ EXPECT_TRUE(StrCmp(u.GetString(), "#frag/stuff") == 0);
+ EXPECT_TRUE(u.GetStringLength() == len);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), "") == 0);
+ EXPECT_TRUE(u.GetBaseStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetFragString(), "#frag/stuff") == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == len);
+
+ u = UriType(c);
+ EXPECT_TRUE(StrCmp(u.GetString(), "#frag/stuff") == 0);
+ EXPECT_TRUE(u.GetStringLength() == len);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), "") == 0);
+ EXPECT_TRUE(u.GetBaseStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetFragString(), "#frag/stuff") == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == len);
+
+ // Incomplete auth treated as path
+ u = UriType("http:/");
+ EXPECT_TRUE(StrCmp(u.GetSchemeString(), "http:") == 0);
+ EXPECT_TRUE(u.GetAuthStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), "/") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), "http:/") == 0);
+}
+
+TEST(Uri, Parse_UTF16) {
+ typedef GenericValue<UTF16<> > Value16;
+ typedef GenericUri<Value16, MemoryPoolAllocator<> > UriType;
+ MemoryPoolAllocator<CrtAllocator> allocator;
+ Value16 v;
+ Value16 w;
+
+ v.SetString(L"http://auth/path/xxx?query#frag", allocator);
+ UriType u = UriType(v, &allocator);
+ EXPECT_TRUE(StrCmp(u.GetSchemeString(), L"http:") == 0);
+ EXPECT_TRUE(StrCmp(u.GetAuthString(), L"//auth") == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), L"/path/xxx") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), L"http://auth/path/xxx?query") == 0);
+ EXPECT_TRUE(StrCmp(u.GetQueryString(), L"?query") == 0);
+ EXPECT_TRUE(StrCmp(u.GetFragString(), L"#frag") == 0);
+ u.Get(w, allocator);
+ EXPECT_TRUE(*w.GetString() == *v.GetString());
+
+ v.SetString(L"urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f", allocator);
+ u = UriType(v, &allocator);
+ EXPECT_TRUE(StrCmp(u.GetSchemeString(), L"urn:") == 0);
+ EXPECT_TRUE(u.GetAuthStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), L"uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), L"urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f") == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == 0);
+ u.Get(w, allocator);
+ EXPECT_TRUE(*w.GetString() == *v.GetString());
+
+ v.SetString(L"", allocator);
+ u = UriType(v, &allocator);
+ EXPECT_TRUE(u.GetSchemeStringLength() == 0);
+ EXPECT_TRUE(u.GetAuthStringLength() == 0);
+ EXPECT_TRUE(u.GetPathStringLength() == 0);
+ EXPECT_TRUE(u.GetBaseStringLength() == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == 0);
+
+ v.SetString(L"http://auth/", allocator);
+ u = UriType(v, &allocator);
+ EXPECT_TRUE(StrCmp(u.GetSchemeString(), L"http:") == 0);
+ EXPECT_TRUE(StrCmp(u.GetAuthString(), L"//auth") == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), L"/") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), L"http://auth/") == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == 0);
+
+ u = UriType(L"/path/sub");
+ EXPECT_TRUE(u.GetSchemeStringLength() == 0);
+ EXPECT_TRUE(u.GetAuthStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), L"/path/sub") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), L"/path/sub") == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == 0);
+
+ // absolute path gets normalized
+ u = UriType(L"/path/../sub/");
+ EXPECT_TRUE(u.GetSchemeStringLength() == 0);
+ EXPECT_TRUE(u.GetAuthStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), L"/sub/") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), L"/sub/") == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == 0);
+
+ // relative path does not
+ u = UriType(L"path/../sub");
+ EXPECT_TRUE(u.GetSchemeStringLength() == 0);
+ EXPECT_TRUE(u.GetAuthStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), L"path/../sub") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), L"path/../sub") == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == 0);
+
+ u = UriType(L"http://auth#frag/stuff");
+ EXPECT_TRUE(StrCmp(u.GetSchemeString(), L"http:") == 0);
+ EXPECT_TRUE(StrCmp(u.GetAuthString(), L"//auth") == 0);
+ EXPECT_TRUE(u.GetPathStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), L"http://auth") == 0);
+ EXPECT_TRUE(u.GetQueryStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetFragString(), L"#frag/stuff") == 0);
+ EXPECT_TRUE(StrCmp(u.GetString(), L"http://auth#frag/stuff") == 0);
+
+ const Value16::Ch c[] = { '#', 'f', 'r', 'a', 'g', '/', 's', 't', 'u', 'f', 'f', '\0'};
+ SizeType len = internal::StrLen<Value16::Ch>(c);
+ u = UriType(c, len);
+ EXPECT_TRUE(StrCmp(u.GetString(), L"#frag/stuff") == 0);
+ EXPECT_TRUE(u.GetStringLength() == len);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), L"") == 0);
+ EXPECT_TRUE(u.GetBaseStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetFragString(), L"#frag/stuff") == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == len);
+
+ u = UriType(c);
+ EXPECT_TRUE(StrCmp(u.GetString(), L"#frag/stuff") == 0);
+ EXPECT_TRUE(u.GetStringLength() == len);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), L"") == 0);
+ EXPECT_TRUE(u.GetBaseStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetFragString(), L"#frag/stuff") == 0);
+ EXPECT_TRUE(u.GetFragStringLength() == len);
+
+ // Incomplete auth treated as path
+ u = UriType(L"http:/");
+ EXPECT_TRUE(StrCmp(u.GetSchemeString(), L"http:") == 0);
+ EXPECT_TRUE(u.GetAuthStringLength() == 0);
+ EXPECT_TRUE(StrCmp(u.GetPathString(), L"/") == 0);
+ EXPECT_TRUE(StrCmp(u.GetBaseString(), L"http:/") == 0);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+TEST(Uri, Parse_Std) {
+ typedef GenericUri<Value, MemoryPoolAllocator<> > UriType;
+ MemoryPoolAllocator<CrtAllocator> allocator;
+ typedef std::basic_string<Value::Ch> String;
+
+ String str = "http://auth/path/xxx?query#frag";
+ const UriType uri = UriType(str, &allocator);
+ EXPECT_TRUE(UriType::GetScheme(uri) == "http:");
+ EXPECT_TRUE(UriType::GetAuth(uri) == "//auth");
+ EXPECT_TRUE(UriType::GetPath(uri) == "/path/xxx");
+ EXPECT_TRUE(UriType::GetBase(uri) == "http://auth/path/xxx?query");
+ EXPECT_TRUE(UriType::GetQuery(uri) == "?query");
+ EXPECT_TRUE(UriType::GetFrag(uri) == "#frag");
+ EXPECT_TRUE(UriType::Get(uri) == str);
+}
+
+TEST(Uri, Parse_UTF16_Std) {
+ typedef GenericValue<UTF16<> > Value16;
+ typedef GenericUri<Value16, MemoryPoolAllocator<> > UriType;
+ MemoryPoolAllocator<CrtAllocator> allocator;
+ typedef std::basic_string<Value16::Ch> String;
+
+ String str = L"http://auth/path/xxx?query#frag";
+ const UriType uri = UriType(str, &allocator);
+ EXPECT_TRUE(UriType::GetScheme(uri) == L"http:");
+ EXPECT_TRUE(UriType::GetAuth(uri) == L"//auth");
+ EXPECT_TRUE(UriType::GetPath(uri) == L"/path/xxx");
+ EXPECT_TRUE(UriType::GetBase(uri) == L"http://auth/path/xxx?query");
+ EXPECT_TRUE(UriType::GetQuery(uri) == L"?query");
+ EXPECT_TRUE(UriType::GetFrag(uri) == L"#frag");
+ EXPECT_TRUE(UriType::Get(uri) == str);
+}
+#endif
+
+TEST(Uri, CopyConstructor) {
+ typedef GenericUri<Value> UriType;
+ CrtAllocator allocator;
+
+ UriType u("http://auth/path/xxx?query#frag", &allocator);
+ UriType u2(u);
+ EXPECT_TRUE(u == u2);
+ EXPECT_NE(&u.GetAllocator(), &u2.GetAllocator());
+}
+
+TEST(Uri, Assignment) {
+ typedef GenericUri<Value> UriType;
+ CrtAllocator allocator;
+
+ UriType u("http://auth/path/xxx?query#frag", &allocator);
+ UriType u2;
+ u2 = u;
+ EXPECT_TRUE(u == u2);
+ EXPECT_NE(&u.GetAllocator(), &u2.GetAllocator());
+}
+
+TEST(Uri, Resolve) {
+ typedef GenericUri<Value> UriType;
+ CrtAllocator allocator;
+
+ // ref is full uri
+ UriType base = UriType("http://auth/path/#frag");
+ UriType ref = UriType("http://newauth/newpath#newfrag");
+ UriType res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://newauth/newpath#newfrag") == 0);
+
+ base = UriType("/path/#frag", &allocator);
+ ref = UriType("http://newauth/newpath#newfrag", &allocator);
+ res = ref.Resolve(base, &allocator);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://newauth/newpath#newfrag") == 0);
+
+ // ref is alternate uri
+ base = UriType("http://auth/path/#frag");
+ ref = UriType("urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f") == 0);
+
+ // ref is absolute path
+ base = UriType("http://auth/path/#");
+ ref = UriType("/newpath#newfrag");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://auth/newpath#newfrag") == 0);
+
+ // ref is relative path
+ base = UriType("http://auth/path/file.json#frag");
+ ref = UriType("newfile.json#");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://auth/path/newfile.json#") == 0);
+
+ base = UriType("http://auth/path/file.json#frag/stuff");
+ ref = UriType("newfile.json#newfrag/newstuff");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://auth/path/newfile.json#newfrag/newstuff") == 0);
+
+ base = UriType("file.json", &allocator);
+ ref = UriType("newfile.json", &base.GetAllocator());
+ res = ref.Resolve(base, &ref.GetAllocator());
+ EXPECT_TRUE(StrCmp(res.GetString(), "newfile.json") == 0);
+
+ base = UriType("file.json", &allocator);
+ ref = UriType("./newfile.json", &allocator);
+ res = ref.Resolve(base, &allocator);
+ EXPECT_TRUE(StrCmp(res.GetString(), "newfile.json") == 0);
+
+ base = UriType("file.json");
+ ref = UriType("parent/../newfile.json");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "newfile.json") == 0);
+
+ base = UriType("file.json");
+ ref = UriType("parent/./newfile.json");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "parent/newfile.json") == 0);
+
+ base = UriType("file.json");
+ ref = UriType("../../parent/.././newfile.json");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "newfile.json") == 0);
+
+ // This adds a joining slash so resolved length is base length + ref length + 1
+ base = UriType("http://auth");
+ ref = UriType("newfile.json");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://auth/newfile.json") == 0);
+
+ // ref is fragment
+ base = UriType("#frag/stuff");
+ ref = UriType("#newfrag/newstuff");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "#newfrag/newstuff") == 0);
+
+ // test ref fragment always wins
+ base = UriType("/path#frag");
+ ref = UriType("");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "/path") == 0);
+
+ // Examples from RFC3896
+ base = UriType("http://a/b/c/d;p?q");
+ ref = UriType("g:h");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "g:h") == 0);
+ ref = UriType("g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/g") == 0);
+ ref = UriType("./g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/g") == 0);
+ ref = UriType("g/");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/g/") == 0);
+ ref = UriType("/g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/g") == 0);
+ ref = UriType("//g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://g") == 0);
+ ref = UriType("?y");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/d;p?y") == 0);
+ ref = UriType("g?y");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/g?y") == 0);
+ ref = UriType("#s");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/d;p?q#s") == 0);
+ ref = UriType("g#s");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/g#s") == 0);
+ ref = UriType("g?y#s");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/g?y#s") == 0);
+ ref = UriType(";x");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/;x") == 0);
+ ref = UriType("g;x");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/g;x") == 0);
+ ref = UriType("g;x?y#s");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/g;x?y#s") == 0);
+ ref = UriType("");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/d;p?q") == 0);
+ ref = UriType(".");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/") == 0);
+ ref = UriType("./");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/") == 0);
+ ref = UriType("..");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/") == 0);
+ ref = UriType("../");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/") == 0);
+ ref = UriType("../g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/g") == 0);
+ ref = UriType("../..");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/") == 0);
+ ref = UriType("../../");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/") == 0);
+ ref = UriType("../../g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/g") == 0);
+ ref = UriType("../../../g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/g") == 0);
+ ref = UriType("../../../../g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/g") == 0);
+ ref = UriType("/./g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/g") == 0);
+ ref = UriType("/../g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/g") == 0);
+ ref = UriType("g.");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/g.") == 0);
+ ref = UriType(".g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/.g") == 0);
+ ref = UriType("g..");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/g..") == 0);
+ ref = UriType("..g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/..g") == 0);
+ ref = UriType("g#s/../x");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://a/b/c/g#s/../x") == 0);
+}
+
+TEST(Uri, Resolve_UTF16) {
+ typedef GenericValue<UTF16<> > Value16;
+ typedef GenericUri<Value16> UriType;
+ CrtAllocator allocator;
+
+ // ref is full uri
+ UriType base = UriType(L"http://auth/path/#frag");
+ UriType ref = UriType(L"http://newauth/newpath#newfrag");
+ UriType res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://newauth/newpath#newfrag") == 0);
+
+ base = UriType(L"/path/#frag");
+ ref = UriType(L"http://newauth/newpath#newfrag");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://newauth/newpath#newfrag") == 0);
+
+ // ref is alternate uri
+ base = UriType(L"http://auth/path/#frag");
+ ref = UriType(L"urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f") == 0);
+
+ // ref is absolute path
+ base = UriType(L"http://auth/path/#");
+ ref = UriType(L"/newpath#newfrag");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://auth/newpath#newfrag") == 0);
+
+ // ref is relative path
+ base = UriType(L"http://auth/path/file.json#frag");
+ ref = UriType(L"newfile.json#");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://auth/path/newfile.json#") == 0);
+
+ base = UriType(L"http://auth/path/file.json#frag/stuff");
+ ref = UriType(L"newfile.json#newfrag/newstuff");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://auth/path/newfile.json#newfrag/newstuff") == 0);
+
+ base = UriType(L"file.json", &allocator);
+ ref = UriType(L"newfile.json", &base.GetAllocator());
+ res = ref.Resolve(base, &ref.GetAllocator());
+ EXPECT_TRUE(StrCmp(res.GetString(), L"newfile.json") == 0);
+
+ base = UriType(L"file.json", &allocator);
+ ref = UriType(L"./newfile.json", &allocator);
+ res = ref.Resolve(base, &allocator);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"newfile.json") == 0);
+
+ base = UriType(L"file.json");
+ ref = UriType(L"parent/../newfile.json");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"newfile.json") == 0);
+
+ base = UriType(L"file.json");
+ ref = UriType(L"parent/./newfile.json");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"parent/newfile.json") == 0);
+
+ base = UriType(L"file.json");
+ ref = UriType(L"../../parent/.././newfile.json");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"newfile.json") == 0);
+
+ // This adds a joining slash so resolved length is base length + ref length + 1
+ base = UriType(L"http://auth");
+ ref = UriType(L"newfile.json");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://auth/newfile.json") == 0);
+
+ // ref is fragment
+ base = UriType(L"#frag/stuff");
+ ref = UriType(L"#newfrag/newstuff");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"#newfrag/newstuff") == 0);
+
+ // test ref fragment always wins
+ base = UriType(L"/path#frag");
+ ref = UriType(L"");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"/path") == 0);
+
+ // Examples from RFC3896
+ base = UriType(L"http://a/b/c/d;p?q");
+ ref = UriType(L"g:h");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"g:h") == 0);
+ ref = UriType(L"g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/g") == 0);
+ ref = UriType(L"./g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/g") == 0);
+ ref = UriType(L"g/");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/g/") == 0);
+ ref = UriType(L"/g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/g") == 0);
+ ref = UriType(L"//g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://g") == 0);
+ ref = UriType(L"?y");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/d;p?y") == 0);
+ ref = UriType(L"g?y");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/g?y") == 0);
+ ref = UriType(L"#s");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/d;p?q#s") == 0);
+ ref = UriType(L"g#s");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/g#s") == 0);
+ ref = UriType(L"g?y#s");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/g?y#s") == 0);
+ ref = UriType(L";x");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/;x") == 0);
+ ref = UriType(L"g;x");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/g;x") == 0);
+ ref = UriType(L"g;x?y#s");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/g;x?y#s") == 0);
+ ref = UriType(L"");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/d;p?q") == 0);
+ ref = UriType(L".");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/") == 0);
+ ref = UriType(L"./");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/") == 0);
+ ref = UriType(L"..");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/") == 0);
+ ref = UriType(L"../");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/") == 0);
+ ref = UriType(L"../g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/g") == 0);
+ ref = UriType(L"../..");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/") == 0);
+ ref = UriType(L"../../");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/") == 0);
+ ref = UriType(L"../../g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/g") == 0);
+ ref = UriType(L"../../../g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/g") == 0);
+ ref = UriType(L"../../../../g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/g") == 0);
+ ref = UriType(L"/./g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/g") == 0);
+ ref = UriType(L"/../g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/g") == 0);
+ ref = UriType(L"g.");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/g.") == 0);
+ ref = UriType(L".g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/.g") == 0);
+ ref = UriType(L"g..");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/g..") == 0);
+ ref = UriType(L"..g");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/..g") == 0);
+ ref = UriType(L"g#s/../x");
+ res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), L"http://a/b/c/g#s/../x") == 0);
+}
+
+TEST(Uri, Equals) {
+ typedef GenericUri<Value> UriType;
+
+ UriType a = UriType("http://a/a#a");
+ UriType b = UriType("http://a/a#b");
+ UriType c = a;
+
+ EXPECT_TRUE(a == a);
+ EXPECT_TRUE(a == c);
+ EXPECT_TRUE(a != b);
+}
+
+TEST(Uri, Match) {
+ typedef GenericUri<Value> UriType;
+
+ UriType a = UriType("http://a/a#a");
+ UriType b = UriType("http://a/a#b");
+ UriType c = a;
+ UriType d;
+
+ EXPECT_TRUE(a.Match(a));
+ EXPECT_TRUE(a.Match(c));
+ EXPECT_FALSE(a.Match(b));
+ EXPECT_FALSE(a.Match(b, true));
+ EXPECT_TRUE(a.Match(b, false)); // Base Uri same
+ EXPECT_FALSE(a.Match(d));
+ EXPECT_FALSE(d.Match(a));
+}
+
+TEST(Uri, Issue1899) {
+ typedef GenericUri<Value, MemoryPoolAllocator<> > UriType;
+
+ UriType base = UriType("http://auth/path/#frag");
+ UriType ref = UriType("http://newauth/newpath#newfrag");
+ UriType res = ref.Resolve(base);
+ EXPECT_TRUE(StrCmp(res.GetString(), "http://newauth/newpath#newfrag") == 0);
+}
+
+#if defined(_MSC_VER) || defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/valuetest.cpp b/3rdparty/rapidjson/test/unittest/valuetest.cpp
index fefc001d45d..13ae1d4054f 100644
--- a/3rdparty/rapidjson/test/unittest/valuetest.cpp
+++ b/3rdparty/rapidjson/test/unittest/valuetest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -26,11 +26,11 @@ using namespace rapidjson;
TEST(Value, Size) {
if (sizeof(SizeType) == 4) {
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
- EXPECT_EQ(16, sizeof(Value));
+ EXPECT_EQ(16u, sizeof(Value));
#elif RAPIDJSON_64BIT
- EXPECT_EQ(24, sizeof(Value));
+ EXPECT_EQ(24u, sizeof(Value));
#else
- EXPECT_EQ(16, sizeof(Value));
+ EXPECT_EQ(16u, sizeof(Value));
#endif
}
}
@@ -439,6 +439,17 @@ TEST(Value, Int) {
EXPECT_EQ(5678, z.Get<int>());
EXPECT_EQ(5679, z.Set(5679).Get<int>());
EXPECT_EQ(5680, z.Set<int>(5680).Get<int>());
+
+#ifdef _MSC_VER
+ // long as int on MSC platforms
+ RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int));
+ z.SetInt(2222);
+ EXPECT_TRUE(z.Is<long>());
+ EXPECT_EQ(2222l, z.Get<long>());
+ EXPECT_EQ(3333l, z.Set(3333l).Get<long>());
+ EXPECT_EQ(4444l, z.Set<long>(4444l).Get<long>());
+ EXPECT_TRUE(z.IsInt());
+#endif
}
TEST(Value, Uint) {
@@ -485,6 +496,17 @@ TEST(Value, Uint) {
EXPECT_EQ(2147483648u, z.Get<unsigned>());
EXPECT_EQ(2147483649u, z.Set(2147483649u).Get<unsigned>());
EXPECT_EQ(2147483650u, z.Set<unsigned>(2147483650u).Get<unsigned>());
+
+#ifdef _MSC_VER
+ // unsigned long as unsigned on MSC platforms
+ RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned));
+ z.SetUint(2222);
+ EXPECT_TRUE(z.Is<unsigned long>());
+ EXPECT_EQ(2222ul, z.Get<unsigned long>());
+ EXPECT_EQ(3333ul, z.Set(3333ul).Get<unsigned long>());
+ EXPECT_EQ(4444ul, z.Set<unsigned long>(4444ul).Get<unsigned long>());
+ EXPECT_TRUE(x.IsUint());
+#endif
}
TEST(Value, Int64) {
@@ -857,9 +879,46 @@ TEST(Value, String) {
}
// Issue 226: Value of string type should not point to NULL
-TEST(Value, SetStringNullException) {
- Value v;
- EXPECT_THROW(v.SetString(0, 0), AssertException);
+TEST(Value, SetStringNull) {
+
+ MemoryPoolAllocator<> allocator;
+ const char* nullPtr = 0;
+ {
+ // Construction with string type creates empty string
+ Value v(kStringType);
+ EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
+ EXPECT_EQ(v.GetStringLength(), 0u);
+
+ // Construction from/setting to null without length not allowed
+ EXPECT_THROW(Value(StringRef(nullPtr)), AssertException);
+ EXPECT_THROW(Value(StringRef(nullPtr), allocator), AssertException);
+ EXPECT_THROW(v.SetString(nullPtr, allocator), AssertException);
+
+ // Non-empty length with null string is not allowed
+ EXPECT_THROW(v.SetString(nullPtr, 17u), AssertException);
+ EXPECT_THROW(v.SetString(nullPtr, 42u, allocator), AssertException);
+
+ // Setting to null string with empty length is allowed
+ v.SetString(nullPtr, 0u);
+ EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
+ EXPECT_EQ(v.GetStringLength(), 0u);
+
+ v.SetNull();
+ v.SetString(nullPtr, 0u, allocator);
+ EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
+ EXPECT_EQ(v.GetStringLength(), 0u);
+ }
+ // Construction with null string and empty length is allowed
+ {
+ Value v(nullPtr,0u);
+ EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
+ EXPECT_EQ(v.GetStringLength(), 0u);
+ }
+ {
+ Value v(nullPtr, 0u, allocator);
+ EXPECT_NE(v.GetString(), nullPtr); // non-null string returned
+ EXPECT_EQ(v.GetStringLength(), 0u);
+ }
}
template <typename T, typename Allocator>
@@ -1001,7 +1060,7 @@ static void TestArray(T& x, Allocator& allocator) {
x.Clear();
for (unsigned i = 0; i < n; i++)
x.PushBack(Value(kArrayType).PushBack(i, allocator).Move(), allocator);
-
+
itr = x.Erase(x.Begin() + first, x.Begin() + last);
if (last == n)
EXPECT_EQ(x.End(), itr);
@@ -1019,9 +1078,9 @@ static void TestArray(T& x, Allocator& allocator) {
}
TEST(Value, Array) {
+ Value::AllocatorType allocator;
Value x(kArrayType);
const Value& y = x;
- Value::AllocatorType allocator;
EXPECT_EQ(kArrayType, x.GetType());
EXPECT_TRUE(x.IsArray());
@@ -1060,6 +1119,16 @@ TEST(Value, Array) {
z.SetArray();
EXPECT_TRUE(z.IsArray());
EXPECT_TRUE(z.Empty());
+
+ // PR #1503: assign from inner Value
+ {
+ CrtAllocator a; // Free() is not a noop
+ GenericValue<UTF8<>, CrtAllocator> nullValue;
+ GenericValue<UTF8<>, CrtAllocator> arrayValue(kArrayType);
+ arrayValue.PushBack(nullValue, a);
+ arrayValue = arrayValue[0]; // shouldn't crash (use after free)
+ EXPECT_TRUE(arrayValue.IsNull());
+ }
}
TEST(Value, ArrayHelper) {
@@ -1076,10 +1145,10 @@ TEST(Value, ArrayHelper) {
a.PushBack(1, allocator);
Value::Array a2(a); // copy constructor
- EXPECT_EQ(1, a2.Size());
+ EXPECT_EQ(1u, a2.Size());
Value::Array a3 = a;
- EXPECT_EQ(1, a3.Size());
+ EXPECT_EQ(1u, a3.Size());
Value::ConstArray y = static_cast<const Value&>(x).GetArray();
(void)y;
@@ -1116,7 +1185,7 @@ TEST(Value, ArrayHelper) {
y.PushBack(123, allocator);
x.PushBack(y.GetArray(), allocator); // Implicit constructor to convert Array to GenericValue
- EXPECT_EQ(1, x.Size());
+ EXPECT_EQ(1u, x.Size());
EXPECT_EQ(123, x[0][0].GetInt());
EXPECT_TRUE(y.IsArray());
EXPECT_TRUE(y.Empty());
@@ -1365,7 +1434,7 @@ static void TestObject(T& x, Allocator& allocator) {
for (; itr != x.MemberEnd(); ++itr) {
size_t i = static_cast<size_t>((itr - x.MemberBegin())) + 1;
EXPECT_STREQ(itr->name.GetString(), keys[i]);
- EXPECT_EQ(i, itr->value[0].GetInt());
+ EXPECT_EQ(static_cast<int>(i), itr->value[0].GetInt());
}
// Erase the last
@@ -1376,7 +1445,7 @@ static void TestObject(T& x, Allocator& allocator) {
for (; itr != x.MemberEnd(); ++itr) {
size_t i = static_cast<size_t>(itr - x.MemberBegin()) + 1;
EXPECT_STREQ(itr->name.GetString(), keys[i]);
- EXPECT_EQ(i, itr->value[0].GetInt());
+ EXPECT_EQ(static_cast<int>(i), itr->value[0].GetInt());
}
// Erase the middle
@@ -1388,7 +1457,7 @@ static void TestObject(T& x, Allocator& allocator) {
size_t i = static_cast<size_t>(itr - x.MemberBegin());
i += (i < 4) ? 1 : 2;
EXPECT_STREQ(itr->name.GetString(), keys[i]);
- EXPECT_EQ(i, itr->value[0].GetInt());
+ EXPECT_EQ(static_cast<int>(i), itr->value[0].GetInt());
}
// EraseMember(ConstMemberIterator, ConstMemberIterator)
@@ -1422,9 +1491,9 @@ static void TestObject(T& x, Allocator& allocator) {
}
TEST(Value, Object) {
+ Value::AllocatorType allocator;
Value x(kObjectType);
const Value& y = x; // const version
- Value::AllocatorType allocator;
EXPECT_EQ(kObjectType, x.GetType());
EXPECT_TRUE(x.IsObject());
@@ -1457,10 +1526,10 @@ TEST(Value, ObjectHelper) {
o.AddMember("1", 1, allocator);
Value::Object o2(o); // copy constructor
- EXPECT_EQ(1, o2.MemberCount());
+ EXPECT_EQ(1u, o2.MemberCount());
Value::Object o3 = o;
- EXPECT_EQ(1, o3.MemberCount());
+ EXPECT_EQ(1u, o3.MemberCount());
Value::ConstObject y = static_cast<const Value&>(x).GetObject();
(void)y;
@@ -1487,7 +1556,7 @@ TEST(Value, ObjectHelper) {
EXPECT_STREQ("apple", y["a"].GetString());
EXPECT_TRUE(x.IsObject()); // Invariant
}
-
+
{
Value x(kObjectType);
x.AddMember("a", "apple", allocator);
@@ -1512,7 +1581,7 @@ TEST(Value, ObjectHelperRangeFor) {
{
int i = 0;
for (auto& m : x.GetObject()) {
- char name[10];
+ char name[11];
sprintf(name, "%d", i);
EXPECT_STREQ(name, m.name.GetString());
EXPECT_EQ(i, m.value.GetInt());
@@ -1523,7 +1592,7 @@ TEST(Value, ObjectHelperRangeFor) {
{
int i = 0;
for (const auto& m : const_cast<const Value&>(x).GetObject()) {
- char name[10];
+ char name[11];
sprintf(name, "%d", i);
EXPECT_STREQ(name, m.name.GetString());
EXPECT_EQ(i, m.value.GetInt());
@@ -1605,7 +1674,7 @@ TEST(Value, BigNestedObject) {
for (SizeType i = 0; i < n; i++) {
char name1[10];
sprintf(name1, "%d", i);
-
+
for (SizeType j = 0; j < n; j++) {
char name2[10];
sprintf(name2, "%d", j);
@@ -1620,8 +1689,8 @@ TEST(Value, BigNestedObject) {
TEST(Value, RemoveLastElement) {
rapidjson::Document doc;
rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
- rapidjson::Value objVal(rapidjson::kObjectType);
- objVal.AddMember("var1", 123, allocator);
+ rapidjson::Value objVal(rapidjson::kObjectType);
+ objVal.AddMember("var1", 123, allocator);
objVal.AddMember("var2", "444", allocator);
objVal.AddMember("var3", 555, allocator);
EXPECT_TRUE(objVal.HasMember("var3"));
@@ -1643,22 +1712,22 @@ TEST(Document, CrtAllocator) {
static void TestShortStringOptimization(const char* str) {
const rapidjson::SizeType len = static_cast<rapidjson::SizeType>(strlen(str));
-
+
rapidjson::Document doc;
rapidjson::Value val;
val.SetString(str, len, doc.GetAllocator());
-
- EXPECT_EQ(val.GetStringLength(), len);
- EXPECT_STREQ(val.GetString(), str);
+
+ EXPECT_EQ(val.GetStringLength(), len);
+ EXPECT_STREQ(val.GetString(), str);
}
TEST(Value, AllocateShortString) {
- TestShortStringOptimization(""); // edge case: empty string
- TestShortStringOptimization("12345678"); // regular case for short strings: 8 chars
- TestShortStringOptimization("12345678901"); // edge case: 11 chars in 32-bit mode (=> short string)
- TestShortStringOptimization("123456789012"); // edge case: 12 chars in 32-bit mode (=> regular string)
- TestShortStringOptimization("123456789012345"); // edge case: 15 chars in 64-bit mode (=> short string)
- TestShortStringOptimization("1234567890123456"); // edge case: 16 chars in 64-bit mode (=> regular string)
+ TestShortStringOptimization(""); // edge case: empty string
+ TestShortStringOptimization("12345678"); // regular case for short strings: 8 chars
+ TestShortStringOptimization("12345678901"); // edge case: 11 chars in 32-bit mode (=> short string)
+ TestShortStringOptimization("123456789012"); // edge case: 12 chars in 32-bit mode (=> regular string)
+ TestShortStringOptimization("123456789012345"); // edge case: 15 chars in 64-bit mode (=> short string)
+ TestShortStringOptimization("1234567890123456"); // edge case: 16 chars in 64-bit mode (=> regular string)
}
template <int e>
@@ -1733,7 +1802,7 @@ static void MergeDuplicateKey(Value& v, Value::AllocatorType& a) {
// Convert all key:value into key:[value]
for (Value::MemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
itr->value = Value(kArrayType).Move().PushBack(itr->value, a);
-
+
// Merge arrays if key is duplicated
for (Value::MemberIterator itr = v.MemberBegin(); itr != v.MemberEnd();) {
Value::MemberIterator itr2 = v.FindMember(itr->name);
diff --git a/3rdparty/rapidjson/test/unittest/writertest.cpp b/3rdparty/rapidjson/test/unittest/writertest.cpp
index 29f7626092c..ac9ad899e17 100644
--- a/3rdparty/rapidjson/test/unittest/writertest.cpp
+++ b/3rdparty/rapidjson/test/unittest/writertest.cpp
@@ -1,6 +1,6 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
@@ -20,6 +20,11 @@
#include "rapidjson/stringbuffer.h"
#include "rapidjson/memorybuffer.h"
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
using namespace rapidjson;
TEST(Writer, Compact) {
@@ -95,6 +100,19 @@ TEST(Writer, String) {
#endif
}
+TEST(Writer, Issue_889) {
+ char buf[100] = "Hello";
+
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartArray();
+ writer.String(buf);
+ writer.EndArray();
+
+ EXPECT_STREQ("[\"Hello\"]", buffer.GetString());
+ EXPECT_TRUE(writer.IsComplete()); \
+}
+
TEST(Writer, ScanWriteUnescapedString) {
const char json[] = "[\" \\\"0123456789ABCDEF\"]";
// ^ scanning stops here.
@@ -394,8 +412,10 @@ TEST(Writer, ValidateEncoding) {
EXPECT_TRUE(writer.String("\xC2\xA2")); // Cents sign U+00A2
EXPECT_TRUE(writer.String("\xE2\x82\xAC")); // Euro sign U+20AC
EXPECT_TRUE(writer.String("\xF0\x9D\x84\x9E")); // G clef sign U+1D11E
+ EXPECT_TRUE(writer.String("\x01")); // SOH control U+0001
+ EXPECT_TRUE(writer.String("\x1B")); // Escape control U+001B
writer.EndArray();
- EXPECT_STREQ("[\"\x24\",\"\xC2\xA2\",\"\xE2\x82\xAC\",\"\xF0\x9D\x84\x9E\"]", buffer.GetString());
+ EXPECT_STREQ("[\"\x24\",\"\xC2\xA2\",\"\xE2\x82\xAC\",\"\xF0\x9D\x84\x9E\",\"\\u0001\",\"\\u001B\"]", buffer.GetString());
}
// Fail in decoding invalid UTF-8 sequence http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
@@ -437,6 +457,28 @@ TEST(Writer, InvalidEventSequence) {
EXPECT_THROW(writer.Int(1), AssertException);
EXPECT_FALSE(writer.IsComplete());
}
+
+ // { 'a' }
+ {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartObject();
+ writer.Key("a");
+ EXPECT_THROW(writer.EndObject(), AssertException);
+ EXPECT_FALSE(writer.IsComplete());
+ }
+
+ // { 'a':'b','c' }
+ {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartObject();
+ writer.Key("a");
+ writer.String("b");
+ writer.Key("c");
+ EXPECT_THROW(writer.EndObject(), AssertException);
+ EXPECT_FALSE(writer.IsComplete());
+ }
}
TEST(Writer, NaN) {
@@ -495,3 +537,62 @@ TEST(Writer, RawValue) {
EXPECT_TRUE(writer.IsComplete());
EXPECT_STREQ("{\"a\":1,\"raw\":[\"Hello\\nWorld\", 123.456]}", buffer.GetString());
}
+
+TEST(Write, RawValue_Issue1152) {
+ {
+ GenericStringBuffer<UTF32<> > sb;
+ Writer<GenericStringBuffer<UTF32<> >, UTF8<>, UTF32<> > writer(sb);
+ writer.RawValue("null", 4, kNullType);
+ EXPECT_TRUE(writer.IsComplete());
+ const unsigned *out = sb.GetString();
+ EXPECT_EQ(static_cast<unsigned>('n'), out[0]);
+ EXPECT_EQ(static_cast<unsigned>('u'), out[1]);
+ EXPECT_EQ(static_cast<unsigned>('l'), out[2]);
+ EXPECT_EQ(static_cast<unsigned>('l'), out[3]);
+ EXPECT_EQ(static_cast<unsigned>(0 ), out[4]);
+ }
+
+ {
+ GenericStringBuffer<UTF8<> > sb;
+ Writer<GenericStringBuffer<UTF8<> >, UTF16<>, UTF8<> > writer(sb);
+ writer.RawValue(L"null", 4, kNullType);
+ EXPECT_TRUE(writer.IsComplete());
+ EXPECT_STREQ("null", sb.GetString());
+ }
+
+ {
+ // Fail in transcoding
+ GenericStringBuffer<UTF16<> > buffer;
+ Writer<GenericStringBuffer<UTF16<> >, UTF8<>, UTF16<> > writer(buffer);
+ EXPECT_FALSE(writer.RawValue("\"\xfe\"", 3, kStringType));
+ }
+
+ {
+ // Fail in encoding validation
+ StringBuffer buffer;
+ Writer<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteValidateEncodingFlag> writer(buffer);
+ EXPECT_FALSE(writer.RawValue("\"\xfe\"", 3, kStringType));
+ }
+}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+static Writer<StringBuffer> WriterGen(StringBuffer &target) {
+ Writer<StringBuffer> writer(target);
+ writer.StartObject();
+ writer.Key("a");
+ writer.Int(1);
+ return writer;
+}
+
+TEST(Writer, MoveCtor) {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(WriterGen(buffer));
+ writer.EndObject();
+ EXPECT_TRUE(writer.IsComplete());
+ EXPECT_STREQ("{\"a\":1}", buffer.GetString());
+}
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/valgrind.supp b/3rdparty/rapidjson/test/valgrind.supp
new file mode 100644
index 00000000000..c9d3d226569
--- /dev/null
+++ b/3rdparty/rapidjson/test/valgrind.supp
@@ -0,0 +1,26 @@
+{
+ Suppress wcslen valgrind report 1
+ Memcheck:Cond
+ fun:__wcslen_sse2
+}
+
+{
+ Suppress wcslen valgrind report 2
+ Memcheck:Addr8
+ fun:__wcslen_sse2
+}
+
+{
+ Suppress wcslen valgrind report 3
+ Memcheck:Value8
+ fun:__wcslen_sse2
+}
+
+{
+ Suppress wmemcmp valgrind report 4
+ Memcheck:Addr32
+ fun:__wmemcmp_avx2_movbe
+ ...
+ fun:*Uri*Parse_UTF16_Std*
+}
+
diff --git a/3rdparty/rapidjson/travis-doxygen.sh b/3rdparty/rapidjson/travis-doxygen.sh
index 31a50cfa921..cf18dc3432e 100644..100755
--- a/3rdparty/rapidjson/travis-doxygen.sh
+++ b/3rdparty/rapidjson/travis-doxygen.sh
@@ -4,12 +4,10 @@
set -e
-DOXYGEN_VER=doxygen-1.8.7
-DOXYGEN_TAR=${DOXYGEN_VER}.linux.bin.tar.gz
-DOXYGEN_URL="http://ftp.stack.nl/pub/users/dimitri/${DOXYGEN_TAR}"
-DOXYGEN_BIN="/usr/local/bin/doxygen"
+DOXYGEN_VER=1_8_16
+DOXYGEN_URL="https://codeload.github.com/doxygen/doxygen/tar.gz/Release_${DOXYGEN_VER}"
-: ${GITHUB_REPO:="miloyip/rapidjson"}
+: ${GITHUB_REPO:="Tencent/rapidjson"}
GITHUB_HOST="github.com"
GITHUB_CLONE="git://${GITHUB_HOST}/${GITHUB_REPO}"
GITHUB_URL="https://${GITHUB_HOST}/${GITHUB_PUSH-${GITHUB_REPO}}"
@@ -48,9 +46,17 @@ abort() {
# install doxygen binary distribution
doxygen_install()
{
- wget -O - "${DOXYGEN_URL}" | \
- tar xz -C ${TMPDIR-/tmp} ${DOXYGEN_VER}/bin/doxygen
- export PATH="${TMPDIR-/tmp}/${DOXYGEN_VER}/bin:$PATH"
+ cd ${TMPDIR-/tmp}
+ curl ${DOXYGEN_URL} -o doxygen.tar.gz
+ tar zxvf doxygen.tar.gz
+ mkdir doxygen_build
+ cd doxygen_build
+ cmake ../doxygen-Release_${DOXYGEN_VER}/
+ make
+
+ export PATH="${TMPDIR-/tmp}/doxygen_build/bin:$PATH"
+
+ cd ../../
}
doxygen_run()
@@ -66,7 +72,7 @@ gh_pages_prepare()
[ ! -d "html" ] || \
abort "Doxygen target directory already exists."
git --version
- git clone -b gh-pages "${GITHUB_CLONE}" html
+ git clone --single-branch -b gh-pages "${GITHUB_CLONE}" html
cd html
# setup git config (with defaults)
git config user.name "${GIT_NAME-travis}"