diff --git a/.clang-tidy b/.clang-tidy index be3d06a52fdedfb972df4d29b1bcafb388be2c81..99e914df9490f45ad0ee43beb1351256704d089e 100755 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,7 +4,7 @@ WarningsAsErrors: '' HeaderFilterRegex: '' AnalyzeTemporaryDtors: false FormatStyle: none -CheckOptions: +CheckOptions: - key: modernize-use-using.IgnoreMacros value: '0' ... diff --git a/.gitattributes b/.gitattributes index ef2ba88ce05a5f01bef67a332f63e7dc7c944272..22d2b7a455a38a4c3eee4fda602a586f396ab811 100755 --- a/.gitattributes +++ b/.gitattributes @@ -9,18 +9,3 @@ *.vcxproj eol=crlf *.sln eol=crlf devtools/agent_vm* eol=crlf -*.tgz filter=lfs diff=lfs merge=lfs -text -*.trp filter=lfs diff=lfs merge=lfs -text -*.apk filter=lfs diff=lfs merge=lfs -text -*.jar filter=lfs diff=lfs merge=lfs -text -*.mp4 filter=lfs diff=lfs merge=lfs -text -*.zip filter=lfs diff=lfs merge=lfs -text -*.asm filter=lfs diff=lfs merge=lfs -text -*.8svn filter=lfs diff=lfs merge=lfs -text -*.9svn filter=lfs diff=lfs merge=lfs -text -*.dylib filter=lfs diff=lfs merge=lfs -text -*.exe filter=lfs diff=lfs merge=lfs -text -*.a filter=lfs diff=lfs merge=lfs -text -*.so filter=lfs diff=lfs merge=lfs -text -*.bin filter=lfs diff=lfs merge=lfs -text -*.dll filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore index 91121c230d0400de73e9b02f71e42c22f1bf1a6c..9682782fa6c10ddaef2582682e9c4ae12830ab03 100755 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ /libs/ /doc/doxyfile /dist/ +/.cache/ # MSVC project files: *.sln @@ -28,9 +29,9 @@ # CMake-generated files: CMakeFiles/ -*.cmake /pkg-config/jsoncpp.pc jsoncpp_lib_static.dir/ +compile_commands.json # In case someone runs cmake in the root-dir: /CMakeCache.txt @@ -51,3 +52,6 @@ jsoncpp_lib_static.dir/ # DS_Store .DS_Store + +# temps +/version diff --git a/.travis.yml b/.travis.yml index 0f007c38e9944936358c1b3bb029b7e147c20d16..23acd4e57d6f548112a5c756340f001bae71e60e 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ # Build matrix / environment variables are explained on: -# http://about.travis-ci.org/docs/user/build-configuration/ +# http://about.travis-ci.com/docs/user/build-configuration/ # This file can be validated on: http://www.yamllint.com/ # Or using the Ruby based travel command line tool: # gem install travis --no-rdoc --no-ri @@ -9,95 +9,48 @@ sudo: false addons: homebrew: packages: - - clang-format - - meson - - ninja + - clang-format + - meson + - ninja update: false # do not update homebrew by default apt: sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-8 + - ubuntu-toolchain-r-test + - llvm-toolchain-xenial-8 packages: - - clang-format-8 - - clang-8 - - valgrind + - clang-format-8 + - clang-8 + - valgrind matrix: - allow_failures: - - os: osx include: - name: Mac clang meson static release testing os: osx osx_image: xcode11 compiler: clang env: - CXX="clang++" - CC="clang" - LIB_TYPE=static - BUILD_TYPE=release - LANGUAGE_STANDARD="11" + CXX="clang++" + CC="clang" + LIB_TYPE=static + BUILD_TYPE=release script: ./.travis_scripts/meson_builder.sh - name: Linux xenial clang meson static release testing os: linux dist: xenial compiler: clang env: - CXX="clang++" - CC="clang" - LIB_TYPE=static - BUILD_TYPE=release - LANGUAGE_STANDARD="11" + CXX="clang++" + CC="clang" + LIB_TYPE=static + BUILD_TYPE=release + PYTHONUSERBASE="$(pwd)/LOCAL" + PATH="$PYTHONUSERBASE/bin:$PATH" # before_install and install steps only needed for linux meson builds before_install: - - source ./.travis_scripts/travis.before_install.${TRAVIS_OS_NAME}.sh + - source ./.travis_scripts/travis.before_install.${TRAVIS_OS_NAME}.sh 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 - - name: Linux xenial gcc-4.6 meson static release with C++03 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="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 + - name: Linux xenial gcc cmake coverage os: linux dist: xenial compiler: gcc @@ -109,77 +62,10 @@ matrix: BUILD_TYPE=Debug LIB_TYPE=shared DESTDIR=/tmp/cmake_json_cpp - LANGUAGE_STANDARD="11" before_install: - - pip install --user cpp-coveralls + - pip install --user cpp-coveralls script: ./.travis_scripts/cmake_builder.sh after_success: - - 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 + - coveralls --include src/lib_json --include include notifications: email: false diff --git a/.travis_scripts/cmake_builder.sh b/.travis_scripts/cmake_builder.sh index 920985fb64f62ec106c828bcae4a6aabaebaa63a..f3d4e46b6081daef13de6a7a315ccecbd84052b2 100755 --- a/.travis_scripts/cmake_builder.sh +++ b/.travis_scripts/cmake_builder.sh @@ -66,7 +66,7 @@ cmake --version echo ${CXX} ${CXX} --version _COMPILER_NAME=`basename ${CXX}` -if [ "${BUILD_TYPE}" = "shared" ]; then +if [ "${LIB_TYPE}" = "shared" ]; then _CMAKE_BUILD_SHARED_LIBS=ON else _CMAKE_BUILD_SHARED_LIBS=OFF @@ -98,14 +98,6 @@ else export _BUILD_EXE=make 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}" mkdir -p ${_BUILD_DIR_NAME} cd "${_BUILD_DIR_NAME}" @@ -120,7 +112,6 @@ cd "${_BUILD_DIR_NAME}" -DCMAKE_BUILD_TYPE:STRING=${BUILD_TYPE} \ -DBUILD_SHARED_LIBS:BOOL=${_CMAKE_BUILD_SHARED_LIBS} \ -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 diff --git a/.travis_scripts/meson_builder.sh b/.travis_scripts/meson_builder.sh index 6026c7dc1f31f3851d92b8e43eb4a6e54a298178..bc74732f6313e055db3deac1fc29e5435fe2076c 100755 --- a/.travis_scripts/meson_builder.sh +++ b/.travis_scripts/meson_builder.sh @@ -64,15 +64,11 @@ ninja --version _COMPILER_NAME=`basename ${CXX}` _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}" +ninja -v -j 2 -C "${_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 if [ "${DESTDIR}" != "/usr/local" ]; then diff --git a/.travis_scripts/run-clang-format.py b/.travis_scripts/run-clang-format.py index 68179aafd745594f52b66d300319c4959863c512..605b5aad19dd3c5eb72e2ec6d8423fc1b52d1406 100755 --- a/.travis_scripts/run-clang-format.py +++ b/.travis_scripts/run-clang-format.py @@ -353,4 +353,4 @@ def main(): if __name__ == '__main__': - sys.exit(main()) \ No newline at end of file + sys.exit(main()) diff --git a/.travis_scripts/run-clang-format.sh b/.travis_scripts/run-clang-format.sh index 91972840df36e96cf9be0db3b2c378b7c265eda9..ded76aaf5f3a2a668b3e31c047c7e03258aa23f2 100755 --- a/.travis_scripts/run-clang-format.sh +++ b/.travis_scripts/run-clang-format.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -python $DIR/run-clang-format.py -r $DIR/../src/**/ $DIR/../include/**/ \ No newline at end of file +python $DIR/run-clang-format.py -r $DIR/../src/**/ $DIR/../include/**/ diff --git a/.travis_scripts/travis.before_install.osx.sh b/.travis_scripts/travis.before_install.osx.sh index 5d83c0c71e6f49a56dbf0e727c2a0cd9856dc279..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100755 --- a/.travis_scripts/travis.before_install.osx.sh +++ b/.travis_scripts/travis.before_install.osx.sh @@ -1 +0,0 @@ -# NOTHING TO DO HERE diff --git a/.travis_scripts/travis.install.linux.sh b/.travis_scripts/travis.install.linux.sh index 7c5846f1a40e7c1f709cdb534a8499377b243651..6495fefe934fe3043fb9843f7caef7b392214a91 100755 --- a/.travis_scripts/travis.install.linux.sh +++ b/.travis_scripts/travis.install.linux.sh @@ -1,10 +1,5 @@ set -vex -wget https://github.com/ninja-build/ninja/releases/download/v1.9.0/ninja-linux.zip -unzip -q ninja-linux.zip -d build - -pip3 install meson -echo ${PATH} -ls /usr/local -ls /usr/local/bin -export PATH="${PWD}"/build:/usr/local/bin:/usr/bin:${PATH} +pip3 install --user meson ninja +which meson +which ninja diff --git a/AUTHORS b/AUTHORS index 6b0fc99fe256a864a67702768ace483750ef29a0..e1fa0fc3ad0b337ea6e5d776d19f04643821c26c 100755 --- a/AUTHORS +++ b/AUTHORS @@ -21,7 +21,7 @@ Braden McDorman Brandon Myers Brendan Drew chason -Chen Guoping chenguopingdota@163.com +chenguoping Chris Gilling Christopher Dawes Christopher Dunn diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100755 index 0000000000000000000000000000000000000000..6d7ac3da9874bf9d31159bc5daf26586335f28e1 --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,37 @@ +licenses(["unencumbered"]) # Public Domain or MIT + +exports_files(["LICENSE"]) + +cc_library( + name = "jsoncpp", + srcs = [ + "src/lib_json/json_reader.cpp", + "src/lib_json/json_tool.h", + "src/lib_json/json_value.cpp", + "src/lib_json/json_writer.cpp", + ], + hdrs = [ + "include/json/allocator.h", + "include/json/assertions.h", + "include/json/config.h", + "include/json/json_features.h", + "include/json/forwards.h", + "include/json/json.h", + "include/json/reader.h", + "include/json/value.h", + "include/json/version.h", + "include/json/writer.h", + ], + copts = [ + "-DJSON_USE_EXCEPTION=0", + "-DJSON_HAS_INT64", + ], + includes = ["include"], + visibility = ["//visibility:public"], + deps = [":private"], +) + +cc_library( + name = "private", + textual_hdrs = ["src/lib_json/json_valueiterator.inl"], +) diff --git a/CMakeLists.txt b/CMakeLists.txt index 430863dd492d98aa14cbd3102ba3cb962d8bd5a0..2841277c0fa2a4db5ffb6f9f5b8da06bc4eae9b6 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,9 @@ else() set(JSONCPP_CMAKE_POLICY_VERSION "${JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION}") endif() cmake_policy(VERSION ${JSONCPP_CMAKE_POLICY_VERSION}) +if(POLICY CMP0091) + cmake_policy(SET CMP0091 NEW) +endif() # # Now enumerate specific policies newer than JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION # that may need to be individually set to NEW/OLD @@ -37,12 +40,20 @@ foreach(pold "") # Currently Empty endif() 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. if(NOT DEFINED CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage.") endif() +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + # --------------------------------------------------------------------------- # use ccache if found, has to be done before project() # --------------------------------------------------------------------------- @@ -53,47 +64,22 @@ if(CCACHE_EXECUTABLE) set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE) 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 PROJECT_SOVERSION!! + VERSION 1.9.5 # [.[.[.]]] 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() +message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") +set(PROJECT_SOVERSION 25) -# 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}") -#if(NOT JSONCPP_VERSION_FOUND) -# message(FATAL_ERROR "Failed to parse version string properly. Expect X.Y.Z") -#endif(NOT JSONCPP_VERSION_FOUND) +include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInSourceBuilds.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInBuildInstalls.cmake) 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) @@ -102,39 +88,10 @@ option(JSONCPP_WITH_STRICT_ISO "Issue all the warnings demanded by strict ISO C 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_EXAMPLE "Compile JsonCpp example" 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) - if(NOT DEFINED CMAKE_CXX_COMPILER) - set(CMAKE_CXX_COMPILER "/usr/bin/g++") - endif() - 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() +option(JSONCPP_STATIC_WINDOWS_RUNTIME "Use static (MT/MTd) Windows runtime" OFF) +option(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." ON) +option(BUILD_STATIC_LIBS "Build jsoncpp_lib as a static library." ON) +option(BUILD_OBJECT_LIBS "Build jsoncpp_lib as a object library." ON) # Adhere to GNU filesystem layout conventions include(GNUInstallDirs) @@ -170,27 +127,36 @@ if(MSVC) # Only enabled in debug because some old versions of VS STL generate # unreachable code warning when compiled in release configuration. add_compile_options($<$:/W4>) + if (JSONCPP_STATIC_WINDOWS_RUNTIME) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + endif() endif() if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # using regular Clang or AppleClang - add_compile_options(-Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare) + add_compile_options(-Wall -Wconversion -Wshadow) + + if(JSONCPP_WITH_WARNING_AS_ERROR) + add_compile_options(-Werror=conversion -Werror=sign-compare) + endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # using GCC add_compile_options(-Wall -Wconversion -Wshadow -Wextra) # not yet ready for -Wsign-conversion if(JSONCPP_WITH_STRICT_ISO) - add_compile_options(-Wall) + add_compile_options(-Wpedantic) endif() if(JSONCPP_WITH_WARNING_AS_ERROR) add_compile_options(-Werror=conversion) endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") # using Intel compiler - add_compile_options(-Wall -Wconversion -Wshadow -Wextra -Werror=conversion) + add_compile_options(-Wall -Wconversion -Wshadow -Wextra) - if(JSONCPP_WITH_STRICT_ISO AND NOT JSONCPP_WITH_WARNING_AS_ERROR) + if(JSONCPP_WITH_WARNING_AS_ERROR) + add_compile_options(-Werror=conversion) + elseif(JSONCPP_WITH_STRICT_ISO) add_compile_options(-Wpedantic) endif() endif() @@ -200,6 +166,11 @@ if(JSONCPP_WITH_WARNING_AS_ERROR) endif() if(JSONCPP_WITH_PKGCONFIG_SUPPORT) + include(JoinPaths) + + join_paths(libdir_for_pc_file "\${exec_prefix}" "${CMAKE_INSTALL_LIBDIR}") + join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}") + configure_file( "pkg-config/jsoncpp.pc.in" "pkg-config/jsoncpp.pc" @@ -212,11 +183,16 @@ if(JSONCPP_WITH_CMAKE_PACKAGE) include(CMakePackageConfigHelpers) install(EXPORT jsoncpp DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp - FILE jsoncppConfig.cmake) + FILE jsoncpp-targets.cmake) + configure_package_config_file(jsoncppConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp) + write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake" - VERSION ${JSONCPP_VERSION} + VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/jsoncpp-namespaced-targets.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp) endif() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9c9fc6a04f4da2586327a6a7996cef9ed081f5b4..8d992bee79711c10db0e3d809703065b708fdf3e 100755 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,7 +19,7 @@ If you wish to install to a directory other than /usr/local, set an environment DESTDIR=/path/to/install/dir Then, - +```sh cd jsoncpp/ BUILD_TYPE=debug #BUILD_TYPE=release @@ -35,6 +35,7 @@ Then, #meson test --no-rebuild --print-errorlogs sudo ninja install +``` ## Building and testing with other build systems See https://github.com/open-source-parsers/jsoncpp/wiki/Building @@ -143,7 +144,9 @@ bool Reader::decodeNumber(Token& token) { ``` Before submitting your code, ensure that you meet the versioning requirements above, follow the style guide of the file you are modifying (or the above rules for new files), and run clang format. Meson exposes clang format with the following command: - ``` ninja -v -C build-${LIB_TYPE}/ clang-format ``` + +For convenience, you can also run the `reformat.sh` script located in the root directory. + diff --git a/CTestConfig.cmake b/CTestConfig.cmake new file mode 100755 index 0000000000000000000000000000000000000000..b8fc6d55b2a387bfcc56bf8284f650c25e729426 --- /dev/null +++ b/CTestConfig.cmake @@ -0,0 +1,15 @@ +## This file should be placed in the root directory of your project. +## Then modify the CMakeLists.txt file in the root directory of your +## project to incorporate the testing dashboard. +## +## # The following are required to submit to the CDash dashboard: +## ENABLE_TESTING() +## INCLUDE(CTest) + +set(CTEST_PROJECT_NAME "jsoncpp") +set(CTEST_NIGHTLY_START_TIME "01:23:45 UTC") + +set(CTEST_DROP_METHOD "https") +set(CTEST_DROP_SITE "my.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=jsoncpp") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/LICENSE b/LICENSE index 89280a6c48a9db51559700d34c849b49e1c49ad1..c41a1d1c77489b0f4a72e6443e530bf34751f1f3 100755 --- a/LICENSE +++ b/LICENSE @@ -1,25 +1,25 @@ -The JsonCpp library's source code, including accompanying documentation, +The JsonCpp library's source code, including accompanying documentation, tests and demonstration applications, are licensed under the following conditions... -Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, +Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, this software is released into the Public Domain. In jurisdictions which do not recognize Public Domain property (e.g. Germany as of 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and The JsonCpp Authors, and is released under the terms of the MIT License (see below). -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual Public Domain/MIT License conditions described here, as they choose. The MIT License is about as close to Public Domain as a license can get, and is described in clear, concise terms at: http://en.wikipedia.org/wiki/MIT_License - + The full text of the MIT License follows: ======================================================================== diff --git a/OAT.xml b/OAT.xml index 622f61380072247d624067c1135d28cffac7183e..f430a9fe481fe66c4dc6e0c94997ab7025bdceb4 100755 --- a/OAT.xml +++ b/OAT.xml @@ -30,5 +30,10 @@ + + + + + diff --git a/README.md b/README.md index 10110743c9987ce7d5345b47c715449c111af19f..5bff8dca2b239d78e0644b155e32e2c0cdf15f40 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # 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 numbers, strings, ordered sequences of values, and collections of name/value 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 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 @@ -31,9 +30,14 @@ but can hardly applied into 0.y.z. * `1.y.z` is built with C++11. * `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. +### 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 @@ -44,7 +48,7 @@ You can download and install JsonCpp using the [vcpkg](https://github.com/Micros cd vcpkg ./bootstrap-vcpkg.sh ./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. diff --git a/appveyor.yml b/appveyor.yml index 0b9c8fe3fea0e9019dd0e242718f89d60db5e1c1..cccce4298f93a3137bc5b6b9aaab6e456f14809d 100755 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,7 @@ clone_folder: c:\projects\jsoncpp environment: + matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 CMAKE_GENERATOR: Visual Studio 14 2015 @@ -13,11 +14,15 @@ environment: build_script: - cmake --version - - cd c:\projects\jsoncpp - - cmake -G "%CMAKE_GENERATOR%" -DCMAKE_INSTALL_PREFIX:PATH=%CD:\=/%/install -DBUILD_SHARED_LIBS:BOOL=ON . + # The build script starts in root. + - set JSONCPP_FOLDER=%cd% + - set JSONCPP_BUILD_FOLDER=%JSONCPP_FOLDER%\build\release + - mkdir -p %JSONCPP_BUILD_FOLDER% + - cd %JSONCPP_BUILD_FOLDER% + - cmake -G "%CMAKE_GENERATOR%" -DCMAKE_INSTALL_PREFIX:PATH=%CD:\=/%/install -DBUILD_SHARED_LIBS:BOOL=ON %JSONCPP_FOLDER% # Use ctest to make a dashboard build: # - ctest -D Experimental(Start|Update|Configure|Build|Test|Coverage|MemCheck|Submit) - # NOTE: Testing on window is not yet finished: + # NOTE: Testing on windows is not yet finished: # - ctest -C Release -D ExperimentalStart -D ExperimentalConfigure -D ExperimentalBuild -D ExperimentalTest -D ExperimentalSubmit - ctest -C Release -D ExperimentalStart -D ExperimentalConfigure -D ExperimentalBuild -D ExperimentalSubmit # Final step is to verify that installation succeeds diff --git a/cmake/JoinPaths.cmake b/cmake/JoinPaths.cmake new file mode 100755 index 0000000000000000000000000000000000000000..2b376b73330169d3142b58ab7ceb6df3b8da2042 --- /dev/null +++ b/cmake/JoinPaths.cmake @@ -0,0 +1,23 @@ +# This module provides a function for joining paths +# known from most languages +# +# SPDX-License-Identifier: (MIT OR CC0-1.0) +# Copyright 2020 Jan Tojnar +# https://github.com/jtojnar/cmake-snips +# +# Modelled after Python’s os.path.join +# https://docs.python.org/3.7/library/os.path.html#os.path.join +# Windows not supported +function(join_paths joined_path first_path_segment) + set(temp_path "${first_path_segment}") + foreach(current_segment IN LISTS ARGN) + if(NOT ("${current_segment}" STREQUAL "")) + if(IS_ABSOLUTE "${current_segment}") + set(temp_path "${current_segment}") + else() + set(temp_path "${temp_path}/${current_segment}") + endif() + endif() + endforeach() + set(${joined_path} "${temp_path}" PARENT_SCOPE) +endfunction() diff --git a/dev.makefile b/dev.makefile index 1a4be6a91346818cd0e0a0330e1e8fbf1fba95c5..545ff27305f5b2888ec2bdfa7e0901de19e351ad 100755 --- a/dev.makefile +++ b/dev.makefile @@ -1,9 +1,11 @@ # This is only for jsoncpp developers/contributors. # We use this to sign releases, generate documentation, etc. -VER?=$(shell cat version.txt) +VER?=$(shell cat version) default: @echo "VER=${VER}" +update-version: + perl get_version.pl meson.build >| version sign: jsoncpp-${VER}.tar.gz gpg --armor --detach-sign $< gpg --verify $<.asc diff --git a/devtools/antglob.py b/devtools/antglob.py index 98437658ce0b7b966132beab4535cbfe5c385f9a..bd2d7aee978c502b5fd0f12b65e8eb1b8a2912a5 100755 --- a/devtools/antglob.py +++ b/devtools/antglob.py @@ -146,7 +146,7 @@ def glob(dir_path, entry_type = is_file and FILE_LINK or DIR_LINK else: entry_type = is_file and FILE or DIR -## print '=> type: %d' % entry_type, +## print '=> type: %d' % entry_type, if (entry_type & entry_type_filter) != 0: ## print ' => KEEP' yield os.path.join(dir_path, entry) diff --git a/devtools/fixeol.py b/devtools/fixeol.py index 45252a07d9237ca41a7042d5c7af9b747fb4dad8..11e1ce2a1294c144466d7ca4cc5b8cc9f8c67dd2 100755 --- a/devtools/fixeol.py +++ b/devtools/fixeol.py @@ -32,8 +32,8 @@ def fix_source_eol(path, is_dry_run = True, verbose = True, eol = '\n'): if verbose: print(is_dry_run and ' NEED FIX' or ' FIXED') return True -## -## +## +## ## ##def _do_fix(is_dry_run = True): ## from waftools import antglob diff --git a/devtools/licenseupdater.py b/devtools/licenseupdater.py index 36bdb5c09b61c984087e41f33c6a9ec63aa0739d..d9b662e0144f5ae2676e8fb39336a3ce4da054b2 100755 --- a/devtools/licenseupdater.py +++ b/devtools/licenseupdater.py @@ -20,7 +20,7 @@ def update_license(path, dry_run, show_diff): dry_run: if True, just print the path of the file that would be updated, but don't change it. show_diff: if True, print the path of the file that would be modified, - as well as the change made to the file. + as well as the change made to the file. """ with open(path, 'rt') as fin: original_text = fin.read().replace('\r\n','\n') @@ -51,7 +51,7 @@ def update_license_in_source_directories(source_dirs, dry_run, show_diff): dry_run: if True, just print the path of the file that would be updated, but don't change it. show_diff: if True, print the path of the file that would be modified, - as well as the change made to the file. + as well as the change made to the file. """ from devtools import antglob prune_dirs = antglob.prune_dirs + 'scons-local* ./build* ./libs ./dist' diff --git a/doxybuild.py b/doxybuild.py index 862c1f43ff4b0d634921da4f7903ab3c2202d871..254ab714b22c41be1c9bc0b7e936c8448f3382ac 100755 --- a/doxybuild.py +++ b/doxybuild.py @@ -46,7 +46,7 @@ def do_subst_in_file(targetfile, sourcefile, dict): with open(sourcefile, 'r') as f: contents = f.read() for (k,v) in list(dict.items()): - v = v.replace('\\','\\\\') + v = v.replace('\\','\\\\') contents = re.sub(k, v, contents) with open(targetfile, 'w') as f: f.write(contents) @@ -158,7 +158,7 @@ def main(): Generates doxygen documentation in build/doxygen. Optionally makes a tarball of the documentation to dist/. - Must be started in the project top directory. + Must be started in the project top directory. """ from optparse import OptionParser parser = OptionParser(usage=usage) diff --git a/example/README.md b/example/README.md index b1ae4c8753ab6beb4d7362359375206c33fe9065..92b925c96782854d80616607dccc272a80aee462 100755 --- a/example/README.md +++ b/example/README.md @@ -1,8 +1,8 @@ -***NOTE*** +***NOTE*** If you get linker errors about undefined references to symbols that involve types in the `std::__cxx11` namespace or the tag `[abi:cxx11]` then it probably indicates that you are trying to link together object files that were compiled with different -values for the _GLIBCXX_USE_CXX11_ABI marco. This commonly happens when linking to a third-party library that was compiled with +values for the _GLIBCXX_USE_CXX11_ABI marco. This commonly happens when linking to a third-party library that was compiled with an older version of GCC. If the third-party library cannot be rebuilt with the new ABI, then you need to recompile your code with the old ABI,just like: **g++ stringWrite.cpp -ljsoncpp -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=0 -o stringWrite** diff --git a/example/readFromStream/readFromStream.cpp b/example/readFromStream/readFromStream.cpp index c4d0dcceb7df89ad96369ea2f97c1485332eaefb..358d2cab0a59ea63f23b16aa2c834018f80e2470 100755 --- a/example/readFromStream/readFromStream.cpp +++ b/example/readFromStream/readFromStream.cpp @@ -1,5 +1,4 @@ #include "json/json.h" -#include #include #include /** \brief Parse from stream, collect comments and capture error info. diff --git a/example/readFromString/readFromString.cpp b/example/readFromString/readFromString.cpp index 2c4c8a8f2693eee08dd8e069b9afa2ac40ecae59..0b29a4e86174f067587d74d731d633e57785a188 100755 --- a/example/readFromString/readFromString.cpp +++ b/example/readFromString/readFromString.cpp @@ -1,6 +1,6 @@ #include "json/json.h" -#include #include +#include /** * \brief Parse a raw string into Value object using the CharReaderBuilder * class, or the legacy Reader class. @@ -11,9 +11,9 @@ * 20 */ int main() { - const std::string rawJson = "{\"Age\": 20, \"Name\": \"colin\"}"; - const int rawJsonLength = static_cast(rawJson.length()); - JSONCPP_CONST bool shouldUseOldWay = false; + const std::string rawJson = R"({"Age": 20, "Name": "colin"})"; + const auto rawJsonLength = static_cast(rawJson.length()); + constexpr bool shouldUseOldWay = false; JSONCPP_STRING err; Json::Value root; @@ -22,13 +22,12 @@ int main() { reader.parse(rawJson, root); } else { Json::CharReaderBuilder builder; - Json::CharReader* reader(builder.newCharReader()); + const std::unique_ptr reader(builder.newCharReader()); if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLength, &root, &err)) { std::cout << "error" << std::endl; return EXIT_FAILURE; } - delete reader; } const std::string name = root["Name"].asString(); const int age = root["Age"].asInt(); diff --git a/example/streamWrite/streamWrite.cpp b/example/streamWrite/streamWrite.cpp index 461bebbdca0436c87a5690a0e64689c2eaa5947e..a72f5a52ed7591638f03b4c13a8b487e6881222f 100755 --- a/example/streamWrite/streamWrite.cpp +++ b/example/streamWrite/streamWrite.cpp @@ -1,5 +1,6 @@ #include "json/json.h" #include +#include /** \brief Write the Value object to a stream. * Example Usage: * $g++ streamWrite.cpp -ljsoncpp -std=c++11 -o streamWrite @@ -12,11 +13,11 @@ int main() { Json::Value root; Json::StreamWriterBuilder builder; - Json::StreamWriter* writer(builder.newStreamWriter()); + const std::unique_ptr writer(builder.newStreamWriter()); root["Name"] = "robin"; root["Age"] = 20; writer->write(root, &std::cout); - delete writer; + return EXIT_SUCCESS; } diff --git a/example/stringWrite/stringWrite.cpp b/example/stringWrite/stringWrite.cpp index 05b13075da34f80a703c37794098feceaf05df5e..d501ba9482f68db9e6f1a7229b12069526e9825a 100755 --- a/example/stringWrite/stringWrite.cpp +++ b/example/stringWrite/stringWrite.cpp @@ -1,5 +1,4 @@ #include "json/json.h" -#include #include /** \brief Write a Value object to a string. * Example Usage: @@ -16,7 +15,7 @@ int main() { Json::Value root; Json::Value data; - JSONCPP_CONST bool shouldUseOldWay = false; + constexpr bool shouldUseOldWay = false; root["action"] = "run"; data["number"] = 1; root["data"] = data; diff --git a/get_version.pl b/get_version.pl new file mode 100755 index 0000000000000000000000000000000000000000..19b6a543ba30aa2ff57c797992358e254af83fef --- /dev/null +++ b/get_version.pl @@ -0,0 +1,5 @@ +while (<>) { + if (/version : '(.+)',/) { + print "$1"; + } +} diff --git a/include/PreventInBuildInstalls.cmake b/include/PreventInBuildInstalls.cmake new file mode 100755 index 0000000000000000000000000000000000000000..accfea64c12f51e8f147de496cbb8f91d1b72b42 --- /dev/null +++ b/include/PreventInBuildInstalls.cmake @@ -0,0 +1,9 @@ +string(TOLOWER "${CMAKE_INSTALL_PREFIX}" _PREFIX) +string(TOLOWER "${ITK_BINARY_DIR}" _BUILD) +if("${_PREFIX}" STREQUAL "${_BUILD}") + message(FATAL_ERROR + "The current CMAKE_INSTALL_PREFIX points at the build tree:\n" + " ${CMAKE_INSTALL_PREFIX}\n" + "This is not supported." + ) +endif() diff --git a/include/PreventInSourceBuilds.cmake b/include/PreventInSourceBuilds.cmake new file mode 100755 index 0000000000000000000000000000000000000000..7ddda546a76c403220fa6c9975fa6007480a9034 --- /dev/null +++ b/include/PreventInSourceBuilds.cmake @@ -0,0 +1,45 @@ +# +# This function will prevent in-source builds +function(AssureOutOfSourceBuilds) + # make sure the user doesn't play dirty with symlinks + get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) + get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) + + # disallow in-source builds + if("${srcdir}" STREQUAL "${bindir}") + message("######################################################") + message("# jsoncpp should not be configured & built in the jsoncpp source directory") + message("# You must run cmake in a build directory.") + message("# For example:") + message("# mkdir jsoncpp-Sandbox ; cd jsoncpp-sandbox") + message("# git clone https://github.com/open-source-parsers/jsoncpp.git # or download & unpack the source tarball") + message("# mkdir jsoncpp-build") + message("# this will create the following directory structure") + message("#") + message("# jsoncpp-Sandbox") + message("# +--jsoncpp") + message("# +--jsoncpp-build") + message("#") + message("# Then you can proceed to configure and build") + message("# by using the following commands") + message("#") + message("# cd jsoncpp-build") + message("# cmake ../jsoncpp # or ccmake, or cmake-gui ") + message("# make") + message("#") + message("# NOTE: Given that you already tried to make an in-source build") + message("# CMake have already created several files & directories") + message("# in your source tree. run 'git status' to find them and") + message("# remove them by doing:") + message("#") + message("# cd jsoncpp-Sandbox/jsoncpp") + message("# git clean -n -d") + message("# git clean -f -d") + message("# git checkout --") + message("#") + message("######################################################") + message(FATAL_ERROR "Quitting configuration") + endif() +endfunction() + +AssureOutOfSourceBuilds() diff --git a/include/json/allocator.h b/include/json/allocator.h index 0f5c224b9d72f74ccb590e9cbd2b3f85ec187faf..95ef8a5ec4d66b9aad6a0e0c1252c20a9a245791 100755 --- a/include/json/allocator.h +++ b/include/json/allocator.h @@ -35,11 +35,10 @@ public: * Release memory which was allocated for N items at pointer P. * * The memory block is filled with zeroes before being released. - * The pointer argument is tagged as "volatile" to prevent the - * compiler optimizing out this critical step. */ - void deallocate(volatile pointer p, size_type n) { - std::memset(p, 0, n * sizeof(T)); + void deallocate(pointer p, size_type n) { + // memset_s is used because memset may be optimized away by the compiler + memset_s(p, n * sizeof(T), 0, n * sizeof(T)); // free using "global operator delete" ::operator delete(p); } diff --git a/include/json/assertions.h b/include/json/assertions.h index 3bdbf8ac67fe921606696442f2e8e66d1214cd59..666fa7f542ccef943baa133f3bbf9e8b19845104 100755 --- a/include/json/assertions.h +++ b/include/json/assertions.h @@ -58,10 +58,4 @@ } \ } 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 diff --git a/include/json/config.h b/include/json/config.h index 7f9ac696bb69d095427e8c2b611b9525691ae748..6359273a2228f822b1e9634a9221cc82f18bd491 100755 --- a/include/json/config.h +++ b/include/json/config.h @@ -5,20 +5,14 @@ #ifndef JSON_CONFIG_H_INCLUDED #define JSON_CONFIG_H_INCLUDED - +#include +#include #include #include #include #include #include - -#if JSONCPP_CXX_STD_11 -#include // typedef ptrdiff_t -#include // typedef int64_t, uint64_t -#else -#include -#include -#endif +#include // If non-zero, the library uses exceptions to report bad input instead of C // assertion macros. The default is to use exceptions. @@ -56,6 +50,11 @@ #define JSON_API #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 // As recommended at // 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. // #define JSON_NO_INT64 1 -#if __cplusplus >= 201103L || defined(_MSC_VER) -#define JSONCPP_OP_EXPLICIT explicit -#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 +// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools. +// C++11 should be used directly in JSONCPP. #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__ #if __has_extension(attribute_deprecated_with_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 #if !defined(JSON_IS_AMALGAMATION) -#if JSONCPP_CXX_STD_11 + #include "allocator.h" -#endif #include "version.h" #endif // if !defined(JSON_IS_AMALGAMATION) namespace Json { - -typedef int Int; -typedef unsigned int UInt; +using Int = int; +using UInt = unsigned int; #if defined(JSON_NO_INT64) -typedef int LargestInt; -typedef unsigned int LargestUInt; +using LargestInt = int; +using LargestUInt = unsigned int; #undef JSON_HAS_INT64 #else // if defined(JSON_NO_INT64) // For Microsoft Visual use specific types as long long is not supported #if defined(_MSC_VER) // Microsoft Visual Studio -typedef __int64 Int64; -typedef unsigned __int64 UInt64; +using Int64 = __int64; +using UInt64 = unsigned __int64; #else // if defined(_MSC_VER) // Other platforms, use long long -typedef int64_t Int64; -typedef uint64_t UInt64; +using Int64 = int64_t; +using UInt64 = uint64_t; #endif // if defined(_MSC_VER) -typedef Int64 LargestInt; -typedef UInt64 LargestUInt; +using LargestInt = Int64; +using LargestUInt = UInt64; #define JSON_HAS_INT64 #endif // if defined(JSON_NO_INT64) -#if JSONCPP_CXX_STD_11 template using Allocator = typename std::conditional, @@ -173,20 +138,13 @@ using OStringStream = String::allocator_type>; using IStream = std::istream; 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 // Legacy names (formerly macros). -typedef Json::String JSONCPP_STRING; -typedef Json::IStringStream JSONCPP_ISTRINGSTREAM; -typedef Json::OStringStream JSONCPP_OSTRINGSTREAM; -typedef Json::IStream JSONCPP_ISTREAM; -typedef Json::OStream JSONCPP_OSTREAM; +using JSONCPP_STRING = Json::String; +using JSONCPP_ISTRINGSTREAM = Json::IStringStream; +using JSONCPP_OSTRINGSTREAM = Json::OStringStream; +using JSONCPP_ISTREAM = Json::IStream; +using JSONCPP_OSTREAM = Json::OStream; #endif // JSON_CONFIG_H_INCLUDED diff --git a/include/json/forwards.h b/include/json/forwards.h index b0d981be035e8e489e5aa856eab7f4ad36e31eef..affe33a7f9ec662ede90eef7dd200da89aa7dede 100755 --- a/include/json/forwards.h +++ b/include/json/forwards.h @@ -29,7 +29,7 @@ class CharReaderBuilder; class Features; // value.h -typedef unsigned int ArrayIndex; +using ArrayIndex = unsigned int; class StaticString; class Path; class PathArgument; diff --git a/include/json/json_features.h b/include/json/json_features.h index 1d7bb4233b28d2dbb859af9d1ecf400941d034c9..7c7e9f5de15e259eba132de8efa5d80b78f9f92c 100755 --- a/include/json/json_features.h +++ b/include/json/json_features.h @@ -41,17 +41,17 @@ public: Features(); /// \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 /// false. - bool strictRoot_; + bool strictRoot_{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. - bool allowNumericKeys_; + bool allowNumericKeys_{false}; }; } // namespace Json diff --git a/include/json/reader.h b/include/json/reader.h index 75f10b42cf7119b4945634d51943528da26631a9..be0d7676abc597c186a481d8e3d84c5643b2a482 100755 --- a/include/json/reader.h +++ b/include/json/reader.h @@ -33,11 +33,10 @@ namespace Json { * \deprecated Use CharReader and CharReaderBuilder. */ -class JSONCPP_DEPRECATED( - "Use CharReader and CharReaderBuilder instead.") JSON_API Reader { +class JSON_API Reader { public: - typedef char Char; - typedef const Char* Location; + using Char = char; + using Location = const Char*; /** \brief An error tagged with where in the JSON text it was encountered. * @@ -51,13 +50,13 @@ public: }; /** \brief Constructs a Reader allowing all features for parsing. + * \deprecated Use CharReader and CharReaderBuilder. */ - JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") Reader(); /** \brief Constructs a Reader allowing the specified feature set for parsing. + * \deprecated Use CharReader and CharReaderBuilder. */ - JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") Reader(const Features& features); /** \brief Read a Value from a JSON @@ -187,7 +186,7 @@ private: Location extra_; }; - typedef std::deque Errors; + using Errors = std::deque; bool readToken(Token& token); void skipSpaces(); @@ -210,8 +209,7 @@ private: unsigned int& unicode); bool decodeUnicodeEscapeSequence(Token& token, Location& current, Location end, unsigned int& unicode); - bool addError(const String& message, Token& token, - Location extra = JSONCPP_NULL); + bool addError(const String& message, Token& token, Location extra = nullptr); bool recoverFromError(TokenType skipUntilToken); bool addErrorAndRecover(const String& message, Token& token, TokenType skipUntilToken); @@ -227,25 +225,25 @@ private: static bool containsNewLine(Location begin, Location end); static String normalizeEOL(Location begin, Location end); - typedef std::stack Nodes; + using Nodes = std::stack; Nodes nodes_; Errors errors_; String document_; - Location begin_; - Location end_; - Location current_; - Location lastValueEnd_; - Value* lastValue_; + Location begin_{}; + Location end_{}; + Location current_{}; + Location lastValueEnd_{}; + Value* lastValue_{}; String commentsBefore_; Features features_; - bool collectComments_; + bool collectComments_{}; }; // Reader /** Interface for reading JSON from a char array. */ class JSON_API CharReader { public: - virtual ~CharReader() {} + virtual ~CharReader() = default; /** \brief Read a Value from a JSON * document. The document must be a UTF-8 encoded string containing the * document to read. @@ -267,7 +265,7 @@ public: class JSON_API Factory { public: - virtual ~Factory() {} + virtual ~Factory() = default; /** \brief Allocate a CharReader via operator new(). * \throw std::exception if something goes wrong (e.g. invalid settings) */ @@ -325,6 +323,9 @@ public: * - `"allowSpecialFloats": false or true` * - If true, special float values (NaNs and infinities) are allowed and * their values are lossfree restorable. + * - `"skipBom": false or true` + * - If true, if the input starts with the Unicode byte order mark (BOM), + * it is skipped. * * You can examine 'settings_` yourself to see the defaults. You can also * write and read them just like any JSON Value. @@ -333,9 +334,9 @@ public: Json::Value settings_; CharReaderBuilder(); - ~CharReaderBuilder() JSONCPP_OVERRIDE; + ~CharReaderBuilder() override; - CharReader* newCharReader() const JSONCPP_OVERRIDE; + CharReader* newCharReader() const override; /** \return true if 'settings' are legal and consistent; * otherwise, indicate bad settings via 'invalid'. diff --git a/include/json/value.h b/include/json/value.h index 988a22c179ab3a77921a990ca66b746235986473..0edeb050ca02dbd85f75751225a8824e23ac6b73 100755 --- a/include/json/value.h +++ b/include/json/value.h @@ -13,16 +13,13 @@ // Conditional NORETURN attribute on the throw functions would: // a) suppress false positives from static code analysis // b) possibly improve optimization opportunities. -// For compatibility, [[noreturn]] is not used #if !defined(JSONCPP_NORETURN) -#if defined(_MSC_VER) +#if defined(_MSC_VER) && _MSC_VER == 1800 #define JSONCPP_NORETURN __declspec(noreturn) -#elif defined(__GNUC__) || defined(__clang__) -#define JSONCPP_NORETURN __attribute__((noreturn)) #else -#define JSONCPP_NORETURN +#define JSONCPP_NORETURN [[noreturn]] +#endif #endif -#endif // if !defined(JSONCPP_NORETURN) // 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 @@ -42,15 +39,10 @@ #endif #endif -#if JSONCPP_CXX_STD_11 -#else -#undef JSONCPP_TEMPLATE_DELETE -#define JSONCPP_TEMPLATE_DELETE -#include -#endif - +#include #include #include +#include #include #include @@ -58,7 +50,7 @@ // be used by... #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma warning(push) -#pragma warning(disable : 4251) +#pragma warning(disable : 4251 4275) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #pragma pack(push, 8) @@ -75,8 +67,8 @@ namespace Json { class JSON_API Exception : public std::exception { public: Exception(String msg); - ~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; - char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; + ~Exception() noexcept override; + char const* what() const noexcept override; protected: String msg_; @@ -154,7 +146,7 @@ enum PrecisionType { */ class JSON_API StaticString { 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_; } @@ -202,21 +194,21 @@ class JSON_API Value { friend class ValueIteratorBase; public: - typedef std::vector Members; - typedef ValueIterator iterator; - typedef ValueConstIterator const_iterator; - typedef Json::UInt UInt; - typedef Json::Int Int; + using Members = std::vector; + using iterator = ValueIterator; + using const_iterator = ValueConstIterator; + using UInt = Json::UInt; + using Int = Json::Int; #if defined(JSON_HAS_INT64) - typedef Json::UInt64 UInt64; - typedef Json::Int64 Int64; + using UInt64 = Json::UInt64; + using Int64 = Json::Int64; #endif // defined(JSON_HAS_INT64) - typedef Json::LargestInt LargestInt; - typedef Json::LargestUInt LargestUInt; - typedef Json::ArrayIndex ArrayIndex; + using LargestInt = Json::LargestInt; + using LargestUInt = Json::LargestUInt; + using ArrayIndex = Json::ArrayIndex; // Required for boost integration, e. g. BOOST_TEST - typedef std::string value_type; + using value_type = std::string; #if JSON_USE_NULLREF // Binary compatibility kludges, do not use. @@ -228,35 +220,34 @@ public: static Value const& nullSingleton(); /// 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)); /// Maximum signed integer value that can be stored in a Json::Value. - static JSONCPP_CONST LargestInt maxLargestInt = - LargestInt(LargestUInt(-1) / 2); + static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2); /// 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. - 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. - 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. - static JSONCPP_CONST UInt maxUInt = UInt(-1); + static constexpr UInt maxUInt = UInt(-1); #if defined(JSON_HAS_INT64) /// 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. - 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. - static JSONCPP_CONST UInt64 maxUInt64 = UInt64(-1); + static constexpr UInt64 maxUInt64 = UInt64(-1); #endif // defined(JSON_HAS_INT64) /// 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 // converting Value::maxUInt64 to a double correctly (AIX/xlC). // 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 // when using gcc and clang backend compilers. CZString // cannot be defined as private. See issue #486 @@ -272,14 +263,11 @@ private: CZString(ArrayIndex index); CZString(char const* str, unsigned length, DuplicationPolicy allocate); CZString(CZString const& other); -#if JSONCPP_CXX_STD_11 - CZString(CZString&& other); -#endif + CZString(CZString&& other) noexcept; ~CZString(); CZString& operator=(const CZString& other); -#if JSONCPP_CXX_STD_11 - CZString& operator=(CZString&& other); -#endif + CZString& operator=(CZString&& other) noexcept; + bool operator<(CZString const& other) const; bool operator==(CZString const& other) const; ArrayIndex index() const; @@ -354,18 +342,15 @@ public: Value(const StaticString& value); Value(const String& value); Value(bool value); + Value(std::nullptr_t ptr) = delete; Value(const Value& other); -#if JSONCPP_CXX_STD_11 - Value(Value&& other); -#endif + Value(Value&& other) noexcept; ~Value(); /// \note Overwrite existing comments. To preserve comments, use /// #swapPayload(). Value& operator=(const Value& other); -#if JSONCPP_CXX_STD_11 - Value& operator=(Value&& other); -#endif + Value& operator=(Value&& other) noexcept; /// Swap everything. void swap(Value& other); @@ -437,7 +422,7 @@ public: bool empty() const; /// Return !isNull() - JSONCPP_OP_EXPLICIT operator bool() const; + explicit operator bool() const; /// Remove all object members and array elements. /// \pre type() is arrayValue, objectValue, or nullValue @@ -478,15 +463,11 @@ public: /// /// Equivalent to jsonvalue[jsonvalue.size()] = value; Value& append(const Value& value); -#if JSONCPP_CXX_STD_11 Value& append(Value&& value); -#endif /// \brief Insert value in array at specific index bool insert(ArrayIndex index, const Value& newValue); -#if JSONCPP_CXX_STD_11 bool insert(ArrayIndex index, Value&& newValue); -#endif /// 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. @@ -582,11 +563,15 @@ public: /// \deprecated Always pass len. 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 /* ... */ - 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 /* ... */ - void setComment(const String& comment, CommentPlacement placement); + void setComment(String comment, CommentPlacement placement); bool hasComment(CommentPlacement placement) const; /// Include delimiters and embedded newlines. String getComment(CommentPlacement placement) const; @@ -648,15 +633,18 @@ private: class Comments { public: - Comments() {} + Comments() = default; Comments(const Comments& that); + Comments(Comments&& that) noexcept; Comments& operator=(const Comments& that); + Comments& operator=(Comments&& that) noexcept; bool has(CommentPlacement slot) const; String get(CommentPlacement slot) const; - void set(CommentPlacement slot, String s); + void set(CommentPlacement slot, String comment); private: - String ptr_[numberOfCommentPlacement]; + using Array = std::array; + std::unique_ptr ptr_; }; Comments comments_; @@ -711,8 +699,8 @@ public: private: enum Kind { kindNone = 0, kindIndex, kindKey }; String key_; - ArrayIndex index_; - Kind kind_; + ArrayIndex index_{}; + Kind kind_{kindNone}; }; /** \brief Experimental and untested: represents a "path" to access a node. @@ -741,8 +729,8 @@ public: Value& make(Value& root) const; private: - typedef std::vector InArgs; - typedef std::vector Args; + using InArgs = std::vector; + using Args = std::vector; void makePath(const String& path, const InArgs& in); void addPathInArg(const String& path, const InArgs& in, @@ -757,10 +745,10 @@ private: */ class JSON_API ValueIteratorBase { public: - typedef std::bidirectional_iterator_tag iterator_category; - typedef unsigned int size_t; - typedef int difference_type; - typedef ValueIteratorBase SelfType; + using iterator_category = std::bidirectional_iterator_tag; + using size_t = unsigned int; + using difference_type = int; + using SelfType = ValueIteratorBase; bool operator==(const SelfType& other) const { return isEqual(other); } @@ -817,14 +805,13 @@ protected: private: Value::ObjectValues::iterator current_; // Indicates that iterator is for a null value. - bool isNull_; + bool isNull_{true}; public: // For some reason, BORLAND needs these at the end, rather // than earlier. No idea why. ValueIteratorBase(); - JSONCPP_OP_EXPLICIT - ValueIteratorBase(const Value::ObjectValues::iterator& current); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); }; /** \brief const iterator for object and array value. @@ -834,12 +821,12 @@ class JSON_API ValueConstIterator : public ValueIteratorBase { friend class Value; public: - typedef const Value value_type; + using value_type = const Value; // typedef unsigned int size_t; // typedef int difference_type; - typedef const Value& reference; - typedef const Value* pointer; - typedef ValueConstIterator SelfType; + using reference = const Value&; + using pointer = const Value*; + using SelfType = ValueConstIterator; ValueConstIterator(); ValueConstIterator(ValueIterator const& other); @@ -847,8 +834,7 @@ public: private: /*! \internal Use by Value to create an iterator. */ - JSONCPP_OP_EXPLICIT - ValueConstIterator(const Value::ObjectValues::iterator& current); + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); public: SelfType& operator=(const ValueIteratorBase& other); @@ -886,22 +872,21 @@ class JSON_API ValueIterator : public ValueIteratorBase { friend class Value; public: - typedef Value value_type; - typedef unsigned int size_t; - typedef int difference_type; - typedef Value& reference; - typedef Value* pointer; - typedef ValueIterator SelfType; + using value_type = Value; + using size_t = unsigned int; + using difference_type = int; + using reference = Value&; + using pointer = Value*; + using SelfType = ValueIterator; ValueIterator(); - JSONCPP_OP_EXPLICIT ValueIterator(const ValueConstIterator& other); + explicit ValueIterator(const ValueConstIterator& other); ValueIterator(const ValueIterator& other); private: /*! \internal Use by Value to create an iterator. */ - JSONCPP_OP_EXPLICIT - ValueIterator(const Value::ObjectValues::iterator& current); + explicit ValueIterator(const Value::ObjectValues::iterator& current); public: SelfType& operator=(const SelfType& other); @@ -933,8 +918,8 @@ public: * because the returned references/pointers can be used * to change state of the base class. */ - reference operator*() { return deref(); } - pointer operator->() { return &deref(); } + reference operator*() const { return const_cast(deref()); } + pointer operator->() const { return const_cast(&deref()); } }; inline void swap(Value& a, Value& b) { a.swap(b); } diff --git a/include/json/version.h b/include/json/version.h index fa681e820d7a27859cd9410ec05b0e77eb34551b..e931d0383e3776af0f80713772912a94e247535f 100755 --- a/include/json/version.h +++ b/include/json/version.h @@ -9,10 +9,10 @@ // 3. /CMakeLists.txt // IMPORTANT: also update the SOVERSION!! -#define JSONCPP_VERSION_STRING "00.11.0" -#define JSONCPP_VERSION_MAJOR 00 -#define JSONCPP_VERSION_MINOR 11 -#define JSONCPP_VERSION_PATCH 0 +#define JSONCPP_VERSION_STRING "1.9.5" +#define JSONCPP_VERSION_MAJOR 1 +#define JSONCPP_VERSION_MINOR 9 +#define JSONCPP_VERSION_PATCH 5 #define JSONCPP_VERSION_QUALIFIER #define JSONCPP_VERSION_HEXA \ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ diff --git a/include/json/writer.h b/include/json/writer.h index e851c377e38e11d3f29d3dcdac73de6680297cae..88a3b12e9ddadc8f5544d3ce86e17289d06dc02f 100755 --- a/include/json/writer.h +++ b/include/json/writer.h @@ -110,6 +110,8 @@ public: * - Number of precision digits for formatting of real values. * - "precisionType": "significant"(default) or "decimal" * - Type of precision for formatting of real values. + * - "emitUTF8": false or true + * - If true, outputs raw UTF8 strings instead of escaping them. * You can examine 'settings_` yourself * to see the defaults. You can also write and read them just like any @@ -119,12 +121,12 @@ public: Json::Value settings_; StreamWriterBuilder(); - ~StreamWriterBuilder() JSONCPP_OVERRIDE; + ~StreamWriterBuilder() override; /** * \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; * otherwise, indicate bad settings via 'invalid'. @@ -145,7 +147,7 @@ public: /** \brief Abstract class for writers. * \deprecated Use StreamWriter. (And really, this is an implementation detail.) */ -class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer { +class JSON_API Writer { public: virtual ~Writer(); @@ -165,11 +167,11 @@ public: #pragma warning(push) #pragma warning(disable : 4996) // Deriving from deprecated class #endif -class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter +class JSON_API FastWriter : public Writer { public: FastWriter(); - ~FastWriter() JSONCPP_OVERRIDE {} + ~FastWriter() override = default; void enableYAMLCompatibility(); @@ -183,15 +185,15 @@ public: void omitEndingLineFeed(); public: // overridden from Writer - String write(const Value& root) JSONCPP_OVERRIDE; + String write(const Value& root) override; private: void writeValue(const Value& value); String document_; - bool yamlCompatibilityEnabled_; - bool dropNullPlaceholders_; - bool omitEndingLineFeed_; + bool yamlCompatibilityEnabled_{false}; + bool dropNullPlaceholders_{false}; + bool omitEndingLineFeed_{false}; }; #if defined(_MSC_VER) #pragma warning(pop) @@ -225,18 +227,18 @@ private: #pragma warning(push) #pragma warning(disable : 4996) // Deriving from deprecated class #endif -class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API +class JSON_API StyledWriter : public Writer { public: StyledWriter(); - ~StyledWriter() JSONCPP_OVERRIDE {} + ~StyledWriter() override = default; public: // overridden from Writer /** \brief Serialize a Value in JSON format. * \param root Value to serialize. * \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: void writeValue(const Value& value); @@ -252,14 +254,14 @@ private: static bool hasCommentForValue(const Value& value); static String normalizeEOL(const String& text); - typedef std::vector ChildValues; + using ChildValues = std::vector; ChildValues childValues_; String document_; String indentString_; - unsigned int rightMargin_; - unsigned int indentSize_; - bool addChildValues_; + unsigned int rightMargin_{74}; + unsigned int indentSize_{3}; + bool addChildValues_{false}; }; #if defined(_MSC_VER) #pragma warning(pop) @@ -294,14 +296,14 @@ private: #pragma warning(push) #pragma warning(disable : 4996) // Deriving from deprecated class #endif -class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API +class JSON_API StyledStreamWriter { public: /** * \param indentation Each level will be indented by this amount extra. */ StyledStreamWriter(String indentation = "\t"); - ~StyledStreamWriter() {} + ~StyledStreamWriter() = default; public: /** \brief Serialize a Value in JSON format. @@ -326,12 +328,12 @@ private: static bool hasCommentForValue(const Value& value); static String normalizeEOL(const String& text); - typedef std::vector ChildValues; + using ChildValues = std::vector; ChildValues childValues_; OStream* document_; String indentString_; - unsigned int rightMargin_; + unsigned int rightMargin_{74}; String indentation_; bool addChildValues_ : 1; bool indented_ : 1; @@ -348,7 +350,7 @@ String JSON_API valueToString(LargestInt value); String JSON_API valueToString(LargestUInt value); String JSON_API valueToString( double value, unsigned int precision = Value::defaultRealPrecision, - PrecisionType precisionType = significantDigits); + PrecisionType precisionType = PrecisionType::significantDigits); String JSON_API valueToString(bool value); String JSON_API valueToQuotedString(const char* value); diff --git a/jsoncpp-namespaced-targets.cmake b/jsoncpp-namespaced-targets.cmake new file mode 100755 index 0000000000000000000000000000000000000000..ac1504e00cc7575ad800452e72df0ff59e5416b3 --- /dev/null +++ b/jsoncpp-namespaced-targets.cmake @@ -0,0 +1,7 @@ +if (TARGET jsoncpp_static) + add_library(JsonCpp::JsonCpp INTERFACE IMPORTED) + set_target_properties(JsonCpp::JsonCpp PROPERTIES INTERFACE_LINK_LIBRARIES "jsoncpp_static") +elseif (TARGET jsoncpp_lib) + add_library(JsonCpp::JsonCpp INTERFACE IMPORTED) + set_target_properties(JsonCpp::JsonCpp PROPERTIES INTERFACE_LINK_LIBRARIES "jsoncpp_lib") +endif () \ No newline at end of file diff --git a/jsoncppConfig.cmake.in b/jsoncppConfig.cmake.in new file mode 100755 index 0000000000000000000000000000000000000000..76570bc3059451d26b906ddb5af8e02a3c094d4b --- /dev/null +++ b/jsoncppConfig.cmake.in @@ -0,0 +1,11 @@ +cmake_policy(PUSH) +cmake_policy(VERSION 3.0) + +@PACKAGE_INIT@ + +include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-targets.cmake" ) +include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-namespaced-targets.cmake" ) + +check_required_components(JsonCpp) + +cmake_policy(POP) diff --git a/meson.build b/meson.build index 040a6bdb93c98d2a8559856dc91416e3a469dfd6..f68db30dd3f1e646039474c601c02fcc0bb634b4 100755 --- a/meson.build +++ b/meson.build @@ -9,7 +9,7 @@ project( # 2. /include/json/version.h # 3. /CMakeLists.txt # IMPORTANT: also update the SOVERSION!! - version : '00.11.0', + version : '1.9.4', default_options : [ 'buildtype=release', 'cpp_std=c++11', @@ -50,7 +50,7 @@ jsoncpp_lib = library( 'src/lib_json/json_value.cpp', 'src/lib_json/json_writer.cpp', ]), - soversion : 23, + soversion : 25, install : true, include_directories : jsoncpp_include_directories, cpp_args: dll_export_flag) @@ -73,7 +73,7 @@ if meson.is_subproject() or not get_option('tests') subdir_done() endif -python = import('python').find_installation('python3') +python = import('python').find_installation() jsoncpp_test = executable( 'jsoncpp_test', files([ diff --git a/pkg-config/jsoncpp.pc.in b/pkg-config/jsoncpp.pc.in index d4fa9ef265a59cdb6890709965c059575b7bd7b3..2a2221069308e653a8e51626a976282fedc08da7 100755 --- a/pkg-config/jsoncpp.pc.in +++ b/pkg-config/jsoncpp.pc.in @@ -1,11 +1,11 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ -libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ -includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ +libdir=@libdir_for_pc_file@ +includedir=@includedir_for_pc_file@ Name: jsoncpp Description: A C++ library for interacting with JSON -Version: @JSONCPP_VERSION@ +Version: @PROJECT_VERSION@ URL: https://github.com/open-source-parsers/jsoncpp Libs: -L${libdir} -ljsoncpp Cflags: -I${includedir} diff --git a/reformat.sh b/reformat.sh new file mode 100755 index 0000000000000000000000000000000000000000..cdc03b1eab40ce0a9e9642d54950c5e368b97676 --- /dev/null +++ b/reformat.sh @@ -0,0 +1 @@ +find src -name '*.cpp' -or -name '*.h' | xargs clang-format -i diff --git a/src/jsontestrunner/CMakeLists.txt b/src/jsontestrunner/CMakeLists.txt index d24aa6f461186455f04e34ca96b8647b7e9017d4..1fc71ea870b89b333930faa754701cfd9d4dc7a0 100755 --- a/src/jsontestrunner/CMakeLists.txt +++ b/src/jsontestrunner/CMakeLists.txt @@ -19,8 +19,10 @@ if(BUILD_SHARED_LIBS) else() add_definitions(-DJSON_DLL) endif() + target_link_libraries(jsontestrunner_exe jsoncpp_lib) +else() + target_link_libraries(jsontestrunner_exe jsoncpp_static) endif() -target_link_libraries(jsontestrunner_exe jsoncpp_lib) set_target_properties(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_exe) diff --git a/src/jsontestrunner/main.cpp b/src/jsontestrunner/main.cpp index 5657c93559e2b86c184d86b74b492293a6104ad0..df717ffd586cc9eaecc604b64f99d8a5e57750c0 100755 --- a/src/jsontestrunner/main.cpp +++ b/src/jsontestrunner/main.cpp @@ -24,9 +24,7 @@ struct Options { Json::String path; Json::Features features; bool parseOnly; - - typedef Json::String (*writeFuncType)(Json::Value const&); - + using writeFuncType = Json::String (*)(Json::Value const&); writeFuncType write; }; @@ -59,11 +57,11 @@ static Json::String readInputTestFile(const char* path) { if (!file) return ""; fseek(file, 0, SEEK_END); - long const size = ftell(file); - size_t const usize = static_cast(size); + auto const size = ftell(file); + auto const usize = static_cast(size); fseek(file, 0, SEEK_SET); - char* buffer = new char[usize + 1]; - buffer[usize] = 0; + auto buffer = new char[size + 1]; + buffer[size] = 0; Json::String text; if (fread(buffer, 1, usize, file) == usize) text = buffer; @@ -113,9 +111,7 @@ static void printValueTree(FILE* fout, Json::Value& value, Json::Value::Members members(value.getMemberNames()); std::sort(members.begin(), members.end()); Json::String suffix = *(path.end() - 1) == '.' ? "" : "."; - for (Json::Value::Members::const_iterator it = members.begin(); - it != members.end(); it++) { - const Json::String& name = *it; + for (const auto& name : members) { printValueTree(fout, value[name], path + suffix + name); } } break; @@ -142,7 +138,7 @@ static int parseAndSaveValueTree(const Json::String& input, features.allowDroppedNullPlaceholders_; builder.settings_["allowNumericKeys"] = features.allowNumericKeys_; - Json::CharReader* reader(builder.newCharReader()); + std::unique_ptr reader(builder.newCharReader()); Json::String errors; const bool parsingSuccessful = reader->parse(input.data(), input.data() + input.size(), root, &errors); @@ -152,7 +148,7 @@ static int parseAndSaveValueTree(const Json::String& input, << errors << std::endl; return 1; } - delete reader; + // We may instead check the legacy implementation (to ensure it doesn't // randomly get broken). } else { @@ -339,6 +335,7 @@ int main(int argc, const char* argv[]) { std::cerr << "Unhandled exception:" << std::endl << e.what() << std::endl; return 1; } + return 0; } #if defined(__GNUC__) diff --git a/src/lib_json/CMakeLists.txt b/src/lib_json/CMakeLists.txt index 6686c4de17c8c7819828a64e808194b0732e668b..b7596e80b426bc59db164fe738e63634196d5b20 100755 --- a/src/lib_json/CMakeLists.txt +++ b/src/lib_json/CMakeLists.txt @@ -11,20 +11,10 @@ include(CheckCXXSymbolExists) check_include_file_cxx(clocale HAVE_CLOCALE) check_cxx_symbol_exists(localeconv clocale HAVE_LOCALECONV) -if(CMAKE_VERSION VERSION_LESS 3.0.0) - # The "LANGUAGE CXX" parameter is not supported in CMake versions below 3, - # so the C compiler and header has to be used. - check_include_file(locale.h HAVE_LOCALE_H) - set(CMAKE_EXTRA_INCLUDE_FILES locale.h) - check_type_size("struct lconv" LCONV_SIZE) - unset(CMAKE_EXTRA_INCLUDE_FILES) - check_struct_has_member("struct lconv" decimal_point locale.h HAVE_DECIMAL_POINT) -else() - set(CMAKE_EXTRA_INCLUDE_FILES clocale) - check_type_size(lconv LCONV_SIZE LANGUAGE CXX) - unset(CMAKE_EXTRA_INCLUDE_FILES) - check_struct_has_member(lconv decimal_point clocale HAVE_DECIMAL_POINT LANGUAGE CXX) -endif() +set(CMAKE_EXTRA_INCLUDE_FILES clocale) +check_type_size(lconv LCONV_SIZE LANGUAGE CXX) +unset(CMAKE_EXTRA_INCLUDE_FILES) +check_struct_has_member(lconv decimal_point clocale HAVE_DECIMAL_POINT LANGUAGE CXX) if(NOT (HAVE_CLOCALE AND HAVE_LCONV_SIZE AND HAVE_DECIMAL_POINT AND HAVE_LOCALECONV)) message(WARNING "Locale functionality is not supported") @@ -50,7 +40,7 @@ set(PUBLIC_HEADERS source_group("Public API" FILES ${PUBLIC_HEADERS}) -set(jsoncpp_sources +set(JSONCPP_SOURCES json_tool.h json_reader.cpp json_valueiterator.inl @@ -65,33 +55,10 @@ else() set(INSTALL_EXPORT) endif() - -if(BUILD_SHARED_LIBS) - if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) - add_compile_definitions(JSON_DLL_BUILD) - else() - add_definitions(-DJSON_DLL_BUILD) - endif() -endif() - -add_library(jsoncpp_lib ${PUBLIC_HEADERS} ${jsoncpp_sources}) -set_target_properties( jsoncpp_lib PROPERTIES - OUTPUT_NAME jsoncpp - VERSION ${JSONCPP_VERSION} - SOVERSION ${JSONCPP_SOVERSION} - POSITION_INDEPENDENT_CODE ON -) - -# Set library's runtime search path on OSX -if(APPLE) - set_target_properties(jsoncpp_lib PROPERTIES INSTALL_RPATH "@loader_path/.") -endif() - # 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 # for complete list of features available -if(CMAKE_CXX_STANDARD EQUAL "11") -target_compile_features(jsoncpp_lib PUBLIC +list(APPEND REQUIRED_FEATURES cxx_std_11 # Compiler mode is aware of C++ 11. #MSVC 1900 cxx_alignas # Alignment control alignas, as defined in N2341. #MSVC 1900 cxx_alignof # Alignment control alignof, as defined in N2341. @@ -137,21 +104,105 @@ target_compile_features(jsoncpp_lib PUBLIC cxx_variadic_macros # Variadic macros, as defined in N1653. cxx_variadic_templates # Variadic templates, as defined in N2242. ) -else() - set(CMAKE_CXX_STANDARD 98) - target_compile_features(jsoncpp_lib PUBLIC) + + +if(BUILD_SHARED_LIBS) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) + add_compile_definitions(JSON_DLL_BUILD) + else() + add_definitions(-DJSON_DLL_BUILD) + endif() + + set(SHARED_LIB ${PROJECT_NAME}_lib) + add_library(${SHARED_LIB} SHARED ${PUBLIC_HEADERS} ${JSONCPP_SOURCES}) + set_target_properties(${SHARED_LIB} PROPERTIES + OUTPUT_NAME jsoncpp + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_SOVERSION} + POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS} + ) + + # Set library's runtime search path on OSX + if(APPLE) + set_target_properties(${SHARED_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.") + endif() + + target_compile_features(${SHARED_LIB} PUBLIC ${REQUIRED_FEATURES}) + + target_include_directories(${SHARED_LIB} PUBLIC + $ + $ + $ + ) + + list(APPEND CMAKE_TARGETS ${SHARED_LIB}) endif() -install(TARGETS jsoncpp_lib ${INSTALL_EXPORT} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -) +if(BUILD_STATIC_LIBS) + set(STATIC_LIB ${PROJECT_NAME}_static) + add_library(${STATIC_LIB} STATIC ${PUBLIC_HEADERS} ${JSONCPP_SOURCES}) + + # avoid name clashes on windows as the shared import lib is alse named jsoncpp.lib + if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS) + if (MSVC) + set(STATIC_SUFFIX "_static") + else() + set(STATIC_SUFFIX "") + endif() + endif() + + set_target_properties(${STATIC_LIB} PROPERTIES + OUTPUT_NAME jsoncpp${STATIC_SUFFIX} + VERSION ${PROJECT_VERSION} + ) + + # Set library's runtime search path on OSX + if(APPLE) + set_target_properties(${STATIC_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.") + endif() + + target_compile_features(${STATIC_LIB} PUBLIC ${REQUIRED_FEATURES}) + + target_include_directories(${STATIC_LIB} PUBLIC + $ + $ + $ + ) + + list(APPEND CMAKE_TARGETS ${STATIC_LIB}) +endif() + +if(BUILD_OBJECT_LIBS) + set(OBJECT_LIB ${PROJECT_NAME}_object) + add_library(${OBJECT_LIB} OBJECT ${PUBLIC_HEADERS} ${JSONCPP_SOURCES}) + + set_target_properties(${OBJECT_LIB} PROPERTIES + OUTPUT_NAME jsoncpp + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_SOVERSION} + POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS} + ) + + # Set library's runtime search path on OSX + if(APPLE) + set_target_properties(${OBJECT_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.") + endif() -if(NOT CMAKE_VERSION VERSION_LESS 2.8.11) - target_include_directories(jsoncpp_lib PUBLIC + target_compile_features(${OBJECT_LIB} PUBLIC ${REQUIRED_FEATURES}) + + target_include_directories(${OBJECT_LIB} PUBLIC $ $ $ ) + + list(APPEND CMAKE_TARGETS ${OBJECT_LIB}) endif() + +install(TARGETS ${CMAKE_TARGETS} ${INSTALL_EXPORT} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp index cf3ec48b8aa62d2d52bc5c1d78f80af424e79867..a6a3f4e30ddd096ca6edefa8c9e7d956719ff7cf 100755 --- a/src/lib_json/json_reader.cpp +++ b/src/lib_json/json_reader.cpp @@ -10,6 +10,7 @@ #include #include #endif // if !defined(JSON_IS_AMALGAMATION) +#include #include #include #include @@ -51,15 +52,18 @@ static size_t const stackLimit_g = namespace Json { -typedef CharReader* CharReaderPtr; +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +using CharReaderPtr = std::unique_ptr; +#else +using CharReaderPtr = std::auto_ptr; +#endif // Implementation of class Features // //////////////////////////////// -Features::Features() - : allowComments_(true), strictRoot_(false), - allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} -Features Features::all() { return Features(); } +Features::Features() = default; + +Features Features::all() { return {}; } Features Features::strictMode() { Features features; @@ -74,24 +78,15 @@ Features Features::strictMode() { // //////////////////////////////// bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { - for (; begin < end; ++begin) - if (*begin == '\n' || *begin == '\r') - return true; - return false; + return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); } // Class Reader // ////////////////////////////////////////////////////////////////// -Reader::Reader() - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), features_(Features::all()), - collectComments_() {} +Reader::Reader() : features_(Features::all()) {} -Reader::Reader(const Features& features) - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), features_(features), collectComments_() { -} +Reader::Reader(const Features& features) : features_(features) {} bool Reader::parse(const std::string& document, Value& root, bool collectComments) { @@ -109,8 +104,7 @@ bool Reader::parse(std::istream& is, Value& root, bool collectComments) { // Since String is reference-counted, this at least does not // create an extra copy. - String doc; - std::getline(is, doc, static_cast EOF); + String doc(std::istreambuf_iterator(is), {}); return parse(doc.data(), doc.data() + doc.size(), root, collectComments); } @@ -124,8 +118,8 @@ bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root, end_ = endDoc; collectComments_ = collectComments; current_ = begin_; - lastValueEnd_ = JSONCPP_NULL; - lastValue_ = JSONCPP_NULL; + lastValueEnd_ = nullptr; + lastValue_ = nullptr; commentsBefore_.clear(); errors_.clear(); while (!nodes_.empty()) @@ -379,7 +373,7 @@ void Reader::addComment(Location begin, Location end, assert(collectComments_); const String& normalized = normalizeEOL(begin, end); if (placement == commentAfterOnSameLine) { - assert(lastValue_ != JSONCPP_NULL); + assert(lastValue_ != nullptr); lastValue_->setComment(normalized, placement); } else { commentsBefore_ += normalized; @@ -568,7 +562,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) { Char c = *current++; if (c < '0' || c > '9') return decodeDouble(token, decoded); - Value::UInt digit(static_cast(c - '0')); + auto digit(static_cast(c - '0')); if (value >= threshold) { // 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 @@ -772,10 +766,6 @@ void Reader::getLocationLineAndColumn(Location location, int& line, while (current < location && current != end_) { Char c = *current++; if (c == '\r') { - // Add boundary check to avoid cross the border - if (current == end_) { - break; - } if (*current == '\n') ++current; lastLineStart = current; @@ -805,9 +795,7 @@ String Reader::getFormatedErrorMessages() const { String Reader::getFormattedErrorMessages() const { String formattedMessage; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); ++itError) { - const ErrorInfo& error = *itError; + for (const auto& error : errors_) { formattedMessage += "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; formattedMessage += " " + error.message_ + "\n"; @@ -820,9 +808,7 @@ String Reader::getFormattedErrorMessages() const { std::vector Reader::getStructuredErrors() const { std::vector allErrors; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); ++itError) { - const ErrorInfo& error = *itError; + for (const auto& error : errors_) { Reader::StructuredError structured; structured.offset_start = error.token_.start_ - begin_; structured.offset_limit = error.token_.end_ - begin_; @@ -843,7 +829,7 @@ bool Reader::pushError(const Value& value, const String& message) { ErrorInfo info; info.token_ = token; info.message_ = message; - info.extra_ = JSONCPP_NULL; + info.extra_ = nullptr; errors_.push_back(info); return true; } @@ -886,7 +872,7 @@ public: size_t stackLimit_; }; // OurFeatures -OurFeatures OurFeatures::all() { return OurFeatures(); } +OurFeatures OurFeatures::all() { return {}; } // Implementation of class Reader // //////////////////////////////// @@ -895,15 +881,15 @@ OurFeatures OurFeatures::all() { return OurFeatures(); } // for implementing JSON reading. class OurReader { public: - typedef char Char; - typedef const Char* Location; + using Char = char; + using Location = const Char*; struct StructuredError { ptrdiff_t offset_start; ptrdiff_t offset_limit; 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 collectComments = true); String getFormattedErrorMessages() const; @@ -947,7 +933,7 @@ private: Location extra_; }; - typedef std::deque Errors; + using Errors = std::deque; bool readToken(Token& token); void skipSpaces(); @@ -972,8 +958,7 @@ private: unsigned int& unicode); bool decodeUnicodeEscapeSequence(Token& token, Location& current, Location end, unsigned int& unicode); - bool addError(const String& message, Token& token, - Location extra = JSONCPP_NULL); + bool addError(const String& message, Token& token, Location extra = nullptr); bool recoverFromError(TokenType skipUntilToken); bool addErrorAndRecover(const String& message, Token& token, TokenType skipUntilToken); @@ -989,38 +974,31 @@ private: static String normalizeEOL(Location begin, Location end); static bool containsNewLine(Location begin, Location end); - typedef std::stack Nodes; + using Nodes = std::stack; - Nodes nodes_; - Errors errors_; - String document_; - Location begin_; - Location end_; - Location current_; - Location lastValueEnd_; - Value* lastValue_; - bool lastValueHasAComment_; - String commentsBefore_; + Nodes nodes_{}; + Errors errors_{}; + String document_{}; + Location begin_ = nullptr; + Location end_ = nullptr; + Location current_ = nullptr; + Location lastValueEnd_ = nullptr; + Value* lastValue_ = nullptr; + bool lastValueHasAComment_ = false; + String commentsBefore_{}; OurFeatures const features_; - bool collectComments_; + bool collectComments_ = false; }; // OurReader // complete copy of Read impl, for OurReader bool OurReader::containsNewLine(OurReader::Location begin, OurReader::Location end) { - for (; begin < end; ++begin) - if (*begin == '\n' || *begin == '\r') - return true; - return false; + return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); } -OurReader::OurReader(OurFeatures const& 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) {} +OurReader::OurReader(OurFeatures const& features) : features_(features) {} bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root, bool collectComments) { @@ -1032,8 +1010,8 @@ bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root, end_ = endDoc; collectComments_ = collectComments; current_ = begin_; - lastValueEnd_ = JSONCPP_NULL; - lastValue_ = JSONCPP_NULL; + lastValueEnd_ = nullptr; + lastValue_ = nullptr; commentsBefore_.clear(); errors_.clear(); while (!nodes_.empty()) @@ -1196,8 +1174,11 @@ bool OurReader::readToken(Token& token) { if (features_.allowSingleQuotes_) { token.type_ = tokenString; ok = readStringSingleQuote(); - break; - } // else fall through + } else { + // If we don't allow single quotes, this is a failure case. + ok = false; + } + break; case '/': token.type_ = tokenComment; ok = readComment(); @@ -1368,7 +1349,7 @@ void OurReader::addComment(Location begin, Location end, assert(collectComments_); const String& normalized = normalizeEOL(begin, end); if (placement == commentAfterOnSameLine) { - assert(lastValue_ != JSONCPP_NULL); + assert(lastValue_ != nullptr); lastValue_->setComment(normalized, placement); } else { commentsBefore_ += normalized; @@ -1584,36 +1565,32 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) { // 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 // into an unsigned integer. - JSONCPP_STATIC_ASSERT(LargestUInt(Value::maxLargestInt) <= - Value::maxLargestUInt, - "Int must be smaller than Uint"); + static_assert(Value::maxLargestInt <= Value::maxLargestUInt, + "Int must be smaller than UInt"); + // We need to convert minLargestInt into a positive number. The easiest way // to do this conversion is to assume our "threshold" value of minLargestInt // divided by 10 can fit in maxLargestInt when absolute valued. This should // be a safe assumption. - JSONCPP_STATIC_ASSERT( - Value::minLargestInt <= -Value::maxLargestInt, - "The absolute value of minLargestInt must ve greater than or" - "equal to maxLargestInt"); - - JSONCPP_STATIC_ASSERT( - 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 = + static_assert(Value::minLargestInt <= -Value::maxLargestInt, + "The absolute value of minLargestInt must be greater than or " + "equal to maxLargestInt"); + static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt, + "The absolute value of minLargestInt must be only 1 magnitude " + "larger than maxLargest Int"); + + static constexpr Value::LargestUInt positive_threshold = Value::maxLargestUInt / 10; - static JSONCPP_CONST Value::UInt positive_last_digit = - Value::maxLargestUInt % 10; + static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10; // For the negative values, we have to be more careful. Since typically // -Value::minLargestInt will cause an overflow, we first divide by 10 and // 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 // 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)); - static JSONCPP_CONST Value::UInt negative_last_digit = + static constexpr auto negative_last_digit = Value::UInt(-(Value::minLargestInt % 10)); const Value::LargestUInt threshold = @@ -1627,7 +1604,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) { if (c < '0' || c > '9') return decodeDouble(token, decoded); - const Value::UInt digit(static_cast(c - '0')); + const auto digit(static_cast(c - '0')); if (value >= threshold) { // 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, @@ -1644,7 +1621,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) { if (isNegative) { // We use the same magnitude assumption here, just in case. - const Value::UInt last_digit = static_cast(value % 10); + const auto last_digit = static_cast(value % 10); decoded = -Value::LargestInt(value / 10) * 10 - last_digit; } else if (value <= Value::LargestUInt(Value::maxLargestInt)) { decoded = Value::LargestInt(value); @@ -1670,12 +1647,6 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) { const String buffer(token.start_, token.end_); IStringStream is(buffer); if (!(is >> value)) { - // the value could be lower than numeric_limits::min(), in this situtation we should return the value with the gurantee - // of conversion which has been performed and no occurances of range error. - if ((value > 0 && value < std::numeric_limits::min()) || (value < 0 && value > -std::numeric_limits::min())) { - decoded = value; - return true; - } return addError( "'" + String(token.start_, token.end_) + "' is not a number.", token); } @@ -1842,10 +1813,6 @@ void OurReader::getLocationLineAndColumn(Location location, int& line, while (current < location && current != end_) { Char c = *current++; if (c == '\r') { - // Add boundary check to avoid cross the border - if (current == end_) { - break; - } if (*current == '\n') ++current; lastLineStart = current; @@ -1870,9 +1837,7 @@ String OurReader::getLocationLineAndColumn(Location location) const { String OurReader::getFormattedErrorMessages() const { String formattedMessage; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); ++itError) { - const ErrorInfo& error = *itError; + for (const auto& error : errors_) { formattedMessage += "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; formattedMessage += " " + error.message_ + "\n"; @@ -1885,9 +1850,7 @@ String OurReader::getFormattedErrorMessages() const { std::vector OurReader::getStructuredErrors() const { std::vector allErrors; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); ++itError) { - const ErrorInfo& error = *itError; + for (const auto& error : errors_) { OurReader::StructuredError structured; structured.offset_start = error.token_.start_ - begin_; structured.offset_limit = error.token_.end_ - begin_; @@ -1905,7 +1868,7 @@ public: OurCharReader(bool collectComments, OurFeatures const& features) : collectComments_(collectComments), reader_(features) {} 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_); if (errs) { *errs = reader_.getFormattedErrorMessages(); @@ -1915,7 +1878,7 @@ public: }; CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } -CharReaderBuilder::~CharReaderBuilder() {} +CharReaderBuilder::~CharReaderBuilder() = default; CharReader* CharReaderBuilder::newCharReader() const { bool collectComments = settings_["collectComments"].asBool(); OurFeatures features = OurFeatures::all(); @@ -1936,38 +1899,34 @@ CharReader* CharReaderBuilder::newCharReader() const { features.skipBom_ = settings_["skipBom"].asBool(); return new OurCharReader(collectComments, features); } -static void getValidReaderKeys(std::set* 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 { - Json::Value my_invalid; - if (!invalid) - invalid = &my_invalid; // so we do not need to test for NULL - Json::Value& inv = *invalid; - std::set valid_keys; - getValidReaderKeys(&valid_keys); - Value::Members keys = settings_.getMemberNames(); - size_t n = keys.size(); - for (size_t i = 0; i < n; ++i) { - String const& key = keys[i]; - if (valid_keys.find(key) == valid_keys.end()) { - inv[key] = settings_[key]; - } + static const auto& valid_keys = *new std::set{ + "collectComments", + "allowComments", + "allowTrailingCommas", + "strictRoot", + "allowDroppedNullPlaceholders", + "allowNumericKeys", + "allowSingleQuotes", + "stackLimit", + "failIfExtra", + "rejectDupKeys", + "allowSpecialFloats", + "skipBom", + }; + for (auto si = settings_.begin(); si != settings_.end(); ++si) { + auto key = si.name(); + if (valid_keys.count(key)) + continue; + if (invalid) + (*invalid)[key] = *si; + else + return false; } - return inv.empty(); + return invalid ? invalid->empty() : true; } + Value& CharReaderBuilder::operator[](const String& key) { return settings_[key]; } @@ -2017,9 +1976,7 @@ bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root, char const* end = begin + doc.size(); // Note that we do not actually need a null-terminator. CharReaderPtr const reader(fact.newCharReader()); - bool ret = reader->parse(begin, end, root, errs); - delete reader; - return ret; + return reader->parse(begin, end, root, errs); } IStream& operator>>(IStream& sin, Value& root) { diff --git a/src/lib_json/json_tool.h b/src/lib_json/json_tool.h index 5c13f1fed207d586b93ececdac8d45e7357289dd..b952c19167af92ddd6f6d12eec73657094850de1 100755 --- a/src/lib_json/json_tool.h +++ b/src/lib_json/json_tool.h @@ -71,7 +71,7 @@ enum { }; // Defines a char buffer for use with uintToString(). -typedef char UIntToStringBuffer[uintToStringBufferSize]; +using UIntToStringBuffer = char[uintToStringBufferSize]; /** Converts an unsigned integer to string. * @param value Unsigned integer to convert to string @@ -116,14 +116,18 @@ template void fixNumericLocaleInput(Iter begin, Iter end) { * Return iterator that would be the new end of the range [begin,end), if we * were to delete zeros in the end of string, but not the last zero before '.'. */ -template Iter fixZerosInTheEnd(Iter begin, Iter end) { +template +Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) { for (; begin != end; --end) { if (*(end - 1) != '0') { return end; } // Don't delete the last zero before the decimal point. - if (begin != (end - 1) && *(end - 2) == '.') { - return end; + if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') { + if (precision) { + return end; + } + return end - 2; } } return end; diff --git a/src/lib_json/json_value.cpp b/src/lib_json/json_value.cpp index 2938ea5bed36aefe8ebe88c78f11b95ab0e90d7e..aa2b744ca83da5fba782e5cb42f1c2e27baf7d09 100755 --- a/src/lib_json/json_value.cpp +++ b/src/lib_json/json_value.cpp @@ -48,6 +48,14 @@ int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size, #define JSON_ASSERT_UNREACHABLE assert(false) namespace Json { +template +static std::unique_ptr cloneUnique(const std::unique_ptr& p) { + std::unique_ptr r; + if (p) { + r = std::unique_ptr(new T(*p)); + } + return r; +} // 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 @@ -110,8 +118,8 @@ static inline char* duplicateStringValue(const char* value, size_t length) { if (length >= static_cast(Value::maxInt)) length = Value::maxInt - 1; - char* newString = static_cast(malloc(length + 1)); - if (newString == JSONCPP_NULL) { + auto newString = static_cast(malloc(length + 1)); + if (newString == nullptr) { throwRuntimeError("in Json::Value::duplicateStringValue(): " "Failed to allocate string value buffer"); } @@ -131,8 +139,8 @@ static inline char* duplicateAndPrefixStringValue(const char* value, "in Json::Value::duplicateAndPrefixStringValue(): " "length too big for prefixing"); size_t actualLength = sizeof(length) + length + 1; - char* newString = static_cast(malloc(actualLength)); - if (newString == JSONCPP_NULL) { + auto newString = static_cast(malloc(actualLength)); + if (newString == nullptr) { throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): " "Failed to allocate string value buffer"); } @@ -192,9 +200,9 @@ static inline void releaseStringValue(char* value, unsigned) { free(value); } namespace Json { #if JSON_USE_EXCEPTION -Exception::Exception(String msg) : msg_(JSONCPP_MOVE(msg)) {} -Exception::~Exception() JSONCPP_NOEXCEPT {} -char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); } +Exception::Exception(String msg) : msg_(std::move(msg)) {} +Exception::~Exception() noexcept = default; +char const* Exception::what() const noexcept { return msg_.c_str(); } RuntimeError::RuntimeError(String const& msg) : Exception(msg) {} LogicError::LogicError(String const& msg) : Exception(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 // a string is stored. -Value::CZString::CZString(ArrayIndex index) - : cstr_(JSONCPP_NULL), index_(index) {} +Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {} Value::CZString::CZString(char const* str, unsigned length, DuplicationPolicy allocate) @@ -237,10 +244,9 @@ Value::CZString::CZString(char const* str, unsigned length, } Value::CZString::CZString(const CZString& other) { - cstr_ = - (other.storage_.policy_ != noDuplication && other.cstr_ != JSONCPP_NULL - ? duplicateStringValue(other.cstr_, other.storage_.length_) - : other.cstr_); + cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_); storage_.policy_ = static_cast( other.cstr_ @@ -252,12 +258,12 @@ Value::CZString::CZString(const CZString& other) { 3U; storage_.length_ = other.storage_.length_; } -#if JSONCPP_CXX_STD_11 -Value::CZString::CZString(CZString&& other) + +Value::CZString::CZString(CZString&& other) noexcept : cstr_(other.cstr_), index_(other.index_) { - other.cstr_ = JSONCPP_NULL; + other.cstr_ = nullptr; } -#endif + Value::CZString::~CZString() { if (cstr_ && storage_.policy_ == duplicate) { releaseStringValue(const_cast(cstr_), @@ -278,14 +284,14 @@ Value::CZString& Value::CZString::operator=(const CZString& other) { index_ = other.index_; return *this; } -#if JSONCPP_CXX_STD_11 -Value::CZString& Value::CZString::operator=(CZString&& other) { + +Value::CZString& Value::CZString::operator=(CZString&& other) noexcept { cstr_ = other.cstr_; index_ = other.index_; - other.cstr_ = JSONCPP_NULL; + other.cstr_ = nullptr; return *this; } -#endif + bool Value::CZString::operator<(const CZString& other) const { if (!cstr_) return index_ < other.index_; @@ -394,7 +400,7 @@ Value::Value(double value) { Value::Value(const char* value) { initBasic(stringValue, true); - JSON_ASSERT_MESSAGE(value != JSONCPP_NULL, + JSON_ASSERT_MESSAGE(value != nullptr, "Null Value Passed to Value Constructor"); value_.string_ = duplicateAndPrefixStringValue( value, static_cast(strlen(value))); @@ -426,12 +432,11 @@ Value::Value(const Value& other) { dupPayload(other); dupMeta(other); } -#if JSONCPP_CXX_STD_11 -Value::Value(Value&& other) { + +Value::Value(Value&& other) noexcept { initBasic(nullValue); swap(other); } -#endif Value::~Value() { releasePayload(); @@ -442,12 +447,11 @@ Value& Value::operator=(const Value& other) { Value(other).swap(*this); return *this; } -#if JSONCPP_CXX_STD_11 -Value& Value::operator=(Value&& other) { + +Value& Value::operator=(Value&& other) noexcept { other.swap(*this); return *this; } -#endif void Value::swapPayload(Value& other) { std::swap(bits_, other.bits_); @@ -499,9 +503,8 @@ bool Value::operator<(const Value& other) const { case booleanValue: return value_.bool_ < other.value_.bool_; case stringValue: { - if ((value_.string_ == JSONCPP_NULL) || - (other.value_.string_ == JSONCPP_NULL)) { - return other.value_.string_ != JSONCPP_NULL; + if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { + return other.value_.string_ != nullptr; } unsigned this_len; unsigned other_len; @@ -522,8 +525,8 @@ bool Value::operator<(const Value& other) const { } case arrayValue: case objectValue: { - long unsigned int thisSize = value_.map_->size(); - long unsigned int otherSize = other.value_.map_->size(); + auto thisSize = value_.map_->size(); + auto otherSize = other.value_.map_->size(); if (thisSize != otherSize) return thisSize < otherSize; return (*value_.map_) < (*other.value_.map_); @@ -555,8 +558,7 @@ bool Value::operator==(const Value& other) const { case booleanValue: return value_.bool_ == other.value_.bool_; case stringValue: { - if ((value_.string_ == JSONCPP_NULL) || - (other.value_.string_ == JSONCPP_NULL)) { + if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { return (value_.string_ == other.value_.string_); } unsigned this_len; @@ -588,8 +590,8 @@ bool Value::operator!=(const Value& other) const { return !(*this == other); } const char* Value::asCString() const { JSON_ASSERT_MESSAGE(type() == stringValue, "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == JSONCPP_NULL) - return JSONCPP_NULL; + if (value_.string_ == nullptr) + return nullptr; unsigned this_len; char const* this_str; 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 { if (type() != stringValue) return false; - if (value_.string_ == JSONCPP_NULL) + if (value_.string_ == nullptr) return false; unsigned length; decodePrefixedString(this->isAllocated(), this->value_.string_, &length, @@ -628,7 +630,7 @@ String Value::asString() const { case nullValue: return ""; case stringValue: { - if (value_.string_ == JSONCPP_NULL) + if (value_.string_ == nullptr) return ""; unsigned this_len; char const* this_str; @@ -811,7 +813,7 @@ bool Value::asBool() const { return value_.uint_ != 0; case realValue: { // 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; } default: @@ -910,7 +912,8 @@ void Value::resize(ArrayIndex newSize) { if (newSize == 0) clear(); else if (newSize > oldSize) - this->operator[](newSize - 1); + for (ArrayIndex i = oldSize; i < newSize; ++i) + (*this)[i]; else { for (ArrayIndex index = newSize; index < oldSize; ++index) { value_.map_->erase(index); @@ -926,7 +929,7 @@ Value& Value::operator[](ArrayIndex index) { if (type() == nullValue) *this = Value(arrayValue); 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) return (*it).second; @@ -965,7 +968,7 @@ const Value& Value::operator[](int index) const { void Value::initBasic(ValueType type, bool allocated) { setType(type); setIsAllocated(allocated); - comments_ = Comments(); + comments_ = Comments{}; start_ = 0; limit_ = 0; } @@ -1040,7 +1043,7 @@ Value& Value::resolveReference(const char* key) { *this = Value(objectValue); CZString actualKey(key, static_cast(strlen(key)), 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) return (*it).second; @@ -1059,7 +1062,7 @@ Value& Value::resolveReference(char const* key, char const* end) { *this = Value(objectValue); CZString actualKey(key, static_cast(end - key), 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) return (*it).second; @@ -1081,12 +1084,12 @@ Value const* Value::find(char const* begin, char const* end) const { "in Json::Value::find(begin, end): requires " "objectValue or nullValue"); if (type() == nullValue) - return JSONCPP_NULL; + return nullptr; CZString actualKey(begin, static_cast(end - begin), CZString::noDuplication); ObjectValues::const_iterator it = value_.map_->find(actualKey); if (it == value_.map_->end()) - return JSONCPP_NULL; + return nullptr; return &(*it).second; } Value* Value::demand(char const* begin, char const* end) { @@ -1120,8 +1123,8 @@ Value& Value::operator[](const StaticString& key) { return resolveReference(key.c_str()); } -#if JSONCPP_CXX_STD_11 Value& Value::append(const Value& value) { return append(Value(value)); } + Value& Value::append(Value&& value) { JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, "in Json::Value::append: requires arrayValue"); @@ -1130,19 +1133,12 @@ Value& Value::append(Value&& value) { } 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) { return insert(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, "in Json::Value::insert: requires arrayValue"); ArrayIndex length = size(); @@ -1150,11 +1146,12 @@ bool Value::insert(ArrayIndex index, const Value& newValue) { return false; } 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; } + Value Value::get(char const* begin, char const* end, Value const& defaultValue) const { Value const* found = find(begin, end); @@ -1173,11 +1170,11 @@ bool Value::removeMember(const char* begin, const char* end, Value* removed) { } CZString actualKey(begin, static_cast(end - begin), CZString::noDuplication); - ObjectValues::iterator it = value_.map_->find(actualKey); + auto it = value_.map_->find(actualKey); if (it == value_.map_->end()) return false; if (removed) - *removed = JSONCPP_MOVE(it->second); + *removed = std::move(it->second); value_.map_->erase(it); return true; } @@ -1203,7 +1200,7 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) { return false; } CZString key(index); - ObjectValues::iterator it = value_.map_->find(key); + auto it = value_.map_->find(key); if (it == value_.map_->end()) { return false; } @@ -1217,14 +1214,14 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) { } // erase the last one ("leftover") CZString keyLast(oldSize - 1); - ObjectValues::iterator itLast = value_.map_->find(keyLast); + auto itLast = value_.map_->find(keyLast); value_.map_->erase(itLast); return true; } bool Value::isMember(char const* begin, char const* end) const { Value const* value = find(begin, end); - return JSONCPP_NULL != value; + return nullptr != value; } bool Value::isMember(char const* key) const { return isMember(key, key + strlen(key)); @@ -1374,44 +1371,52 @@ bool Value::isArray() const { return type() == arrayValue; } bool Value::isObject() const { return type() == objectValue; } -Value::Comments::Comments(const Comments& that) { - for (size_t i = 0; i < numberOfCommentPlacement; i++) { - ptr_[i] = that.ptr_[i]; - } -} +Value::Comments::Comments(const Comments& that) + : ptr_{cloneUnique(that.ptr_)} {} + +Value::Comments::Comments(Comments&& that) noexcept + : ptr_{std::move(that.ptr_)} {} + Value::Comments& Value::Comments::operator=(const Comments& that) { - for (size_t i = 0; i < numberOfCommentPlacement; i++) { - ptr_[i] = that.ptr_[i]; - } + ptr_ = cloneUnique(that.ptr_); + return *this; +} + +Value::Comments& Value::Comments::operator=(Comments&& that) noexcept { + ptr_ = std::move(that.ptr_); return *this; } + bool Value::Comments::has(CommentPlacement slot) const { - return !ptr_[slot].empty(); + return ptr_ && !(*ptr_)[slot].empty(); } -String Value::Comments::get(CommentPlacement slot) const { return ptr_[slot]; } +String Value::Comments::get(CommentPlacement slot) const { + if (!ptr_) + return {}; + return (*ptr_)[slot]; +} void Value::Comments::set(CommentPlacement slot, String comment) { - // check comments array boundry. - if (slot < numberOfCommentPlacement) { - ptr_[slot] = comment; - } + if (slot >= CommentPlacement::numberOfCommentPlacement) + return; + if (!ptr_) + ptr_ = std::unique_ptr(new Array()); + (*ptr_)[slot] = std::move(comment); } -void Value::setComment(const char* comment, CommentPlacement placement) { - setComment(comment, strlen(comment), placement); -} -void Value::setComment(const char* comment, size_t len, - CommentPlacement placement) { - if ((len > 0) && (comment[len - 1] == '\n')) { +void Value::setComment(String comment, CommentPlacement placement) { + if (!comment.empty() && (comment.back() == '\n')) { // Always discard trailing newline, to aid indentation. - len -= 1; + comment.pop_back(); } - comments_.set(placement, String(comment, len)); -} -void Value::setComment(const String& comment, CommentPlacement placement) { - setComment(comment.c_str(), comment.length(), placement); + JSON_ASSERT(!comment.empty()); + JSON_ASSERT_MESSAGE( + comment[0] == '\0' || comment[0] == '/', + "in Json::Value::setComment(): Comments must start with /"); + comments_.set(placement, std::move(comment)); } + bool Value::hasComment(CommentPlacement placement) const { return comments_.has(placement); } @@ -1448,7 +1453,7 @@ Value::const_iterator Value::begin() const { default: break; } - return const_iterator(); + return {}; } Value::const_iterator Value::end() const { @@ -1461,7 +1466,7 @@ Value::const_iterator Value::end() const { default: break; } - return const_iterator(); + return {}; } Value::iterator Value::begin() { @@ -1493,15 +1498,14 @@ Value::iterator Value::end() { // class PathArgument // ////////////////////////////////////////////////////////////////// -PathArgument::PathArgument() {} +PathArgument::PathArgument() = default; PathArgument::PathArgument(ArrayIndex index) : index_(index), kind_(kindIndex) {} PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {} -PathArgument::PathArgument(String key) - : key_(JSONCPP_MOVE(key)), kind_(kindKey) {} +PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {} // 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) { const char* current = path.c_str(); const char* end = current + path.length(); - InArgs::const_iterator itInArg = in.begin(); + auto itInArg = in.begin(); while (current != end) { if (*current == '[') { ++current; @@ -1568,9 +1572,7 @@ void Path::invalidPath(const String& /*path*/, int /*location*/) { const Value& Path::resolve(const Value& root) const { const Value* node = &root; - for (Args::const_iterator itArg = args_.begin(); itArg != args_.end(); - ++itArg) { - const PathArgument& arg = *itArg; + for (const auto& arg : args_) { if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray() || !node->isValidIndex(arg.index_)) { // 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 { const Value* node = &root; - for (Args::const_iterator itArg = args_.begin(); itArg != args_.end(); - ++itArg) { - const PathArgument& arg = *itArg; + for (const auto& arg : args_) { if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray() || !node->isValidIndex(arg.index_)) return defaultValue; @@ -1615,9 +1615,7 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const { Value& Path::make(Value& root) const { Value* node = &root; - for (Args::const_iterator itArg = args_.begin(); itArg != args_.end(); - ++itArg) { - const PathArgument& arg = *itArg; + for (const auto& arg : args_) { if (arg.kind_ == PathArgument::kindIndex) { if (!node->isArray()) { // Error: node is not an array at position ... diff --git a/src/lib_json/json_valueiterator.inl b/src/lib_json/json_valueiterator.inl index 9b65584bffb2ed528ead6bfad5192e0f4a593408..d6128b8edf091d57ca6e86af77069ddb9f098bc9 100755 --- a/src/lib_json/json_valueiterator.inl +++ b/src/lib_json/json_valueiterator.inl @@ -15,7 +15,7 @@ namespace Json { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// -ValueIteratorBase::ValueIteratorBase() : current_(), isNull_(true) {} +ValueIteratorBase::ValueIteratorBase() : current_() {} ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator& current) @@ -98,8 +98,8 @@ char const* ValueIteratorBase::memberName() const { char const* ValueIteratorBase::memberName(char const** end) const { const char* cname = (*current_).first.data(); if (!cname) { - *end = JSONCPP_NULL; - return JSONCPP_NULL; + *end = nullptr; + return nullptr; } *end = cname + (*current_).first.length(); return cname; @@ -113,7 +113,7 @@ char const* ValueIteratorBase::memberName(char const** end) const { // ////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////// -ValueConstIterator::ValueConstIterator() {} +ValueConstIterator::ValueConstIterator() = default; ValueConstIterator::ValueConstIterator( 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) : ValueIteratorBase(current) {} @@ -146,8 +146,7 @@ ValueIterator::ValueIterator(const ValueConstIterator& other) throwRuntimeError("ConstIterator to Iterator should never be allowed."); } -ValueIterator::ValueIterator(const ValueIterator& other) - : ValueIteratorBase(other) {} +ValueIterator::ValueIterator(const ValueIterator& other) = default; ValueIterator& ValueIterator::operator=(const SelfType& other) { copy(other); diff --git a/src/lib_json/json_writer.cpp b/src/lib_json/json_writer.cpp index 6602920046138cb3651a66f204acd76fa147ef69..0dd160e452e24557084b526944d9878962fbe506 100755 --- a/src/lib_json/json_writer.cpp +++ b/src/lib_json/json_writer.cpp @@ -7,7 +7,9 @@ #include "json_tool.h" #include #endif // if !defined(JSON_IS_AMALGAMATION) +#include #include +#include #include #include #include @@ -66,7 +68,7 @@ #if !defined(isnan) // IEEE standard states that NaN values will not compare to themselves -#define isnan(x) (x != x) +#define isnan(x) ((x) != (x)) #endif #if !defined(__APPLE__) @@ -83,7 +85,11 @@ namespace Json { -typedef StreamWriter* StreamWriterPtr; +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +using StreamWriterPtr = std::unique_ptr; +#else +using StreamWriterPtr = std::auto_ptr; +#endif String valueToString(LargestInt value) { UIntToStringBuffer buffer; @@ -132,12 +138,12 @@ String valueToString(double value, bool useSpecialFloats, String buffer(size_t(36), '\0'); while (true) { - int len = - jsoncpp_snprintf(&*buffer.begin(), buffer.size(), - (precisionType == significantDigits) ? "%.*g" : "%.*f", - precision, value); + int len = jsoncpp_snprintf( + &*buffer.begin(), buffer.size(), + (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f", + precision, value); assert(len >= 0); - size_t wouldPrint = static_cast(len); + auto wouldPrint = static_cast(len); if (wouldPrint >= buffer.size()) { buffer.resize(wouldPrint + 1); continue; @@ -148,16 +154,18 @@ String valueToString(double value, bool useSpecialFloats, buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); - // strip the zero padding from the right - if (precisionType == decimalPlaces) { - buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end()); - } - // try to ensure we preserve the fact that this was given to us as a double on // input if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) { buffer += ".0"; } + + // strip the zero padding from the right + if (precisionType == PrecisionType::decimalPlaces) { + buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end(), precision), + buffer.end()); + } + return buffer; } } // namespace @@ -169,17 +177,12 @@ String valueToString(double value, unsigned int precision, String valueToString(bool value) { return value ? "true" : "false"; } -static bool isAnyCharRequiredQuoting(char const* s, size_t n) { +static bool doesAnyCharRequireEscaping(char const* s, size_t n) { assert(s || !n); - char const* const end = s + n; - for (char const* cur = s; cur < end; ++cur) { - if (*cur == '\\' || *cur == '\"' || - static_cast(*cur) < ' ' || - static_cast(*cur) >= 0x80) - return true; - } - return false; + return std::any_of(s, s + n, [](unsigned char c) { + return c == '\\' || c == '"' || c < 0x20 || c > 0x7F; + }); } static unsigned int utf8ToCodepoint(const char*& s, const char* e) { @@ -261,12 +264,20 @@ static String toHex16Bit(unsigned int x) { return result; } -static String valueToQuotedStringN(const char* value, unsigned length, +static void appendRaw(String& result, unsigned ch) { + result += static_cast(ch); +} + +static void appendHex(String& result, unsigned ch) { + result.append("\\u").append(toHex16Bit(ch)); +} + +static String valueToQuotedStringN(const char* value, size_t length, bool emitUTF8 = false) { - if (value == JSONCPP_NULL) + if (value == nullptr) return ""; - if (!isAnyCharRequiredQuoting(value, length)) + if (!doesAnyCharRequireEscaping(value, length)) return String("\"") + value + "\""; // We have to walk value and escape any special characters. // Appending to String is not efficient, but this should be rare. @@ -309,29 +320,26 @@ static String valueToQuotedStringN(const char* value, unsigned length, // sequence from occurring. default: { if (emitUTF8) { - result += *c; + unsigned codepoint = static_cast(*c); + if (codepoint < 0x20) { + appendHex(result, codepoint); + } else { + appendRaw(result, codepoint); + } } else { - unsigned int codepoint = utf8ToCodepoint(c, end); - const unsigned int FIRST_NON_CONTROL_CODEPOINT = 0x20; - const unsigned int LAST_NON_CONTROL_CODEPOINT = 0x7F; - const unsigned int FIRST_SURROGATE_PAIR_CODEPOINT = 0x10000; - // don't escape non-control characters - // (short escape sequence are applied above) - if (FIRST_NON_CONTROL_CODEPOINT <= codepoint && - codepoint <= LAST_NON_CONTROL_CODEPOINT) { - result += static_cast(codepoint); - } else if (codepoint < - FIRST_SURROGATE_PAIR_CODEPOINT) { // codepoint is in Basic - // Multilingual Plane - result += "\\u"; - result += toHex16Bit(codepoint); - } else { // codepoint is not in Basic Multilingual Plane - // convert to surrogate pair first - codepoint -= FIRST_SURROGATE_PAIR_CODEPOINT; - result += "\\u"; - result += toHex16Bit((codepoint >> 10) + 0xD800); - result += "\\u"; - result += toHex16Bit((codepoint & 0x3FF) + 0xDC00); + unsigned codepoint = utf8ToCodepoint(c, end); // modifies `c` + if (codepoint < 0x20) { + appendHex(result, codepoint); + } else if (codepoint < 0x80) { + appendRaw(result, codepoint); + } else if (codepoint < 0x10000) { + // Basic Multilingual Plane + appendHex(result, codepoint); + } else { + // Extended Unicode. Encode 20 bits as a surrogate pair. + codepoint -= 0x10000; + appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff)); + appendHex(result, 0xdc00 + (codepoint & 0x3ff)); } } } break; @@ -342,19 +350,19 @@ static String valueToQuotedStringN(const char* value, unsigned length, } String valueToQuotedString(const char* value) { - return valueToQuotedStringN(value, static_cast(strlen(value))); + return valueToQuotedStringN(value, strlen(value)); } // Class Writer // ////////////////////////////////////////////////////////////////// -Writer::~Writer() {} +Writer::~Writer() = default; // Class FastWriter // ////////////////////////////////////////////////////////////////// FastWriter::FastWriter() - : yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false), - omitEndingLineFeed_(false) {} + + = default; void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } @@ -391,7 +399,7 @@ void FastWriter::writeValue(const Value& value) { char const* end; bool ok = value.getString(&str, &end); if (ok) - document_ += valueToQuotedStringN(str, static_cast(end - str)); + document_ += valueToQuotedStringN(str, static_cast(end - str)); break; } case booleanValue: @@ -410,13 +418,11 @@ void FastWriter::writeValue(const Value& value) { case objectValue: { Value::Members members(value.getMemberNames()); document_ += '{'; - for (Value::Members::const_iterator it = members.begin(); - it != members.end(); ++it) { + for (auto it = members.begin(); it != members.end(); ++it) { const String& name = *it; if (it != members.begin()) document_ += ','; - document_ += valueToQuotedStringN(name.data(), - static_cast(name.length())); + document_ += valueToQuotedStringN(name.data(), name.length()); document_ += yamlCompatibilityEnabled_ ? ": " : ":"; writeValue(value[name]); } @@ -428,8 +434,7 @@ void FastWriter::writeValue(const Value& value) { // Class StyledWriter // ////////////////////////////////////////////////////////////////// -StyledWriter::StyledWriter() - : rightMargin_(74), indentSize_(3), addChildValues_() {} +StyledWriter::StyledWriter() = default; String StyledWriter::write(const Value& root) { document_.clear(); @@ -462,7 +467,7 @@ void StyledWriter::writeValue(const Value& value) { char const* end; bool ok = value.getString(&str, &end); if (ok) - pushValue(valueToQuotedStringN(str, static_cast(end - str))); + pushValue(valueToQuotedStringN(str, static_cast(end - str))); else pushValue(""); break; @@ -480,7 +485,7 @@ void StyledWriter::writeValue(const Value& value) { else { writeWithIndent("{"); indent(); - Value::Members::const_iterator it = members.begin(); + auto it = members.begin(); for (;;) { const String& name = *it; const Value& childValue = value[name]; @@ -503,7 +508,7 @@ void StyledWriter::writeValue(const Value& value) { } void StyledWriter::writeArrayValue(const Value& value) { - unsigned size = value.size(); + size_t size = value.size(); if (size == 0) pushValue("[]"); else { @@ -512,7 +517,7 @@ void StyledWriter::writeArrayValue(const Value& value) { writeWithIndent("["); indent(); bool hasChildValue = !childValues_.empty(); - unsigned index = 0; + ArrayIndex index = 0; for (;;) { const Value& childValue = value[index]; writeCommentBeforeValue(childValue); @@ -535,7 +540,7 @@ void StyledWriter::writeArrayValue(const Value& value) { { assert(childValues_.size() == size); document_ += "[ "; - for (unsigned index = 0; index < size; ++index) { + for (size_t index = 0; index < size; ++index) { if (index > 0) document_ += ", "; document_ += childValues_[index]; @@ -642,9 +647,8 @@ bool StyledWriter::hasCommentForValue(const Value& value) { // ////////////////////////////////////////////////////////////////// StyledStreamWriter::StyledStreamWriter(String indentation) - : document_(JSONCPP_NULL), rightMargin_(74), - indentation_(JSONCPP_MOVE(indentation)), addChildValues_(), - indented_(false) {} + : document_(nullptr), indentation_(std::move(indentation)), + addChildValues_(), indented_(false) {} void StyledStreamWriter::write(OStream& out, const Value& root) { document_ = &out; @@ -658,7 +662,7 @@ void StyledStreamWriter::write(OStream& out, const Value& root) { writeValue(root); writeCommentAfterValueOnSameLine(root); *document_ << "\n"; - document_ = JSONCPP_NULL; // Forget the stream, for safety. + document_ = nullptr; // Forget the stream, for safety. } void StyledStreamWriter::writeValue(const Value& value) { @@ -681,7 +685,7 @@ void StyledStreamWriter::writeValue(const Value& value) { char const* end; bool ok = value.getString(&str, &end); if (ok) - pushValue(valueToQuotedStringN(str, static_cast(end - str))); + pushValue(valueToQuotedStringN(str, static_cast(end - str))); else pushValue(""); break; @@ -699,7 +703,7 @@ void StyledStreamWriter::writeValue(const Value& value) { else { writeWithIndent("{"); indent(); - Value::Members::const_iterator it = members.begin(); + auto it = members.begin(); for (;;) { const String& name = *it; const Value& childValue = value[name]; @@ -877,7 +881,7 @@ struct BuiltStyledStreamWriter : public StreamWriter { String endingLineFeedSymbol, bool useSpecialFloats, bool emitUTF8, unsigned int precision, PrecisionType precisionType); - int write(Value const& root, OStream* sout) JSONCPP_OVERRIDE; + int write(Value const& root, OStream* sout) override; private: void writeValue(Value const& value); @@ -892,7 +896,7 @@ private: void writeCommentAfterValueOnSameLine(Value const& root); static bool hasCommentForValue(const Value& value); - typedef std::vector ChildValues; + using ChildValues = std::vector; ChildValues childValues_; String indentString_; @@ -913,10 +917,9 @@ BuiltStyledStreamWriter::BuiltStyledStreamWriter( String indentation, CommentStyle::Enum cs, String colonSymbol, String nullSymbol, String endingLineFeedSymbol, bool useSpecialFloats, bool emitUTF8, unsigned int precision, PrecisionType precisionType) - : rightMargin_(74), indentation_(JSONCPP_MOVE(indentation)), cs_(cs), - colonSymbol_(JSONCPP_MOVE(colonSymbol)), - nullSymbol_(JSONCPP_MOVE(nullSymbol)), - endingLineFeedSymbol_(JSONCPP_MOVE(endingLineFeedSymbol)), + : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs), + colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)), + endingLineFeedSymbol_(std::move(endingLineFeedSymbol)), addChildValues_(false), indented_(false), useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8), precision_(precision), precisionType_(precisionType) {} @@ -932,7 +935,7 @@ int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) { writeValue(root); writeCommentAfterValueOnSameLine(root); *sout_ << endingLineFeedSymbol_; - sout_ = JSONCPP_NULL; + sout_ = nullptr; return 0; } void BuiltStyledStreamWriter::writeValue(Value const& value) { @@ -956,8 +959,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) { char const* end; bool ok = value.getString(&str, &end); if (ok) - pushValue(valueToQuotedStringN(str, static_cast(end - str), - emitUTF8_)); + pushValue( + valueToQuotedStringN(str, static_cast(end - str), emitUTF8_)); else pushValue(""); break; @@ -975,13 +978,13 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) { else { writeWithIndent("{"); indent(); - Value::Members::const_iterator it = members.begin(); + auto it = members.begin(); for (;;) { String const& name = *it; Value const& childValue = value[name]; writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedStringN( - name.data(), static_cast(name.length()), emitUTF8_)); + writeWithIndent( + valueToQuotedStringN(name.data(), name.length(), emitUTF8_)); *sout_ << colonSymbol_; writeValue(childValue); if (++it == members.end()) { @@ -1151,11 +1154,11 @@ bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { /////////////// // StreamWriter -StreamWriter::StreamWriter() : sout_(JSONCPP_NULL) {} -StreamWriter::~StreamWriter() {} -StreamWriter::Factory::~Factory() {} +StreamWriter::StreamWriter() : sout_(nullptr) {} +StreamWriter::~StreamWriter() = default; +StreamWriter::Factory::~Factory() = default; StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); } -StreamWriterBuilder::~StreamWriterBuilder() {} +StreamWriterBuilder::~StreamWriterBuilder() = default; StreamWriter* StreamWriterBuilder::newStreamWriter() const { const String indentation = settings_["indentation"].asString(); const String cs_str = settings_["commentStyle"].asString(); @@ -1175,9 +1178,9 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const { } PrecisionType precisionType(significantDigits); if (pt_str == "significant") { - precisionType = significantDigits; + precisionType = PrecisionType::significantDigits; } else if (pt_str == "decimal") { - precisionType = decimalPlaces; + precisionType = PrecisionType::decimalPlaces; } else { throwRuntimeError("precisionType must be 'significant' or 'decimal'"); } @@ -1198,34 +1201,30 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const { endingLineFeedSymbol, usf, emitUTF8, pre, precisionType); } -static void getValidWriterKeys(std::set* 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 { - Json::Value my_invalid; - if (!invalid) - invalid = &my_invalid; // so we do not need to test for NULL - Json::Value& inv = *invalid; - std::set valid_keys; - getValidWriterKeys(&valid_keys); - Value::Members keys = settings_.getMemberNames(); - size_t n = keys.size(); - for (size_t i = 0; i < n; ++i) { - String const& key = keys[i]; - if (valid_keys.find(key) == valid_keys.end()) { - inv[key] = settings_[key]; - } + static const auto& valid_keys = *new std::set{ + "indentation", + "commentStyle", + "enableYAMLCompatibility", + "dropNullPlaceholders", + "useSpecialFloats", + "emitUTF8", + "precision", + "precisionType", + }; + for (auto si = settings_.begin(); si != settings_.end(); ++si) { + auto key = si.name(); + if (valid_keys.count(key)) + continue; + if (invalid) + (*invalid)[key] = *si; + else + return false; } - return inv.empty(); + return invalid ? invalid->empty() : true; } + Value& StreamWriterBuilder::operator[](const String& key) { return settings_[key]; } @@ -1247,7 +1246,6 @@ String writeString(StreamWriter::Factory const& factory, Value const& root) { OStringStream sout; StreamWriterPtr const writer(factory.newStreamWriter()); writer->write(root, &sout); - delete writer; return sout.str(); } @@ -1255,7 +1253,6 @@ OStream& operator<<(OStream& sout, Value const& root) { StreamWriterBuilder builder; StreamWriterPtr const writer(builder.newStreamWriter()); writer->write(root, &sout); - delete writer; return sout; } diff --git a/src/test_lib_json/CMakeLists.txt b/src/test_lib_json/CMakeLists.txt index b803db669e8e4a72f3a762cff1fedb40429f9616..1c3fce913c173ecf09809258177a47361b9813af 100755 --- a/src/test_lib_json/CMakeLists.txt +++ b/src/test_lib_json/CMakeLists.txt @@ -15,8 +15,10 @@ if(BUILD_SHARED_LIBS) else() add_definitions( -DJSON_DLL ) endif() + target_link_libraries(jsoncpp_test jsoncpp_lib) +else() + target_link_libraries(jsoncpp_test jsoncpp_static) endif() -target_link_libraries(jsoncpp_test jsoncpp_lib) # another way to solve issue #90 #set_target_properties(jsoncpp_test PROPERTIES COMPILE_FLAGS -ffloat-store) diff --git a/src/test_lib_json/fuzz.cpp b/src/test_lib_json/fuzz.cpp index 8dfc929ba6e12e90b93e224b762d526f1dbb9be8..5b75c22e6e960eab19d1f310c26b508002948c4f 100755 --- a/src/test_lib_json/fuzz.cpp +++ b/src/test_lib_json/fuzz.cpp @@ -5,6 +5,7 @@ #include "fuzz.h" +#include #include #include #include @@ -40,14 +41,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { builder.settings_["collectComments"] = hash_settings & (1 << 9); builder.settings_["allowTrailingCommas_"] = hash_settings & (1 << 10); - Json::CharReader* reader(builder.newCharReader()); + std::unique_ptr reader(builder.newCharReader()); + Json::Value root; - const char* data_str = reinterpret_cast(data); + const auto data_str = reinterpret_cast(data); try { - reader->parse(data_str, data_str + size, &root, JSONCPP_NULL); + reader->parse(data_str, data_str + size, &root, nullptr); } catch (Json::Exception const&) { } - delete reader; // Whether it succeeded or not doesn't matter. return 0; } diff --git a/src/test_lib_json/jsontest.cpp b/src/test_lib_json/jsontest.cpp index 93718add76afe2adacbbbbecbef5068c7695a234..0b7d12b974b5e304fe0f30a9ad0b0a8fea25c2a1 100755 --- a/src/test_lib_json/jsontest.cpp +++ b/src/test_lib_json/jsontest.cpp @@ -73,11 +73,10 @@ namespace JsonTest { // class TestResult // ////////////////////////////////////////////////////////////////// -TestResult::TestResult() - : predicateId_(1), lastUsedPredicateId_(0), messageTarget_(JSONCPP_NULL) { +TestResult::TestResult() { // The root predicate has id 0 rootPredicateNode_.id_ = 0; - rootPredicateNode_.next_ = JSONCPP_NULL; + rootPredicateNode_.next_ = nullptr; predicateStackTail_ = &rootPredicateNode_; } @@ -89,7 +88,7 @@ TestResult& TestResult::addFailure(const char* file, unsigned int line, /// added. unsigned int nestingLevel = 0; PredicateContext* lastNode = rootPredicateNode_.next_; - for (; lastNode != JSONCPP_NULL; lastNode = lastNode->next_) { + for (; lastNode != nullptr; lastNode = lastNode->next_) { if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext { lastUsedPredicateId_ = lastNode->id_; @@ -122,18 +121,17 @@ void TestResult::addFailureInfo(const char* file, unsigned int line, TestResult& TestResult::popPredicateContext() { PredicateContext* lastNode = &rootPredicateNode_; - while (lastNode->next_ != JSONCPP_NULL && - lastNode->next_->next_ != JSONCPP_NULL) { + while (lastNode->next_ != nullptr && lastNode->next_->next_ != nullptr) { lastNode = lastNode->next_; } // Set message target to popped failure PredicateContext* tail = lastNode->next_; - if (tail != JSONCPP_NULL && tail->failure_ != JSONCPP_NULL) { + if (tail != nullptr && tail->failure_ != nullptr) { messageTarget_ = tail->failure_; } // Remove tail from list predicateStackTail_ = lastNode; - lastNode->next_ = JSONCPP_NULL; + lastNode->next_ = nullptr; return *this; } @@ -149,9 +147,7 @@ void TestResult::printFailure(bool printTestName) const { } // Print in reverse to display the callstack in the right order - for (Failures::const_iterator it = failures_.begin(); it != failures_.end(); - ++it) { - const Failure& failure = *it; + for (const auto& failure : failures_) { Json::String indent(failure.nestingLevel_ * 2, ' '); if (failure.file_) { 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) { - if (messageTarget_ != JSONCPP_NULL) { + if (messageTarget_ != nullptr) { messageTarget_->message_ += message; } return *this; @@ -206,9 +202,9 @@ TestResult& TestResult::operator<<(bool value) { // class TestCase // ////////////////////////////////////////////////////////////////// -TestCase::TestCase() : result_(JSONCPP_NULL) {} +TestCase::TestCase() = default; -TestCase::~TestCase() {} +TestCase::~TestCase() = default; void TestCase::run(TestResult& result) { result_ = &result; @@ -218,7 +214,7 @@ void TestCase::run(TestResult& result) { // class Runner // ////////////////////////////////////////////////////////////////// -Runner::Runner() {} +Runner::Runner() = default; Runner& Runner::add(TestCaseFactory factory) { tests_.push_back(factory); @@ -272,8 +268,7 @@ bool Runner::runAllTest(bool printSummary) const { } return true; } - for (size_t index = 0; index < failures.size(); ++index) { - TestResult& result = failures[index]; + for (auto& result : failures) { result.printFailure(count > 1); } diff --git a/src/test_lib_json/jsontest.h b/src/test_lib_json/jsontest.h index 9e2bcc0b5653951bdff0acfbc343a5380bdc77bd..4e8af0f2592b8b41127e37e8530a3b87b21977cb 100755 --- a/src/test_lib_json/jsontest.h +++ b/src/test_lib_json/jsontest.h @@ -42,7 +42,7 @@ public: /// Must be a POD to allow inline initialisation without stepping /// into the debugger. struct PredicateContext { - typedef unsigned int Id; + using Id = unsigned int; Id id_; const char* file_; unsigned int line_; @@ -61,7 +61,7 @@ public: /// Not encapsulated to prevent step into when debugging failed assertions /// Incremented by one on assertion predicate entry, decreased by one /// by addPredicateContext(). - PredicateContext::Id predicateId_; + PredicateContext::Id predicateId_{1}; /// \internal Implementation detail for predicate macros PredicateContext* predicateStackTail_; @@ -70,7 +70,7 @@ public: /// Adds an assertion failure. 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 /// chained list. @@ -84,9 +84,7 @@ public: // Generic operator that will work with anything ostream can deal with. template TestResult& operator<<(const T& value) { Json::OStringStream oss; - oss.precision(16); - oss.setf(std::ios_base::floatfield); - oss << value; + oss << std::setprecision(16) << std::hexfloat << value; return addToLastFailure(oss.str()); } @@ -104,13 +102,13 @@ private: static Json::String indentText(const Json::String& text, const Json::String& indent); - typedef std::deque Failures; + using Failures = std::deque; Failures failures_; Json::String name_; PredicateContext rootPredicateNode_; - PredicateContext::Id lastUsedPredicateId_; + PredicateContext::Id lastUsedPredicateId_{0}; /// Failure which is the target of the messages added using operator << - Failure* messageTarget_; + Failure* messageTarget_{nullptr}; }; class TestCase { @@ -124,14 +122,14 @@ public: virtual const char* testName() const = 0; protected: - TestResult* result_; + TestResult* result_{nullptr}; private: virtual void runTestCase() = 0; }; /// Function pointer type for TestCase factory -typedef TestCase* (*TestCaseFactory)(); +using TestCaseFactory = TestCase* (*)(); class Runner { public: @@ -161,8 +159,8 @@ public: static void printUsage(const char* appName); private: // prevents copy construction and assignment - Runner(const Runner& other) JSONCPP_CTOR_DELETE; - Runner& operator=(const Runner& other) JSONCPP_CTOR_DELETE; + Runner(const Runner& other) = delete; + Runner& operator=(const Runner& other) = delete; private: void listTests() const; @@ -170,7 +168,7 @@ private: static void preventDialogOnCrash(); private: - typedef std::deque Factories; + using Factories = std::deque; Factories tests_; }; @@ -253,10 +251,8 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected, } \ \ public: /* overridden from TestCase */ \ - const char* testName() const JSONCPP_OVERRIDE { \ - return #FixtureType "/" #name; \ - } \ - void runTestCase() JSONCPP_OVERRIDE; \ + const char* testName() const override { return #FixtureType "/" #name; } \ + void runTestCase() override; \ }; \ \ void Test##FixtureType##name::runTestCase() @@ -280,10 +276,8 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected, } \ \ public: /* overridden from TestCase */ \ - const char* testName() const JSONCPP_OVERRIDE { \ - return #FixtureType "/" #name; \ - } \ - void runTestCase() JSONCPP_OVERRIDE; \ + const char* testName() const override { return #FixtureType "/" #name; } \ + void runTestCase() override; \ }; \ \ static bool test##FixtureType##name##collect = \ diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 229944ad11875e92e8d273c10dbff4523c2f3dfb..d0f5364acbde8dc01dfadaae016eae9ba1410ff3 100755 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -12,6 +12,7 @@ #include "fuzz.h" #include "jsontest.h" +#include #include #include #include @@ -24,8 +25,9 @@ #include #include #include +#include -typedef Json::CharReader* CharReaderPtr; +using CharReaderPtr = std::unique_ptr; // Make numeric limits more convenient to talk about. // Assumes int type in 32 bits. @@ -65,27 +67,22 @@ static std::deque local_; struct ValueTest : JsonTest::TestCase { Json::Value null_; - Json::Value emptyArray_; - Json::Value emptyObject_; - Json::Value integer_; - Json::Value unsignedInteger_; - Json::Value smallUnsignedInteger_; - Json::Value real_; - Json::Value float_; + Json::Value emptyArray_{Json::arrayValue}; + Json::Value emptyObject_{Json::objectValue}; + Json::Value integer_{123456789}; + Json::Value unsignedInteger_{34567890}; + Json::Value smallUnsignedInteger_{Json::Value::UInt(Json::Value::maxInt)}; + Json::Value real_{1234.56789}; + Json::Value float_{0.00390625f}; Json::Value array1_; Json::Value object1_; - Json::Value emptyString_; - Json::Value string1_; - Json::Value string_; - Json::Value true_; - Json::Value false_; - - 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) { + Json::Value emptyString_{""}; + Json::Value string1_{"a"}; + Json::Value string_{"sometext with space"}; + Json::Value true_{true}; + Json::Value false_{false}; + + ValueTest() { array1_.append(1234); object1_["id"] = 1234; } @@ -94,19 +91,19 @@ struct ValueTest : JsonTest::TestCase { /// Initialize all checks to \c false by default. IsCheck(); - bool isObject_; - bool isArray_; - bool isBool_; - bool isString_; - bool isNull_; - - bool isInt_; - bool isInt64_; - bool isUInt_; - bool isUInt64_; - bool isIntegral_; - bool isDouble_; - bool isNumeric_; + bool isObject_{false}; + bool isArray_{false}; + bool isBool_{false}; + bool isString_{false}; + bool isNull_{false}; + + bool isInt_{false}; + bool isInt64_{false}; + bool isUInt_{false}; + bool isUInt64_{false}; + bool isIntegral_{false}; + bool isDouble_{false}; + bool isNumeric_{false}; }; void checkConstMemberCount(const Json::Value& value, @@ -126,14 +123,13 @@ struct ValueTest : JsonTest::TestCase { }; 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) return s; 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); - std::string::size_type indexDigit = - s.find_first_not_of('0', exponentStartIndex); + auto indexDigit = s.find_first_not_of('0', exponentStartIndex); Json::String exponent = "0"; if (indexDigit != s.npos) { // nonzero exponent exponent = s.substr(indexDigit); @@ -163,9 +159,7 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, checkNormalizeFloatingPointStr) { {"1234e+100", "1234e+100"}, {"1234e-100", "1234e-100"}, }; - for (unsigned int index = 0; index < sizeof(testData) / sizeof(testData[0]); - ++index) { - const struct TestData td = testData[index]; + for (const auto& td : testData) { JSONTEST_ASSERT_STRING_EQUAL(normalizeFloatingPointStr(td.in), td.out); } } @@ -223,22 +217,22 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, objects) { // Access through find() const char idKey[] = "id"; 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); const char unknownIdKey[] = "unknown id"; const Json::Value* foundUnknownId = object1_.find(unknownIdKey, unknownIdKey + strlen(unknownIdKey)); - JSONTEST_ASSERT(JSONCPP_NULL == foundUnknownId); + JSONTEST_ASSERT_EQUAL(nullptr, foundUnknownId); // Access through demand() const char yetAnotherIdKey[] = "yet another id"; const Json::Value* foundYetAnotherId = object1_.find(yetAnotherIdKey, yetAnotherIdKey + strlen(yetAnotherIdKey)); - JSONTEST_ASSERT(JSONCPP_NULL == foundYetAnotherId); + JSONTEST_ASSERT_EQUAL(nullptr, foundYetAnotherId); Json::Value* demandedYetAnotherId = object1_.demand( yetAnotherIdKey, yetAnotherIdKey + strlen(yetAnotherIdKey)); - JSONTEST_ASSERT(demandedYetAnotherId != JSONCPP_NULL); + JSONTEST_ASSERT(demandedYetAnotherId != nullptr); *demandedYetAnotherId = "baz"; JSONTEST_ASSERT_EQUAL(Json::Value("baz"), object1_["yet another id"]); @@ -263,9 +257,9 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, objects) { JSONTEST_ASSERT_EQUAL(false, did); object1_["some other id"] = "foo"; - Json::Value* gotPtr = JSONCPP_NULL; + Json::Value* gotPtr = nullptr; did = object1_.removeMember("some other id", gotPtr); - JSONTEST_ASSERT(JSONCPP_NULL == gotPtr); + JSONTEST_ASSERT_EQUAL(nullptr, gotPtr); JSONTEST_ASSERT_EQUAL(true, did); // Using other removeMember interfaces, the test idea is the same as above. @@ -355,6 +349,17 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, resizeArray) { JSONTEST_ASSERT_EQUAL(array.size(), 0); } } + +JSONTEST_FIXTURE_LOCAL(ValueTest, resizePopulatesAllMissingElements) { + Json::ArrayIndex n = 10; + Json::Value v; + v.resize(n); + JSONTEST_ASSERT_EQUAL(n, v.size()); + JSONTEST_ASSERT_EQUAL(n, std::distance(v.begin(), v.end())); + for (const Json::Value& e : v) + JSONTEST_ASSERT_EQUAL(e, Json::Value{}); +} + JSONTEST_FIXTURE_LOCAL(ValueTest, getArrayValue) { Json::Value array; for (Json::ArrayIndex i = 0; i < 5; i++) @@ -1190,7 +1195,7 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, integers) { normalizeFloatingPointStr(JsonTest::ToJsonString(val.asString()))); // 10^19 - const Json::UInt64 ten_to_19 = static_cast(1e19); + const auto ten_to_19 = static_cast(1e19); val = Json::Value(Json::UInt64(ten_to_19)); JSONTEST_ASSERT_EQUAL(Json::uintValue, val.type()); @@ -1484,11 +1489,7 @@ void ValueTest::checkMemberCount(Json::Value& value, JSONTEST_ASSERT_PRED(checkConstMemberCount(value, expectedCount)); } -ValueTest::IsCheck::IsCheck() - : isObject_(false), isArray_(false), isBool_(false), isString_(false), - isNull_(false), isInt_(false), isInt64_(false), isUInt_(false), - isUInt64_(false), isIntegral_(false), isDouble_(false), - isNumeric_(false) {} +ValueTest::IsCheck::IsCheck() = default; void ValueTest::checkIs(const Json::Value& value, const IsCheck& check) { JSONTEST_ASSERT_EQUAL(check.isObject_, value.isObject()); @@ -1673,19 +1674,19 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, CopyObject) { Json::Value srcObject, objectCopy, otherObject; srcObject["key0"] = 10; objectCopy.copy(srcObject); - JSONTEST_ASSERT(srcObject["key0"].asInt() == 10); - JSONTEST_ASSERT(objectCopy["key0"].asInt() == 10); + JSONTEST_ASSERT(srcObject["key0"] == 10); + JSONTEST_ASSERT(objectCopy["key0"] == 10); JSONTEST_ASSERT(srcObject.getMemberNames().size() == 1); JSONTEST_ASSERT(objectCopy.getMemberNames().size() == 1); otherObject["key1"] = 15; otherObject["key2"] = 16; JSONTEST_ASSERT(otherObject.getMemberNames().size() == 2); objectCopy.copy(otherObject); - JSONTEST_ASSERT(objectCopy["key1"].asInt() == 15); - JSONTEST_ASSERT(objectCopy["key2"].asInt() == 16); + JSONTEST_ASSERT(objectCopy["key1"] == 15); + JSONTEST_ASSERT(objectCopy["key2"] == 16); JSONTEST_ASSERT(objectCopy.getMemberNames().size() == 2); otherObject["key1"] = 20; - JSONTEST_ASSERT(objectCopy["key1"].asInt() == 15); + JSONTEST_ASSERT(objectCopy["key1"] == 15); } } @@ -1829,7 +1830,7 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, StaticString) { JSONTEST_FIXTURE_LOCAL(ValueTest, WideString) { // 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; { Json::Value v; @@ -2017,6 +2018,34 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, precision) { result = Json::writeString(b, v); JSONTEST_ASSERT_STRING_EQUAL(expected, result); + b.settings_["precision"] = 0; + b.settings_["precisionType"] = "decimal"; + v = 123.56345694873740545068; + expected = "124"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 1; + b.settings_["precisionType"] = "decimal"; + v = 1230.001; + expected = "1230.0"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 0; + b.settings_["precisionType"] = "decimal"; + v = 1230.001; + expected = "1230"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + + b.settings_["precision"] = 0; + b.settings_["precisionType"] = "decimal"; + v = 1231.5; + expected = "1232"; + result = Json::writeString(b, v); + JSONTEST_ASSERT_STRING_EQUAL(expected, result); + b.settings_["precision"] = 10; b.settings_["precisionType"] = "decimal"; v = 0.23300000; @@ -2604,7 +2633,7 @@ JSONTEST_FIXTURE_LOCAL(StreamWriterTest, indentation) { JSONTEST_FIXTURE_LOCAL(StreamWriterTest, writeZeroes) { Json::String binary("hi", 3); // include trailing 0 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::Value root; @@ -2651,7 +2680,97 @@ JSONTEST_FIXTURE_LOCAL(StreamWriterTest, unicode) { "{\n\t\"test\" : " "\"\\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(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 << "\""; + } + } +} + +#ifdef _WIN32 +JSONTEST_FIXTURE_LOCAL(StreamWriterTest, escapeTabCharacterWindows) { + // Get the current locale before changing it + std::string currentLocale = setlocale(LC_ALL, NULL); + setlocale(LC_ALL, "English_United States.1252"); + + Json::Value root; + root["test"] = "\tTabTesting\t"; + + Json::StreamWriterBuilder b; + + JSONTEST_ASSERT(Json::writeString(b, root) == "{\n\t\"test\" : " + "\"\\tTabTesting\\t\"\n}"); + + b.settings_["emitUTF8"] = true; + JSONTEST_ASSERT(Json::writeString(b, root) == "{\n\t\"test\" : " + "\"\\tTabTesting\\t\"\n}"); + + b.settings_["emitUTF8"] = false; + JSONTEST_ASSERT(Json::writeString(b, root) == "{\n\t\"test\" : " + "\"\\tTabTesting\\t\"\n}"); + + // Restore the locale + if (!currentLocale.empty()) + setlocale(LC_ALL, currentLocale.c_str()); +} +#endif + struct ReaderTest : JsonTest::TestCase { void setStrictMode() { reader = std::unique_ptr( @@ -2700,43 +2819,43 @@ struct ReaderTest : JsonTest::TestCase { }; JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrors) { - checkParse("{ \"property\" : \"value\" }"); + checkParse(R"({ "property" : "value" })"); } JSONTEST_FIXTURE_LOCAL(ReaderTest, parseObject) { - checkParse("{\"property\"}", + checkParse(R"({"property"})", {{11, 12, "Missing ':' after object member name"}}, "* Line 1, Column 12\n Missing ':' after object member name\n"); checkParse( - "{\"property\" : \"value\" ", + R"({"property" : "value" )", {{22, 22, "Missing ',' or '}' in object declaration"}}, "* 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"}}, "* Line 1, Column 24\n Missing '}' or object member name\n"); } JSONTEST_FIXTURE_LOCAL(ReaderTest, parseArray) { 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"); checkParse( - "[ \"value1\" \"value2\" ] ", + R"([ "value1" "value2" ] )", {{11, 19, "Missing ',' or ']' in array declaration"}}, "* Line 1, Column 12\n Missing ',' or ']' in array declaration\n"); } JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) { - checkParse("[ \"\u8a2a\" ]"); + checkParse(R"([ "\u8a2a" ])"); checkParse( - "[ \"\\ud801\" ]", + R"([ "\ud801" ])", {{2, 10, "additional six characters expected to parse unicode surrogate " "pair."}}, "* Line 1, Column 3\n" " additional six characters expected to parse unicode surrogate pair.\n" "See Line 1, Column 10 for detail.\n"); - checkParse("[ \"\\ud801\\d1234\" ]", + checkParse(R"([ "\ud801\d1234" ])", {{2, 16, "expecting another \\u token to begin the " "second half of a unicode surrogate pair"}}, @@ -2744,7 +2863,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) { " expecting another \\u token to begin the " "second half of a unicode surrogate pair\n" "See Line 1, Column 12 for detail.\n"); - checkParse("[ \"\\ua3t@\" ]", + checkParse(R"([ "\ua3t@" ])", {{2, 10, "Bad unicode escape sequence in string: " "hexadecimal digit expected."}}, @@ -2753,7 +2872,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) { "hexadecimal digit expected.\n" "See Line 1, Column 9 for detail.\n"); checkParse( - "[ \"\\ua3t\" ]", + R"([ "\ua3t" ])", {{2, 9, "Bad unicode escape sequence in string: four digits expected."}}, "* Line 1, Column 3\n" " Bad unicode escape sequence in string: four digits expected.\n" @@ -2762,29 +2881,29 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) { JSONTEST_FIXTURE_LOCAL(ReaderTest, parseComment) { checkParse( - "{ /*commentBeforeValue*/ \"property\" : \"value\" }//commentAfterValue" + R"({ /*commentBeforeValue*/ "property" : "value" }//commentAfterValue)" "\n"); checkParse(" true //comment1\n//comment2\r//comment3\r\n"); } JSONTEST_FIXTURE_LOCAL(ReaderTest, streamParseWithNoErrors) { - std::string styled = "{ \"property\" : \"value\" }"; + std::string styled = R"({ "property" : "value" })"; std::istringstream iss(styled); checkParse(iss); } JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrorsTestingOffsets) { - checkParse("{" - " \"property\" : [\"value\", \"value2\"]," - " \"obj\" : { \"nested\" : -6.2e+15, \"bool\" : true}," - " \"null\" : null," - " \"false\" : false" - "}"); + checkParse(R"({)" + R"( "property" : ["value", "value2"],)" + R"( "obj" : { "nested" : -6.2e+15, "bool" : true},)" + R"( "null" : null,)" + R"( "false" : false)" + R"( })"); auto checkOffsets = [&](const Json::Value& v, int start, int limit) { JSONTEST_ASSERT_EQUAL(start, v.getOffsetStart()); JSONTEST_ASSERT_EQUAL(limit, v.getOffsetLimit()); }; - checkOffsets(root, 0, 114); + checkOffsets(root, 0, 115); checkOffsets(root["property"], 15, 34); checkOffsets(root["property"][0], 16, 23); checkOffsets(root["property"][1], 25, 33); @@ -2796,7 +2915,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrorsTestingOffsets) { } JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithOneError) { - checkParse("{ \"property\" :: \"value\" }", + checkParse(R"({ "property" :: "value" })", {{14, 15, "Syntax error: value, object or array expected."}}, "* Line 1, Column 15\n Syntax error: value, object or array " "expected.\n"); @@ -2806,11 +2925,11 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithOneError) { } JSONTEST_FIXTURE_LOCAL(ReaderTest, parseSpecialFloat) { - checkParse("{ \"a\" : Infi }", + checkParse(R"({ "a" : Infi })", {{8, 9, "Syntax error: value, object or array expected."}}, "* Line 1, Column 9\n Syntax error: value, object or array " "expected.\n"); - checkParse("{ \"a\" : Infiniaa }", + checkParse(R"({ "a" : Infiniaa })", {{8, 9, "Syntax error: value, object or array expected."}}, "* Line 1, Column 9\n Syntax error: value, object or array " "expected.\n"); @@ -2827,20 +2946,16 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, strictModeParseNumber) { } JSONTEST_FIXTURE_LOCAL(ReaderTest, parseChineseWithOneError) { - checkParse("{ \"pr" -#if JSONCPP_CXX_STD_11 + checkParse(R"({ "pr)" u8"\u4f50\u85e4" // 佐藤 -#else - "\u4f50\u85e4" // 佐藤 -#endif - "erty\" :: \"value\" }", + R"(erty" :: "value" })", {{18, 19, "Syntax error: value, object or array expected."}}, "* Line 1, Column 19\n Syntax error: value, object or array " "expected.\n"); } JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithDetailError) { - checkParse("{ \"property\" : \"v\\alue\" }", + checkParse(R"({ "property" : "v\alue" })", {{15, 23, "Bad escape sequence in string"}}, "* Line 1, Column 16\n" " Bad escape sequence in string\n" @@ -2848,7 +2963,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithDetailError) { } JSONTEST_FIXTURE_LOCAL(ReaderTest, pushErrorTest) { - checkParse("{ \"AUTHOR\" : 123 }"); + checkParse(R"({ "AUTHOR" : 123 })"); if (!root["AUTHOR"].isString()) { JSONTEST_ASSERT( reader->pushError(root["AUTHOR"], "AUTHOR must be a string")); @@ -2857,7 +2972,7 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, pushErrorTest) { "* Line 1, Column 14\n" " AUTHOR must be a string\n"); - checkParse("{ \"AUTHOR\" : 123 }"); + checkParse(R"({ "AUTHOR" : 123 })"); if (!root["AUTHOR"].isString()) { JSONTEST_ASSERT(reader->pushError(root["AUTHOR"], "AUTHOR must be a string", root["AUTHOR"])); @@ -2872,9 +2987,9 @@ JSONTEST_FIXTURE_LOCAL(ReaderTest, allowNumericKeysTest) { Json::Features features; features.allowNumericKeys_ = true; setFeatures(features); - checkParse("{ 123 : \"abc\" }"); + checkParse(R"({ 123 : "abc" })"); } -#endif // JSONCPP_CXX_STD_11 + struct CharReaderTest : JsonTest::TestCase {}; JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrors) { @@ -2882,11 +2997,10 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrors) { CharReaderPtr reader(b.newCharReader()); Json::String errs; 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); JSONTEST_ASSERT(ok); JSONTEST_ASSERT(errs.empty()); - delete reader; } JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrorsTestingOffsets) { @@ -2900,7 +3014,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrorsTestingOffsets) { bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(ok); JSONTEST_ASSERT(errs.empty()); - delete reader; } JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseNumber) { @@ -2917,7 +3030,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseNumber) { JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT_EQUAL(1.1111111111111111e+020, root[0]); } - delete reader; } JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) { @@ -2933,18 +3045,14 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) { 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); JSONTEST_ASSERT(ok); JSONTEST_ASSERT(errs.empty()); -#if JSONCPP_CXX_STD_11 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); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 3\n" @@ -2953,7 +3061,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) { "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); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 3\n" @@ -2962,7 +3070,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) { "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); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 3\n" @@ -2971,7 +3079,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) { "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); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT( @@ -2980,18 +3088,16 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) { " Bad unicode escape sequence in string: four digits expected.\n" "See Line 1, Column 6 for detail.\n"); } - delete reader; { b.settings_["allowSingleQuotes"] = true; - CharReaderPtr charReader(b.newCharReader()); - char const doc[] = "{'a': 'x\\ty', \"b\":'x\\\\y'}"; - bool ok = charReader->parse(doc, doc + std::strlen(doc), &root, &errs); + CharReaderPtr charreader(b.newCharReader()); + char const doc[] = R"({'a': 'x\ty', "b":'x\\y'})"; + bool ok = charreader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(ok); JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_EQUAL(2u, root.size()); JSONTEST_ASSERT_STRING_EQUAL("x\ty", root["a"].asString()); JSONTEST_ASSERT_STRING_EQUAL("x\\y", root["b"].asString()); - delete charReader; } } @@ -3024,7 +3130,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseComment) { JSONTEST_ASSERT_EQUAL("value", root[0]); JSONTEST_ASSERT_EQUAL(true, root[1]); } - delete reader; } JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) { @@ -3033,7 +3138,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) { Json::Value root; 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); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 24\n" @@ -3041,14 +3146,13 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) { 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); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 25\n" " Missing '}' or object member name\n"); JSONTEST_ASSERT_EQUAL("value", root["property"]); } - delete reader; } JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseArrayWithErrors) { @@ -3065,14 +3169,13 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseArrayWithErrors) { 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); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 12\n" " Missing ',' or ']' in array declaration\n"); JSONTEST_ASSERT_EQUAL("value1", root[0]); } - delete reader; } JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithOneError) { @@ -3080,13 +3183,12 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithOneError) { CharReaderPtr reader(b.newCharReader()); Json::String errs; 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); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 15\n Syntax error: value, object or array " "expected.\n"); - delete reader; } JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseChineseWithOneError) { @@ -3100,7 +3202,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseChineseWithOneError) { JSONTEST_ASSERT(errs == "* Line 1, Column 19\n Syntax error: value, object or array " "expected.\n"); - delete reader; } JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithDetailError) { @@ -3108,19 +3209,18 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithDetailError) { CharReaderPtr reader(b.newCharReader()); Json::String errs; 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); JSONTEST_ASSERT(!ok); JSONTEST_ASSERT(errs == "* Line 1, Column 16\n Bad escape sequence in string\nSee " "Line 1, Column 20 for detail.\n"); - delete reader; } JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) { Json::CharReaderBuilder b; Json::Value root; - char const doc[] = "{ \"property\" : \"value\" }"; + char const doc[] = R"({ "property" : "value" })"; { b.settings_["stackLimit"] = 2; CharReaderPtr reader(b.newCharReader()); @@ -3129,7 +3229,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) { JSONTEST_ASSERT(ok); JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT_EQUAL("value", root["property"]); - delete reader; } { b.settings_["stackLimit"] = 1; @@ -3137,12 +3236,11 @@ JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) { Json::String errs; JSONTEST_ASSERT_THROWS( reader->parse(doc, doc + std::strlen(doc), &root, &errs)); - delete reader; } } JSONTEST_FIXTURE_LOCAL(CharReaderTest, testOperator) { - const std::string styled = "{ \"property\" : \"value\" }"; + const std::string styled = R"({ "property" : "value" })"; std::istringstream iss(styled); Json::Value root; iss >> root; @@ -3155,7 +3253,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderStrictModeTest, dupKeys) { Json::CharReaderBuilder b; Json::Value root; char const doc[] = - "{ \"property\" : \"value\", \"key\" : \"val1\", \"key\" : \"val2\" }"; + R"({ "property" : "value", "key" : "val1", "key" : "val2" })"; { b.strictMode(&b.settings_); CharReaderPtr reader(b.newCharReader()); @@ -3166,7 +3264,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderStrictModeTest, dupKeys) { " Duplicate key: 'key'\n", errs); JSONTEST_ASSERT_EQUAL("val1", root["key"]); // so far - delete reader; } } struct CharReaderFailIfExtraTest : JsonTest::TestCase {}; @@ -3175,7 +3272,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) { // This is interpreted as a string value followed by a colon. Json::CharReaderBuilder b; Json::Value root; - char const doc[] = " \"property\" : \"value\" }"; + char const doc[] = R"( "property" : "value" })"; { b.settings_["failIfExtra"] = false; CharReaderPtr reader(b.newCharReader()); @@ -3184,7 +3281,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) { JSONTEST_ASSERT(ok); JSONTEST_ASSERT(errs.empty()); JSONTEST_ASSERT_EQUAL("property", root); - delete reader; } { b.settings_["failIfExtra"] = true; @@ -3196,7 +3292,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) { " Extra non-whitespace after JSON value.\n", errs); JSONTEST_ASSERT_EQUAL("property", root); - delete reader; } { b.strictMode(&b.settings_); @@ -3208,7 +3303,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) { " Extra non-whitespace after JSON value.\n", errs); JSONTEST_ASSERT_EQUAL("property", root); - delete reader; } { b.strictMode(&b.settings_); @@ -3222,7 +3316,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue164) { " A valid JSON document must be either an array or an object value.\n", errs); JSONTEST_ASSERT_EQUAL("property", root); - delete reader; } } @@ -3240,7 +3333,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue107) { " Extra non-whitespace after JSON value.\n", errs); JSONTEST_ASSERT_EQUAL(1, root.asInt()); - delete reader; } JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterObject) { Json::CharReaderBuilder b; @@ -3254,7 +3346,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterObject) { JSONTEST_ASSERT(ok); JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_EQUAL("value", root["property"]); - delete reader; } } JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterArray) { @@ -3268,7 +3359,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterArray) { JSONTEST_ASSERT(ok); JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_EQUAL("value", root[1u]); - delete reader; } JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterBool) { Json::CharReaderBuilder b; @@ -3281,7 +3371,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterBool) { JSONTEST_ASSERT(ok); JSONTEST_ASSERT_STRING_EQUAL("", errs); JSONTEST_ASSERT_EQUAL(true, root.asBool()); - delete reader; } JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, parseComment) { @@ -3315,12 +3404,11 @@ JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, parseComment) { errs); JSONTEST_ASSERT_EQUAL(true, root.asBool()); } - delete reader; } -#if JSONCPP_CXX_STD_11 + struct CharReaderAllowDropNullTest : JsonTest::TestCase { - typedef Json::Value Value; - typedef std::function ValueCheck; + using Value = Json::Value; + using ValueCheck = std::function; Value nullValue = Value{Json::nullValue}; Value emptyArray = Value{Json::arrayValue}; @@ -3329,11 +3417,11 @@ struct CharReaderAllowDropNullTest : JsonTest::TestCase { 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)); }; } - ValueCheck arrGetAnd(int idx, ValueCheck f) { + static ValueCheck arrGetAnd(int idx, ValueCheck f) { return [=](const Value& root) { f(root[idx]); }; } }; @@ -3346,19 +3434,19 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowDropNullTest, issue178) { ValueCheck onRoot; }; const TestSpec specs[] = { - {__LINE__, "{\"a\":,\"b\":true}", 2, objGetAnd("a", checkEq(nullValue))}, - {__LINE__, "{\"a\":,\"b\":true}", 2, objGetAnd("a", checkEq(nullValue))}, - {__LINE__, "{\"a\":}", 1, objGetAnd("a", checkEq(nullValue))}, + {__LINE__, R"({"a":,"b":true})", 2, objGetAnd("a", checkEq(nullValue))}, + {__LINE__, R"({"a":,"b":true})", 2, objGetAnd("a", checkEq(nullValue))}, + {__LINE__, R"({"a":})", 1, objGetAnd("a", checkEq(nullValue))}, {__LINE__, "[]", 0, checkEq(emptyArray)}, - {__LINE__, "[null]", 1, JSONCPP_NULL}, - {__LINE__, "[,]", 2, JSONCPP_NULL}, - {__LINE__, "[,,,]", 4, JSONCPP_NULL}, - {__LINE__, "[null,]", 2, JSONCPP_NULL}, - {__LINE__, "[,null]", 2, JSONCPP_NULL}, - {__LINE__, "[,,]", 3, JSONCPP_NULL}, - {__LINE__, "[null,,]", 3, JSONCPP_NULL}, - {__LINE__, "[,null,]", 3, JSONCPP_NULL}, - {__LINE__, "[,,null]", 3, JSONCPP_NULL}, + {__LINE__, "[null]", 1, nullptr}, + {__LINE__, "[,]", 2, nullptr}, + {__LINE__, "[,,,]", 4, nullptr}, + {__LINE__, "[null,]", 2, nullptr}, + {__LINE__, "[,null]", 2, nullptr}, + {__LINE__, "[,,]", 3, nullptr}, + {__LINE__, "[null,,]", 3, nullptr}, + {__LINE__, "[,null,]", 3, nullptr}, + {__LINE__, "[,,null]", 3, nullptr}, {__LINE__, "[[],,,]", 4, arrGetAnd(0, checkEq(emptyArray))}, {__LINE__, "[,[],,]", 4, arrGetAnd(1, checkEq(emptyArray))}, {__LINE__, "[,,,[]]", 4, arrGetAnd(3, checkEq(emptyArray))}, @@ -3379,7 +3467,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowDropNullTest, issue178) { } } } -#endif // JSONCPP_CXX_STD_11 + struct CharReaderAllowNumericKeysTest : JsonTest::TestCase {}; JSONTEST_FIXTURE_LOCAL(CharReaderAllowNumericKeysTest, allowNumericKeys) { @@ -3396,7 +3484,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowNumericKeysTest, allowNumericKeys) { JSONTEST_ASSERT_EQUAL(true, root.get("15", false)); JSONTEST_ASSERT_EQUAL(true, root.get("-16", false)); JSONTEST_ASSERT_EQUAL(true, root.get("12.01", false)); - delete reader; } struct CharReaderAllowSingleQuotesTest : JsonTest::TestCase {}; @@ -3425,7 +3512,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSingleQuotesTest, issue182) { JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString()); JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString()); } - delete reader; } struct CharReaderAllowZeroesTest : JsonTest::TestCase {}; @@ -3454,7 +3540,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowZeroesTest, issue176) { JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString()); JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString()); } - delete reader; } struct CharReaderAllowSpecialFloatsTest : JsonTest::TestCase {}; @@ -3482,7 +3567,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, specialFloat) { " Syntax error: value, object or array expected.\n", errs); } - delete reader; } JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) { @@ -3492,8 +3576,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) { Json::String errs; CharReaderPtr reader(b.newCharReader()); { - char const doc[] = - "{\"a\":NaN,\"b\":Infinity,\"c\":-Infinity,\"d\":+Infinity}"; + char const doc[] = R"({"a":NaN,"b":Infinity,"c":-Infinity,"d":+Infinity})"; bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(ok); JSONTEST_ASSERT_STRING_EQUAL("", errs); @@ -3532,9 +3615,7 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) { {__LINE__, true, "{\"a\":-Infinity}"}, // {__LINE__, true, "{\"a\":+Infinity}"} // }; - for (unsigned int index = 0; index < sizeof(test_data) / sizeof(test_data[0]); - ++index) { - const struct TestData td = test_data[index]; + for (const auto& td : test_data) { bool ok = reader->parse(&*td.in.begin(), &*td.in.begin() + td.in.size(), &root, &errs); JSONTEST_ASSERT(td.ok == ok) << "line:" << td.line << "\n" @@ -3546,7 +3627,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); JSONTEST_ASSERT(ok); JSONTEST_ASSERT_STRING_EQUAL("", errs); @@ -3556,7 +3637,6 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) { JSONTEST_ASSERT_EQUAL(-std::numeric_limits::infinity(), root["NegInf"].asDouble()); } - delete reader; } struct EscapeSequenceTest : JsonTest::TestCase {}; @@ -3584,7 +3664,6 @@ JSONTEST_FIXTURE_LOCAL(EscapeSequenceTest, charReaderParseEscapeSequence) { bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs); JSONTEST_ASSERT(ok); JSONTEST_ASSERT(errs.empty()); - delete reader; } JSONTEST_FIXTURE_LOCAL(EscapeSequenceTest, writeEscapeSequence) { @@ -3660,7 +3739,7 @@ struct IteratorTest : JsonTest::TestCase {}; JSONTEST_FIXTURE_LOCAL(IteratorTest, convert) { Json::Value j; const Json::Value& cj = j; - Json::Value::const_iterator it = j.begin(); + auto it = j.begin(); Json::Value::const_iterator cit; cit = it; JSONTEST_ASSERT(cit == cj.begin()); @@ -3671,17 +3750,11 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, decrement) { json["k1"] = "a"; json["k2"] = "b"; std::vector values; - std::vector expected; - expected.push_back("b"); - expected.push_back("a"); - for (Json::Value::const_iterator it = json.end(); it != json.begin();) { + for (auto it = json.end(); it != json.begin();) { --it; values.push_back(it->asString()); } - JSONTEST_ASSERT(values.size() == expected.size()); - for (unsigned int i = 0; i < expected.size(); i++) { - JSONTEST_ASSERT(values.at(i) == expected.at(i)); - } + JSONTEST_ASSERT((values == std::vector{"b", "a"})); } JSONTEST_FIXTURE_LOCAL(IteratorTest, reverseIterator) { @@ -3689,19 +3762,12 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, reverseIterator) { json["k1"] = "a"; json["k2"] = "b"; std::vector values; - typedef Json::Value::const_iterator Iter; - std::reverse_iterator re = std::reverse_iterator(json.begin()); - for (std::reverse_iterator it = std::reverse_iterator(json.end()); - it != re; ++it) { + using Iter = decltype(json.begin()); + auto re = std::reverse_iterator(json.begin()); + for (auto it = std::reverse_iterator(json.end()); it != re; ++it) { values.push_back(it->asString()); } - std::vector expected; - 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_ASSERT((values == std::vector{"b", "a"})); } JSONTEST_FIXTURE_LOCAL(IteratorTest, distance) { @@ -3710,9 +3776,9 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, distance) { json["k1"] = "a"; json["k2"] = "b"; int i = 0; - Json::Value::const_iterator it = json.begin(); + auto it = json.begin(); for (;; ++it, ++i) { - Json::ValueIteratorBase::difference_type dist = it - json.begin(); + auto dist = it - json.begin(); JSONTEST_ASSERT_EQUAL(i, dist); if (it == json.end()) break; @@ -3728,8 +3794,8 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, distance) { JSONTEST_FIXTURE_LOCAL(IteratorTest, nullValues) { { Json::Value json; - Json::Value::const_iterator end = json.end(); - Json::Value::const_iterator endCopy = end; + auto end = json.end(); + auto endCopy = end; JSONTEST_ASSERT(endCopy == end); endCopy = end; JSONTEST_ASSERT(endCopy == end); @@ -3737,8 +3803,8 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, nullValues) { { // Same test, now with const Value. const Json::Value json; - Json::Value::const_iterator end = json.end(); - Json::Value::const_iterator endCopy = end; + auto end = json.end(); + auto endCopy = end; JSONTEST_ASSERT(endCopy == end); endCopy = end; JSONTEST_ASSERT(endCopy == end); @@ -3809,10 +3875,10 @@ JSONTEST_FIXTURE_LOCAL(IteratorTest, constness) { for (; iter != value.end(); ++iter) { out << *iter << ','; } - Json::String expected = "\" 9\",\"10\",\"11\","; + Json::String expected = R"(" 9","10","11",)"; JSONTEST_ASSERT_STRING_EQUAL(expected, out.str()); } -#if JSONCPP_CXX_STD_11 + struct RValueTest : JsonTest::TestCase {}; JSONTEST_FIXTURE_LOCAL(RValueTest, moveConstruction) { @@ -3824,7 +3890,7 @@ JSONTEST_FIXTURE_LOCAL(RValueTest, moveConstruction) { JSONTEST_ASSERT_EQUAL(Json::objectValue, moved.type()); JSONTEST_ASSERT_EQUAL(Json::stringValue, moved["key"].type()); } -#endif // JSONCPP_CXX_STD_11 + struct FuzzTest : JsonTest::TestCase {}; // Build and run the fuzz test without any fuzzer, so that it's guaranteed not @@ -3840,14 +3906,13 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) { int main(int argc, const char* argv[]) { JsonTest::Runner runner; - for (unsigned int index = 0; index < local_.size(); ++index) { - JsonTest::TestCaseFactory local = local_[index]; + for (auto& local : local_) { runner.add(local); } return runner.runCommandLine(argc, argv); } -#if JSONCPP_CXX_STD_11 + struct MemberTemplateAs : JsonTest::TestCase { template JsonTest::TestResult& EqEval(T v, F f) const { @@ -3876,13 +3941,12 @@ JSONTEST_FIXTURE_LOCAL(MemberTemplateAs, BehavesSameAsNamedAs) { EqEval(false, [](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 {}; JSONTEST_FIXTURE_LOCAL(MemberTemplateIs, BehavesSameAsNamedIs) { const Json::Value values[] = {true, 142, 40.63, "hello world"}; - for (size_t index = 0; index < sizeof(values) / sizeof(values[0]); index++) { - const Json::Value& j = values[index]; + for (const Json::Value& j : values) { JSONTEST_ASSERT_EQUAL(j.is(), j.isBool()); JSONTEST_ASSERT_EQUAL(j.is(), j.isInt()); JSONTEST_ASSERT_EQUAL(j.is(), j.isInt64()); @@ -3893,6 +3957,15 @@ JSONTEST_FIXTURE_LOCAL(MemberTemplateIs, BehavesSameAsNamedIs) { } } +class VersionTest : public JsonTest::TestCase {}; + +JSONTEST_FIXTURE_LOCAL(VersionTest, VersionNumbersMatch) { + std::ostringstream vstr; + vstr << JSONCPP_VERSION_MAJOR << '.' << JSONCPP_VERSION_MINOR << '.' + << JSONCPP_VERSION_PATCH; + JSONTEST_ASSERT_EQUAL(vstr.str(), std::string(JSONCPP_VERSION_STRING)); +} + #if defined(__GNUC__) #pragma GCC diagnostic pop #endif diff --git a/test/data/fail_invalid_quote.json b/test/data/fail_invalid_quote.json new file mode 100755 index 0000000000000000000000000000000000000000..dae27f53ff979a04a83f0de85139a1c0afb16a7c --- /dev/null +++ b/test/data/fail_invalid_quote.json @@ -0,0 +1 @@ +{'//this is bad JSON.'} \ No newline at end of file diff --git a/test/data/legacy_test_array_06.json b/test/data/legacy_test_array_06.json index 7f6c516afdeb309ac419747049e1449cbbd9dc99..1fda03bb1d9c7fbd3ab271e1910e24feff9dd406 100755 --- a/test/data/legacy_test_array_06.json +++ b/test/data/legacy_test_array_06.json @@ -1,4 +1,4 @@ -[ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", +[ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "ccccccccccccccccccccccc", "dddddddddddddddddddddddddddddddddddddddddddddddddddd" ] \ No newline at end of file diff --git a/test/data/legacy_test_complex_01.json b/test/data/legacy_test_complex_01.json index cc0f30f5c3478ec75dd703c840f96d7ac4144e4b..2c4a869abe76d8a49126b0f29ae6ba775608e9b1 100755 --- a/test/data/legacy_test_complex_01.json +++ b/test/data/legacy_test_complex_01.json @@ -1,17 +1,17 @@ -{ +{ "count" : 1234, "name" : { "aka" : "T.E.S.T.", "id" : 123987 }, - "attribute" : [ - "random", - "short", - "bold", - 12, - { "height" : 7, "width" : 64 } + "attribute" : [ + "random", + "short", + "bold", + 12, + { "height" : 7, "width" : 64 } ], - "test": { "1" : - { "2" : - { "3" : { "coord" : [ 1,2] } - } + "test": { "1" : + { "2" : + { "3" : { "coord" : [ 1,2] } + } } } } diff --git a/test/data/legacy_test_object_03.json b/test/data/legacy_test_object_03.json index 4fcd4d821d4062c9c6f25c7241f3715f5e22317f..90dba2af88bb6af031f3beb62576d3c1c065257f 100755 --- a/test/data/legacy_test_object_03.json +++ b/test/data/legacy_test_object_03.json @@ -1,4 +1,4 @@ -{ +{ "count" : 1234, "name" : "test", "attribute" : "random" diff --git a/test/data/legacy_test_object_04.json b/test/data/legacy_test_object_04.json index 450762d71e59a8a51dcd081289a0e329b3ec82ce..9e43ff89bef51a7ac3f44a5a28ab51ab24fe69af 100755 --- a/test/data/legacy_test_object_04.json +++ b/test/data/legacy_test_object_04.json @@ -1,3 +1,3 @@ -{ +{ "" : 1234 } diff --git a/test/data/legacy_test_preserve_comment_01.expected b/test/data/legacy_test_preserve_comment_01.expected index 2797aa7d6bedf542549f1e928177e992617d6105..d6c11b4c95f5cb143703cf059a57df8a83835732 100755 --- a/test/data/legacy_test_preserve_comment_01.expected +++ b/test/data/legacy_test_preserve_comment_01.expected @@ -6,6 +6,6 @@ /* Comment before 'second' */ .second=2 -/* A comment at +/* A comment at the end of the file. */ diff --git a/test/data/legacy_test_preserve_comment_01.json b/test/data/legacy_test_preserve_comment_01.json index fabd55dd96639ea5ec7759b5b54d35a1b74bcbef..21b5ea7fa1448156132248b08081eb88b7c3ab4d 100755 --- a/test/data/legacy_test_preserve_comment_01.json +++ b/test/data/legacy_test_preserve_comment_01.json @@ -9,6 +9,6 @@ "second" : 2 } -/* A comment at +/* A comment at the end of the file. */ diff --git a/test/pyjsontestrunner.py b/test/pyjsontestrunner.py index bd749b530f30e8264221faf0f92df65de7294910..8acdbd2deaee1dd0e7ff3a3c1a1206845932e11a 100755 --- a/test/pyjsontestrunner.py +++ b/test/pyjsontestrunner.py @@ -15,7 +15,7 @@ import types if len(sys.argv) != 2: print("Usage: %s input-json-file", sys.argv[0]) sys.exit(3) - + input_path = sys.argv[1] base_path = os.path.splitext(input_path)[0] actual_path = base_path + '.actual' @@ -23,7 +23,7 @@ rewrite_path = base_path + '.rewrite' rewrite_actual_path = base_path + '.actual-rewrite' def valueTreeToString(fout, value, path = '.'): - ty = type(value) + ty = type(value) if ty is types.DictType: fout.write('%s={}\n' % path) suffix = path[-1] != '.' and '.' or '' @@ -49,7 +49,7 @@ def valueTreeToString(fout, value, path = '.'): fout.write('%s=null\n' % path) else: assert False and "Unexpected value type" - + def parseAndSaveValueTree(input, actual_path): root = json.loads(input) fout = file(actual_path, 'wt') @@ -62,7 +62,7 @@ def rewriteValueTree(value, rewrite_path): #rewrite = rewrite[1:-1] # Somehow the string is quoted ! jsonpy bug ? file(rewrite_path, 'wt').write(rewrite + '\n') return rewrite - + input = file(input_path, 'rt').read() root = parseAndSaveValueTree(input, actual_path) rewrite = rewriteValueTree(json.write(root), rewrite_path)