Compare commits

..

7 Commits

Author SHA1 Message Date
kabeer27
6aba23f4a8 Fixes Oss-Fuzz issue: 21916 (#1180)
* Fix heap-buffer-overflow in json_reader
2020-05-29 21:50:26 +08:00
Billy Donahue
c161f4ac69 Escape control chars even if emitting UTF8 (#1178)
* Escape control chars even if emitting UTF8

See #1176
Fixes #1175

* review comments

* fix test by stopping early enough to punt on utf8-input.
2020-05-21 11:30:59 -04:00
Billy Donahue
75b360af4a spot fix #1171: isprint argument must be representable as unsigned char (#1173) 2020-05-13 18:37:02 -04:00
Rosen Penev
e36cff19f0 clang-tidy + any_of usage (#1171)
* [clang-tidy] change functions to static

Found with readability-convert-member-functions-to-static

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* optimize JsonWriter::validate #1171

* do the same for json_reader

Signed-off-by: Rosen Penev <rosenp@gmail.com>

* use std::any_of

Also simplified two loops.

Signed-off-by: Rosen Penev <rosenp@gmail.com>

Co-authored-by: Billy Donahue <billy.donahue@gmail.com>
2020-05-12 19:19:36 -04:00
Edward Brey
b8cb8889aa Added current dir specifier for PowerShell (#1169)
The `./` is needed before `vcpkg install jsoncpp` when installing with PowerShell.
2020-05-08 09:00:12 +08:00
Chen
d2d4c74a03 Update README.md and add dota17 to AUTHORS list. (#1168)
* update README

* add dota17 to AUTHORS list
2020-04-30 18:05:17 +08:00
Chen
8b7ea09b80 Bump soversion to 24 (#1167) 2020-04-30 17:58:07 +08:00
30 changed files with 713 additions and 1019 deletions

View File

@@ -34,7 +34,6 @@ matrix:
CC="clang" CC="clang"
LIB_TYPE=static LIB_TYPE=static
BUILD_TYPE=release BUILD_TYPE=release
LANGUAGE_STANDARD="11"
script: ./.travis_scripts/meson_builder.sh script: ./.travis_scripts/meson_builder.sh
- name: Linux xenial clang meson static release testing - name: Linux xenial clang meson static release testing
os: linux os: linux
@@ -45,59 +44,13 @@ matrix:
CC="clang" CC="clang"
LIB_TYPE=static LIB_TYPE=static
BUILD_TYPE=release BUILD_TYPE=release
LANGUAGE_STANDARD="11"
# before_install and install steps only needed for linux meson builds # before_install and install steps only needed for linux meson builds
before_install: before_install:
- source ./.travis_scripts/travis.before_install.${TRAVIS_OS_NAME}.sh - source ./.travis_scripts/travis.before_install.${TRAVIS_OS_NAME}.sh
install: install:
- source ./.travis_scripts/travis.install.${TRAVIS_OS_NAME}.sh - source ./.travis_scripts/travis.install.${TRAVIS_OS_NAME}.sh
script: ./.travis_scripts/meson_builder.sh script: ./.travis_scripts/meson_builder.sh
- name: Linux xenial gcc-4.6 meson static release with C++03 testing - name: Linux xenial gcc cmake coverage
os: linux
dist: xenial
compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.6
env:
CC=gcc-4.6
CXX=g++-4.6
LIB_TYPE=static
BUILD_TYPE=release
LANGUAGE_STANDARD="03"
# before_install and install steps only needed for linux meson builds
before_install:
- source ./.travis_scripts/travis.before_install.${TRAVIS_OS_NAME}.sh
install:
- source ./.travis_scripts/travis.install.${TRAVIS_OS_NAME}.sh
script: ./.travis_scripts/meson_builder.sh
- name: Linux xenial gcc-4.6 meson static release with C++98 testing
os: linux
dist: xenial
compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.6
env:
CC=gcc-4.6
CXX=g++-4.6
LIB_TYPE=static
BUILD_TYPE=release
LANGUAGE_STANDARD="98"
# before_install and install steps only needed for linux meson builds
before_install:
- source ./.travis_scripts/travis.before_install.${TRAVIS_OS_NAME}.sh
install:
- source ./.travis_scripts/travis.install.${TRAVIS_OS_NAME}.sh
script: ./.travis_scripts/meson_builder.sh
- name: Linux xenial gcc-5.4 cmake-3.12 coverage
os: linux os: linux
dist: xenial dist: xenial
compiler: gcc compiler: gcc
@@ -109,77 +62,10 @@ matrix:
BUILD_TYPE=Debug BUILD_TYPE=Debug
LIB_TYPE=shared LIB_TYPE=shared
DESTDIR=/tmp/cmake_json_cpp DESTDIR=/tmp/cmake_json_cpp
LANGUAGE_STANDARD="11"
before_install: before_install:
- pip install --user cpp-coveralls - pip install --user cpp-coveralls
script: ./.travis_scripts/cmake_builder.sh script: ./.travis_scripts/cmake_builder.sh
after_success: after_success:
- coveralls --include src/lib_json --include include - coveralls --include src/lib_json --include include
- name: Linux xenial gcc-4.6 cmake-3.12 with C++98 testing
os: linux
dist: xenial
compiler: gcc
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.6
- valgrind
env:
CC=gcc-4.6
CXX=g++-4.6
DO_MemCheck=ON
BUILD_TOOL="Unix Makefiles"
LIB_TYPE=static
BUILD_TYPE=release
DESTDIR=/tmp/cmake_json_cpp
LANGUAGE_STANDARD="98"
before_install:
- sudo apt-get update
- sudo apt-get install python3
script: ./.travis_scripts/cmake_builder.sh
- name: Linux xenial gcc-5.4 cmake-3.12 with C++98 testing
os: linux
dist: xenial
compiler: gcc
env:
CC=gcc
CXX=g++
DO_MemCheck=ON
BUILD_TOOL="Unix Makefiles"
LIB_TYPE=static
BUILD_TYPE=release
DESTDIR=/tmp/cmake_json_cpp
LANGUAGE_STANDARD="98"
script: ./.travis_scripts/cmake_builder.sh
- name: Linux xenial clang cmake-3.12 with C++11 testing
os: linux
dist: xenial
compiler: clang
env:
CC=clang
CXX=clang++
DO_MemCheck=ON
BUILD_TOOL="Unix Makefiles"
LIB_TYPE=static
BUILD_TYPE=release
DESTDIR=/tmp/cmake_json_cpp
LANGUAGE_STANDARD="11"
script: ./.travis_scripts/cmake_builder.sh
- name: Linux xenial clang cmake-3.12 with C++98 testing
os: linux
dist: xenial
compiler: gcc
env:
CC=clang
CXX=clang++
DO_MemCheck=ON
BUILD_TOOL="Unix Makefiles"
LIB_TYPE=static
BUILD_TYPE=release
DESTDIR=/tmp/cmake_json_cpp
LANGUAGE_STANDARD="98"
script: ./.travis_scripts/cmake_builder.sh
notifications: notifications:
email: false email: false

View File

@@ -66,7 +66,7 @@ cmake --version
echo ${CXX} echo ${CXX}
${CXX} --version ${CXX} --version
_COMPILER_NAME=`basename ${CXX}` _COMPILER_NAME=`basename ${CXX}`
if [ "${BUILD_TYPE}" = "shared" ]; then if [ "${BUILD_TYPE}" == "shared" ]; then
_CMAKE_BUILD_SHARED_LIBS=ON _CMAKE_BUILD_SHARED_LIBS=ON
else else
_CMAKE_BUILD_SHARED_LIBS=OFF _CMAKE_BUILD_SHARED_LIBS=OFF
@@ -98,14 +98,6 @@ else
export _BUILD_EXE=make export _BUILD_EXE=make
fi fi
# Language standard
# Set default to ON
if [ "${LANGUAGE_STANDARD}" = "98" ]; then
_BUILD_WITH_CXX_11=OFF
else
_BUILD_WITH_CXX_11=ON
fi
_BUILD_DIR_NAME="build-cmake_${BUILD_TYPE}_${LIB_TYPE}_${_COMPILER_NAME}_${_BUILD_EXE}" _BUILD_DIR_NAME="build-cmake_${BUILD_TYPE}_${LIB_TYPE}_${_COMPILER_NAME}_${_BUILD_EXE}"
mkdir -p ${_BUILD_DIR_NAME} mkdir -p ${_BUILD_DIR_NAME}
cd "${_BUILD_DIR_NAME}" cd "${_BUILD_DIR_NAME}"
@@ -120,7 +112,6 @@ cd "${_BUILD_DIR_NAME}"
-DCMAKE_BUILD_TYPE:STRING=${BUILD_TYPE} \ -DCMAKE_BUILD_TYPE:STRING=${BUILD_TYPE} \
-DBUILD_SHARED_LIBS:BOOL=${_CMAKE_BUILD_SHARED_LIBS} \ -DBUILD_SHARED_LIBS:BOOL=${_CMAKE_BUILD_SHARED_LIBS} \
-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR} \ -DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR} \
-DBUILD_WITH_CXX_11=${_BUILD_WITH_CXX_11} \
../ ../
ctest -C ${BUILD_TYPE} -D ExperimentalStart -D ExperimentalConfigure -D ExperimentalBuild ${CTEST_TESTING_OPTION} -D ExperimentalSubmit ctest -C ${BUILD_TYPE} -D ExperimentalStart -D ExperimentalConfigure -D ExperimentalBuild ${CTEST_TESTING_OPTION} -D ExperimentalSubmit

View File

@@ -64,15 +64,11 @@ ninja --version
_COMPILER_NAME=`basename ${CXX}` _COMPILER_NAME=`basename ${CXX}`
_BUILD_DIR_NAME="build-${BUILD_TYPE}_${LIB_TYPE}_${_COMPILER_NAME}" _BUILD_DIR_NAME="build-${BUILD_TYPE}_${LIB_TYPE}_${_COMPILER_NAME}"
# if LANGUAGE_STANDARD not set or null, set it to 11
_CPP_STD=${LANGUAGE_STANDARD:="11"}
./.travis_scripts/run-clang-format.sh ./.travis_scripts/run-clang-format.sh
meson --fatal-meson-warnings --werror --buildtype ${BUILD_TYPE} --default-library ${LIB_TYPE} . "${_BUILD_DIR_NAME}" meson --fatal-meson-warnings --werror --buildtype ${BUILD_TYPE} --default-library ${LIB_TYPE} . "${_BUILD_DIR_NAME}"
ninja -v -j 2 -C "${_BUILD_DIR_NAME}"
cd "${_BUILD_DIR_NAME}" cd "${_BUILD_DIR_NAME}"
meson configure -Dcpp_std="c++${_CPP_STD}"
ninja -v -j 2 -C ./
meson test --no-rebuild --print-errorlogs meson test --no-rebuild --print-errorlogs
if [ "${DESTDIR}" != "/usr/local" ]; then if [ "${DESTDIR}" != "/usr/local" ]; then

View File

@@ -21,7 +21,7 @@ Braden McDorman <bmcdorman@gmail.com>
Brandon Myers <bmyers1788@gmail.com> Brandon Myers <bmyers1788@gmail.com>
Brendan Drew <brendan.drew@daqri.com> Brendan Drew <brendan.drew@daqri.com>
chason <cxchao802@gmail.com> chason <cxchao802@gmail.com>
Chen Guoping chenguopingdota@163.com chenguoping <chenguopingdota@163.com>
Chris Gilling <cgilling@iparadigms.com> Chris Gilling <cgilling@iparadigms.com>
Christopher Dawes <christopher.dawes.1981@googlemail.com> Christopher Dawes <christopher.dawes.1981@googlemail.com>
Christopher Dunn <cdunn2001@gmail.com> Christopher Dunn <cdunn2001@gmail.com>

View File

@@ -37,6 +37,12 @@ foreach(pold "") # Currently Empty
endif() endif()
endforeach() endforeach()
# Build the library with C++11 standard support, independent from other including
# software which may use a different CXX_STANDARD or CMAKE_CXX_STANDARD.
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Ensure that CMAKE_BUILD_TYPE has a value specified for single configuration generators. # Ensure that CMAKE_BUILD_TYPE has a value specified for single configuration generators.
if(NOT DEFINED CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES) if(NOT DEFINED CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING set(CMAKE_BUILD_TYPE Release CACHE STRING
@@ -53,47 +59,19 @@ if(CCACHE_EXECUTABLE)
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE) set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE)
endif() endif()
# Note: project(VERSION XX) - the VERSION here is number, but VERSION in meson is string.
# Thus, it is better to be consistent.
project(JSONCPP project(JSONCPP
# Note: version must be updated in three places when doing a release. This
# annoying process ensures that amalgamate, CMake, and meson all report the
# correct version.
# 1. ./meson.build
# 2. ./include/json/version.h
# 3. ./CMakeLists.txt
# IMPORTANT: also update the JSONCPP_SOVERSION!!
VERSION 1.9.3 # <major>[.<minor>[.<patch>[.<tweak>]]]
LANGUAGES CXX) LANGUAGES CXX)
# Set variable named ${VAR_NAME} to value ${VALUE}
function(set_using_dynamic_name VAR_NAME VALUE)
set( "${VAR_NAME}" "${VALUE}" PARENT_SCOPE)
endfunction()
# Extract major, minor, patch from version text
# Parse a version string "X.Y.Z" and outputs
# version parts in ${OUPUT_PREFIX}_MAJOR, _MINOR, _PATCH.
# If parse succeeds then ${OUPUT_PREFIX}_FOUND is TRUE.
macro(jsoncpp_parse_version VERSION_TEXT OUPUT_PREFIX)
set(VERSION_REGEX "[0-9]+\\.[0-9]+\\.[0-9]+(-[a-zA-Z0-9_]+)?")
if( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} )
string(REGEX MATCHALL "[0-9]+|-([A-Za-z0-9_]+)" VERSION_PARTS ${VERSION_TEXT})
list(GET VERSION_PARTS 0 ${OUPUT_PREFIX}_MAJOR)
list(GET VERSION_PARTS 1 ${OUPUT_PREFIX}_MINOR)
list(GET VERSION_PARTS 2 ${OUPUT_PREFIX}_PATCH)
set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" TRUE )
else( ${VERSION_TEXT} MATCHES ${VERSION_REGEX} )
set_using_dynamic_name( "${OUPUT_PREFIX}_FOUND" FALSE )
endif()
endmacro()
# Note: version must be updated in three places when doing a release. This
# annoying process ensures that amalgamate, CMake, and meson all report the
# correct version.
# 1. ./meson.build
# 2. ./include/json/version.h
# 3. ./CMakeLists.txt
# IMPORTANT: also update the JSONCPP_SOVERSION!!
set( JSONCPP_VERSION 00.11.0 )
set( JSONCPP_SOVERSION 23 )
jsoncpp_parse_version( ${JSONCPP_VERSION} JSONCPP_VERSION )
message(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}") message(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}")
#if(NOT JSONCPP_VERSION_FOUND) set(JSONCPP_SOVERSION 24)
# message(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z")
#endif(NOT JSONCPP_VERSION_FOUND)
option(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" ON) option(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" ON)
option(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON) option(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON)
@@ -103,36 +81,6 @@ option(JSONCPP_WITH_PKGCONFIG_SUPPORT "Generate and install .pc files" ON)
option(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" ON) option(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" ON)
option(JSONCPP_WITH_EXAMPLE "Compile JsonCpp example" OFF) option(JSONCPP_WITH_EXAMPLE "Compile JsonCpp example" OFF)
option(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." OFF) option(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." OFF)
option(BUILD_WITH_CXX_11 "Build jsoncpp_lib with C++11 standard." ON)
## To compatible with C++0x and C++1x
set(CMAKE_MINIMUN_CXX_STANDARD 98)
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_COMPILER "/usr/bin/g++")
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE CXX_VERSION)
if(CXX_VERSION VERSION_GREATER 4.8.0)
if(BUILD_WITH_CXX_11)
set(CMAKE_CXX_STANDARD 11)
message(STATUS "Compiled with C++11(or newer) standard!")
else()
set(CMAKE_CXX_STANDARD 98)
message(STATUS "Compiled with C++0x standard!")
endif()
else()
set(CMAKE_CXX_STANDARD 98)
message(STATUS "Compiled with C++0x standard!")
endif()
endif()
if (NOT CMAKE_CXX_STANDARD)
if (BUILD_WITH_CXX_11)
set(CMAKE_CXX_STANDARD 11)
message(STATUS "Compiled with C++1x standard!")
else()
set(CMAKE_CXX_STANDARD 98)
message(STATUS "Compiled with C++0x standard!")
endif()
endif()
# Adhere to GNU filesystem layout conventions # Adhere to GNU filesystem layout conventions
include(GNUInstallDirs) include(GNUInstallDirs)
@@ -179,7 +127,7 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# not yet ready for -Wsign-conversion # not yet ready for -Wsign-conversion
if(JSONCPP_WITH_STRICT_ISO) if(JSONCPP_WITH_STRICT_ISO)
add_compile_options(-Wall) add_compile_options(-Wpedantic)
endif() endif()
if(JSONCPP_WITH_WARNING_AS_ERROR) if(JSONCPP_WITH_WARNING_AS_ERROR)
add_compile_options(-Werror=conversion) add_compile_options(-Werror=conversion)
@@ -212,7 +160,7 @@ if(JSONCPP_WITH_CMAKE_PACKAGE)
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp
FILE jsoncppConfig.cmake) FILE jsoncppConfig.cmake)
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake" write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake"
VERSION ${JSONCPP_VERSION} VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion) COMPATIBILITY SameMajorVersion)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp) DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp)

View File

@@ -1,5 +1,11 @@
# JsonCpp # JsonCpp
[![badge](https://img.shields.io/badge/conan.io-jsoncpp%2F1.8.0-green.svg?logo=data:image/png;base64%2CiVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAA1VBMVEUAAABhlctjlstkl8tlmMtlmMxlmcxmmcxnmsxpnMxpnM1qnc1sn85voM91oM11oc1xotB2oc56pNF6pNJ2ptJ8ptJ8ptN9ptN8p9N5qNJ9p9N9p9R8qtOBqdSAqtOAqtR%2BrNSCrNJ/rdWDrNWCsNWCsNaJs9eLs9iRvNuVvdyVv9yXwd2Zwt6axN6dxt%2Bfx%2BChyeGiyuGjyuCjyuGly%2BGlzOKmzOGozuKoz%2BKqz%2BOq0OOv1OWw1OWw1eWx1eWy1uay1%2Baz1%2Baz1%2Bez2Oe02Oe12ee22ujUGwH3AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgBQkREyOxFIh/AAAAiklEQVQI12NgAAMbOwY4sLZ2NtQ1coVKWNvoc/Eq8XDr2wB5Ig62ekza9vaOqpK2TpoMzOxaFtwqZua2Bm4makIM7OzMAjoaCqYuxooSUqJALjs7o4yVpbowvzSUy87KqSwmxQfnsrPISyFzWeWAXCkpMaBVIC4bmCsOdgiUKwh3JojLgAQ4ZCE0AMm2D29tZwe6AAAAAElFTkSuQmCC)](https://bintray.com/theirix/conan-repo/jsoncpp%3Atheirix)
[![badge](https://img.shields.io/badge/license-MIT-blue)](https://github.com/open-source-parsers/jsoncpp/blob/master/LICENSE)
[![badge](https://img.shields.io/badge/document-doxygen-brightgreen)](http://open-source-parsers.github.io/jsoncpp-docs/doxygen/index.html)
[![Coverage Status](https://coveralls.io/repos/github/open-source-parsers/jsoncpp/badge.svg?branch=master)](https://coveralls.io/github/open-source-parsers/jsoncpp?branch=master)
[JSON][json-org] is a lightweight data-interchange format. It can represent [JSON][json-org] is a lightweight data-interchange format. It can represent
numbers, strings, ordered sequences of values, and collections of name/value numbers, strings, ordered sequences of values, and collections of name/value
pairs. pairs.
@@ -11,13 +17,6 @@ serialization and deserialization to and from strings. It can also preserve
existing comment in unserialization/serialization steps, making it a convenient existing comment in unserialization/serialization steps, making it a convenient
format to store user input files. format to store user input files.
## Release notes
The 00.11.z branch is a new version, its major version number `00` is to shows that it is
different from branch 0.y.z and 1.y.z. The main purpose of this branch is to give users a
third choice, that is, users can only have a copy of the code, but can build in different environments,
so it can be used with old or newer compilers.
The benefit is that users can used some new features in this new branch that introduced in 1.y.z,
but can hardly applied into 0.y.z.
## Documentation ## Documentation
@@ -31,9 +30,14 @@ but can hardly applied into 0.y.z.
* `1.y.z` is built with C++11. * `1.y.z` is built with C++11.
* `0.y.z` can be used with older compilers. * `0.y.z` can be used with older compilers.
* `00.11.z` can be used with older compilers , with new features from `1.y.z` * `00.11.z` can be used both in old and new compilers.
* Major versions maintain binary-compatibility. * Major versions maintain binary-compatibility.
### Special note
The branch `00.11.z`is a new branch, its major version number `00` is to show that it is
different from `0.y.z` and `1.y.z`, the main purpose of this branch is to make a balance
between the other two branches. Thus, users can use some new features in this new branch
that introduced in 1.y.z, but can hardly applied into 0.y.z.
## Using JsonCpp in your project ## Using JsonCpp in your project
@@ -44,7 +48,7 @@ You can download and install JsonCpp using the [vcpkg](https://github.com/Micros
cd vcpkg cd vcpkg
./bootstrap-vcpkg.sh ./bootstrap-vcpkg.sh
./vcpkg integrate install ./vcpkg integrate install
vcpkg install jsoncpp ./vcpkg install jsoncpp
The JsonCpp port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. The JsonCpp port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.

View File

@@ -1,5 +1,4 @@
#include "json/json.h" #include "json/json.h"
#include <cstdlib>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
/** \brief Parse from stream, collect comments and capture error info. /** \brief Parse from stream, collect comments and capture error info.

View File

@@ -1,5 +1,4 @@
#include "json/json.h" #include "json/json.h"
#include <cstdlib>
#include <iostream> #include <iostream>
/** /**
* \brief Parse a raw string into Value object using the CharReaderBuilder * \brief Parse a raw string into Value object using the CharReaderBuilder
@@ -11,9 +10,9 @@
* 20 * 20
*/ */
int main() { int main() {
const std::string rawJson = "{\"Age\": 20, \"Name\": \"colin\"}"; const std::string rawJson = R"({"Age": 20, "Name": "colin"})";
const int rawJsonLength = static_cast<int>(rawJson.length()); const auto rawJsonLength = static_cast<int>(rawJson.length());
JSONCPP_CONST bool shouldUseOldWay = false; constexpr bool shouldUseOldWay = false;
JSONCPP_STRING err; JSONCPP_STRING err;
Json::Value root; Json::Value root;
@@ -22,13 +21,12 @@ int main() {
reader.parse(rawJson, root); reader.parse(rawJson, root);
} else { } else {
Json::CharReaderBuilder builder; Json::CharReaderBuilder builder;
Json::CharReader* reader(builder.newCharReader()); const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLength, &root, if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLength, &root,
&err)) { &err)) {
std::cout << "error" << std::endl; std::cout << "error" << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
delete reader;
} }
const std::string name = root["Name"].asString(); const std::string name = root["Name"].asString();
const int age = root["Age"].asInt(); const int age = root["Age"].asInt();

View File

@@ -12,11 +12,11 @@
int main() { int main() {
Json::Value root; Json::Value root;
Json::StreamWriterBuilder builder; Json::StreamWriterBuilder builder;
Json::StreamWriter* writer(builder.newStreamWriter()); const std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
root["Name"] = "robin"; root["Name"] = "robin";
root["Age"] = 20; root["Age"] = 20;
writer->write(root, &std::cout); writer->write(root, &std::cout);
delete writer;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -1,5 +1,4 @@
#include "json/json.h" #include "json/json.h"
#include <cstdlib>
#include <iostream> #include <iostream>
/** \brief Write a Value object to a string. /** \brief Write a Value object to a string.
* Example Usage: * Example Usage:
@@ -16,7 +15,7 @@
int main() { int main() {
Json::Value root; Json::Value root;
Json::Value data; Json::Value data;
JSONCPP_CONST bool shouldUseOldWay = false; constexpr bool shouldUseOldWay = false;
root["action"] = "run"; root["action"] = "run";
data["number"] = 1; data["number"] = 1;
root["data"] = data; root["data"] = data;

View File

@@ -58,10 +58,4 @@
} \ } \
} while (0) } while (0)
#if JSONCPP_CXX_STD_11
#define JSONCPP_STATIC_ASSERT static_assert
#else
#define JSONCPP_STATIC_ASSERT JSON_ASSERT_MESSAGE
#endif
#endif // JSON_ASSERTIONS_H_INCLUDED #endif // JSON_ASSERTIONS_H_INCLUDED

View File

@@ -5,20 +5,14 @@
#ifndef JSON_CONFIG_H_INCLUDED #ifndef JSON_CONFIG_H_INCLUDED
#define JSON_CONFIG_H_INCLUDED #define JSON_CONFIG_H_INCLUDED
#include <cstddef>
#include <cstdint>
#include <istream> #include <istream>
#include <memory> #include <memory>
#include <ostream> #include <ostream>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <type_traits>
#if JSONCPP_CXX_STD_11
#include <cstddef> // typedef ptrdiff_t
#include <cstdint> // typedef int64_t, uint64_t
#else
#include <stddef.h>
#include <stdint.h>
#endif
// If non-zero, the library uses exceptions to report bad input instead of C // If non-zero, the library uses exceptions to report bad input instead of C
// assertion macros. The default is to use exceptions. // assertion macros. The default is to use exceptions.
@@ -56,6 +50,11 @@
#define JSON_API #define JSON_API
#endif #endif
#if defined(_MSC_VER) && _MSC_VER < 1800
#error \
"ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities"
#endif
#if defined(_MSC_VER) && _MSC_VER < 1900 #if defined(_MSC_VER) && _MSC_VER < 1900
// As recommended at // As recommended at
// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 // https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
@@ -71,41 +70,10 @@ extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
// Storages, and 64 bits integer support is disabled. // Storages, and 64 bits integer support is disabled.
// #define JSON_NO_INT64 1 // #define JSON_NO_INT64 1
#if __cplusplus >= 201103L || defined(_MSC_VER) // JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools.
#define JSONCPP_OP_EXPLICIT explicit // C++11 should be used directly in JSONCPP.
#else
#define JSONCPP_OP_EXPLICIT
#endif
// These Macros are maintained for backwards compatibility of external tools.
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || \
(defined(__GNUC__) && __cplusplus >= 201103L) || \
(defined(__clang__) && __clang_major__ == 3 && __clang_minor__ >= 3)
#define JSONCPP_CXX_STD_11 1
#else
#define JSONCPP_CXX_STD_11 0
#endif
#if JSONCPP_CXX_STD_11
#define JSONCPP_NULL nullptr
#define JSONCPP_CONST constexpr
#define JSONCPP_CTOR_DELETE = delete
#define JSONCPP_NOEXCEPT noexcept
#define JSONCPP_OVERRIDE override #define JSONCPP_OVERRIDE override
#define JSONCPP_MOVE(value) std::move(value)
#else
#define JSONCPP_NULL NULL
#define JSONCPP_CONST const
#define JSONCPP_CTOR_DELETE
#define JSONCPP_NOEXCEPT throw()
#define JSONCPP_OVERRIDE
#define JSONCPP_MOVE(value) value
#endif
// Define *deprecated* attribute
// [[deprecated]] is in C++14 or in Visual Studio 2015 and later
// For compatibility, [[deprecated]] is not used
#ifdef __clang__ #ifdef __clang__
#if __has_extension(attribute_deprecated_with_message) #if __has_extension(attribute_deprecated_with_message)
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message))) #define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
@@ -130,36 +98,33 @@ extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
#endif #endif
#if !defined(JSON_IS_AMALGAMATION) #if !defined(JSON_IS_AMALGAMATION)
#if JSONCPP_CXX_STD_11
#include "allocator.h" #include "allocator.h"
#endif
#include "version.h" #include "version.h"
#endif // if !defined(JSON_IS_AMALGAMATION) #endif // if !defined(JSON_IS_AMALGAMATION)
namespace Json { namespace Json {
using Int = int;
typedef int Int; using UInt = unsigned int;
typedef unsigned int UInt;
#if defined(JSON_NO_INT64) #if defined(JSON_NO_INT64)
typedef int LargestInt; using LargestInt = int;
typedef unsigned int LargestUInt; using LargestUInt = unsigned int;
#undef JSON_HAS_INT64 #undef JSON_HAS_INT64
#else // if defined(JSON_NO_INT64) #else // if defined(JSON_NO_INT64)
// For Microsoft Visual use specific types as long long is not supported // For Microsoft Visual use specific types as long long is not supported
#if defined(_MSC_VER) // Microsoft Visual Studio #if defined(_MSC_VER) // Microsoft Visual Studio
typedef __int64 Int64; using Int64 = __int64;
typedef unsigned __int64 UInt64; using UInt64 = unsigned __int64;
#else // if defined(_MSC_VER) // Other platforms, use long long #else // if defined(_MSC_VER) // Other platforms, use long long
typedef int64_t Int64; using Int64 = int64_t;
typedef uint64_t UInt64; using UInt64 = uint64_t;
#endif // if defined(_MSC_VER) #endif // if defined(_MSC_VER)
typedef Int64 LargestInt; using LargestInt = Int64;
typedef UInt64 LargestUInt; using LargestUInt = UInt64;
#define JSON_HAS_INT64 #define JSON_HAS_INT64
#endif // if defined(JSON_NO_INT64) #endif // if defined(JSON_NO_INT64)
#if JSONCPP_CXX_STD_11
template <typename T> template <typename T>
using Allocator = using Allocator =
typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>, typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>,
@@ -173,20 +138,13 @@ using OStringStream =
String::allocator_type>; String::allocator_type>;
using IStream = std::istream; using IStream = std::istream;
using OStream = std::ostream; using OStream = std::ostream;
#else
typedef std::string String;
typedef std::istringstream IStringStream;
typedef std::ostringstream OStringStream;
typedef std::istream IStream;
typedef std::ostream OStream;
#endif // JSONCPP_CXX_STD_11
} // namespace Json } // namespace Json
// Legacy names (formerly macros). // Legacy names (formerly macros).
typedef Json::String JSONCPP_STRING; using JSONCPP_STRING = Json::String;
typedef Json::IStringStream JSONCPP_ISTRINGSTREAM; using JSONCPP_ISTRINGSTREAM = Json::IStringStream;
typedef Json::OStringStream JSONCPP_OSTRINGSTREAM; using JSONCPP_OSTRINGSTREAM = Json::OStringStream;
typedef Json::IStream JSONCPP_ISTREAM; using JSONCPP_ISTREAM = Json::IStream;
typedef Json::OStream JSONCPP_OSTREAM; using JSONCPP_OSTREAM = Json::OStream;
#endif // JSON_CONFIG_H_INCLUDED #endif // JSON_CONFIG_H_INCLUDED

View File

@@ -29,7 +29,7 @@ class CharReaderBuilder;
class Features; class Features;
// value.h // value.h
typedef unsigned int ArrayIndex; using ArrayIndex = unsigned int;
class StaticString; class StaticString;
class Path; class Path;
class PathArgument; class PathArgument;

View File

@@ -41,17 +41,17 @@ public:
Features(); Features();
/// \c true if comments are allowed. Default: \c true. /// \c true if comments are allowed. Default: \c true.
bool allowComments_; bool allowComments_{true};
/// \c true if root must be either an array or an object value. Default: \c /// \c true if root must be either an array or an object value. Default: \c
/// false. /// false.
bool strictRoot_; bool strictRoot_{false};
/// \c true if dropped null placeholders are allowed. Default: \c false. /// \c true if dropped null placeholders are allowed. Default: \c false.
bool allowDroppedNullPlaceholders_; bool allowDroppedNullPlaceholders_{false};
/// \c true if numeric object key are allowed. Default: \c false. /// \c true if numeric object key are allowed. Default: \c false.
bool allowNumericKeys_; bool allowNumericKeys_{false};
}; };
} // namespace Json } // namespace Json

View File

@@ -36,8 +36,8 @@ namespace Json {
class JSONCPP_DEPRECATED( class JSONCPP_DEPRECATED(
"Use CharReader and CharReaderBuilder instead.") JSON_API Reader { "Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
public: public:
typedef char Char; using Char = char;
typedef const Char* Location; using Location = const Char*;
/** \brief An error tagged with where in the JSON text it was encountered. /** \brief An error tagged with where in the JSON text it was encountered.
* *
@@ -187,7 +187,7 @@ private:
Location extra_; Location extra_;
}; };
typedef std::deque<ErrorInfo> Errors; using Errors = std::deque<ErrorInfo>;
bool readToken(Token& token); bool readToken(Token& token);
void skipSpaces(); void skipSpaces();
@@ -210,8 +210,7 @@ private:
unsigned int& unicode); unsigned int& unicode);
bool decodeUnicodeEscapeSequence(Token& token, Location& current, bool decodeUnicodeEscapeSequence(Token& token, Location& current,
Location end, unsigned int& unicode); Location end, unsigned int& unicode);
bool addError(const String& message, Token& token, bool addError(const String& message, Token& token, Location extra = nullptr);
Location extra = JSONCPP_NULL);
bool recoverFromError(TokenType skipUntilToken); bool recoverFromError(TokenType skipUntilToken);
bool addErrorAndRecover(const String& message, Token& token, bool addErrorAndRecover(const String& message, Token& token,
TokenType skipUntilToken); TokenType skipUntilToken);
@@ -227,25 +226,25 @@ private:
static bool containsNewLine(Location begin, Location end); static bool containsNewLine(Location begin, Location end);
static String normalizeEOL(Location begin, Location end); static String normalizeEOL(Location begin, Location end);
typedef std::stack<Value*> Nodes; using Nodes = std::stack<Value*>;
Nodes nodes_; Nodes nodes_;
Errors errors_; Errors errors_;
String document_; String document_;
Location begin_; Location begin_{};
Location end_; Location end_{};
Location current_; Location current_{};
Location lastValueEnd_; Location lastValueEnd_{};
Value* lastValue_; Value* lastValue_{};
String commentsBefore_; String commentsBefore_;
Features features_; Features features_;
bool collectComments_; bool collectComments_{};
}; // Reader }; // Reader
/** Interface for reading JSON from a char array. /** Interface for reading JSON from a char array.
*/ */
class JSON_API CharReader { class JSON_API CharReader {
public: public:
virtual ~CharReader() {} virtual ~CharReader() = default;
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
* document. The document must be a UTF-8 encoded string containing the * document. The document must be a UTF-8 encoded string containing the
* document to read. * document to read.
@@ -267,7 +266,7 @@ public:
class JSON_API Factory { class JSON_API Factory {
public: public:
virtual ~Factory() {} virtual ~Factory() = default;
/** \brief Allocate a CharReader via operator new(). /** \brief Allocate a CharReader via operator new().
* \throw std::exception if something goes wrong (e.g. invalid settings) * \throw std::exception if something goes wrong (e.g. invalid settings)
*/ */
@@ -333,9 +332,9 @@ public:
Json::Value settings_; Json::Value settings_;
CharReaderBuilder(); CharReaderBuilder();
~CharReaderBuilder() JSONCPP_OVERRIDE; ~CharReaderBuilder() override;
CharReader* newCharReader() const JSONCPP_OVERRIDE; CharReader* newCharReader() const override;
/** \return true if 'settings' are legal and consistent; /** \return true if 'settings' are legal and consistent;
* otherwise, indicate bad settings via 'invalid'. * otherwise, indicate bad settings via 'invalid'.

View File

@@ -13,16 +13,13 @@
// Conditional NORETURN attribute on the throw functions would: // Conditional NORETURN attribute on the throw functions would:
// a) suppress false positives from static code analysis // a) suppress false positives from static code analysis
// b) possibly improve optimization opportunities. // b) possibly improve optimization opportunities.
// For compatibility, [[noreturn]] is not used
#if !defined(JSONCPP_NORETURN) #if !defined(JSONCPP_NORETURN)
#if defined(_MSC_VER) #if defined(_MSC_VER) && _MSC_VER == 1800
#define JSONCPP_NORETURN __declspec(noreturn) #define JSONCPP_NORETURN __declspec(noreturn)
#elif defined(__GNUC__) || defined(__clang__)
#define JSONCPP_NORETURN __attribute__((noreturn))
#else #else
#define JSONCPP_NORETURN #define JSONCPP_NORETURN [[noreturn]]
#endif
#endif #endif
#endif // if !defined(JSONCPP_NORETURN)
// Support for '= delete' with template declarations was a late addition // Support for '= delete' with template declarations was a late addition
// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2 // to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2
@@ -42,15 +39,10 @@
#endif #endif
#endif #endif
#if JSONCPP_CXX_STD_11 #include <array>
#else
#undef JSONCPP_TEMPLATE_DELETE
#define JSONCPP_TEMPLATE_DELETE
#include <string.h>
#endif
#include <exception> #include <exception>
#include <map> #include <map>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -75,8 +67,8 @@ namespace Json {
class JSON_API Exception : public std::exception { class JSON_API Exception : public std::exception {
public: public:
Exception(String msg); Exception(String msg);
~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; ~Exception() noexcept override;
char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; char const* what() const noexcept override;
protected: protected:
String msg_; String msg_;
@@ -154,7 +146,7 @@ enum PrecisionType {
*/ */
class JSON_API StaticString { class JSON_API StaticString {
public: public:
JSONCPP_OP_EXPLICIT StaticString(const char* czstring) : c_str_(czstring) {} explicit StaticString(const char* czstring) : c_str_(czstring) {}
operator const char*() const { return c_str_; } operator const char*() const { return c_str_; }
@@ -202,21 +194,21 @@ class JSON_API Value {
friend class ValueIteratorBase; friend class ValueIteratorBase;
public: public:
typedef std::vector<String> Members; using Members = std::vector<String>;
typedef ValueIterator iterator; using iterator = ValueIterator;
typedef ValueConstIterator const_iterator; using const_iterator = ValueConstIterator;
typedef Json::UInt UInt; using UInt = Json::UInt;
typedef Json::Int Int; using Int = Json::Int;
#if defined(JSON_HAS_INT64) #if defined(JSON_HAS_INT64)
typedef Json::UInt64 UInt64; using UInt64 = Json::UInt64;
typedef Json::Int64 Int64; using Int64 = Json::Int64;
#endif // defined(JSON_HAS_INT64) #endif // defined(JSON_HAS_INT64)
typedef Json::LargestInt LargestInt; using LargestInt = Json::LargestInt;
typedef Json::LargestUInt LargestUInt; using LargestUInt = Json::LargestUInt;
typedef Json::ArrayIndex ArrayIndex; using ArrayIndex = Json::ArrayIndex;
// Required for boost integration, e. g. BOOST_TEST // Required for boost integration, e. g. BOOST_TEST
typedef std::string value_type; using value_type = std::string;
#if JSON_USE_NULLREF #if JSON_USE_NULLREF
// Binary compatibility kludges, do not use. // Binary compatibility kludges, do not use.
@@ -228,35 +220,34 @@ public:
static Value const& nullSingleton(); static Value const& nullSingleton();
/// Minimum signed integer value that can be stored in a Json::Value. /// Minimum signed integer value that can be stored in a Json::Value.
static JSONCPP_CONST LargestInt minLargestInt = static constexpr LargestInt minLargestInt =
LargestInt(~(LargestUInt(-1) / 2)); LargestInt(~(LargestUInt(-1) / 2));
/// Maximum signed integer value that can be stored in a Json::Value. /// Maximum signed integer value that can be stored in a Json::Value.
static JSONCPP_CONST LargestInt maxLargestInt = static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2);
LargestInt(LargestUInt(-1) / 2);
/// Maximum unsigned integer value that can be stored in a Json::Value. /// Maximum unsigned integer value that can be stored in a Json::Value.
static JSONCPP_CONST LargestUInt maxLargestUInt = LargestUInt(-1); static constexpr LargestUInt maxLargestUInt = LargestUInt(-1);
/// Minimum signed int value that can be stored in a Json::Value. /// Minimum signed int value that can be stored in a Json::Value.
static JSONCPP_CONST Int minInt = Int(~(UInt(-1) / 2)); static constexpr Int minInt = Int(~(UInt(-1) / 2));
/// Maximum signed int value that can be stored in a Json::Value. /// Maximum signed int value that can be stored in a Json::Value.
static JSONCPP_CONST Int maxInt = Int(UInt(-1) / 2); static constexpr Int maxInt = Int(UInt(-1) / 2);
/// Maximum unsigned int value that can be stored in a Json::Value. /// Maximum unsigned int value that can be stored in a Json::Value.
static JSONCPP_CONST UInt maxUInt = UInt(-1); static constexpr UInt maxUInt = UInt(-1);
#if defined(JSON_HAS_INT64) #if defined(JSON_HAS_INT64)
/// Minimum signed 64 bits int value that can be stored in a Json::Value. /// Minimum signed 64 bits int value that can be stored in a Json::Value.
static JSONCPP_CONST Int64 minInt64 = Int64(~(UInt64(-1) / 2)); static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2));
/// Maximum signed 64 bits int value that can be stored in a Json::Value. /// Maximum signed 64 bits int value that can be stored in a Json::Value.
static JSONCPP_CONST Int64 maxInt64 = Int64(UInt64(-1) / 2); static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2);
/// Maximum unsigned 64 bits int value that can be stored in a Json::Value. /// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
static JSONCPP_CONST UInt64 maxUInt64 = UInt64(-1); static constexpr UInt64 maxUInt64 = UInt64(-1);
#endif // defined(JSON_HAS_INT64) #endif // defined(JSON_HAS_INT64)
/// Default precision for real value for string representation. /// Default precision for real value for string representation.
static JSONCPP_CONST UInt defaultRealPrecision = 17; static constexpr UInt defaultRealPrecision = 17;
// The constant is hard-coded because some compiler have trouble // The constant is hard-coded because some compiler have trouble
// converting Value::maxUInt64 to a double correctly (AIX/xlC). // converting Value::maxUInt64 to a double correctly (AIX/xlC).
// Assumes that UInt64 is a 64 bits integer. // Assumes that UInt64 is a 64 bits integer.
static JSONCPP_CONST double maxUInt64AsDouble = 18446744073709551615.0; static constexpr double maxUInt64AsDouble = 18446744073709551615.0;
// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler // Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler
// when using gcc and clang backend compilers. CZString // when using gcc and clang backend compilers. CZString
// cannot be defined as private. See issue #486 // cannot be defined as private. See issue #486
@@ -272,14 +263,11 @@ private:
CZString(ArrayIndex index); CZString(ArrayIndex index);
CZString(char const* str, unsigned length, DuplicationPolicy allocate); CZString(char const* str, unsigned length, DuplicationPolicy allocate);
CZString(CZString const& other); CZString(CZString const& other);
#if JSONCPP_CXX_STD_11
CZString(CZString&& other); CZString(CZString&& other);
#endif
~CZString(); ~CZString();
CZString& operator=(const CZString& other); CZString& operator=(const CZString& other);
#if JSONCPP_CXX_STD_11
CZString& operator=(CZString&& other); CZString& operator=(CZString&& other);
#endif
bool operator<(CZString const& other) const; bool operator<(CZString const& other) const;
bool operator==(CZString const& other) const; bool operator==(CZString const& other) const;
ArrayIndex index() const; ArrayIndex index() const;
@@ -355,17 +343,13 @@ public:
Value(const String& value); Value(const String& value);
Value(bool value); Value(bool value);
Value(const Value& other); Value(const Value& other);
#if JSONCPP_CXX_STD_11
Value(Value&& other); Value(Value&& other);
#endif
~Value(); ~Value();
/// \note Overwrite existing comments. To preserve comments, use /// \note Overwrite existing comments. To preserve comments, use
/// #swapPayload(). /// #swapPayload().
Value& operator=(const Value& other); Value& operator=(const Value& other);
#if JSONCPP_CXX_STD_11
Value& operator=(Value&& other); Value& operator=(Value&& other);
#endif
/// Swap everything. /// Swap everything.
void swap(Value& other); void swap(Value& other);
@@ -437,7 +421,7 @@ public:
bool empty() const; bool empty() const;
/// Return !isNull() /// Return !isNull()
JSONCPP_OP_EXPLICIT operator bool() const; explicit operator bool() const;
/// Remove all object members and array elements. /// Remove all object members and array elements.
/// \pre type() is arrayValue, objectValue, or nullValue /// \pre type() is arrayValue, objectValue, or nullValue
@@ -478,15 +462,11 @@ public:
/// ///
/// Equivalent to jsonvalue[jsonvalue.size()] = value; /// Equivalent to jsonvalue[jsonvalue.size()] = value;
Value& append(const Value& value); Value& append(const Value& value);
#if JSONCPP_CXX_STD_11
Value& append(Value&& value); Value& append(Value&& value);
#endif
/// \brief Insert value in array at specific index /// \brief Insert value in array at specific index
bool insert(ArrayIndex index, const Value& newValue); bool insert(ArrayIndex index, const Value& newValue);
#if JSONCPP_CXX_STD_11
bool insert(ArrayIndex index, Value&& newValue); bool insert(ArrayIndex index, Value&& newValue);
#endif
/// Access an object value by name, create a null member if it does not exist. /// Access an object value by name, create a null member if it does not exist.
/// \note Because of our implementation, keys are limited to 2^30 -1 chars. /// \note Because of our implementation, keys are limited to 2^30 -1 chars.
@@ -582,11 +562,15 @@ public:
/// \deprecated Always pass len. /// \deprecated Always pass len.
JSONCPP_DEPRECATED("Use setComment(String const&) instead.") JSONCPP_DEPRECATED("Use setComment(String const&) instead.")
void setComment(const char* comment, CommentPlacement placement); void setComment(const char* comment, CommentPlacement placement) {
setComment(String(comment, strlen(comment)), placement);
}
/// Comments must be //... or /* ... */ /// Comments must be //... or /* ... */
void setComment(const char* comment, size_t len, CommentPlacement placement); void setComment(const char* comment, size_t len, CommentPlacement placement) {
setComment(String(comment, len), placement);
}
/// Comments must be //... or /* ... */ /// Comments must be //... or /* ... */
void setComment(const String& comment, CommentPlacement placement); void setComment(String comment, CommentPlacement placement);
bool hasComment(CommentPlacement placement) const; bool hasComment(CommentPlacement placement) const;
/// Include delimiters and embedded newlines. /// Include delimiters and embedded newlines.
String getComment(CommentPlacement placement) const; String getComment(CommentPlacement placement) const;
@@ -648,15 +632,18 @@ private:
class Comments { class Comments {
public: public:
Comments() {} Comments() = default;
Comments(const Comments& that); Comments(const Comments& that);
Comments(Comments&& that);
Comments& operator=(const Comments& that); Comments& operator=(const Comments& that);
Comments& operator=(Comments&& that);
bool has(CommentPlacement slot) const; bool has(CommentPlacement slot) const;
String get(CommentPlacement slot) const; String get(CommentPlacement slot) const;
void set(CommentPlacement slot, String s); void set(CommentPlacement slot, String comment);
private: private:
String ptr_[numberOfCommentPlacement]; using Array = std::array<String, numberOfCommentPlacement>;
std::unique_ptr<Array> ptr_;
}; };
Comments comments_; Comments comments_;
@@ -711,8 +698,8 @@ public:
private: private:
enum Kind { kindNone = 0, kindIndex, kindKey }; enum Kind { kindNone = 0, kindIndex, kindKey };
String key_; String key_;
ArrayIndex index_; ArrayIndex index_{};
Kind kind_; Kind kind_{kindNone};
}; };
/** \brief Experimental and untested: represents a "path" to access a node. /** \brief Experimental and untested: represents a "path" to access a node.
@@ -741,8 +728,8 @@ public:
Value& make(Value& root) const; Value& make(Value& root) const;
private: private:
typedef std::vector<const PathArgument*> InArgs; using InArgs = std::vector<const PathArgument*>;
typedef std::vector<PathArgument> Args; using Args = std::vector<PathArgument>;
void makePath(const String& path, const InArgs& in); void makePath(const String& path, const InArgs& in);
void addPathInArg(const String& path, const InArgs& in, void addPathInArg(const String& path, const InArgs& in,
@@ -757,10 +744,10 @@ private:
*/ */
class JSON_API ValueIteratorBase { class JSON_API ValueIteratorBase {
public: public:
typedef std::bidirectional_iterator_tag iterator_category; using iterator_category = std::bidirectional_iterator_tag;
typedef unsigned int size_t; using size_t = unsigned int;
typedef int difference_type; using difference_type = int;
typedef ValueIteratorBase SelfType; using SelfType = ValueIteratorBase;
bool operator==(const SelfType& other) const { return isEqual(other); } bool operator==(const SelfType& other) const { return isEqual(other); }
@@ -817,14 +804,13 @@ protected:
private: private:
Value::ObjectValues::iterator current_; Value::ObjectValues::iterator current_;
// Indicates that iterator is for a null value. // Indicates that iterator is for a null value.
bool isNull_; bool isNull_{true};
public: public:
// For some reason, BORLAND needs these at the end, rather // For some reason, BORLAND needs these at the end, rather
// than earlier. No idea why. // than earlier. No idea why.
ValueIteratorBase(); ValueIteratorBase();
JSONCPP_OP_EXPLICIT explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
ValueIteratorBase(const Value::ObjectValues::iterator& current);
}; };
/** \brief const iterator for object and array value. /** \brief const iterator for object and array value.
@@ -834,12 +820,12 @@ class JSON_API ValueConstIterator : public ValueIteratorBase {
friend class Value; friend class Value;
public: public:
typedef const Value value_type; using value_type = const Value;
// typedef unsigned int size_t; // typedef unsigned int size_t;
// typedef int difference_type; // typedef int difference_type;
typedef const Value& reference; using reference = const Value&;
typedef const Value* pointer; using pointer = const Value*;
typedef ValueConstIterator SelfType; using SelfType = ValueConstIterator;
ValueConstIterator(); ValueConstIterator();
ValueConstIterator(ValueIterator const& other); ValueConstIterator(ValueIterator const& other);
@@ -847,8 +833,7 @@ public:
private: private:
/*! \internal Use by Value to create an iterator. /*! \internal Use by Value to create an iterator.
*/ */
JSONCPP_OP_EXPLICIT explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
ValueConstIterator(const Value::ObjectValues::iterator& current);
public: public:
SelfType& operator=(const ValueIteratorBase& other); SelfType& operator=(const ValueIteratorBase& other);
@@ -886,22 +871,21 @@ class JSON_API ValueIterator : public ValueIteratorBase {
friend class Value; friend class Value;
public: public:
typedef Value value_type; using value_type = Value;
typedef unsigned int size_t; using size_t = unsigned int;
typedef int difference_type; using difference_type = int;
typedef Value& reference; using reference = Value&;
typedef Value* pointer; using pointer = Value*;
typedef ValueIterator SelfType; using SelfType = ValueIterator;
ValueIterator(); ValueIterator();
JSONCPP_OP_EXPLICIT ValueIterator(const ValueConstIterator& other); explicit ValueIterator(const ValueConstIterator& other);
ValueIterator(const ValueIterator& other); ValueIterator(const ValueIterator& other);
private: private:
/*! \internal Use by Value to create an iterator. /*! \internal Use by Value to create an iterator.
*/ */
JSONCPP_OP_EXPLICIT explicit ValueIterator(const Value::ObjectValues::iterator& current);
ValueIterator(const Value::ObjectValues::iterator& current);
public: public:
SelfType& operator=(const SelfType& other); SelfType& operator=(const SelfType& other);

View File

@@ -9,10 +9,10 @@
// 3. /CMakeLists.txt // 3. /CMakeLists.txt
// IMPORTANT: also update the SOVERSION!! // IMPORTANT: also update the SOVERSION!!
#define JSONCPP_VERSION_STRING "00.11.0" #define JSONCPP_VERSION_STRING "1.9.3"
#define JSONCPP_VERSION_MAJOR 00 #define JSONCPP_VERSION_MAJOR 1
#define JSONCPP_VERSION_MINOR 11 #define JSONCPP_VERSION_MINOR 9
#define JSONCPP_VERSION_PATCH 0 #define JSONCPP_VERSION_PATCH 3
#define JSONCPP_VERSION_QUALIFIER #define JSONCPP_VERSION_QUALIFIER
#define JSONCPP_VERSION_HEXA \ #define JSONCPP_VERSION_HEXA \
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \

View File

@@ -119,12 +119,12 @@ public:
Json::Value settings_; Json::Value settings_;
StreamWriterBuilder(); StreamWriterBuilder();
~StreamWriterBuilder() JSONCPP_OVERRIDE; ~StreamWriterBuilder() override;
/** /**
* \throw std::exception if something goes wrong (e.g. invalid settings) * \throw std::exception if something goes wrong (e.g. invalid settings)
*/ */
StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; StreamWriter* newStreamWriter() const override;
/** \return true if 'settings' are legal and consistent; /** \return true if 'settings' are legal and consistent;
* otherwise, indicate bad settings via 'invalid'. * otherwise, indicate bad settings via 'invalid'.
@@ -169,7 +169,7 @@ class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter
: public Writer { : public Writer {
public: public:
FastWriter(); FastWriter();
~FastWriter() JSONCPP_OVERRIDE {} ~FastWriter() override = default;
void enableYAMLCompatibility(); void enableYAMLCompatibility();
@@ -183,15 +183,15 @@ public:
void omitEndingLineFeed(); void omitEndingLineFeed();
public: // overridden from Writer public: // overridden from Writer
String write(const Value& root) JSONCPP_OVERRIDE; String write(const Value& root) override;
private: private:
void writeValue(const Value& value); void writeValue(const Value& value);
String document_; String document_;
bool yamlCompatibilityEnabled_; bool yamlCompatibilityEnabled_{false};
bool dropNullPlaceholders_; bool dropNullPlaceholders_{false};
bool omitEndingLineFeed_; bool omitEndingLineFeed_{false};
}; };
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(pop) #pragma warning(pop)
@@ -229,14 +229,14 @@ class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
StyledWriter : public Writer { StyledWriter : public Writer {
public: public:
StyledWriter(); StyledWriter();
~StyledWriter() JSONCPP_OVERRIDE {} ~StyledWriter() override = default;
public: // overridden from Writer public: // overridden from Writer
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param root Value to serialize. * \param root Value to serialize.
* \return String containing the JSON document that represents the root value. * \return String containing the JSON document that represents the root value.
*/ */
String write(const Value& root) JSONCPP_OVERRIDE; String write(const Value& root) override;
private: private:
void writeValue(const Value& value); void writeValue(const Value& value);
@@ -252,14 +252,14 @@ private:
static bool hasCommentForValue(const Value& value); static bool hasCommentForValue(const Value& value);
static String normalizeEOL(const String& text); static String normalizeEOL(const String& text);
typedef std::vector<String> ChildValues; using ChildValues = std::vector<String>;
ChildValues childValues_; ChildValues childValues_;
String document_; String document_;
String indentString_; String indentString_;
unsigned int rightMargin_; unsigned int rightMargin_{74};
unsigned int indentSize_; unsigned int indentSize_{3};
bool addChildValues_; bool addChildValues_{false};
}; };
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(pop) #pragma warning(pop)
@@ -301,7 +301,7 @@ public:
* \param indentation Each level will be indented by this amount extra. * \param indentation Each level will be indented by this amount extra.
*/ */
StyledStreamWriter(String indentation = "\t"); StyledStreamWriter(String indentation = "\t");
~StyledStreamWriter() {} ~StyledStreamWriter() = default;
public: public:
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format. /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
@@ -326,12 +326,12 @@ private:
static bool hasCommentForValue(const Value& value); static bool hasCommentForValue(const Value& value);
static String normalizeEOL(const String& text); static String normalizeEOL(const String& text);
typedef std::vector<String> ChildValues; using ChildValues = std::vector<String>;
ChildValues childValues_; ChildValues childValues_;
OStream* document_; OStream* document_;
String indentString_; String indentString_;
unsigned int rightMargin_; unsigned int rightMargin_{74};
String indentation_; String indentation_;
bool addChildValues_ : 1; bool addChildValues_ : 1;
bool indented_ : 1; bool indented_ : 1;
@@ -348,7 +348,7 @@ String JSON_API valueToString(LargestInt value);
String JSON_API valueToString(LargestUInt value); String JSON_API valueToString(LargestUInt value);
String JSON_API valueToString( String JSON_API valueToString(
double value, unsigned int precision = Value::defaultRealPrecision, double value, unsigned int precision = Value::defaultRealPrecision,
PrecisionType precisionType = significantDigits); PrecisionType precisionType = PrecisionType::significantDigits);
String JSON_API valueToString(bool value); String JSON_API valueToString(bool value);
String JSON_API valueToQuotedString(const char* value); String JSON_API valueToQuotedString(const char* value);

View File

@@ -9,7 +9,7 @@ project(
# 2. /include/json/version.h # 2. /include/json/version.h
# 3. /CMakeLists.txt # 3. /CMakeLists.txt
# IMPORTANT: also update the SOVERSION!! # IMPORTANT: also update the SOVERSION!!
version : '00.11.0', version : '1.9.3',
default_options : [ default_options : [
'buildtype=release', 'buildtype=release',
'cpp_std=c++11', 'cpp_std=c++11',
@@ -50,7 +50,7 @@ jsoncpp_lib = library(
'src/lib_json/json_value.cpp', 'src/lib_json/json_value.cpp',
'src/lib_json/json_writer.cpp', 'src/lib_json/json_writer.cpp',
]), ]),
soversion : 23, soversion : 24,
install : true, install : true,
include_directories : jsoncpp_include_directories, include_directories : jsoncpp_include_directories,
cpp_args: dll_export_flag) cpp_args: dll_export_flag)

View File

@@ -24,9 +24,7 @@ struct Options {
Json::String path; Json::String path;
Json::Features features; Json::Features features;
bool parseOnly; bool parseOnly;
using writeFuncType = Json::String (*)(Json::Value const&);
typedef Json::String (*writeFuncType)(Json::Value const&);
writeFuncType write; writeFuncType write;
}; };
@@ -59,11 +57,11 @@ static Json::String readInputTestFile(const char* path) {
if (!file) if (!file)
return ""; return "";
fseek(file, 0, SEEK_END); fseek(file, 0, SEEK_END);
long const size = ftell(file); auto const size = ftell(file);
size_t const usize = static_cast<size_t>(size); auto const usize = static_cast<size_t>(size);
fseek(file, 0, SEEK_SET); fseek(file, 0, SEEK_SET);
char* buffer = new char[usize + 1]; auto buffer = new char[size + 1];
buffer[usize] = 0; buffer[size] = 0;
Json::String text; Json::String text;
if (fread(buffer, 1, usize, file) == usize) if (fread(buffer, 1, usize, file) == usize)
text = buffer; text = buffer;
@@ -113,9 +111,7 @@ static void printValueTree(FILE* fout, Json::Value& value,
Json::Value::Members members(value.getMemberNames()); Json::Value::Members members(value.getMemberNames());
std::sort(members.begin(), members.end()); std::sort(members.begin(), members.end());
Json::String suffix = *(path.end() - 1) == '.' ? "" : "."; Json::String suffix = *(path.end() - 1) == '.' ? "" : ".";
for (Json::Value::Members::const_iterator it = members.begin(); for (const auto& name : members) {
it != members.end(); it++) {
const Json::String& name = *it;
printValueTree(fout, value[name], path + suffix + name); printValueTree(fout, value[name], path + suffix + name);
} }
} break; } break;
@@ -142,7 +138,7 @@ static int parseAndSaveValueTree(const Json::String& input,
features.allowDroppedNullPlaceholders_; features.allowDroppedNullPlaceholders_;
builder.settings_["allowNumericKeys"] = features.allowNumericKeys_; builder.settings_["allowNumericKeys"] = features.allowNumericKeys_;
Json::CharReader* reader(builder.newCharReader()); std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
Json::String errors; Json::String errors;
const bool parsingSuccessful = const bool parsingSuccessful =
reader->parse(input.data(), input.data() + input.size(), root, &errors); reader->parse(input.data(), input.data() + input.size(), root, &errors);
@@ -152,7 +148,7 @@ static int parseAndSaveValueTree(const Json::String& input,
<< errors << std::endl; << errors << std::endl;
return 1; return 1;
} }
delete reader;
// We may instead check the legacy implementation (to ensure it doesn't // We may instead check the legacy implementation (to ensure it doesn't
// randomly get broken). // randomly get broken).
} else { } else {

View File

@@ -90,7 +90,6 @@ endif()
# Specify compiler features required when compiling a given target. # Specify compiler features required when compiling a given target.
# See https://cmake.org/cmake/help/v3.1/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html#prop_gbl:CMAKE_CXX_KNOWN_FEATURES # See https://cmake.org/cmake/help/v3.1/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html#prop_gbl:CMAKE_CXX_KNOWN_FEATURES
# for complete list of features available # for complete list of features available
if(CMAKE_CXX_STANDARD EQUAL "11")
target_compile_features(jsoncpp_lib PUBLIC target_compile_features(jsoncpp_lib PUBLIC
cxx_std_11 # Compiler mode is aware of C++ 11. cxx_std_11 # Compiler mode is aware of C++ 11.
#MSVC 1900 cxx_alignas # Alignment control alignas, as defined in N2341. #MSVC 1900 cxx_alignas # Alignment control alignas, as defined in N2341.
@@ -137,10 +136,6 @@ target_compile_features(jsoncpp_lib PUBLIC
cxx_variadic_macros # Variadic macros, as defined in N1653. cxx_variadic_macros # Variadic macros, as defined in N1653.
cxx_variadic_templates # Variadic templates, as defined in N2242. cxx_variadic_templates # Variadic templates, as defined in N2242.
) )
else()
set(CMAKE_CXX_STANDARD 98)
target_compile_features(jsoncpp_lib PUBLIC)
endif()
install(TARGETS jsoncpp_lib ${INSTALL_EXPORT} install(TARGETS jsoncpp_lib ${INSTALL_EXPORT}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}

View File

@@ -10,6 +10,7 @@
#include <json/reader.h> #include <json/reader.h>
#include <json/value.h> #include <json/value.h>
#endif // if !defined(JSON_IS_AMALGAMATION) #endif // if !defined(JSON_IS_AMALGAMATION)
#include <algorithm>
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
@@ -51,15 +52,18 @@ static size_t const stackLimit_g =
namespace Json { namespace Json {
typedef CharReader* CharReaderPtr; #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
using CharReaderPtr = std::unique_ptr<CharReader>;
#else
using CharReaderPtr = std::auto_ptr<CharReader>;
#endif
// Implementation of class Features // Implementation of class Features
// //////////////////////////////// // ////////////////////////////////
Features::Features() Features::Features() = default;
: allowComments_(true), strictRoot_(false),
allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} Features Features::all() { return {}; }
Features Features::all() { return Features(); }
Features Features::strictMode() { Features Features::strictMode() {
Features features; Features features;
@@ -74,24 +78,15 @@ Features Features::strictMode() {
// //////////////////////////////// // ////////////////////////////////
bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
for (; begin < end; ++begin) return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
if (*begin == '\n' || *begin == '\r')
return true;
return false;
} }
// Class Reader // Class Reader
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
Reader::Reader() Reader::Reader() : features_(Features::all()) {}
: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
lastValue_(), commentsBefore_(), features_(Features::all()),
collectComments_() {}
Reader::Reader(const Features& features) Reader::Reader(const Features& features) : features_(features) {}
: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
lastValue_(), commentsBefore_(), features_(features), collectComments_() {
}
bool Reader::parse(const std::string& document, Value& root, bool Reader::parse(const std::string& document, Value& root,
bool collectComments) { bool collectComments) {
@@ -124,8 +119,8 @@ bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
end_ = endDoc; end_ = endDoc;
collectComments_ = collectComments; collectComments_ = collectComments;
current_ = begin_; current_ = begin_;
lastValueEnd_ = JSONCPP_NULL; lastValueEnd_ = nullptr;
lastValue_ = JSONCPP_NULL; lastValue_ = nullptr;
commentsBefore_.clear(); commentsBefore_.clear();
errors_.clear(); errors_.clear();
while (!nodes_.empty()) while (!nodes_.empty())
@@ -379,7 +374,7 @@ void Reader::addComment(Location begin, Location end,
assert(collectComments_); assert(collectComments_);
const String& normalized = normalizeEOL(begin, end); const String& normalized = normalizeEOL(begin, end);
if (placement == commentAfterOnSameLine) { if (placement == commentAfterOnSameLine) {
assert(lastValue_ != JSONCPP_NULL); assert(lastValue_ != nullptr);
lastValue_->setComment(normalized, placement); lastValue_->setComment(normalized, placement);
} else { } else {
commentsBefore_ += normalized; commentsBefore_ += normalized;
@@ -568,7 +563,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
Char c = *current++; Char c = *current++;
if (c < '0' || c > '9') if (c < '0' || c > '9')
return decodeDouble(token, decoded); return decodeDouble(token, decoded);
Value::UInt digit(static_cast<Value::UInt>(c - '0')); auto digit(static_cast<Value::UInt>(c - '0'));
if (value >= threshold) { if (value >= threshold) {
// We've hit or exceeded the max value divided by 10 (rounded down). If // We've hit or exceeded the max value divided by 10 (rounded down). If
// a) we've only just touched the limit, b) this is the last digit, and // a) we've only just touched the limit, b) this is the last digit, and
@@ -801,9 +796,7 @@ String Reader::getFormatedErrorMessages() const {
String Reader::getFormattedErrorMessages() const { String Reader::getFormattedErrorMessages() const {
String formattedMessage; String formattedMessage;
for (Errors::const_iterator itError = errors_.begin(); for (const auto& error : errors_) {
itError != errors_.end(); ++itError) {
const ErrorInfo& error = *itError;
formattedMessage += formattedMessage +=
"* " + getLocationLineAndColumn(error.token_.start_) + "\n"; "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
formattedMessage += " " + error.message_ + "\n"; formattedMessage += " " + error.message_ + "\n";
@@ -816,9 +809,7 @@ String Reader::getFormattedErrorMessages() const {
std::vector<Reader::StructuredError> Reader::getStructuredErrors() const { std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
std::vector<Reader::StructuredError> allErrors; std::vector<Reader::StructuredError> allErrors;
for (Errors::const_iterator itError = errors_.begin(); for (const auto& error : errors_) {
itError != errors_.end(); ++itError) {
const ErrorInfo& error = *itError;
Reader::StructuredError structured; Reader::StructuredError structured;
structured.offset_start = error.token_.start_ - begin_; structured.offset_start = error.token_.start_ - begin_;
structured.offset_limit = error.token_.end_ - begin_; structured.offset_limit = error.token_.end_ - begin_;
@@ -839,7 +830,7 @@ bool Reader::pushError(const Value& value, const String& message) {
ErrorInfo info; ErrorInfo info;
info.token_ = token; info.token_ = token;
info.message_ = message; info.message_ = message;
info.extra_ = JSONCPP_NULL; info.extra_ = nullptr;
errors_.push_back(info); errors_.push_back(info);
return true; return true;
} }
@@ -882,7 +873,7 @@ public:
size_t stackLimit_; size_t stackLimit_;
}; // OurFeatures }; // OurFeatures
OurFeatures OurFeatures::all() { return OurFeatures(); } OurFeatures OurFeatures::all() { return {}; }
// Implementation of class Reader // Implementation of class Reader
// //////////////////////////////// // ////////////////////////////////
@@ -891,15 +882,15 @@ OurFeatures OurFeatures::all() { return OurFeatures(); }
// for implementing JSON reading. // for implementing JSON reading.
class OurReader { class OurReader {
public: public:
typedef char Char; using Char = char;
typedef const Char* Location; using Location = const Char*;
struct StructuredError { struct StructuredError {
ptrdiff_t offset_start; ptrdiff_t offset_start;
ptrdiff_t offset_limit; ptrdiff_t offset_limit;
String message; String message;
}; };
JSONCPP_OP_EXPLICIT OurReader(OurFeatures const& features); explicit OurReader(OurFeatures const& features);
bool parse(const char* beginDoc, const char* endDoc, Value& root, bool parse(const char* beginDoc, const char* endDoc, Value& root,
bool collectComments = true); bool collectComments = true);
String getFormattedErrorMessages() const; String getFormattedErrorMessages() const;
@@ -943,7 +934,7 @@ private:
Location extra_; Location extra_;
}; };
typedef std::deque<ErrorInfo> Errors; using Errors = std::deque<ErrorInfo>;
bool readToken(Token& token); bool readToken(Token& token);
void skipSpaces(); void skipSpaces();
@@ -968,8 +959,7 @@ private:
unsigned int& unicode); unsigned int& unicode);
bool decodeUnicodeEscapeSequence(Token& token, Location& current, bool decodeUnicodeEscapeSequence(Token& token, Location& current,
Location end, unsigned int& unicode); Location end, unsigned int& unicode);
bool addError(const String& message, Token& token, bool addError(const String& message, Token& token, Location extra = nullptr);
Location extra = JSONCPP_NULL);
bool recoverFromError(TokenType skipUntilToken); bool recoverFromError(TokenType skipUntilToken);
bool addErrorAndRecover(const String& message, Token& token, bool addErrorAndRecover(const String& message, Token& token,
TokenType skipUntilToken); TokenType skipUntilToken);
@@ -985,38 +975,31 @@ private:
static String normalizeEOL(Location begin, Location end); static String normalizeEOL(Location begin, Location end);
static bool containsNewLine(Location begin, Location end); static bool containsNewLine(Location begin, Location end);
typedef std::stack<Value*> Nodes; using Nodes = std::stack<Value*>;
Nodes nodes_; Nodes nodes_{};
Errors errors_; Errors errors_{};
String document_; String document_{};
Location begin_; Location begin_ = nullptr;
Location end_; Location end_ = nullptr;
Location current_; Location current_ = nullptr;
Location lastValueEnd_; Location lastValueEnd_ = nullptr;
Value* lastValue_; Value* lastValue_ = nullptr;
bool lastValueHasAComment_; bool lastValueHasAComment_ = false;
String commentsBefore_; String commentsBefore_{};
OurFeatures const features_; OurFeatures const features_;
bool collectComments_; bool collectComments_ = false;
}; // OurReader }; // OurReader
// complete copy of Read impl, for OurReader // complete copy of Read impl, for OurReader
bool OurReader::containsNewLine(OurReader::Location begin, bool OurReader::containsNewLine(OurReader::Location begin,
OurReader::Location end) { OurReader::Location end) {
for (; begin < end; ++begin) return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
if (*begin == '\n' || *begin == '\r')
return true;
return false;
} }
OurReader::OurReader(OurFeatures const& features) OurReader::OurReader(OurFeatures const& features) : features_(features) {}
: errors_(), document_(), begin_(JSONCPP_NULL), end_(JSONCPP_NULL),
current_(JSONCPP_NULL), lastValueEnd_(JSONCPP_NULL),
lastValue_(JSONCPP_NULL), lastValueHasAComment_(false), commentsBefore_(),
features_(features), collectComments_(false) {}
bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root, bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
bool collectComments) { bool collectComments) {
@@ -1028,8 +1011,8 @@ bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
end_ = endDoc; end_ = endDoc;
collectComments_ = collectComments; collectComments_ = collectComments;
current_ = begin_; current_ = begin_;
lastValueEnd_ = JSONCPP_NULL; lastValueEnd_ = nullptr;
lastValue_ = JSONCPP_NULL; lastValue_ = nullptr;
commentsBefore_.clear(); commentsBefore_.clear();
errors_.clear(); errors_.clear();
while (!nodes_.empty()) while (!nodes_.empty())
@@ -1287,7 +1270,7 @@ void OurReader::skipSpaces() {
void OurReader::skipBom(bool skipBom) { void OurReader::skipBom(bool skipBom) {
// The default behavior is to skip BOM. // The default behavior is to skip BOM.
if (skipBom) { if (skipBom) {
if (strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) { if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) {
begin_ += 3; begin_ += 3;
current_ = begin_; current_ = begin_;
} }
@@ -1364,7 +1347,7 @@ void OurReader::addComment(Location begin, Location end,
assert(collectComments_); assert(collectComments_);
const String& normalized = normalizeEOL(begin, end); const String& normalized = normalizeEOL(begin, end);
if (placement == commentAfterOnSameLine) { if (placement == commentAfterOnSameLine) {
assert(lastValue_ != JSONCPP_NULL); assert(lastValue_ != nullptr);
lastValue_->setComment(normalized, placement); lastValue_->setComment(normalized, placement);
} else { } else {
commentsBefore_ += normalized; commentsBefore_ += normalized;
@@ -1580,36 +1563,32 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
// We assume we can represent the largest and smallest integer types as // We assume we can represent the largest and smallest integer types as
// unsigned integers with separate sign. This is only true if they can fit // unsigned integers with separate sign. This is only true if they can fit
// into an unsigned integer. // into an unsigned integer.
JSONCPP_STATIC_ASSERT(LargestUInt(Value::maxLargestInt) <= static_assert(Value::maxLargestInt <= Value::maxLargestUInt,
Value::maxLargestUInt, "Int must be smaller than UInt");
"Int must be smaller than Uint");
// We need to convert minLargestInt into a positive number. The easiest way // We need to convert minLargestInt into a positive number. The easiest way
// to do this conversion is to assume our "threshold" value of minLargestInt // to do this conversion is to assume our "threshold" value of minLargestInt
// divided by 10 can fit in maxLargestInt when absolute valued. This should // divided by 10 can fit in maxLargestInt when absolute valued. This should
// be a safe assumption. // be a safe assumption.
JSONCPP_STATIC_ASSERT( static_assert(Value::minLargestInt <= -Value::maxLargestInt,
Value::minLargestInt <= -Value::maxLargestInt, "The absolute value of minLargestInt must be greater than or "
"The absolute value of minLargestInt must ve greater than or"
"equal to maxLargestInt"); "equal to maxLargestInt");
static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt,
"The absolute value of minLargestInt must be only 1 magnitude "
"larger than maxLargest Int");
JSONCPP_STATIC_ASSERT( static constexpr Value::LargestUInt positive_threshold =
Value::minLargestInt / 10 >= -Value::maxLargestInt,
"The absolute value of minLargestInt must be only 1 magnitude"
"larger than maxLargestInt");
static JSONCPP_CONST Value::LargestUInt positive_threshold =
Value::maxLargestUInt / 10; Value::maxLargestUInt / 10;
static JSONCPP_CONST Value::UInt positive_last_digit = static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10;
Value::maxLargestUInt % 10;
// For the negative values, we have to be more careful. Since typically // For the negative values, we have to be more careful. Since typically
// -Value::minLargestInt will cause an overflow, we first divide by 10 and // -Value::minLargestInt will cause an overflow, we first divide by 10 and
// then take the inverse. This assumes that minLargestInt is only a single // then take the inverse. This assumes that minLargestInt is only a single
// power of 10 different in magnitude, which we check above. For the last // power of 10 different in magnitude, which we check above. For the last
// digit, we take the modulus before negating for the same reason. // digit, we take the modulus before negating for the same reason.
static JSONCPP_CONST Value::LargestUInt negative_threshold = static constexpr auto negative_threshold =
Value::LargestUInt(-(Value::minLargestInt / 10)); Value::LargestUInt(-(Value::minLargestInt / 10));
static JSONCPP_CONST Value::UInt negative_last_digit = static constexpr auto negative_last_digit =
Value::UInt(-(Value::minLargestInt % 10)); Value::UInt(-(Value::minLargestInt % 10));
const Value::LargestUInt threshold = const Value::LargestUInt threshold =
@@ -1623,7 +1602,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
if (c < '0' || c > '9') if (c < '0' || c > '9')
return decodeDouble(token, decoded); return decodeDouble(token, decoded);
const Value::UInt digit(static_cast<Value::UInt>(c - '0')); const auto digit(static_cast<Value::UInt>(c - '0'));
if (value >= threshold) { if (value >= threshold) {
// We've hit or exceeded the max value divided by 10 (rounded down). If // We've hit or exceeded the max value divided by 10 (rounded down). If
// a) we've only just touched the limit, meaing value == threshold, // a) we've only just touched the limit, meaing value == threshold,
@@ -1640,7 +1619,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
if (isNegative) { if (isNegative) {
// We use the same magnitude assumption here, just in case. // We use the same magnitude assumption here, just in case.
const Value::UInt last_digit = static_cast<Value::UInt>(value % 10); const auto last_digit = static_cast<Value::UInt>(value % 10);
decoded = -Value::LargestInt(value / 10) * 10 - last_digit; decoded = -Value::LargestInt(value / 10) * 10 - last_digit;
} else if (value <= Value::LargestUInt(Value::maxLargestInt)) { } else if (value <= Value::LargestUInt(Value::maxLargestInt)) {
decoded = Value::LargestInt(value); decoded = Value::LargestInt(value);
@@ -1856,9 +1835,7 @@ String OurReader::getLocationLineAndColumn(Location location) const {
String OurReader::getFormattedErrorMessages() const { String OurReader::getFormattedErrorMessages() const {
String formattedMessage; String formattedMessage;
for (Errors::const_iterator itError = errors_.begin(); for (const auto& error : errors_) {
itError != errors_.end(); ++itError) {
const ErrorInfo& error = *itError;
formattedMessage += formattedMessage +=
"* " + getLocationLineAndColumn(error.token_.start_) + "\n"; "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
formattedMessage += " " + error.message_ + "\n"; formattedMessage += " " + error.message_ + "\n";
@@ -1871,9 +1848,7 @@ String OurReader::getFormattedErrorMessages() const {
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const { std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
std::vector<OurReader::StructuredError> allErrors; std::vector<OurReader::StructuredError> allErrors;
for (Errors::const_iterator itError = errors_.begin(); for (const auto& error : errors_) {
itError != errors_.end(); ++itError) {
const ErrorInfo& error = *itError;
OurReader::StructuredError structured; OurReader::StructuredError structured;
structured.offset_start = error.token_.start_ - begin_; structured.offset_start = error.token_.start_ - begin_;
structured.offset_limit = error.token_.end_ - begin_; structured.offset_limit = error.token_.end_ - begin_;
@@ -1891,7 +1866,7 @@ public:
OurCharReader(bool collectComments, OurFeatures const& features) OurCharReader(bool collectComments, OurFeatures const& features)
: collectComments_(collectComments), reader_(features) {} : collectComments_(collectComments), reader_(features) {}
bool parse(char const* beginDoc, char const* endDoc, Value* root, bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) JSONCPP_OVERRIDE { String* errs) override {
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
if (errs) { if (errs) {
*errs = reader_.getFormattedErrorMessages(); *errs = reader_.getFormattedErrorMessages();
@@ -1901,7 +1876,7 @@ public:
}; };
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
CharReaderBuilder::~CharReaderBuilder() {} CharReaderBuilder::~CharReaderBuilder() = default;
CharReader* CharReaderBuilder::newCharReader() const { CharReader* CharReaderBuilder::newCharReader() const {
bool collectComments = settings_["collectComments"].asBool(); bool collectComments = settings_["collectComments"].asBool();
OurFeatures features = OurFeatures::all(); OurFeatures features = OurFeatures::all();
@@ -1922,38 +1897,34 @@ CharReader* CharReaderBuilder::newCharReader() const {
features.skipBom_ = settings_["skipBom"].asBool(); features.skipBom_ = settings_["skipBom"].asBool();
return new OurCharReader(collectComments, features); return new OurCharReader(collectComments, features);
} }
static void getValidReaderKeys(std::set<String>* valid_keys) {
valid_keys->clear();
valid_keys->insert("collectComments");
valid_keys->insert("allowComments");
valid_keys->insert("allowTrailingCommas");
valid_keys->insert("strictRoot");
valid_keys->insert("allowDroppedNullPlaceholders");
valid_keys->insert("allowNumericKeys");
valid_keys->insert("allowSingleQuotes");
valid_keys->insert("stackLimit");
valid_keys->insert("failIfExtra");
valid_keys->insert("rejectDupKeys");
valid_keys->insert("allowSpecialFloats");
valid_keys->insert("skipBom");
}
bool CharReaderBuilder::validate(Json::Value* invalid) const { bool CharReaderBuilder::validate(Json::Value* invalid) const {
Json::Value my_invalid; static const auto& valid_keys = *new std::set<String>{
if (!invalid) "collectComments",
invalid = &my_invalid; // so we do not need to test for NULL "allowComments",
Json::Value& inv = *invalid; "allowTrailingCommas",
std::set<String> valid_keys; "strictRoot",
getValidReaderKeys(&valid_keys); "allowDroppedNullPlaceholders",
Value::Members keys = settings_.getMemberNames(); "allowNumericKeys",
size_t n = keys.size(); "allowSingleQuotes",
for (size_t i = 0; i < n; ++i) { "stackLimit",
String const& key = keys[i]; "failIfExtra",
if (valid_keys.find(key) == valid_keys.end()) { "rejectDupKeys",
inv[key] = settings_[key]; "allowSpecialFloats",
"skipBom",
};
for (auto si = settings_.begin(); si != settings_.end(); ++si) {
auto key = si.name();
if (valid_keys.count(key))
continue;
if (invalid)
(*invalid)[std::move(key)] = *si;
else
return false;
} }
} return invalid ? invalid->empty() : true;
return inv.empty();
} }
Value& CharReaderBuilder::operator[](const String& key) { Value& CharReaderBuilder::operator[](const String& key) {
return settings_[key]; return settings_[key];
} }
@@ -2003,9 +1974,7 @@ bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,
char const* end = begin + doc.size(); char const* end = begin + doc.size();
// Note that we do not actually need a null-terminator. // Note that we do not actually need a null-terminator.
CharReaderPtr const reader(fact.newCharReader()); CharReaderPtr const reader(fact.newCharReader());
bool ret = reader->parse(begin, end, root, errs); return reader->parse(begin, end, root, errs);
delete reader;
return ret;
} }
IStream& operator>>(IStream& sin, Value& root) { IStream& operator>>(IStream& sin, Value& root) {

View File

@@ -71,7 +71,7 @@ enum {
}; };
// Defines a char buffer for use with uintToString(). // Defines a char buffer for use with uintToString().
typedef char UIntToStringBuffer[uintToStringBufferSize]; using UIntToStringBuffer = char[uintToStringBufferSize];
/** Converts an unsigned integer to string. /** Converts an unsigned integer to string.
* @param value Unsigned integer to convert to string * @param value Unsigned integer to convert to string

View File

@@ -48,6 +48,14 @@ int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
#define JSON_ASSERT_UNREACHABLE assert(false) #define JSON_ASSERT_UNREACHABLE assert(false)
namespace Json { namespace Json {
template <typename T>
static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {
std::unique_ptr<T> r;
if (p) {
r = std::unique_ptr<T>(new T(*p));
}
return r;
}
// This is a walkaround to avoid the static initialization of Value::null. // This is a walkaround to avoid the static initialization of Value::null.
// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of // kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
@@ -110,8 +118,8 @@ static inline char* duplicateStringValue(const char* value, size_t length) {
if (length >= static_cast<size_t>(Value::maxInt)) if (length >= static_cast<size_t>(Value::maxInt))
length = Value::maxInt - 1; length = Value::maxInt - 1;
char* newString = static_cast<char*>(malloc(length + 1)); auto newString = static_cast<char*>(malloc(length + 1));
if (newString == JSONCPP_NULL) { if (newString == nullptr) {
throwRuntimeError("in Json::Value::duplicateStringValue(): " throwRuntimeError("in Json::Value::duplicateStringValue(): "
"Failed to allocate string value buffer"); "Failed to allocate string value buffer");
} }
@@ -131,8 +139,8 @@ static inline char* duplicateAndPrefixStringValue(const char* value,
"in Json::Value::duplicateAndPrefixStringValue(): " "in Json::Value::duplicateAndPrefixStringValue(): "
"length too big for prefixing"); "length too big for prefixing");
size_t actualLength = sizeof(length) + length + 1; size_t actualLength = sizeof(length) + length + 1;
char* newString = static_cast<char*>(malloc(actualLength)); auto newString = static_cast<char*>(malloc(actualLength));
if (newString == JSONCPP_NULL) { if (newString == nullptr) {
throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): " throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
"Failed to allocate string value buffer"); "Failed to allocate string value buffer");
} }
@@ -192,9 +200,9 @@ static inline void releaseStringValue(char* value, unsigned) { free(value); }
namespace Json { namespace Json {
#if JSON_USE_EXCEPTION #if JSON_USE_EXCEPTION
Exception::Exception(String msg) : msg_(JSONCPP_MOVE(msg)) {} Exception::Exception(String msg) : msg_(std::move(msg)) {}
Exception::~Exception() JSONCPP_NOEXCEPT {} Exception::~Exception() noexcept = default;
char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); } char const* Exception::what() const noexcept { return msg_.c_str(); }
RuntimeError::RuntimeError(String const& msg) : Exception(msg) {} RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
LogicError::LogicError(String const& msg) : Exception(msg) {} LogicError::LogicError(String const& msg) : Exception(msg) {}
JSONCPP_NORETURN void throwRuntimeError(String const& msg) { JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
@@ -225,8 +233,7 @@ JSONCPP_NORETURN void throwLogicError(String const& msg) {
// Notes: policy_ indicates if the string was allocated when // Notes: policy_ indicates if the string was allocated when
// a string is stored. // a string is stored.
Value::CZString::CZString(ArrayIndex index) Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {}
: cstr_(JSONCPP_NULL), index_(index) {}
Value::CZString::CZString(char const* str, unsigned length, Value::CZString::CZString(char const* str, unsigned length,
DuplicationPolicy allocate) DuplicationPolicy allocate)
@@ -237,8 +244,7 @@ Value::CZString::CZString(char const* str, unsigned length,
} }
Value::CZString::CZString(const CZString& other) { Value::CZString::CZString(const CZString& other) {
cstr_ = cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr
(other.storage_.policy_ != noDuplication && other.cstr_ != JSONCPP_NULL
? duplicateStringValue(other.cstr_, other.storage_.length_) ? duplicateStringValue(other.cstr_, other.storage_.length_)
: other.cstr_); : other.cstr_);
storage_.policy_ = storage_.policy_ =
@@ -252,12 +258,12 @@ Value::CZString::CZString(const CZString& other) {
3U; 3U;
storage_.length_ = other.storage_.length_; storage_.length_ = other.storage_.length_;
} }
#if JSONCPP_CXX_STD_11
Value::CZString::CZString(CZString&& other) Value::CZString::CZString(CZString&& other)
: cstr_(other.cstr_), index_(other.index_) { : cstr_(other.cstr_), index_(other.index_) {
other.cstr_ = JSONCPP_NULL; other.cstr_ = nullptr;
} }
#endif
Value::CZString::~CZString() { Value::CZString::~CZString() {
if (cstr_ && storage_.policy_ == duplicate) { if (cstr_ && storage_.policy_ == duplicate) {
releaseStringValue(const_cast<char*>(cstr_), releaseStringValue(const_cast<char*>(cstr_),
@@ -278,14 +284,14 @@ Value::CZString& Value::CZString::operator=(const CZString& other) {
index_ = other.index_; index_ = other.index_;
return *this; return *this;
} }
#if JSONCPP_CXX_STD_11
Value::CZString& Value::CZString::operator=(CZString&& other) { Value::CZString& Value::CZString::operator=(CZString&& other) {
cstr_ = other.cstr_; cstr_ = other.cstr_;
index_ = other.index_; index_ = other.index_;
other.cstr_ = JSONCPP_NULL; other.cstr_ = nullptr;
return *this; return *this;
} }
#endif
bool Value::CZString::operator<(const CZString& other) const { bool Value::CZString::operator<(const CZString& other) const {
if (!cstr_) if (!cstr_)
return index_ < other.index_; return index_ < other.index_;
@@ -394,7 +400,7 @@ Value::Value(double value) {
Value::Value(const char* value) { Value::Value(const char* value) {
initBasic(stringValue, true); initBasic(stringValue, true);
JSON_ASSERT_MESSAGE(value != JSONCPP_NULL, JSON_ASSERT_MESSAGE(value != nullptr,
"Null Value Passed to Value Constructor"); "Null Value Passed to Value Constructor");
value_.string_ = duplicateAndPrefixStringValue( value_.string_ = duplicateAndPrefixStringValue(
value, static_cast<unsigned>(strlen(value))); value, static_cast<unsigned>(strlen(value)));
@@ -426,12 +432,11 @@ Value::Value(const Value& other) {
dupPayload(other); dupPayload(other);
dupMeta(other); dupMeta(other);
} }
#if JSONCPP_CXX_STD_11
Value::Value(Value&& other) { Value::Value(Value&& other) {
initBasic(nullValue); initBasic(nullValue);
swap(other); swap(other);
} }
#endif
Value::~Value() { Value::~Value() {
releasePayload(); releasePayload();
@@ -442,12 +447,11 @@ Value& Value::operator=(const Value& other) {
Value(other).swap(*this); Value(other).swap(*this);
return *this; return *this;
} }
#if JSONCPP_CXX_STD_11
Value& Value::operator=(Value&& other) { Value& Value::operator=(Value&& other) {
other.swap(*this); other.swap(*this);
return *this; return *this;
} }
#endif
void Value::swapPayload(Value& other) { void Value::swapPayload(Value& other) {
std::swap(bits_, other.bits_); std::swap(bits_, other.bits_);
@@ -499,9 +503,8 @@ bool Value::operator<(const Value& other) const {
case booleanValue: case booleanValue:
return value_.bool_ < other.value_.bool_; return value_.bool_ < other.value_.bool_;
case stringValue: { case stringValue: {
if ((value_.string_ == JSONCPP_NULL) || if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
(other.value_.string_ == JSONCPP_NULL)) { return other.value_.string_ != nullptr;
return other.value_.string_ != JSONCPP_NULL;
} }
unsigned this_len; unsigned this_len;
unsigned other_len; unsigned other_len;
@@ -522,8 +525,8 @@ bool Value::operator<(const Value& other) const {
} }
case arrayValue: case arrayValue:
case objectValue: { case objectValue: {
long unsigned int thisSize = value_.map_->size(); auto thisSize = value_.map_->size();
long unsigned int otherSize = other.value_.map_->size(); auto otherSize = other.value_.map_->size();
if (thisSize != otherSize) if (thisSize != otherSize)
return thisSize < otherSize; return thisSize < otherSize;
return (*value_.map_) < (*other.value_.map_); return (*value_.map_) < (*other.value_.map_);
@@ -555,8 +558,7 @@ bool Value::operator==(const Value& other) const {
case booleanValue: case booleanValue:
return value_.bool_ == other.value_.bool_; return value_.bool_ == other.value_.bool_;
case stringValue: { case stringValue: {
if ((value_.string_ == JSONCPP_NULL) || if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
(other.value_.string_ == JSONCPP_NULL)) {
return (value_.string_ == other.value_.string_); return (value_.string_ == other.value_.string_);
} }
unsigned this_len; unsigned this_len;
@@ -588,8 +590,8 @@ bool Value::operator!=(const Value& other) const { return !(*this == other); }
const char* Value::asCString() const { const char* Value::asCString() const {
JSON_ASSERT_MESSAGE(type() == stringValue, JSON_ASSERT_MESSAGE(type() == stringValue,
"in Json::Value::asCString(): requires stringValue"); "in Json::Value::asCString(): requires stringValue");
if (value_.string_ == JSONCPP_NULL) if (value_.string_ == nullptr)
return JSONCPP_NULL; return nullptr;
unsigned this_len; unsigned this_len;
char const* this_str; char const* this_str;
decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
@@ -614,7 +616,7 @@ unsigned Value::getCStringLength() const {
bool Value::getString(char const** begin, char const** end) const { bool Value::getString(char const** begin, char const** end) const {
if (type() != stringValue) if (type() != stringValue)
return false; return false;
if (value_.string_ == JSONCPP_NULL) if (value_.string_ == nullptr)
return false; return false;
unsigned length; unsigned length;
decodePrefixedString(this->isAllocated(), this->value_.string_, &length, decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
@@ -628,7 +630,7 @@ String Value::asString() const {
case nullValue: case nullValue:
return ""; return "";
case stringValue: { case stringValue: {
if (value_.string_ == JSONCPP_NULL) if (value_.string_ == nullptr)
return ""; return "";
unsigned this_len; unsigned this_len;
char const* this_str; char const* this_str;
@@ -811,7 +813,7 @@ bool Value::asBool() const {
return value_.uint_ != 0; return value_.uint_ != 0;
case realValue: { case realValue: {
// According to JavaScript language zero or NaN is regarded as false // According to JavaScript language zero or NaN is regarded as false
const int value_classification = std::fpclassify(value_.real_); const auto value_classification = std::fpclassify(value_.real_);
return value_classification != FP_ZERO && value_classification != FP_NAN; return value_classification != FP_ZERO && value_classification != FP_NAN;
} }
default: default:
@@ -926,7 +928,7 @@ Value& Value::operator[](ArrayIndex index) {
if (type() == nullValue) if (type() == nullValue)
*this = Value(arrayValue); *this = Value(arrayValue);
CZString key(index); CZString key(index);
ObjectValues::iterator it = value_.map_->lower_bound(key); auto it = value_.map_->lower_bound(key);
if (it != value_.map_->end() && (*it).first == key) if (it != value_.map_->end() && (*it).first == key)
return (*it).second; return (*it).second;
@@ -965,7 +967,7 @@ const Value& Value::operator[](int index) const {
void Value::initBasic(ValueType type, bool allocated) { void Value::initBasic(ValueType type, bool allocated) {
setType(type); setType(type);
setIsAllocated(allocated); setIsAllocated(allocated);
comments_ = Comments(); comments_ = Comments{};
start_ = 0; start_ = 0;
limit_ = 0; limit_ = 0;
} }
@@ -1040,7 +1042,7 @@ Value& Value::resolveReference(const char* key) {
*this = Value(objectValue); *this = Value(objectValue);
CZString actualKey(key, static_cast<unsigned>(strlen(key)), CZString actualKey(key, static_cast<unsigned>(strlen(key)),
CZString::noDuplication); // NOTE! CZString::noDuplication); // NOTE!
ObjectValues::iterator it = value_.map_->lower_bound(actualKey); auto it = value_.map_->lower_bound(actualKey);
if (it != value_.map_->end() && (*it).first == actualKey) if (it != value_.map_->end() && (*it).first == actualKey)
return (*it).second; return (*it).second;
@@ -1059,7 +1061,7 @@ Value& Value::resolveReference(char const* key, char const* end) {
*this = Value(objectValue); *this = Value(objectValue);
CZString actualKey(key, static_cast<unsigned>(end - key), CZString actualKey(key, static_cast<unsigned>(end - key),
CZString::duplicateOnCopy); CZString::duplicateOnCopy);
ObjectValues::iterator it = value_.map_->lower_bound(actualKey); auto it = value_.map_->lower_bound(actualKey);
if (it != value_.map_->end() && (*it).first == actualKey) if (it != value_.map_->end() && (*it).first == actualKey)
return (*it).second; return (*it).second;
@@ -1081,12 +1083,12 @@ Value const* Value::find(char const* begin, char const* end) const {
"in Json::Value::find(begin, end): requires " "in Json::Value::find(begin, end): requires "
"objectValue or nullValue"); "objectValue or nullValue");
if (type() == nullValue) if (type() == nullValue)
return JSONCPP_NULL; return nullptr;
CZString actualKey(begin, static_cast<unsigned>(end - begin), CZString actualKey(begin, static_cast<unsigned>(end - begin),
CZString::noDuplication); CZString::noDuplication);
ObjectValues::const_iterator it = value_.map_->find(actualKey); ObjectValues::const_iterator it = value_.map_->find(actualKey);
if (it == value_.map_->end()) if (it == value_.map_->end())
return JSONCPP_NULL; return nullptr;
return &(*it).second; return &(*it).second;
} }
Value* Value::demand(char const* begin, char const* end) { Value* Value::demand(char const* begin, char const* end) {
@@ -1120,8 +1122,8 @@ Value& Value::operator[](const StaticString& key) {
return resolveReference(key.c_str()); return resolveReference(key.c_str());
} }
#if JSONCPP_CXX_STD_11
Value& Value::append(const Value& value) { return append(Value(value)); } Value& Value::append(const Value& value) { return append(Value(value)); }
Value& Value::append(Value&& value) { Value& Value::append(Value&& value) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
"in Json::Value::append: requires arrayValue"); "in Json::Value::append: requires arrayValue");
@@ -1130,19 +1132,12 @@ Value& Value::append(Value&& value) {
} }
return this->value_.map_->emplace(size(), std::move(value)).first->second; return this->value_.map_->emplace(size(), std::move(value)).first->second;
} }
#else
Value& Value::append(const Value& value) { return (*this)[size()] = value; }
#endif
#if JSONCPP_CXX_STD_11
bool Value::insert(ArrayIndex index, const Value& newValue) { bool Value::insert(ArrayIndex index, const Value& newValue) {
return insert(index, Value(newValue)); return insert(index, Value(newValue));
} }
bool Value::insert(ArrayIndex index, Value&& newValue) { bool Value::insert(ArrayIndex index, Value&& newValue) {
#else
bool Value::insert(ArrayIndex index, const Value& newValue) {
#endif
JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
"in Json::Value::insert: requires arrayValue"); "in Json::Value::insert: requires arrayValue");
ArrayIndex length = size(); ArrayIndex length = size();
@@ -1150,11 +1145,12 @@ bool Value::insert(ArrayIndex index, const Value& newValue) {
return false; return false;
} }
for (ArrayIndex i = length; i > index; i--) { for (ArrayIndex i = length; i > index; i--) {
(*this)[i] = JSONCPP_MOVE((*this)[i - 1]); (*this)[i] = std::move((*this)[i - 1]);
} }
(*this)[index] = JSONCPP_MOVE(newValue); (*this)[index] = std::move(newValue);
return true; return true;
} }
Value Value::get(char const* begin, char const* end, Value Value::get(char const* begin, char const* end,
Value const& defaultValue) const { Value const& defaultValue) const {
Value const* found = find(begin, end); Value const* found = find(begin, end);
@@ -1173,11 +1169,11 @@ bool Value::removeMember(const char* begin, const char* end, Value* removed) {
} }
CZString actualKey(begin, static_cast<unsigned>(end - begin), CZString actualKey(begin, static_cast<unsigned>(end - begin),
CZString::noDuplication); CZString::noDuplication);
ObjectValues::iterator it = value_.map_->find(actualKey); auto it = value_.map_->find(actualKey);
if (it == value_.map_->end()) if (it == value_.map_->end())
return false; return false;
if (removed) if (removed)
*removed = JSONCPP_MOVE(it->second); *removed = std::move(it->second);
value_.map_->erase(it); value_.map_->erase(it);
return true; return true;
} }
@@ -1203,7 +1199,7 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
return false; return false;
} }
CZString key(index); CZString key(index);
ObjectValues::iterator it = value_.map_->find(key); auto it = value_.map_->find(key);
if (it == value_.map_->end()) { if (it == value_.map_->end()) {
return false; return false;
} }
@@ -1217,14 +1213,14 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
} }
// erase the last one ("leftover") // erase the last one ("leftover")
CZString keyLast(oldSize - 1); CZString keyLast(oldSize - 1);
ObjectValues::iterator itLast = value_.map_->find(keyLast); auto itLast = value_.map_->find(keyLast);
value_.map_->erase(itLast); value_.map_->erase(itLast);
return true; return true;
} }
bool Value::isMember(char const* begin, char const* end) const { bool Value::isMember(char const* begin, char const* end) const {
Value const* value = find(begin, end); Value const* value = find(begin, end);
return JSONCPP_NULL != value; return nullptr != value;
} }
bool Value::isMember(char const* key) const { bool Value::isMember(char const* key) const {
return isMember(key, key + strlen(key)); return isMember(key, key + strlen(key));
@@ -1374,44 +1370,53 @@ bool Value::isArray() const { return type() == arrayValue; }
bool Value::isObject() const { return type() == objectValue; } bool Value::isObject() const { return type() == objectValue; }
Value::Comments::Comments(const Comments& that) { Value::Comments::Comments(const Comments& that)
for (size_t i = 0; i < numberOfCommentPlacement; i++) { : ptr_{cloneUnique(that.ptr_)} {}
ptr_[i] = that.ptr_[i];
} Value::Comments::Comments(Comments&& that) : ptr_{std::move(that.ptr_)} {}
}
Value::Comments& Value::Comments::operator=(const Comments& that) { Value::Comments& Value::Comments::operator=(const Comments& that) {
for (size_t i = 0; i < numberOfCommentPlacement; i++) { ptr_ = cloneUnique(that.ptr_);
ptr_[i] = that.ptr_[i];
}
return *this; return *this;
} }
bool Value::Comments::has(CommentPlacement slot) const {
return !ptr_[slot].empty(); Value::Comments& Value::Comments::operator=(Comments&& that) {
ptr_ = std::move(that.ptr_);
return *this;
} }
String Value::Comments::get(CommentPlacement slot) const { return ptr_[slot]; } bool Value::Comments::has(CommentPlacement slot) const {
return ptr_ && !(*ptr_)[slot].empty();
}
String Value::Comments::get(CommentPlacement slot) const {
if (!ptr_)
return {};
return (*ptr_)[slot];
}
void Value::Comments::set(CommentPlacement slot, String comment) { void Value::Comments::set(CommentPlacement slot, String comment) {
if (!ptr_) {
ptr_ = std::unique_ptr<Array>(new Array());
}
// check comments array boundry. // check comments array boundry.
if (slot < numberOfCommentPlacement) { if (slot < CommentPlacement::numberOfCommentPlacement) {
ptr_[slot] = comment; (*ptr_)[slot] = std::move(comment);
} }
} }
void Value::setComment(const char* comment, CommentPlacement placement) { void Value::setComment(String comment, CommentPlacement placement) {
setComment(comment, strlen(comment), placement); if (!comment.empty() && (comment.back() == '\n')) {
}
void Value::setComment(const char* comment, size_t len,
CommentPlacement placement) {
if ((len > 0) && (comment[len - 1] == '\n')) {
// Always discard trailing newline, to aid indentation. // Always discard trailing newline, to aid indentation.
len -= 1; comment.pop_back();
} }
comments_.set(placement, String(comment, len)); JSON_ASSERT(!comment.empty());
} JSON_ASSERT_MESSAGE(
void Value::setComment(const String& comment, CommentPlacement placement) { comment[0] == '\0' || comment[0] == '/',
setComment(comment.c_str(), comment.length(), placement); "in Json::Value::setComment(): Comments must start with /");
comments_.set(placement, std::move(comment));
} }
bool Value::hasComment(CommentPlacement placement) const { bool Value::hasComment(CommentPlacement placement) const {
return comments_.has(placement); return comments_.has(placement);
} }
@@ -1448,7 +1453,7 @@ Value::const_iterator Value::begin() const {
default: default:
break; break;
} }
return const_iterator(); return {};
} }
Value::const_iterator Value::end() const { Value::const_iterator Value::end() const {
@@ -1461,7 +1466,7 @@ Value::const_iterator Value::end() const {
default: default:
break; break;
} }
return const_iterator(); return {};
} }
Value::iterator Value::begin() { Value::iterator Value::begin() {
@@ -1493,15 +1498,14 @@ Value::iterator Value::end() {
// class PathArgument // class PathArgument
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
PathArgument::PathArgument() {} PathArgument::PathArgument() = default;
PathArgument::PathArgument(ArrayIndex index) PathArgument::PathArgument(ArrayIndex index)
: index_(index), kind_(kindIndex) {} : index_(index), kind_(kindIndex) {}
PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {} PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {}
PathArgument::PathArgument(String key) PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {}
: key_(JSONCPP_MOVE(key)), kind_(kindKey) {}
// class Path // class Path
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
@@ -1522,7 +1526,7 @@ Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2,
void Path::makePath(const String& path, const InArgs& in) { void Path::makePath(const String& path, const InArgs& in) {
const char* current = path.c_str(); const char* current = path.c_str();
const char* end = current + path.length(); const char* end = current + path.length();
InArgs::const_iterator itInArg = in.begin(); auto itInArg = in.begin();
while (current != end) { while (current != end) {
if (*current == '[') { if (*current == '[') {
++current; ++current;
@@ -1568,9 +1572,7 @@ void Path::invalidPath(const String& /*path*/, int /*location*/) {
const Value& Path::resolve(const Value& root) const { const Value& Path::resolve(const Value& root) const {
const Value* node = &root; const Value* node = &root;
for (Args::const_iterator itArg = args_.begin(); itArg != args_.end(); for (const auto& arg : args_) {
++itArg) {
const PathArgument& arg = *itArg;
if (arg.kind_ == PathArgument::kindIndex) { if (arg.kind_ == PathArgument::kindIndex) {
if (!node->isArray() || !node->isValidIndex(arg.index_)) { if (!node->isArray() || !node->isValidIndex(arg.index_)) {
// Error: unable to resolve path (array value expected at position... ) // Error: unable to resolve path (array value expected at position... )
@@ -1595,9 +1597,7 @@ const Value& Path::resolve(const Value& root) const {
Value Path::resolve(const Value& root, const Value& defaultValue) const { Value Path::resolve(const Value& root, const Value& defaultValue) const {
const Value* node = &root; const Value* node = &root;
for (Args::const_iterator itArg = args_.begin(); itArg != args_.end(); for (const auto& arg : args_) {
++itArg) {
const PathArgument& arg = *itArg;
if (arg.kind_ == PathArgument::kindIndex) { if (arg.kind_ == PathArgument::kindIndex) {
if (!node->isArray() || !node->isValidIndex(arg.index_)) if (!node->isArray() || !node->isValidIndex(arg.index_))
return defaultValue; return defaultValue;
@@ -1615,9 +1615,7 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const {
Value& Path::make(Value& root) const { Value& Path::make(Value& root) const {
Value* node = &root; Value* node = &root;
for (Args::const_iterator itArg = args_.begin(); itArg != args_.end(); for (const auto& arg : args_) {
++itArg) {
const PathArgument& arg = *itArg;
if (arg.kind_ == PathArgument::kindIndex) { if (arg.kind_ == PathArgument::kindIndex) {
if (!node->isArray()) { if (!node->isArray()) {
// Error: node is not an array at position ... // Error: node is not an array at position ...

View File

@@ -15,7 +15,7 @@ namespace Json {
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
ValueIteratorBase::ValueIteratorBase() : current_(), isNull_(true) {} ValueIteratorBase::ValueIteratorBase() : current_() {}
ValueIteratorBase::ValueIteratorBase( ValueIteratorBase::ValueIteratorBase(
const Value::ObjectValues::iterator& current) const Value::ObjectValues::iterator& current)
@@ -98,8 +98,8 @@ char const* ValueIteratorBase::memberName() const {
char const* ValueIteratorBase::memberName(char const** end) const { char const* ValueIteratorBase::memberName(char const** end) const {
const char* cname = (*current_).first.data(); const char* cname = (*current_).first.data();
if (!cname) { if (!cname) {
*end = JSONCPP_NULL; *end = nullptr;
return JSONCPP_NULL; return nullptr;
} }
*end = cname + (*current_).first.length(); *end = cname + (*current_).first.length();
return cname; return cname;
@@ -113,7 +113,7 @@ char const* ValueIteratorBase::memberName(char const** end) const {
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
ValueConstIterator::ValueConstIterator() {} ValueConstIterator::ValueConstIterator() = default;
ValueConstIterator::ValueConstIterator( ValueConstIterator::ValueConstIterator(
const Value::ObjectValues::iterator& current) const Value::ObjectValues::iterator& current)
@@ -136,7 +136,7 @@ operator=(const ValueIteratorBase& other) {
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
ValueIterator::ValueIterator() {} ValueIterator::ValueIterator() = default;
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
: ValueIteratorBase(current) {} : ValueIteratorBase(current) {}
@@ -146,8 +146,7 @@ ValueIterator::ValueIterator(const ValueConstIterator& other)
throwRuntimeError("ConstIterator to Iterator should never be allowed."); throwRuntimeError("ConstIterator to Iterator should never be allowed.");
} }
ValueIterator::ValueIterator(const ValueIterator& other) ValueIterator::ValueIterator(const ValueIterator& other) = default;
: ValueIteratorBase(other) {}
ValueIterator& ValueIterator::operator=(const SelfType& other) { ValueIterator& ValueIterator::operator=(const SelfType& other) {
copy(other); copy(other);

View File

@@ -7,7 +7,9 @@
#include "json_tool.h" #include "json_tool.h"
#include <json/writer.h> #include <json/writer.h>
#endif // if !defined(JSON_IS_AMALGAMATION) #endif // if !defined(JSON_IS_AMALGAMATION)
#include <algorithm>
#include <cassert> #include <cassert>
#include <cctype>
#include <cstring> #include <cstring>
#include <iomanip> #include <iomanip>
#include <memory> #include <memory>
@@ -83,7 +85,11 @@
namespace Json { namespace Json {
typedef StreamWriter* StreamWriterPtr; #if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
using StreamWriterPtr = std::unique_ptr<StreamWriter>;
#else
using StreamWriterPtr = std::auto_ptr<StreamWriter>;
#endif
String valueToString(LargestInt value) { String valueToString(LargestInt value) {
UIntToStringBuffer buffer; UIntToStringBuffer buffer;
@@ -132,12 +138,12 @@ String valueToString(double value, bool useSpecialFloats,
String buffer(size_t(36), '\0'); String buffer(size_t(36), '\0');
while (true) { while (true) {
int len = int len = jsoncpp_snprintf(
jsoncpp_snprintf(&*buffer.begin(), buffer.size(), &*buffer.begin(), buffer.size(),
(precisionType == significantDigits) ? "%.*g" : "%.*f", (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f",
precision, value); precision, value);
assert(len >= 0); assert(len >= 0);
size_t wouldPrint = static_cast<size_t>(len); auto wouldPrint = static_cast<size_t>(len);
if (wouldPrint >= buffer.size()) { if (wouldPrint >= buffer.size()) {
buffer.resize(wouldPrint + 1); buffer.resize(wouldPrint + 1);
continue; continue;
@@ -149,7 +155,7 @@ String valueToString(double value, bool useSpecialFloats,
buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
// strip the zero padding from the right // strip the zero padding from the right
if (precisionType == decimalPlaces) { if (precisionType == PrecisionType::decimalPlaces) {
buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end()); buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end());
} }
@@ -172,14 +178,9 @@ String valueToString(bool value) { return value ? "true" : "false"; }
static bool isAnyCharRequiredQuoting(char const* s, size_t n) { static bool isAnyCharRequiredQuoting(char const* s, size_t n) {
assert(s || !n); assert(s || !n);
char const* const end = s + n; return std::any_of(s, s + n, [](unsigned char c) {
for (char const* cur = s; cur < end; ++cur) { return c == '\\' || c == '"' || !std::isprint(c);
if (*cur == '\\' || *cur == '\"' || });
static_cast<unsigned char>(*cur) < ' ' ||
static_cast<unsigned char>(*cur) >= 0x80)
return true;
}
return false;
} }
static unsigned int utf8ToCodepoint(const char*& s, const char* e) { static unsigned int utf8ToCodepoint(const char*& s, const char* e) {
@@ -261,9 +262,17 @@ static String toHex16Bit(unsigned int x) {
return result; return result;
} }
static void appendRaw(String& result, unsigned ch) {
result += static_cast<char>(ch);
}
static void appendHex(String& result, unsigned ch) {
result.append("\\u").append(toHex16Bit(ch));
}
static String valueToQuotedStringN(const char* value, unsigned length, static String valueToQuotedStringN(const char* value, unsigned length,
bool emitUTF8 = false) { bool emitUTF8 = false) {
if (value == JSONCPP_NULL) if (value == nullptr)
return ""; return "";
if (!isAnyCharRequiredQuoting(value, length)) if (!isAnyCharRequiredQuoting(value, length))
@@ -309,29 +318,26 @@ static String valueToQuotedStringN(const char* value, unsigned length,
// sequence from occurring. // sequence from occurring.
default: { default: {
if (emitUTF8) { if (emitUTF8) {
result += *c; unsigned codepoint = static_cast<unsigned char>(*c);
if (codepoint < 0x20) {
appendHex(result, codepoint);
} else { } else {
unsigned int codepoint = utf8ToCodepoint(c, end); appendRaw(result, codepoint);
const unsigned int FIRST_NON_CONTROL_CODEPOINT = 0x20; }
const unsigned int LAST_NON_CONTROL_CODEPOINT = 0x7F; } else {
const unsigned int FIRST_SURROGATE_PAIR_CODEPOINT = 0x10000; unsigned codepoint = utf8ToCodepoint(c, end); // modifies `c`
// don't escape non-control characters if (codepoint < 0x20) {
// (short escape sequence are applied above) appendHex(result, codepoint);
if (FIRST_NON_CONTROL_CODEPOINT <= codepoint && } else if (codepoint < 0x80) {
codepoint <= LAST_NON_CONTROL_CODEPOINT) { appendRaw(result, codepoint);
result += static_cast<char>(codepoint); } else if (codepoint < 0x10000) {
} else if (codepoint < // Basic Multilingual Plane
FIRST_SURROGATE_PAIR_CODEPOINT) { // codepoint is in Basic appendHex(result, codepoint);
// Multilingual Plane } else {
result += "\\u"; // Extended Unicode. Encode 20 bits as a surrogate pair.
result += toHex16Bit(codepoint); codepoint -= 0x10000;
} else { // codepoint is not in Basic Multilingual Plane appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff));
// convert to surrogate pair first appendHex(result, 0xdc00 + (codepoint & 0x3ff));
codepoint -= FIRST_SURROGATE_PAIR_CODEPOINT;
result += "\\u";
result += toHex16Bit((codepoint >> 10) + 0xD800);
result += "\\u";
result += toHex16Bit((codepoint & 0x3FF) + 0xDC00);
} }
} }
} break; } break;
@@ -347,14 +353,14 @@ String valueToQuotedString(const char* value) {
// Class Writer // Class Writer
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
Writer::~Writer() {} Writer::~Writer() = default;
// Class FastWriter // Class FastWriter
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
FastWriter::FastWriter() FastWriter::FastWriter()
: yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false),
omitEndingLineFeed_(false) {} = default;
void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; }
@@ -410,8 +416,7 @@ void FastWriter::writeValue(const Value& value) {
case objectValue: { case objectValue: {
Value::Members members(value.getMemberNames()); Value::Members members(value.getMemberNames());
document_ += '{'; document_ += '{';
for (Value::Members::const_iterator it = members.begin(); for (auto it = members.begin(); it != members.end(); ++it) {
it != members.end(); ++it) {
const String& name = *it; const String& name = *it;
if (it != members.begin()) if (it != members.begin())
document_ += ','; document_ += ',';
@@ -428,8 +433,7 @@ void FastWriter::writeValue(const Value& value) {
// Class StyledWriter // Class StyledWriter
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
StyledWriter::StyledWriter() StyledWriter::StyledWriter() = default;
: rightMargin_(74), indentSize_(3), addChildValues_() {}
String StyledWriter::write(const Value& root) { String StyledWriter::write(const Value& root) {
document_.clear(); document_.clear();
@@ -480,7 +484,7 @@ void StyledWriter::writeValue(const Value& value) {
else { else {
writeWithIndent("{"); writeWithIndent("{");
indent(); indent();
Value::Members::const_iterator it = members.begin(); auto it = members.begin();
for (;;) { for (;;) {
const String& name = *it; const String& name = *it;
const Value& childValue = value[name]; const Value& childValue = value[name];
@@ -642,9 +646,8 @@ bool StyledWriter::hasCommentForValue(const Value& value) {
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
StyledStreamWriter::StyledStreamWriter(String indentation) StyledStreamWriter::StyledStreamWriter(String indentation)
: document_(JSONCPP_NULL), rightMargin_(74), : document_(nullptr), indentation_(std::move(indentation)),
indentation_(JSONCPP_MOVE(indentation)), addChildValues_(), addChildValues_(), indented_(false) {}
indented_(false) {}
void StyledStreamWriter::write(OStream& out, const Value& root) { void StyledStreamWriter::write(OStream& out, const Value& root) {
document_ = &out; document_ = &out;
@@ -658,7 +661,7 @@ void StyledStreamWriter::write(OStream& out, const Value& root) {
writeValue(root); writeValue(root);
writeCommentAfterValueOnSameLine(root); writeCommentAfterValueOnSameLine(root);
*document_ << "\n"; *document_ << "\n";
document_ = JSONCPP_NULL; // Forget the stream, for safety. document_ = nullptr; // Forget the stream, for safety.
} }
void StyledStreamWriter::writeValue(const Value& value) { void StyledStreamWriter::writeValue(const Value& value) {
@@ -699,7 +702,7 @@ void StyledStreamWriter::writeValue(const Value& value) {
else { else {
writeWithIndent("{"); writeWithIndent("{");
indent(); indent();
Value::Members::const_iterator it = members.begin(); auto it = members.begin();
for (;;) { for (;;) {
const String& name = *it; const String& name = *it;
const Value& childValue = value[name]; const Value& childValue = value[name];
@@ -877,7 +880,7 @@ struct BuiltStyledStreamWriter : public StreamWriter {
String endingLineFeedSymbol, bool useSpecialFloats, String endingLineFeedSymbol, bool useSpecialFloats,
bool emitUTF8, unsigned int precision, bool emitUTF8, unsigned int precision,
PrecisionType precisionType); PrecisionType precisionType);
int write(Value const& root, OStream* sout) JSONCPP_OVERRIDE; int write(Value const& root, OStream* sout) override;
private: private:
void writeValue(Value const& value); void writeValue(Value const& value);
@@ -892,7 +895,7 @@ private:
void writeCommentAfterValueOnSameLine(Value const& root); void writeCommentAfterValueOnSameLine(Value const& root);
static bool hasCommentForValue(const Value& value); static bool hasCommentForValue(const Value& value);
typedef std::vector<String> ChildValues; using ChildValues = std::vector<String>;
ChildValues childValues_; ChildValues childValues_;
String indentString_; String indentString_;
@@ -913,10 +916,9 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter(
String indentation, CommentStyle::Enum cs, String colonSymbol, String indentation, CommentStyle::Enum cs, String colonSymbol,
String nullSymbol, String endingLineFeedSymbol, bool useSpecialFloats, String nullSymbol, String endingLineFeedSymbol, bool useSpecialFloats,
bool emitUTF8, unsigned int precision, PrecisionType precisionType) bool emitUTF8, unsigned int precision, PrecisionType precisionType)
: rightMargin_(74), indentation_(JSONCPP_MOVE(indentation)), cs_(cs), : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs),
colonSymbol_(JSONCPP_MOVE(colonSymbol)), colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)),
nullSymbol_(JSONCPP_MOVE(nullSymbol)), endingLineFeedSymbol_(std::move(endingLineFeedSymbol)),
endingLineFeedSymbol_(JSONCPP_MOVE(endingLineFeedSymbol)),
addChildValues_(false), indented_(false), addChildValues_(false), indented_(false),
useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8), useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8),
precision_(precision), precisionType_(precisionType) {} precision_(precision), precisionType_(precisionType) {}
@@ -932,7 +934,7 @@ int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) {
writeValue(root); writeValue(root);
writeCommentAfterValueOnSameLine(root); writeCommentAfterValueOnSameLine(root);
*sout_ << endingLineFeedSymbol_; *sout_ << endingLineFeedSymbol_;
sout_ = JSONCPP_NULL; sout_ = nullptr;
return 0; return 0;
} }
void BuiltStyledStreamWriter::writeValue(Value const& value) { void BuiltStyledStreamWriter::writeValue(Value const& value) {
@@ -975,7 +977,7 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
else { else {
writeWithIndent("{"); writeWithIndent("{");
indent(); indent();
Value::Members::const_iterator it = members.begin(); auto it = members.begin();
for (;;) { for (;;) {
String const& name = *it; String const& name = *it;
Value const& childValue = value[name]; Value const& childValue = value[name];
@@ -1151,11 +1153,11 @@ bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
/////////////// ///////////////
// StreamWriter // StreamWriter
StreamWriter::StreamWriter() : sout_(JSONCPP_NULL) {} StreamWriter::StreamWriter() : sout_(nullptr) {}
StreamWriter::~StreamWriter() {} StreamWriter::~StreamWriter() = default;
StreamWriter::Factory::~Factory() {} StreamWriter::Factory::~Factory() = default;
StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); } StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); }
StreamWriterBuilder::~StreamWriterBuilder() {} StreamWriterBuilder::~StreamWriterBuilder() = default;
StreamWriter* StreamWriterBuilder::newStreamWriter() const { StreamWriter* StreamWriterBuilder::newStreamWriter() const {
const String indentation = settings_["indentation"].asString(); const String indentation = settings_["indentation"].asString();
const String cs_str = settings_["commentStyle"].asString(); const String cs_str = settings_["commentStyle"].asString();
@@ -1175,9 +1177,9 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const {
} }
PrecisionType precisionType(significantDigits); PrecisionType precisionType(significantDigits);
if (pt_str == "significant") { if (pt_str == "significant") {
precisionType = significantDigits; precisionType = PrecisionType::significantDigits;
} else if (pt_str == "decimal") { } else if (pt_str == "decimal") {
precisionType = decimalPlaces; precisionType = PrecisionType::decimalPlaces;
} else { } else {
throwRuntimeError("precisionType must be 'significant' or 'decimal'"); throwRuntimeError("precisionType must be 'significant' or 'decimal'");
} }
@@ -1198,34 +1200,30 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const {
endingLineFeedSymbol, usf, emitUTF8, pre, endingLineFeedSymbol, usf, emitUTF8, pre,
precisionType); precisionType);
} }
static void getValidWriterKeys(std::set<String>* valid_keys) {
valid_keys->clear();
valid_keys->insert("indentation");
valid_keys->insert("commentStyle");
valid_keys->insert("enableYAMLCompatibility");
valid_keys->insert("dropNullPlaceholders");
valid_keys->insert("useSpecialFloats");
valid_keys->insert("emitUTF8");
valid_keys->insert("precision");
valid_keys->insert("precisionType");
}
bool StreamWriterBuilder::validate(Json::Value* invalid) const { bool StreamWriterBuilder::validate(Json::Value* invalid) const {
Json::Value my_invalid; static const auto& valid_keys = *new std::set<String>{
if (!invalid) "indentation",
invalid = &my_invalid; // so we do not need to test for NULL "commentStyle",
Json::Value& inv = *invalid; "enableYAMLCompatibility",
std::set<String> valid_keys; "dropNullPlaceholders",
getValidWriterKeys(&valid_keys); "useSpecialFloats",
Value::Members keys = settings_.getMemberNames(); "emitUTF8",
size_t n = keys.size(); "precision",
for (size_t i = 0; i < n; ++i) { "precisionType",
String const& key = keys[i]; };
if (valid_keys.find(key) == valid_keys.end()) { for (auto si = settings_.begin(); si != settings_.end(); ++si) {
inv[key] = settings_[key]; auto key = si.name();
if (valid_keys.count(key))
continue;
if (invalid)
(*invalid)[std::move(key)] = *si;
else
return false;
} }
} return invalid ? invalid->empty() : true;
return inv.empty();
} }
Value& StreamWriterBuilder::operator[](const String& key) { Value& StreamWriterBuilder::operator[](const String& key) {
return settings_[key]; return settings_[key];
} }
@@ -1247,7 +1245,6 @@ String writeString(StreamWriter::Factory const& factory, Value const& root) {
OStringStream sout; OStringStream sout;
StreamWriterPtr const writer(factory.newStreamWriter()); StreamWriterPtr const writer(factory.newStreamWriter());
writer->write(root, &sout); writer->write(root, &sout);
delete writer;
return sout.str(); return sout.str();
} }
@@ -1255,7 +1252,6 @@ OStream& operator<<(OStream& sout, Value const& root) {
StreamWriterBuilder builder; StreamWriterBuilder builder;
StreamWriterPtr const writer(builder.newStreamWriter()); StreamWriterPtr const writer(builder.newStreamWriter());
writer->write(root, &sout); writer->write(root, &sout);
delete writer;
return sout; return sout;
} }

View File

@@ -5,6 +5,7 @@
#include "fuzz.h" #include "fuzz.h"
#include <cstdint>
#include <json/config.h> #include <json/config.h>
#include <json/json.h> #include <json/json.h>
#include <memory> #include <memory>
@@ -40,14 +41,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
builder.settings_["collectComments"] = hash_settings & (1 << 9); builder.settings_["collectComments"] = hash_settings & (1 << 9);
builder.settings_["allowTrailingCommas_"] = hash_settings & (1 << 10); builder.settings_["allowTrailingCommas_"] = hash_settings & (1 << 10);
Json::CharReader* reader(builder.newCharReader()); std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
Json::Value root; Json::Value root;
const char* data_str = reinterpret_cast<const char*>(data); const auto data_str = reinterpret_cast<const char*>(data);
try { try {
reader->parse(data_str, data_str + size, &root, JSONCPP_NULL); reader->parse(data_str, data_str + size, &root, nullptr);
} catch (Json::Exception const&) { } catch (Json::Exception const&) {
} }
delete reader;
// Whether it succeeded or not doesn't matter. // Whether it succeeded or not doesn't matter.
return 0; return 0;
} }

View File

@@ -73,11 +73,10 @@ namespace JsonTest {
// class TestResult // class TestResult
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
TestResult::TestResult() TestResult::TestResult() {
: predicateId_(1), lastUsedPredicateId_(0), messageTarget_(JSONCPP_NULL) {
// The root predicate has id 0 // The root predicate has id 0
rootPredicateNode_.id_ = 0; rootPredicateNode_.id_ = 0;
rootPredicateNode_.next_ = JSONCPP_NULL; rootPredicateNode_.next_ = nullptr;
predicateStackTail_ = &rootPredicateNode_; predicateStackTail_ = &rootPredicateNode_;
} }
@@ -89,7 +88,7 @@ TestResult& TestResult::addFailure(const char* file, unsigned int line,
/// added. /// added.
unsigned int nestingLevel = 0; unsigned int nestingLevel = 0;
PredicateContext* lastNode = rootPredicateNode_.next_; PredicateContext* lastNode = rootPredicateNode_.next_;
for (; lastNode != JSONCPP_NULL; lastNode = lastNode->next_) { for (; lastNode != nullptr; lastNode = lastNode->next_) {
if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext
{ {
lastUsedPredicateId_ = lastNode->id_; lastUsedPredicateId_ = lastNode->id_;
@@ -122,18 +121,17 @@ void TestResult::addFailureInfo(const char* file, unsigned int line,
TestResult& TestResult::popPredicateContext() { TestResult& TestResult::popPredicateContext() {
PredicateContext* lastNode = &rootPredicateNode_; PredicateContext* lastNode = &rootPredicateNode_;
while (lastNode->next_ != JSONCPP_NULL && while (lastNode->next_ != nullptr && lastNode->next_->next_ != nullptr) {
lastNode->next_->next_ != JSONCPP_NULL) {
lastNode = lastNode->next_; lastNode = lastNode->next_;
} }
// Set message target to popped failure // Set message target to popped failure
PredicateContext* tail = lastNode->next_; PredicateContext* tail = lastNode->next_;
if (tail != JSONCPP_NULL && tail->failure_ != JSONCPP_NULL) { if (tail != nullptr && tail->failure_ != nullptr) {
messageTarget_ = tail->failure_; messageTarget_ = tail->failure_;
} }
// Remove tail from list // Remove tail from list
predicateStackTail_ = lastNode; predicateStackTail_ = lastNode;
lastNode->next_ = JSONCPP_NULL; lastNode->next_ = nullptr;
return *this; return *this;
} }
@@ -149,9 +147,7 @@ void TestResult::printFailure(bool printTestName) const {
} }
// Print in reverse to display the callstack in the right order // Print in reverse to display the callstack in the right order
for (Failures::const_iterator it = failures_.begin(); it != failures_.end(); for (const auto& failure : failures_) {
++it) {
const Failure& failure = *it;
Json::String indent(failure.nestingLevel_ * 2, ' '); Json::String indent(failure.nestingLevel_ * 2, ' ');
if (failure.file_) { if (failure.file_) {
printf("%s%s(%u): ", indent.c_str(), failure.file_, failure.line_); printf("%s%s(%u): ", indent.c_str(), failure.file_, failure.line_);
@@ -185,7 +181,7 @@ Json::String TestResult::indentText(const Json::String& text,
} }
TestResult& TestResult::addToLastFailure(const Json::String& message) { TestResult& TestResult::addToLastFailure(const Json::String& message) {
if (messageTarget_ != JSONCPP_NULL) { if (messageTarget_ != nullptr) {
messageTarget_->message_ += message; messageTarget_->message_ += message;
} }
return *this; return *this;
@@ -206,9 +202,9 @@ TestResult& TestResult::operator<<(bool value) {
// class TestCase // class TestCase
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
TestCase::TestCase() : result_(JSONCPP_NULL) {} TestCase::TestCase() = default;
TestCase::~TestCase() {} TestCase::~TestCase() = default;
void TestCase::run(TestResult& result) { void TestCase::run(TestResult& result) {
result_ = &result; result_ = &result;
@@ -218,7 +214,7 @@ void TestCase::run(TestResult& result) {
// class Runner // class Runner
// ////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////
Runner::Runner() {} Runner::Runner() = default;
Runner& Runner::add(TestCaseFactory factory) { Runner& Runner::add(TestCaseFactory factory) {
tests_.push_back(factory); tests_.push_back(factory);
@@ -272,8 +268,7 @@ bool Runner::runAllTest(bool printSummary) const {
} }
return true; return true;
} }
for (size_t index = 0; index < failures.size(); ++index) { for (auto& result : failures) {
TestResult& result = failures[index];
result.printFailure(count > 1); result.printFailure(count > 1);
} }

View File

@@ -42,7 +42,7 @@ public:
/// Must be a POD to allow inline initialisation without stepping /// Must be a POD to allow inline initialisation without stepping
/// into the debugger. /// into the debugger.
struct PredicateContext { struct PredicateContext {
typedef unsigned int Id; using Id = unsigned int;
Id id_; Id id_;
const char* file_; const char* file_;
unsigned int line_; unsigned int line_;
@@ -61,7 +61,7 @@ public:
/// Not encapsulated to prevent step into when debugging failed assertions /// Not encapsulated to prevent step into when debugging failed assertions
/// Incremented by one on assertion predicate entry, decreased by one /// Incremented by one on assertion predicate entry, decreased by one
/// by addPredicateContext(). /// by addPredicateContext().
PredicateContext::Id predicateId_; PredicateContext::Id predicateId_{1};
/// \internal Implementation detail for predicate macros /// \internal Implementation detail for predicate macros
PredicateContext* predicateStackTail_; PredicateContext* predicateStackTail_;
@@ -70,7 +70,7 @@ public:
/// Adds an assertion failure. /// Adds an assertion failure.
TestResult& addFailure(const char* file, unsigned int line, TestResult& addFailure(const char* file, unsigned int line,
const char* expr = JSONCPP_NULL); const char* expr = nullptr);
/// Removes the last PredicateContext added to the predicate stack /// Removes the last PredicateContext added to the predicate stack
/// chained list. /// chained list.
@@ -84,9 +84,7 @@ public:
// Generic operator that will work with anything ostream can deal with. // Generic operator that will work with anything ostream can deal with.
template <typename T> TestResult& operator<<(const T& value) { template <typename T> TestResult& operator<<(const T& value) {
Json::OStringStream oss; Json::OStringStream oss;
oss.precision(16); oss << std::setprecision(16) << std::hexfloat << value;
oss.setf(std::ios_base::floatfield);
oss << value;
return addToLastFailure(oss.str()); return addToLastFailure(oss.str());
} }
@@ -104,13 +102,13 @@ private:
static Json::String indentText(const Json::String& text, static Json::String indentText(const Json::String& text,
const Json::String& indent); const Json::String& indent);
typedef std::deque<Failure> Failures; using Failures = std::deque<Failure>;
Failures failures_; Failures failures_;
Json::String name_; Json::String name_;
PredicateContext rootPredicateNode_; PredicateContext rootPredicateNode_;
PredicateContext::Id lastUsedPredicateId_; PredicateContext::Id lastUsedPredicateId_{0};
/// Failure which is the target of the messages added using operator << /// Failure which is the target of the messages added using operator <<
Failure* messageTarget_; Failure* messageTarget_{nullptr};
}; };
class TestCase { class TestCase {
@@ -124,14 +122,14 @@ public:
virtual const char* testName() const = 0; virtual const char* testName() const = 0;
protected: protected:
TestResult* result_; TestResult* result_{nullptr};
private: private:
virtual void runTestCase() = 0; virtual void runTestCase() = 0;
}; };
/// Function pointer type for TestCase factory /// Function pointer type for TestCase factory
typedef TestCase* (*TestCaseFactory)(); using TestCaseFactory = TestCase* (*)();
class Runner { class Runner {
public: public:
@@ -161,8 +159,8 @@ public:
static void printUsage(const char* appName); static void printUsage(const char* appName);
private: // prevents copy construction and assignment private: // prevents copy construction and assignment
Runner(const Runner& other) JSONCPP_CTOR_DELETE; Runner(const Runner& other) = delete;
Runner& operator=(const Runner& other) JSONCPP_CTOR_DELETE; Runner& operator=(const Runner& other) = delete;
private: private:
void listTests() const; void listTests() const;
@@ -170,7 +168,7 @@ private:
static void preventDialogOnCrash(); static void preventDialogOnCrash();
private: private:
typedef std::deque<TestCaseFactory> Factories; using Factories = std::deque<TestCaseFactory>;
Factories tests_; Factories tests_;
}; };
@@ -253,10 +251,8 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected,
} \ } \
\ \
public: /* overridden from TestCase */ \ public: /* overridden from TestCase */ \
const char* testName() const JSONCPP_OVERRIDE { \ const char* testName() const override { return #FixtureType "/" #name; } \
return #FixtureType "/" #name; \ void runTestCase() override; \
} \
void runTestCase() JSONCPP_OVERRIDE; \
}; \ }; \
\ \
void Test##FixtureType##name::runTestCase() void Test##FixtureType##name::runTestCase()
@@ -280,10 +276,8 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected,
} \ } \
\ \
public: /* overridden from TestCase */ \ public: /* overridden from TestCase */ \
const char* testName() const JSONCPP_OVERRIDE { \ const char* testName() const override { return #FixtureType "/" #name; } \
return #FixtureType "/" #name; \ void runTestCase() override; \
} \
void runTestCase() JSONCPP_OVERRIDE; \
}; \ }; \
\ \
static bool test##FixtureType##name##collect = \ static bool test##FixtureType##name##collect = \

View File

@@ -25,7 +25,7 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
typedef Json::CharReader* CharReaderPtr; using CharReaderPtr = std::unique_ptr<Json::CharReader>;
// Make numeric limits more convenient to talk about. // Make numeric limits more convenient to talk about.
// Assumes int type in 32 bits. // Assumes int type in 32 bits.
@@ -65,27 +65,22 @@ static std::deque<JsonTest::TestCaseFactory> local_;
struct ValueTest : JsonTest::TestCase { struct ValueTest : JsonTest::TestCase {
Json::Value null_; Json::Value null_;
Json::Value emptyArray_; Json::Value emptyArray_{Json::arrayValue};
Json::Value emptyObject_; Json::Value emptyObject_{Json::objectValue};
Json::Value integer_; Json::Value integer_{123456789};
Json::Value unsignedInteger_; Json::Value unsignedInteger_{34567890};
Json::Value smallUnsignedInteger_; Json::Value smallUnsignedInteger_{Json::Value::UInt(Json::Value::maxInt)};
Json::Value real_; Json::Value real_{1234.56789};
Json::Value float_; Json::Value float_{0.00390625f};
Json::Value array1_; Json::Value array1_;
Json::Value object1_; Json::Value object1_;
Json::Value emptyString_; Json::Value emptyString_{""};
Json::Value string1_; Json::Value string1_{"a"};
Json::Value string_; Json::Value string_{"sometext with space"};
Json::Value true_; Json::Value true_{true};
Json::Value false_; Json::Value false_{false};
ValueTest() ValueTest() {
: emptyArray_(Json::arrayValue), emptyObject_(Json::objectValue),
integer_(123456789), unsignedInteger_(34567890u),
smallUnsignedInteger_(Json::Value::UInt(Json::Value::maxInt)),
real_(1234.56789), float_(0.00390625f), emptyString_(""), string1_("a"),
string_("sometext with space"), true_(true), false_(false) {
array1_.append(1234); array1_.append(1234);
object1_["id"] = 1234; object1_["id"] = 1234;
} }
@@ -94,19 +89,19 @@ struct ValueTest : JsonTest::TestCase {
/// Initialize all checks to \c false by default. /// Initialize all checks to \c false by default.
IsCheck(); IsCheck();
bool isObject_; bool isObject_{false};
bool isArray_; bool isArray_{false};
bool isBool_; bool isBool_{false};
bool isString_; bool isString_{false};
bool isNull_; bool isNull_{false};
bool isInt_; bool isInt_{false};
bool isInt64_; bool isInt64_{false};
bool isUInt_; bool isUInt_{false};
bool isUInt64_; bool isUInt64_{false};
bool isIntegral_; bool isIntegral_{false};
bool isDouble_; bool isDouble_{false};
bool isNumeric_; bool isNumeric_{false};
}; };
void checkConstMemberCount(const Json::Value& value, void checkConstMemberCount(const Json::Value& value,
@@ -126,14 +121,13 @@ struct ValueTest : JsonTest::TestCase {
}; };
Json::String ValueTest::normalizeFloatingPointStr(const Json::String& s) { Json::String ValueTest::normalizeFloatingPointStr(const Json::String& s) {
std::string::size_type index = s.find_last_of("eE"); auto index = s.find_last_of("eE");
if (index == s.npos) if (index == s.npos)
return s; return s;
std::size_t signWidth = (s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0; std::size_t signWidth = (s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0;
std::string::size_type exponentStartIndex = index + 1 + signWidth; auto exponentStartIndex = index + 1 + signWidth;
Json::String normalized = s.substr(0, exponentStartIndex); Json::String normalized = s.substr(0, exponentStartIndex);
std::string::size_type indexDigit = auto indexDigit = s.find_first_not_of('0', exponentStartIndex);
s.find_first_not_of('0', exponentStartIndex);
Json::String exponent = "0"; Json::String exponent = "0";
if (indexDigit != s.npos) { // nonzero exponent if (indexDigit != s.npos) { // nonzero exponent
exponent = s.substr(indexDigit); exponent = s.substr(indexDigit);
@@ -163,9 +157,7 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, checkNormalizeFloatingPointStr) {
{"1234e+100", "1234e+100"}, {"1234e+100", "1234e+100"},
{"1234e-100", "1234e-100"}, {"1234e-100", "1234e-100"},
}; };
for (unsigned int index = 0; index < sizeof(testData) / sizeof(testData[0]); for (const auto& td : testData) {
++index) {
const struct TestData td = testData[index];
JSONTEST_ASSERT_STRING_EQUAL(normalizeFloatingPointStr(td.in), td.out); JSONTEST_ASSERT_STRING_EQUAL(normalizeFloatingPointStr(td.in), td.out);
} }
} }
@@ -223,22 +215,22 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, objects) {
// Access through find() // Access through find()
const char idKey[] = "id"; const char idKey[] = "id";
const Json::Value* foundId = object1_.find(idKey, idKey + strlen(idKey)); const Json::Value* foundId = object1_.find(idKey, idKey + strlen(idKey));
JSONTEST_ASSERT(foundId != JSONCPP_NULL); JSONTEST_ASSERT(foundId != nullptr);
JSONTEST_ASSERT_EQUAL(Json::Value(1234), *foundId); JSONTEST_ASSERT_EQUAL(Json::Value(1234), *foundId);
const char unknownIdKey[] = "unknown id"; const char unknownIdKey[] = "unknown id";
const Json::Value* foundUnknownId = const Json::Value* foundUnknownId =
object1_.find(unknownIdKey, unknownIdKey + strlen(unknownIdKey)); object1_.find(unknownIdKey, unknownIdKey + strlen(unknownIdKey));
JSONTEST_ASSERT(JSONCPP_NULL == foundUnknownId); JSONTEST_ASSERT_EQUAL(nullptr, foundUnknownId);
// Access through demand() // Access through demand()
const char yetAnotherIdKey[] = "yet another id"; const char yetAnotherIdKey[] = "yet another id";
const Json::Value* foundYetAnotherId = const Json::Value* foundYetAnotherId =
object1_.find(yetAnotherIdKey, yetAnotherIdKey + strlen(yetAnotherIdKey)); object1_.find(yetAnotherIdKey, yetAnotherIdKey + strlen(yetAnotherIdKey));
JSONTEST_ASSERT(JSONCPP_NULL == foundYetAnotherId); JSONTEST_ASSERT_EQUAL(nullptr, foundYetAnotherId);
Json::Value* demandedYetAnotherId = object1_.demand( Json::Value* demandedYetAnotherId = object1_.demand(
yetAnotherIdKey, yetAnotherIdKey + strlen(yetAnotherIdKey)); yetAnotherIdKey, yetAnotherIdKey + strlen(yetAnotherIdKey));
JSONTEST_ASSERT(demandedYetAnotherId != JSONCPP_NULL); JSONTEST_ASSERT(demandedYetAnotherId != nullptr);
*demandedYetAnotherId = "baz"; *demandedYetAnotherId = "baz";
JSONTEST_ASSERT_EQUAL(Json::Value("baz"), object1_["yet another id"]); JSONTEST_ASSERT_EQUAL(Json::Value("baz"), object1_["yet another id"]);
@@ -263,9 +255,9 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, objects) {
JSONTEST_ASSERT_EQUAL(false, did); JSONTEST_ASSERT_EQUAL(false, did);
object1_["some other id"] = "foo"; object1_["some other id"] = "foo";
Json::Value* gotPtr = JSONCPP_NULL; Json::Value* gotPtr = nullptr;
did = object1_.removeMember("some other id", gotPtr); did = object1_.removeMember("some other id", gotPtr);
JSONTEST_ASSERT(JSONCPP_NULL == gotPtr); JSONTEST_ASSERT_EQUAL(nullptr, gotPtr);
JSONTEST_ASSERT_EQUAL(true, did); JSONTEST_ASSERT_EQUAL(true, did);
// Using other removeMember interfaces, the test idea is the same as above. // Using other removeMember interfaces, the test idea is the same as above.
@@ -1190,7 +1182,7 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, integers) {
normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString())));
// 10^19 // 10^19
const Json::UInt64 ten_to_19 = static_cast<Json::UInt64>(1e19); const auto ten_to_19 = static_cast<Json::UInt64>(1e19);
val = Json::Value(Json::UInt64(ten_to_19)); val = Json::Value(Json::UInt64(ten_to_19));
JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type()); JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type());
@@ -1484,11 +1476,7 @@ void ValueTest::checkMemberCount(Json::Value& value,
JSONTEST_ASSERT_PRED(checkConstMemberCount(value, expectedCount)); JSONTEST_ASSERT_PRED(checkConstMemberCount(value, expectedCount));
} }
ValueTest::IsCheck::IsCheck() ValueTest::IsCheck::IsCheck() = default;
: isObject_(false), isArray_(false), isBool_(false), isString_(false),
isNull_(false), isInt_(false), isInt64_(false), isUInt_(false),
isUInt64_(false), isIntegral_(false), isDouble_(false),
isNumeric_(false) {}
void ValueTest::checkIs(const Json::Value& value, const IsCheck& check) { void ValueTest::checkIs(const Json::Value& value, const IsCheck& check) {
JSONTEST_ASSERT_EQUAL(check.isObject_, value.isObject()); JSONTEST_ASSERT_EQUAL(check.isObject_, value.isObject());
@@ -1673,19 +1661,19 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, CopyObject) {
Json::Value srcObject, objectCopy, otherObject; Json::Value srcObject, objectCopy, otherObject;
srcObject["key0"] = 10; srcObject["key0"] = 10;
objectCopy.copy(srcObject); objectCopy.copy(srcObject);
JSONTEST_ASSERT(srcObject["key0"].asInt() == 10); JSONTEST_ASSERT(srcObject["key0"] == 10);
JSONTEST_ASSERT(objectCopy["key0"].asInt() == 10); JSONTEST_ASSERT(objectCopy["key0"] == 10);
JSONTEST_ASSERT(srcObject.getMemberNames().size() == 1); JSONTEST_ASSERT(srcObject.getMemberNames().size() == 1);
JSONTEST_ASSERT(objectCopy.getMemberNames().size() == 1); JSONTEST_ASSERT(objectCopy.getMemberNames().size() == 1);
otherObject["key1"] = 15; otherObject["key1"] = 15;
otherObject["key2"] = 16; otherObject["key2"] = 16;
JSONTEST_ASSERT(otherObject.getMemberNames().size() == 2); JSONTEST_ASSERT(otherObject.getMemberNames().size() == 2);
objectCopy.copy(otherObject); objectCopy.copy(otherObject);
JSONTEST_ASSERT(objectCopy["key1"].asInt() == 15); JSONTEST_ASSERT(objectCopy["key1"] == 15);
JSONTEST_ASSERT(objectCopy["key2"].asInt() == 16); JSONTEST_ASSERT(objectCopy["key2"] == 16);
JSONTEST_ASSERT(objectCopy.getMemberNames().size() == 2); JSONTEST_ASSERT(objectCopy.getMemberNames().size() == 2);
otherObject["key1"] = 20; otherObject["key1"] = 20;
JSONTEST_ASSERT(objectCopy["key1"].asInt() == 15); JSONTEST_ASSERT(objectCopy["key1"] == 15);
} }
} }
@@ -1829,7 +1817,7 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, StaticString) {
JSONTEST_FIXTURE_LOCAL(ValueTest, WideString) { JSONTEST_FIXTURE_LOCAL(ValueTest, WideString) {
// https://github.com/open-source-parsers/jsoncpp/issues/756 // https://github.com/open-source-parsers/jsoncpp/issues/756
const std::string uni = "\u5f0f\uff0c\u8fdb"; // "式,进" const std::string uni = u8"\u5f0f\uff0c\u8fdb"; // "式,进"
std::string styled; std::string styled;
{ {
Json::Value v; Json::Value v;
@@ -2604,7 +2592,7 @@ JSONTEST_FIXTURE_LOCAL(StreamWriterTest, indentation) {
JSONTEST_FIXTURE_LOCAL(StreamWriterTest, writeZeroes) { JSONTEST_FIXTURE_LOCAL(StreamWriterTest, writeZeroes) {
Json::String binary("hi", 3); // include trailing 0 Json::String binary("hi", 3); // include trailing 0
JSONTEST_ASSERT_EQUAL(3, binary.length()); JSONTEST_ASSERT_EQUAL(3, binary.length());
Json::String expected("\"hi\\u0000\""); // unicoded zero Json::String expected(R"("hi\u0000")"); // unicoded zero
Json::StreamWriterBuilder b; Json::StreamWriterBuilder b;
{ {
Json::Value root; Json::Value root;
@@ -2651,7 +2639,69 @@ JSONTEST_FIXTURE_LOCAL(StreamWriterTest, unicode) {
"{\n\t\"test\" : " "{\n\t\"test\" : "
"\"\\t\\n\\ud806\\udca1=\\u0133\\ud82c\\udd1b\\uff67\"\n}"); "\"\\t\\n\\ud806\\udca1=\\u0133\\ud82c\\udd1b\\uff67\"\n}");
} }
#if JSONCPP_CXX_STD_11
// Control chars should be escaped regardless of UTF-8 input encoding.
JSONTEST_FIXTURE_LOCAL(StreamWriterTest, escapeControlCharacters) {
auto uEscape = [](unsigned ch) {
static const char h[] = "0123456789abcdef";
std::string r = "\\u";
r += h[(ch >> (3 * 4)) & 0xf];
r += h[(ch >> (2 * 4)) & 0xf];
r += h[(ch >> (1 * 4)) & 0xf];
r += h[(ch >> (0 * 4)) & 0xf];
return r;
};
auto shortEscape = [](unsigned ch) -> const char* {
switch (ch) {
case '\"':
return "\\\"";
case '\\':
return "\\\\";
case '\b':
return "\\b";
case '\f':
return "\\f";
case '\n':
return "\\n";
case '\r':
return "\\r";
case '\t':
return "\\t";
default:
return nullptr;
}
};
Json::StreamWriterBuilder b;
for (bool emitUTF8 : {true, false}) {
b.settings_["emitUTF8"] = emitUTF8;
for (unsigned i = 0; i != 0x100; ++i) {
if (!emitUTF8 && i >= 0x80)
break; // The algorithm would try to parse UTF-8, so stop here.
std::string raw({static_cast<char>(i)});
std::string esc = raw;
if (i < 0x20)
esc = uEscape(i);
if (const char* shEsc = shortEscape(i))
esc = shEsc;
// std::cout << "emit=" << emitUTF8 << ", i=" << std::hex << i << std::dec
// << std::endl;
Json::Value root;
root["test"] = raw;
JSONTEST_ASSERT_STRING_EQUAL(
std::string("{\n\t\"test\" : \"").append(esc).append("\"\n}"),
Json::writeString(b, root))
<< ", emit=" << emitUTF8 << ", i=" << i << ", raw=\"" << raw << "\""
<< ", esc=\"" << esc << "\"";
}
}
}
struct ReaderTest : JsonTest::TestCase { struct ReaderTest : JsonTest::TestCase {
void setStrictMode() { void setStrictMode() {
reader = std::unique_ptr<Json::Reader>( reader = std::unique_ptr<Json::Reader>(
@@ -2700,43 +2750,43 @@ struct ReaderTest : JsonTest::TestCase {
}; };
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrors) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrors) {
checkParse("{ \"property\" : \"value\" }"); checkParse(R"({ "property" : "value" })");
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseObject) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseObject) {
checkParse("{\"property\"}", checkParse(R"({"property"})",
{{11, 12, "Missing ':' after object member name"}}, {{11, 12, "Missing ':' after object member name"}},
"* Line 1, Column 12\n Missing ':' after object member name\n"); "* Line 1, Column 12\n Missing ':' after object member name\n");
checkParse( checkParse(
"{\"property\" : \"value\" ", R"({"property" : "value" )",
{{22, 22, "Missing ',' or '}' in object declaration"}}, {{22, 22, "Missing ',' or '}' in object declaration"}},
"* Line 1, Column 23\n Missing ',' or '}' in object declaration\n"); "* Line 1, Column 23\n Missing ',' or '}' in object declaration\n");
checkParse("{\"property\" : \"value\", ", checkParse(R"({"property" : "value", )",
{{23, 23, "Missing '}' or object member name"}}, {{23, 23, "Missing '}' or object member name"}},
"* Line 1, Column 24\n Missing '}' or object member name\n"); "* Line 1, Column 24\n Missing '}' or object member name\n");
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseArray) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseArray) {
checkParse( checkParse(
"[ \"value\" ", {{10, 10, "Missing ',' or ']' in array declaration"}}, R"([ "value" )", {{10, 10, "Missing ',' or ']' in array declaration"}},
"* Line 1, Column 11\n Missing ',' or ']' in array declaration\n"); "* Line 1, Column 11\n Missing ',' or ']' in array declaration\n");
checkParse( checkParse(
"[ \"value1\" \"value2\" ] ", R"([ "value1" "value2" ] )",
{{11, 19, "Missing ',' or ']' in array declaration"}}, {{11, 19, "Missing ',' or ']' in array declaration"}},
"* Line 1, Column 12\n Missing ',' or ']' in array declaration\n"); "* Line 1, Column 12\n Missing ',' or ']' in array declaration\n");
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) {
checkParse("[ \"\u8a2a\" ]"); checkParse(R"([ "\u8a2a" ])");
checkParse( checkParse(
"[ \"\\ud801\" ]", R"([ "\ud801" ])",
{{2, 10, {{2, 10,
"additional six characters expected to parse unicode surrogate " "additional six characters expected to parse unicode surrogate "
"pair."}}, "pair."}},
"* Line 1, Column 3\n" "* Line 1, Column 3\n"
" additional six characters expected to parse unicode surrogate pair.\n" " additional six characters expected to parse unicode surrogate pair.\n"
"See Line 1, Column 10 for detail.\n"); "See Line 1, Column 10 for detail.\n");
checkParse("[ \"\\ud801\\d1234\" ]", checkParse(R"([ "\ud801\d1234" ])",
{{2, 16, {{2, 16,
"expecting another \\u token to begin the " "expecting another \\u token to begin the "
"second half of a unicode surrogate pair"}}, "second half of a unicode surrogate pair"}},
@@ -2744,7 +2794,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) {
" expecting another \\u token to begin the " " expecting another \\u token to begin the "
"second half of a unicode surrogate pair\n" "second half of a unicode surrogate pair\n"
"See Line 1, Column 12 for detail.\n"); "See Line 1, Column 12 for detail.\n");
checkParse("[ \"\\ua3t@\" ]", checkParse(R"([ "\ua3t@" ])",
{{2, 10, {{2, 10,
"Bad unicode escape sequence in string: " "Bad unicode escape sequence in string: "
"hexadecimal digit expected."}}, "hexadecimal digit expected."}},
@@ -2753,7 +2803,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) {
"hexadecimal digit expected.\n" "hexadecimal digit expected.\n"
"See Line 1, Column 9 for detail.\n"); "See Line 1, Column 9 for detail.\n");
checkParse( checkParse(
"[ \"\\ua3t\" ]", R"([ "\ua3t" ])",
{{2, 9, "Bad unicode escape sequence in string: four digits expected."}}, {{2, 9, "Bad unicode escape sequence in string: four digits expected."}},
"* Line 1, Column 3\n" "* Line 1, Column 3\n"
" Bad unicode escape sequence in string: four digits expected.\n" " Bad unicode escape sequence in string: four digits expected.\n"
@@ -2762,29 +2812,29 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) {
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseComment) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseComment) {
checkParse( checkParse(
"{ /*commentBeforeValue*/ \"property\" : \"value\" }//commentAfterValue" R"({ /*commentBeforeValue*/ "property" : "value" }//commentAfterValue)"
"\n"); "\n");
checkParse(" true //comment1\n//comment2\r//comment3\r\n"); checkParse(" true //comment1\n//comment2\r//comment3\r\n");
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, streamParseWithNoErrors) { JSONTEST_FIXTURE_LOCAL(ReaderTest, streamParseWithNoErrors) {
std::string styled = "{ \"property\" : \"value\" }"; std::string styled = R"({ "property" : "value" })";
std::istringstream iss(styled); std::istringstream iss(styled);
checkParse(iss); checkParse(iss);
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrorsTestingOffsets) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrorsTestingOffsets) {
checkParse("{" checkParse(R"({)"
" \"property\" : [\"value\", \"value2\"]," R"( "property" : ["value", "value2"],)"
" \"obj\" : { \"nested\" : -6.2e+15, \"bool\" : true}," R"( "obj" : { "nested" : -6.2e+15, "bool" : true},)"
" \"null\" : null," R"( "null" : null,)"
" \"false\" : false" R"( "false" : false)"
"}"); R"( })");
auto checkOffsets = [&](const Json::Value& v, int start, int limit) { auto checkOffsets = [&](const Json::Value& v, int start, int limit) {
JSONTEST_ASSERT_EQUAL(start, v.getOffsetStart()); JSONTEST_ASSERT_EQUAL(start, v.getOffsetStart());
JSONTEST_ASSERT_EQUAL(limit, v.getOffsetLimit()); JSONTEST_ASSERT_EQUAL(limit, v.getOffsetLimit());
}; };
checkOffsets(root, 0, 114); checkOffsets(root, 0, 115);
checkOffsets(root["property"], 15, 34); checkOffsets(root["property"], 15, 34);
checkOffsets(root["property"][0], 16, 23); checkOffsets(root["property"][0], 16, 23);
checkOffsets(root["property"][1], 25, 33); checkOffsets(root["property"][1], 25, 33);
@@ -2796,7 +2846,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrorsTestingOffsets) {
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithOneError) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithOneError) {
checkParse("{ \"property\" :: \"value\" }", checkParse(R"({ "property" :: "value" })",
{{14, 15, "Syntax error: value, object or array expected."}}, {{14, 15, "Syntax error: value, object or array expected."}},
"* Line 1, Column 15\n Syntax error: value, object or array " "* Line 1, Column 15\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
@@ -2806,11 +2856,11 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithOneError) {
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseSpecialFloat) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseSpecialFloat) {
checkParse("{ \"a\" : Infi }", checkParse(R"({ "a" : Infi })",
{{8, 9, "Syntax error: value, object or array expected."}}, {{8, 9, "Syntax error: value, object or array expected."}},
"* Line 1, Column 9\n Syntax error: value, object or array " "* Line 1, Column 9\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
checkParse("{ \"a\" : Infiniaa }", checkParse(R"({ "a" : Infiniaa })",
{{8, 9, "Syntax error: value, object or array expected."}}, {{8, 9, "Syntax error: value, object or array expected."}},
"* Line 1, Column 9\n Syntax error: value, object or array " "* Line 1, Column 9\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
@@ -2827,20 +2877,16 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, strictModeParseNumber) {
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseChineseWithOneError) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseChineseWithOneError) {
checkParse("{ \"pr" checkParse(R"({ "pr)"
#if JSONCPP_CXX_STD_11
u8"\u4f50\u85e4" // 佐藤 u8"\u4f50\u85e4" // 佐藤
#else R"(erty" :: "value" })",
"\u4f50\u85e4" // 佐藤
#endif
"erty\" :: \"value\" }",
{{18, 19, "Syntax error: value, object or array expected."}}, {{18, 19, "Syntax error: value, object or array expected."}},
"* Line 1, Column 19\n Syntax error: value, object or array " "* Line 1, Column 19\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithDetailError) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithDetailError) {
checkParse("{ \"property\" : \"v\\alue\" }", checkParse(R"({ "property" : "v\alue" })",
{{15, 23, "Bad escape sequence in string"}}, {{15, 23, "Bad escape sequence in string"}},
"* Line 1, Column 16\n" "* Line 1, Column 16\n"
" Bad escape sequence in string\n" " Bad escape sequence in string\n"
@@ -2848,7 +2894,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithDetailError) {
} }
JSONTEST_FIXTURE_LOCAL(ReaderTest, pushErrorTest) { JSONTEST_FIXTURE_LOCAL(ReaderTest, pushErrorTest) {
checkParse("{ \"AUTHOR\" : 123 }"); checkParse(R"({ "AUTHOR" : 123 })");
if (!root["AUTHOR"].isString()) { if (!root["AUTHOR"].isString()) {
JSONTEST_ASSERT( JSONTEST_ASSERT(
reader->pushError(root["AUTHOR"], "AUTHOR must be a string")); reader->pushError(root["AUTHOR"], "AUTHOR must be a string"));
@@ -2857,7 +2903,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, pushErrorTest) {
"* Line 1, Column 14\n" "* Line 1, Column 14\n"
" AUTHOR must be a string\n"); " AUTHOR must be a string\n");
checkParse("{ \"AUTHOR\" : 123 }"); checkParse(R"({ "AUTHOR" : 123 })");
if (!root["AUTHOR"].isString()) { if (!root["AUTHOR"].isString()) {
JSONTEST_ASSERT(reader->pushError(root["AUTHOR"], "AUTHOR must be a string", JSONTEST_ASSERT(reader->pushError(root["AUTHOR"], "AUTHOR must be a string",
root["AUTHOR"])); root["AUTHOR"]));
@@ -2872,9 +2918,9 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, allowNumericKeysTest) {
Json::Features features; Json::Features features;
features.allowNumericKeys_ = true; features.allowNumericKeys_ = true;
setFeatures(features); setFeatures(features);
checkParse("{ 123 : \"abc\" }"); checkParse(R"({ 123 : "abc" })");
} }
#endif // JSONCPP_CXX_STD_11
struct CharReaderTest : JsonTest::TestCase {}; struct CharReaderTest : JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrors) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrors) {
@@ -2882,11 +2928,10 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrors) {
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
Json::String errs; Json::String errs;
Json::Value root; Json::Value root;
char const doc[] = "{ \"property\" : \"value\" }"; char const doc[] = R"({ "property" : "value" })";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrorsTestingOffsets) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrorsTestingOffsets) {
@@ -2900,7 +2945,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrorsTestingOffsets) {
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseNumber) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseNumber) {
@@ -2917,7 +2961,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseNumber) {
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
JSONTEST_ASSERT_EQUAL(1.1111111111111111e+020, root[0]); JSONTEST_ASSERT_EQUAL(1.1111111111111111e+020, root[0]);
} }
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
@@ -2933,18 +2976,14 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
JSONTEST_ASSERT_EQUAL("", root[0]); JSONTEST_ASSERT_EQUAL("", root[0]);
} }
{ {
char const doc[] = "[\"\\u8A2a\"]"; char const doc[] = R"(["\u8A2a"])";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
#if JSONCPP_CXX_STD_11
JSONTEST_ASSERT_EQUAL(u8"\u8A2a", root[0].asString()); // "訪" JSONTEST_ASSERT_EQUAL(u8"\u8A2a", root[0].asString()); // "訪"
#else
JSONTEST_ASSERT_EQUAL("\u8A2a", root[0].asString()); // "訪"
#endif // JSONCPP_CXX_STD_11
} }
{ {
char const doc[] = "[ \"\\uD801\" ]"; char const doc[] = R"([ "\uD801" ])";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == "* Line 1, Column 3\n" JSONTEST_ASSERT(errs == "* Line 1, Column 3\n"
@@ -2953,7 +2992,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
"See Line 1, Column 10 for detail.\n"); "See Line 1, Column 10 for detail.\n");
} }
{ {
char const doc[] = "[ \"\\uD801\\d1234\" ]"; char const doc[] = R"([ "\uD801\d1234" ])";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == "* Line 1, Column 3\n" JSONTEST_ASSERT(errs == "* Line 1, Column 3\n"
@@ -2962,7 +3001,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
"See Line 1, Column 12 for detail.\n"); "See Line 1, Column 12 for detail.\n");
} }
{ {
char const doc[] = "[ \"\\ua3t@\" ]"; char const doc[] = R"([ "\ua3t@" ])";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == "* Line 1, Column 3\n" JSONTEST_ASSERT(errs == "* Line 1, Column 3\n"
@@ -2971,7 +3010,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
"See Line 1, Column 9 for detail.\n"); "See Line 1, Column 9 for detail.\n");
} }
{ {
char const doc[] = "[ \"\\ua3t\" ]"; char const doc[] = R"([ "\ua3t" ])";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT( JSONTEST_ASSERT(
@@ -2980,18 +3019,16 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
" Bad unicode escape sequence in string: four digits expected.\n" " Bad unicode escape sequence in string: four digits expected.\n"
"See Line 1, Column 6 for detail.\n"); "See Line 1, Column 6 for detail.\n");
} }
delete reader;
{ {
b.settings_["allowSingleQuotes"] = true; b.settings_["allowSingleQuotes"] = true;
CharReaderPtr charReader(b.newCharReader()); CharReaderPtr charreader(b.newCharReader());
char const doc[] = "{'a': 'x\\ty', \"b\":'x\\\\y'}"; char const doc[] = R"({'a': 'x\ty', "b":'x\\y'})";
bool ok = charReader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = charreader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(2u, root.size()); JSONTEST_ASSERT_EQUAL(2u, root.size());
JSONTEST_ASSERT_STRING_EQUAL("x\ty", root["a"].asString()); JSONTEST_ASSERT_STRING_EQUAL("x\ty", root["a"].asString());
JSONTEST_ASSERT_STRING_EQUAL("x\\y", root["b"].asString()); JSONTEST_ASSERT_STRING_EQUAL("x\\y", root["b"].asString());
delete charReader;
} }
} }
@@ -3024,7 +3061,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseComment) {
JSONTEST_ASSERT_EQUAL("value", root[0]); JSONTEST_ASSERT_EQUAL("value", root[0]);
JSONTEST_ASSERT_EQUAL(true, root[1]); JSONTEST_ASSERT_EQUAL(true, root[1]);
} }
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) {
@@ -3033,7 +3069,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) {
Json::Value root; Json::Value root;
Json::String errs; Json::String errs;
{ {
char const doc[] = "{ \"property\" : \"value\" "; char const doc[] = R"({ "property" : "value" )";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == "* Line 1, Column 24\n" JSONTEST_ASSERT(errs == "* Line 1, Column 24\n"
@@ -3041,14 +3077,13 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) {
JSONTEST_ASSERT_EQUAL("value", root["property"]); JSONTEST_ASSERT_EQUAL("value", root["property"]);
} }
{ {
char const doc[] = "{ \"property\" : \"value\" ,"; char const doc[] = R"({ "property" : "value" ,)";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == "* Line 1, Column 25\n" JSONTEST_ASSERT(errs == "* Line 1, Column 25\n"
" Missing '}' or object member name\n"); " Missing '}' or object member name\n");
JSONTEST_ASSERT_EQUAL("value", root["property"]); JSONTEST_ASSERT_EQUAL("value", root["property"]);
} }
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseArrayWithErrors) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseArrayWithErrors) {
@@ -3065,14 +3100,13 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseArrayWithErrors) {
JSONTEST_ASSERT_EQUAL("value", root[0]); JSONTEST_ASSERT_EQUAL("value", root[0]);
} }
{ {
char const doc[] = "[ \"value1\" \"value2\" ]"; char const doc[] = R"([ "value1" "value2" ])";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == "* Line 1, Column 12\n" JSONTEST_ASSERT(errs == "* Line 1, Column 12\n"
" Missing ',' or ']' in array declaration\n"); " Missing ',' or ']' in array declaration\n");
JSONTEST_ASSERT_EQUAL("value1", root[0]); JSONTEST_ASSERT_EQUAL("value1", root[0]);
} }
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithOneError) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithOneError) {
@@ -3080,13 +3114,12 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithOneError) {
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
Json::String errs; Json::String errs;
Json::Value root; Json::Value root;
char const doc[] = "{ \"property\" :: \"value\" }"; char const doc[] = R"({ "property" :: "value" })";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == JSONTEST_ASSERT(errs ==
"* Line 1, Column 15\n Syntax error: value, object or array " "* Line 1, Column 15\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseChineseWithOneError) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseChineseWithOneError) {
@@ -3100,7 +3133,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseChineseWithOneError) {
JSONTEST_ASSERT(errs == JSONTEST_ASSERT(errs ==
"* Line 1, Column 19\n Syntax error: value, object or array " "* Line 1, Column 19\n Syntax error: value, object or array "
"expected.\n"); "expected.\n");
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithDetailError) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithDetailError) {
@@ -3108,19 +3140,18 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithDetailError) {
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
Json::String errs; Json::String errs;
Json::Value root; Json::Value root;
char const doc[] = "{ \"property\" : \"v\\alue\" }"; char const doc[] = R"({ "property" : "v\alue" })";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs == JSONTEST_ASSERT(errs ==
"* Line 1, Column 16\n Bad escape sequence in string\nSee " "* Line 1, Column 16\n Bad escape sequence in string\nSee "
"Line 1, Column 20 for detail.\n"); "Line 1, Column 20 for detail.\n");
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) {
Json::CharReaderBuilder b; Json::CharReaderBuilder b;
Json::Value root; Json::Value root;
char const doc[] = "{ \"property\" : \"value\" }"; char const doc[] = R"({ "property" : "value" })";
{ {
b.settings_["stackLimit"] = 2; b.settings_["stackLimit"] = 2;
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
@@ -3129,7 +3160,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) {
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
JSONTEST_ASSERT_EQUAL("value", root["property"]); JSONTEST_ASSERT_EQUAL("value", root["property"]);
delete reader;
} }
{ {
b.settings_["stackLimit"] = 1; b.settings_["stackLimit"] = 1;
@@ -3137,12 +3167,11 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) {
Json::String errs; Json::String errs;
JSONTEST_ASSERT_THROWS( JSONTEST_ASSERT_THROWS(
reader->parse(doc, doc + std::strlen(doc), &root, &errs)); reader->parse(doc, doc + std::strlen(doc), &root, &errs));
delete reader;
} }
} }
JSONTEST_FIXTURE_LOCAL(CharReaderTest, testOperator) { JSONTEST_FIXTURE_LOCAL(CharReaderTest, testOperator) {
const std::string styled = "{ \"property\" : \"value\" }"; const std::string styled = R"({ "property" : "value" })";
std::istringstream iss(styled); std::istringstream iss(styled);
Json::Value root; Json::Value root;
iss >> root; iss >> root;
@@ -3155,7 +3184,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderStrictModeTest, dupKeys) {
Json::CharReaderBuilder b; Json::CharReaderBuilder b;
Json::Value root; Json::Value root;
char const doc[] = char const doc[] =
"{ \"property\" : \"value\", \"key\" : \"val1\", \"key\" : \"val2\" }"; R"({ "property" : "value", "key" : "val1", "key" : "val2" })";
{ {
b.strictMode(&b.settings_); b.strictMode(&b.settings_);
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
@@ -3166,7 +3195,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderStrictModeTest, dupKeys) {
" Duplicate key: 'key'\n", " Duplicate key: 'key'\n",
errs); errs);
JSONTEST_ASSERT_EQUAL("val1", root["key"]); // so far JSONTEST_ASSERT_EQUAL("val1", root["key"]); // so far
delete reader;
} }
} }
struct CharReaderFailIfExtraTest : JsonTest::TestCase {}; struct CharReaderFailIfExtraTest : JsonTest::TestCase {};
@@ -3175,7 +3203,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) {
// This is interpreted as a string value followed by a colon. // This is interpreted as a string value followed by a colon.
Json::CharReaderBuilder b; Json::CharReaderBuilder b;
Json::Value root; Json::Value root;
char const doc[] = " \"property\" : \"value\" }"; char const doc[] = R"( "property" : "value" })";
{ {
b.settings_["failIfExtra"] = false; b.settings_["failIfExtra"] = false;
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
@@ -3184,7 +3212,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) {
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
JSONTEST_ASSERT_EQUAL("property", root); JSONTEST_ASSERT_EQUAL("property", root);
delete reader;
} }
{ {
b.settings_["failIfExtra"] = true; b.settings_["failIfExtra"] = true;
@@ -3196,7 +3223,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) {
" Extra non-whitespace after JSON value.\n", " Extra non-whitespace after JSON value.\n",
errs); errs);
JSONTEST_ASSERT_EQUAL("property", root); JSONTEST_ASSERT_EQUAL("property", root);
delete reader;
} }
{ {
b.strictMode(&b.settings_); b.strictMode(&b.settings_);
@@ -3208,7 +3234,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) {
" Extra non-whitespace after JSON value.\n", " Extra non-whitespace after JSON value.\n",
errs); errs);
JSONTEST_ASSERT_EQUAL("property", root); JSONTEST_ASSERT_EQUAL("property", root);
delete reader;
} }
{ {
b.strictMode(&b.settings_); b.strictMode(&b.settings_);
@@ -3222,7 +3247,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) {
" A valid JSON document must be either an array or an object value.\n", " A valid JSON document must be either an array or an object value.\n",
errs); errs);
JSONTEST_ASSERT_EQUAL("property", root); JSONTEST_ASSERT_EQUAL("property", root);
delete reader;
} }
} }
@@ -3240,7 +3264,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue107) {
" Extra non-whitespace after JSON value.\n", " Extra non-whitespace after JSON value.\n",
errs); errs);
JSONTEST_ASSERT_EQUAL(1, root.asInt()); JSONTEST_ASSERT_EQUAL(1, root.asInt());
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterObject) { JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterObject) {
Json::CharReaderBuilder b; Json::CharReaderBuilder b;
@@ -3254,7 +3277,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterObject) {
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL("value", root["property"]); JSONTEST_ASSERT_EQUAL("value", root["property"]);
delete reader;
} }
} }
JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterArray) { JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterArray) {
@@ -3268,7 +3290,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterArray) {
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL("value", root[1u]); JSONTEST_ASSERT_EQUAL("value", root[1u]);
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterBool) { JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterBool) {
Json::CharReaderBuilder b; Json::CharReaderBuilder b;
@@ -3281,7 +3302,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterBool) {
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(true, root.asBool()); JSONTEST_ASSERT_EQUAL(true, root.asBool());
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, parseComment) { JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, parseComment) {
@@ -3315,12 +3335,11 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, parseComment) {
errs); errs);
JSONTEST_ASSERT_EQUAL(true, root.asBool()); JSONTEST_ASSERT_EQUAL(true, root.asBool());
} }
delete reader;
} }
#if JSONCPP_CXX_STD_11
struct CharReaderAllowDropNullTest : JsonTest::TestCase { struct CharReaderAllowDropNullTest : JsonTest::TestCase {
typedef Json::Value Value; using Value = Json::Value;
typedef std::function<void(const Value&)> ValueCheck; using ValueCheck = std::function<void(const Value&)>;
Value nullValue = Value{Json::nullValue}; Value nullValue = Value{Json::nullValue};
Value emptyArray = Value{Json::arrayValue}; Value emptyArray = Value{Json::arrayValue};
@@ -3329,11 +3348,11 @@ struct CharReaderAllowDropNullTest : JsonTest::TestCase {
return [=](const Value& root) { JSONTEST_ASSERT_EQUAL(root, v); }; return [=](const Value& root) { JSONTEST_ASSERT_EQUAL(root, v); };
} }
ValueCheck objGetAnd(std::string idx, ValueCheck f) { static ValueCheck objGetAnd(std::string idx, ValueCheck f) {
return [=](const Value& root) { f(root.get(idx, true)); }; return [=](const Value& root) { f(root.get(idx, true)); };
} }
ValueCheck arrGetAnd(int idx, ValueCheck f) { static ValueCheck arrGetAnd(int idx, ValueCheck f) {
return [=](const Value& root) { f(root[idx]); }; return [=](const Value& root) { f(root[idx]); };
} }
}; };
@@ -3346,19 +3365,19 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowDropNullTest, issue178) {
ValueCheck onRoot; ValueCheck onRoot;
}; };
const TestSpec specs[] = { const TestSpec specs[] = {
{__LINE__, "{\"a\":,\"b\":true}", 2, objGetAnd("a", checkEq(nullValue))}, {__LINE__, R"({"a":,"b":true})", 2, objGetAnd("a", checkEq(nullValue))},
{__LINE__, "{\"a\":,\"b\":true}", 2, objGetAnd("a", checkEq(nullValue))}, {__LINE__, R"({"a":,"b":true})", 2, objGetAnd("a", checkEq(nullValue))},
{__LINE__, "{\"a\":}", 1, objGetAnd("a", checkEq(nullValue))}, {__LINE__, R"({"a":})", 1, objGetAnd("a", checkEq(nullValue))},
{__LINE__, "[]", 0, checkEq(emptyArray)}, {__LINE__, "[]", 0, checkEq(emptyArray)},
{__LINE__, "[null]", 1, JSONCPP_NULL}, {__LINE__, "[null]", 1, nullptr},
{__LINE__, "[,]", 2, JSONCPP_NULL}, {__LINE__, "[,]", 2, nullptr},
{__LINE__, "[,,,]", 4, JSONCPP_NULL}, {__LINE__, "[,,,]", 4, nullptr},
{__LINE__, "[null,]", 2, JSONCPP_NULL}, {__LINE__, "[null,]", 2, nullptr},
{__LINE__, "[,null]", 2, JSONCPP_NULL}, {__LINE__, "[,null]", 2, nullptr},
{__LINE__, "[,,]", 3, JSONCPP_NULL}, {__LINE__, "[,,]", 3, nullptr},
{__LINE__, "[null,,]", 3, JSONCPP_NULL}, {__LINE__, "[null,,]", 3, nullptr},
{__LINE__, "[,null,]", 3, JSONCPP_NULL}, {__LINE__, "[,null,]", 3, nullptr},
{__LINE__, "[,,null]", 3, JSONCPP_NULL}, {__LINE__, "[,,null]", 3, nullptr},
{__LINE__, "[[],,,]", 4, arrGetAnd(0, checkEq(emptyArray))}, {__LINE__, "[[],,,]", 4, arrGetAnd(0, checkEq(emptyArray))},
{__LINE__, "[,[],,]", 4, arrGetAnd(1, checkEq(emptyArray))}, {__LINE__, "[,[],,]", 4, arrGetAnd(1, checkEq(emptyArray))},
{__LINE__, "[,,,[]]", 4, arrGetAnd(3, checkEq(emptyArray))}, {__LINE__, "[,,,[]]", 4, arrGetAnd(3, checkEq(emptyArray))},
@@ -3379,7 +3398,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowDropNullTest, issue178) {
} }
} }
} }
#endif // JSONCPP_CXX_STD_11
struct CharReaderAllowNumericKeysTest : JsonTest::TestCase {}; struct CharReaderAllowNumericKeysTest : JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(CharReaderAllowNumericKeysTest, allowNumericKeys) { JSONTEST_FIXTURE_LOCAL(CharReaderAllowNumericKeysTest, allowNumericKeys) {
@@ -3396,7 +3415,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowNumericKeysTest, allowNumericKeys) {
JSONTEST_ASSERT_EQUAL(true, root.get("15", false)); JSONTEST_ASSERT_EQUAL(true, root.get("15", false));
JSONTEST_ASSERT_EQUAL(true, root.get("-16", false)); JSONTEST_ASSERT_EQUAL(true, root.get("-16", false));
JSONTEST_ASSERT_EQUAL(true, root.get("12.01", false)); JSONTEST_ASSERT_EQUAL(true, root.get("12.01", false));
delete reader;
} }
struct CharReaderAllowSingleQuotesTest : JsonTest::TestCase {}; struct CharReaderAllowSingleQuotesTest : JsonTest::TestCase {};
@@ -3425,7 +3443,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSingleQuotesTest, issue182) {
JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString()); JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString());
JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString()); JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString());
} }
delete reader;
} }
struct CharReaderAllowZeroesTest : JsonTest::TestCase {}; struct CharReaderAllowZeroesTest : JsonTest::TestCase {};
@@ -3454,7 +3471,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowZeroesTest, issue176) {
JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString()); JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString());
JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString()); JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString());
} }
delete reader;
} }
struct CharReaderAllowSpecialFloatsTest : JsonTest::TestCase {}; struct CharReaderAllowSpecialFloatsTest : JsonTest::TestCase {};
@@ -3482,7 +3498,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, specialFloat) {
" Syntax error: value, object or array expected.\n", " Syntax error: value, object or array expected.\n",
errs); errs);
} }
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) { JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) {
@@ -3492,8 +3507,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) {
Json::String errs; Json::String errs;
CharReaderPtr reader(b.newCharReader()); CharReaderPtr reader(b.newCharReader());
{ {
char const doc[] = char const doc[] = R"({"a":NaN,"b":Infinity,"c":-Infinity,"d":+Infinity})";
"{\"a\":NaN,\"b\":Infinity,\"c\":-Infinity,\"d\":+Infinity}";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_STRING_EQUAL("", errs);
@@ -3532,9 +3546,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) {
{__LINE__, true, "{\"a\":-Infinity}"}, // {__LINE__, true, "{\"a\":-Infinity}"}, //
{__LINE__, true, "{\"a\":+Infinity}"} // {__LINE__, true, "{\"a\":+Infinity}"} //
}; };
for (unsigned int index = 0; index < sizeof(test_data) / sizeof(test_data[0]); for (const auto& td : test_data) {
++index) {
const struct TestData td = test_data[index];
bool ok = reader->parse(&*td.in.begin(), &*td.in.begin() + td.in.size(), bool ok = reader->parse(&*td.in.begin(), &*td.in.begin() + td.in.size(),
&root, &errs); &root, &errs);
JSONTEST_ASSERT(td.ok == ok) << "line:" << td.line << "\n" JSONTEST_ASSERT(td.ok == ok) << "line:" << td.line << "\n"
@@ -3546,7 +3558,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) {
} }
{ {
char const doc[] = "{\"posInf\": +Infinity, \"NegInf\": -Infinity}"; char const doc[] = R"({"posInf": +Infinity, "NegInf": -Infinity})";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_STRING_EQUAL("", errs);
@@ -3556,7 +3568,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) {
JSONTEST_ASSERT_EQUAL(-std::numeric_limits<double>::infinity(), JSONTEST_ASSERT_EQUAL(-std::numeric_limits<double>::infinity(),
root["NegInf"].asDouble()); root["NegInf"].asDouble());
} }
delete reader;
} }
struct EscapeSequenceTest : JsonTest::TestCase {}; struct EscapeSequenceTest : JsonTest::TestCase {};
@@ -3584,7 +3595,6 @@ JSONTEST_FIXTURE_LOCAL(EscapeSequenceTest, charReaderParseEscapeSequence) {
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok); JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT(errs.empty());
delete reader;
} }
JSONTEST_FIXTURE_LOCAL(EscapeSequenceTest, writeEscapeSequence) { JSONTEST_FIXTURE_LOCAL(EscapeSequenceTest, writeEscapeSequence) {
@@ -3660,7 +3670,7 @@ struct IteratorTest : JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(IteratorTest, convert) { JSONTEST_FIXTURE_LOCAL(IteratorTest, convert) {
Json::Value j; Json::Value j;
const Json::Value& cj = j; const Json::Value& cj = j;
Json::Value::const_iterator it = j.begin(); auto it = j.begin();
Json::Value::const_iterator cit; Json::Value::const_iterator cit;
cit = it; cit = it;
JSONTEST_ASSERT(cit == cj.begin()); JSONTEST_ASSERT(cit == cj.begin());
@@ -3671,17 +3681,11 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, decrement) {
json["k1"] = "a"; json["k1"] = "a";
json["k2"] = "b"; json["k2"] = "b";
std::vector<std::string> values; std::vector<std::string> values;
std::vector<std::string> expected; for (auto it = json.end(); it != json.begin();) {
expected.push_back("b");
expected.push_back("a");
for (Json::Value::const_iterator it = json.end(); it != json.begin();) {
--it; --it;
values.push_back(it->asString()); values.push_back(it->asString());
} }
JSONTEST_ASSERT(values.size() == expected.size()); JSONTEST_ASSERT((values == std::vector<std::string>{"b", "a"}));
for (unsigned int i = 0; i < expected.size(); i++) {
JSONTEST_ASSERT(values.at(i) == expected.at(i));
}
} }
JSONTEST_FIXTURE_LOCAL(IteratorTest, reverseIterator) { JSONTEST_FIXTURE_LOCAL(IteratorTest, reverseIterator) {
@@ -3689,19 +3693,12 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, reverseIterator) {
json["k1"] = "a"; json["k1"] = "a";
json["k2"] = "b"; json["k2"] = "b";
std::vector<std::string> values; std::vector<std::string> values;
typedef Json::Value::const_iterator Iter; using Iter = decltype(json.begin());
std::reverse_iterator<Iter> re = std::reverse_iterator<Iter>(json.begin()); auto re = std::reverse_iterator<Iter>(json.begin());
for (std::reverse_iterator<Iter> it = std::reverse_iterator<Iter>(json.end()); for (auto it = std::reverse_iterator<Iter>(json.end()); it != re; ++it) {
it != re; ++it) {
values.push_back(it->asString()); values.push_back(it->asString());
} }
std::vector<std::string> expected; JSONTEST_ASSERT((values == std::vector<std::string>{"b", "a"}));
expected.push_back("b");
expected.push_back("a");
JSONTEST_ASSERT(values.size() == expected.size());
for (unsigned int i = 0; i < expected.size(); i++) {
JSONTEST_ASSERT(values.at(i) == expected.at(i));
}
} }
JSONTEST_FIXTURE_LOCAL(IteratorTest, distance) { JSONTEST_FIXTURE_LOCAL(IteratorTest, distance) {
@@ -3710,9 +3707,9 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, distance) {
json["k1"] = "a"; json["k1"] = "a";
json["k2"] = "b"; json["k2"] = "b";
int i = 0; int i = 0;
Json::Value::const_iterator it = json.begin(); auto it = json.begin();
for (;; ++it, ++i) { for (;; ++it, ++i) {
Json::ValueIteratorBase::difference_type dist = it - json.begin(); auto dist = it - json.begin();
JSONTEST_ASSERT_EQUAL(i, dist); JSONTEST_ASSERT_EQUAL(i, dist);
if (it == json.end()) if (it == json.end())
break; break;
@@ -3728,8 +3725,8 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, distance) {
JSONTEST_FIXTURE_LOCAL(IteratorTest, nullValues) { JSONTEST_FIXTURE_LOCAL(IteratorTest, nullValues) {
{ {
Json::Value json; Json::Value json;
Json::Value::const_iterator end = json.end(); auto end = json.end();
Json::Value::const_iterator endCopy = end; auto endCopy = end;
JSONTEST_ASSERT(endCopy == end); JSONTEST_ASSERT(endCopy == end);
endCopy = end; endCopy = end;
JSONTEST_ASSERT(endCopy == end); JSONTEST_ASSERT(endCopy == end);
@@ -3737,8 +3734,8 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, nullValues) {
{ {
// Same test, now with const Value. // Same test, now with const Value.
const Json::Value json; const Json::Value json;
Json::Value::const_iterator end = json.end(); auto end = json.end();
Json::Value::const_iterator endCopy = end; auto endCopy = end;
JSONTEST_ASSERT(endCopy == end); JSONTEST_ASSERT(endCopy == end);
endCopy = end; endCopy = end;
JSONTEST_ASSERT(endCopy == end); JSONTEST_ASSERT(endCopy == end);
@@ -3809,10 +3806,10 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, constness) {
for (; iter != value.end(); ++iter) { for (; iter != value.end(); ++iter) {
out << *iter << ','; out << *iter << ',';
} }
Json::String expected = "\" 9\",\"10\",\"11\","; Json::String expected = R"(" 9","10","11",)";
JSONTEST_ASSERT_STRING_EQUAL(expected, out.str()); JSONTEST_ASSERT_STRING_EQUAL(expected, out.str());
} }
#if JSONCPP_CXX_STD_11
struct RValueTest : JsonTest::TestCase {}; struct RValueTest : JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(RValueTest, moveConstruction) { JSONTEST_FIXTURE_LOCAL(RValueTest, moveConstruction) {
@@ -3824,7 +3821,7 @@ JSONTEST_FIXTURE_LOCAL(RValueTest, moveConstruction) {
JSONTEST_ASSERT_EQUAL(Json::objectValue, moved.type()); JSONTEST_ASSERT_EQUAL(Json::objectValue, moved.type());
JSONTEST_ASSERT_EQUAL(Json::stringValue, moved["key"].type()); JSONTEST_ASSERT_EQUAL(Json::stringValue, moved["key"].type());
} }
#endif // JSONCPP_CXX_STD_11
struct FuzzTest : JsonTest::TestCase {}; struct FuzzTest : JsonTest::TestCase {};
// Build and run the fuzz test without any fuzzer, so that it's guaranteed not // Build and run the fuzz test without any fuzzer, so that it's guaranteed not
@@ -3840,14 +3837,13 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) {
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
JsonTest::Runner runner; JsonTest::Runner runner;
for (unsigned int index = 0; index < local_.size(); ++index) { for (auto& local : local_) {
JsonTest::TestCaseFactory local = local_[index];
runner.add(local); runner.add(local);
} }
return runner.runCommandLine(argc, argv); return runner.runCommandLine(argc, argv);
} }
#if JSONCPP_CXX_STD_11
struct MemberTemplateAs : JsonTest::TestCase { struct MemberTemplateAs : JsonTest::TestCase {
template <typename T, typename F> template <typename T, typename F>
JsonTest::TestResult& EqEval(T v, F f) const { JsonTest::TestResult& EqEval(T v, F f) const {
@@ -3876,13 +3872,12 @@ JSONTEST_FIXTURE_LOCAL(MemberTemplateAs, BehavesSameAsNamedAs) {
EqEval(false, [](const Json::Value& j) { return j.asBool(); }); EqEval(false, [](const Json::Value& j) { return j.asBool(); });
EqEval(true, [](const Json::Value& j) { return j.asBool(); }); EqEval(true, [](const Json::Value& j) { return j.asBool(); });
} }
#endif // JSONCPP_CXX_STD_11
class MemberTemplateIs : public JsonTest::TestCase {}; class MemberTemplateIs : public JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(MemberTemplateIs, BehavesSameAsNamedIs) { JSONTEST_FIXTURE_LOCAL(MemberTemplateIs, BehavesSameAsNamedIs) {
const Json::Value values[] = {true, 142, 40.63, "hello world"}; const Json::Value values[] = {true, 142, 40.63, "hello world"};
for (size_t index = 0; index < sizeof(values) / sizeof(values[0]); index++) { for (const Json::Value& j : values) {
const Json::Value& j = values[index];
JSONTEST_ASSERT_EQUAL(j.is<bool>(), j.isBool()); JSONTEST_ASSERT_EQUAL(j.is<bool>(), j.isBool());
JSONTEST_ASSERT_EQUAL(j.is<Json::Int>(), j.isInt()); JSONTEST_ASSERT_EQUAL(j.is<Json::Int>(), j.isInt());
JSONTEST_ASSERT_EQUAL(j.is<Json::Int64>(), j.isInt64()); JSONTEST_ASSERT_EQUAL(j.is<Json::Int64>(), j.isInt64());