mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-10-15 07:14:45 +02:00
Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7c186e549f | ||
![]() |
d9ffdc4bcb | ||
![]() |
d2c205206d |
@@ -1,4 +1,4 @@
|
||||
BasedOnStyle: LLVM
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
SpacesBeforeTrailingComments: 1
|
||||
|
||||
|
20
.github/workflows/clang-format.yml
vendored
20
.github/workflows/clang-format.yml
vendored
@@ -1,20 +0,0 @@
|
||||
name: clang-format check
|
||||
on: [check_run, pull_request, push]
|
||||
|
||||
jobs:
|
||||
formatting-check:
|
||||
name: formatting check
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
path:
|
||||
- 'src'
|
||||
- 'examples'
|
||||
- 'include'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: runs clang-format style check for C/C++/Protobuf programs.
|
||||
uses: jidicula/clang-format-action@v4.13.0
|
||||
with:
|
||||
clang-format-version: '18'
|
||||
check-path: ${{ matrix.path }}
|
18
.github/workflows/cmake.yml
vendored
18
.github/workflows/cmake.yml
vendored
@@ -1,18 +0,0 @@
|
||||
name: cmake
|
||||
on: [check_run, push, pull_request]
|
||||
jobs:
|
||||
cmake-publish:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
|
||||
steps:
|
||||
- name: checkout project
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: build project
|
||||
uses: threeal/cmake-action@v2.0.0
|
||||
|
65
.github/workflows/meson.yml
vendored
65
.github/workflows/meson.yml
vendored
@@ -1,65 +0,0 @@
|
||||
name: meson build and test
|
||||
run-name: update pushed to ${{ github.ref }}
|
||||
on: [check_run, push, pull_request]
|
||||
|
||||
jobs:
|
||||
meson-publish:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup python
|
||||
uses: actions/setup-python@v5
|
||||
|
||||
- name: meson build
|
||||
uses: BSFishy/meson-build@v1.0.3
|
||||
with:
|
||||
meson-version: 1.5.1
|
||||
ninja-version: 1.11.1.1
|
||||
action: build
|
||||
|
||||
- name: meson test
|
||||
uses: BSFishy/meson-build@v1.0.3
|
||||
with:
|
||||
meson-version: 1.5.1
|
||||
ninja-version: 1.11.1.1
|
||||
action: test
|
||||
|
||||
meson-coverage:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup python
|
||||
uses: actions/setup-python@v5
|
||||
|
||||
- name: meson build
|
||||
uses: BSFishy/meson-build@v1.0.3
|
||||
with:
|
||||
meson-version: 1.5.1
|
||||
ninja-version: 1.11.1.1
|
||||
setup-options: -Db_coverage=true
|
||||
action: build
|
||||
|
||||
- name: meson test
|
||||
uses: BSFishy/meson-build@v1.0.3
|
||||
with:
|
||||
meson-version: 1.5.1
|
||||
ninja-version: 1.11.1.1
|
||||
setup-options: -Db_coverage=true
|
||||
action: test
|
||||
|
||||
- name: generate code coverage report
|
||||
uses: threeal/gcovr-action@v1.0.0
|
||||
with:
|
||||
coveralls-send: true
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
6
.gitignore
vendored
6
.gitignore
vendored
@@ -10,7 +10,6 @@
|
||||
/libs/
|
||||
/doc/doxyfile
|
||||
/dist/
|
||||
/.cache/
|
||||
|
||||
# MSVC project files:
|
||||
*.sln
|
||||
@@ -29,9 +28,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
|
||||
@@ -52,6 +51,3 @@ compile_commands.json
|
||||
|
||||
# DS_Store
|
||||
.DS_Store
|
||||
|
||||
# temps
|
||||
/version
|
||||
|
185
.travis.yml
Normal file
185
.travis.yml
Normal file
@@ -0,0 +1,185 @@
|
||||
# Build matrix / environment variables are explained on:
|
||||
# http://about.travis-ci.org/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
|
||||
# travis lint .travis.yml
|
||||
language: cpp
|
||||
sudo: false
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- clang-format
|
||||
- meson
|
||||
- ninja
|
||||
update: false # do not update homebrew by default
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-xenial-8
|
||||
packages:
|
||||
- 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"
|
||||
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"
|
||||
# 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++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
|
||||
os: linux
|
||||
dist: xenial
|
||||
compiler: gcc
|
||||
env:
|
||||
CXX=g++
|
||||
CC=gcc
|
||||
DO_Coverage=ON
|
||||
BUILD_TOOL="Unix Makefiles"
|
||||
BUILD_TYPE=Debug
|
||||
LIB_TYPE=shared
|
||||
DESTDIR=/tmp/cmake_json_cpp
|
||||
LANGUAGE_STANDARD="11"
|
||||
before_install:
|
||||
- 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
|
||||
notifications:
|
||||
email: false
|
139
.travis_scripts/cmake_builder.sh
Executable file
139
.travis_scripts/cmake_builder.sh
Executable file
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env sh
|
||||
# This script can be used on the command line directly to configure several
|
||||
# different build environments.
|
||||
# This is called by `.travis.yml` via Travis CI.
|
||||
# Travis supplies $TRAVIS_OS_NAME.
|
||||
# http://docs.travis-ci.com/user/multi-os/
|
||||
# Our .travis.yml also defines:
|
||||
|
||||
# - BUILD_TYPE=Release/Debug
|
||||
# - LIB_TYPE=static/shared
|
||||
#
|
||||
# Optional environmental variables
|
||||
# - DESTDIR <- used for setting the install prefix
|
||||
# - BUILD_TOOL=["Unix Makefile"|"Ninja"]
|
||||
# - BUILDNAME <- how to identify this build on the dashboard
|
||||
# - DO_MemCheck <- if set, try to use valgrind
|
||||
# - DO_Coverage <- if set, try to do dashboard coverage testing
|
||||
#
|
||||
|
||||
env_set=1
|
||||
if ${BUILD_TYPE+false}; then
|
||||
echo "BUILD_TYPE not set in environment."
|
||||
env_set=0
|
||||
fi
|
||||
if ${LIB_TYPE+false}; then
|
||||
echo "LIB_TYPE not set in environment."
|
||||
env_set=0
|
||||
fi
|
||||
if ${CXX+false}; then
|
||||
echo "CXX not set in environment."
|
||||
env_set=0
|
||||
fi
|
||||
|
||||
|
||||
if [ ${env_set} -eq 0 ]; then
|
||||
echo "USAGE: CXX=$(which clang++) BUILD_TYPE=[Release|Debug] LIB_TYPE=[static|shared] $0"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " CXX=$(which clang++) BUILD_TYPE=Release LIB_TYPE=shared DESTDIR=/tmp/cmake_json_cpp $0"
|
||||
echo " CXX=$(which clang++) BUILD_TYPE=Debug LIB_TYPE=shared DESTDIR=/tmp/cmake_json_cpp $0"
|
||||
echo " CXX=$(which clang++) BUILD_TYPE=Release LIB_TYPE=static DESTDIR=/tmp/cmake_json_cpp $0"
|
||||
echo " CXX=$(which clang++) BUILD_TYPE=Debug LIB_TYPE=static DESTDIR=/tmp/cmake_json_cpp $0"
|
||||
|
||||
echo " CXX=$(which g++) BUILD_TYPE=Release LIB_TYPE=shared DESTDIR=/tmp/cmake_json_cpp $0"
|
||||
echo " CXX=$(which g++) BUILD_TYPE=Debug LIB_TYPE=shared DESTDIR=/tmp/cmake_json_cpp $0"
|
||||
echo " CXX=$(which g++) BUILD_TYPE=Release LIB_TYPE=static DESTDIR=/tmp/cmake_json_cpp $0"
|
||||
echo " CXX=$(which g++) BUILD_TYPE=Debug LIB_TYPE=static DESTDIR=/tmp/cmake_json_cpp $0"
|
||||
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if ${DESTDIR+false}; then
|
||||
DESTDIR="/usr/local"
|
||||
fi
|
||||
|
||||
# -e: fail on error
|
||||
# -v: show commands
|
||||
# -x: show expanded commands
|
||||
set -vex
|
||||
|
||||
env | sort
|
||||
|
||||
which cmake
|
||||
cmake --version
|
||||
|
||||
echo ${CXX}
|
||||
${CXX} --version
|
||||
_COMPILER_NAME=`basename ${CXX}`
|
||||
if [ "${BUILD_TYPE}" = "shared" ]; then
|
||||
_CMAKE_BUILD_SHARED_LIBS=ON
|
||||
else
|
||||
_CMAKE_BUILD_SHARED_LIBS=OFF
|
||||
fi
|
||||
|
||||
CTEST_TESTING_OPTION="-D ExperimentalTest"
|
||||
# - DO_MemCheck <- if set, try to use valgrind
|
||||
if ! ${DO_MemCheck+false}; then
|
||||
valgrind --version
|
||||
CTEST_TESTING_OPTION="-D ExperimentalMemCheck"
|
||||
else
|
||||
# - DO_Coverage <- if set, try to do dashboard coverage testing
|
||||
if ! ${DO_Coverage+false}; then
|
||||
export CXXFLAGS="-fprofile-arcs -ftest-coverage"
|
||||
export LDFLAGS="-fprofile-arcs -ftest-coverage"
|
||||
CTEST_TESTING_OPTION="-D ExperimentalTest -D ExperimentalCoverage"
|
||||
#gcov --version
|
||||
fi
|
||||
fi
|
||||
|
||||
# Ninja = Generates build.ninja files.
|
||||
if ${BUILD_TOOL+false}; then
|
||||
BUILD_TOOL="Ninja"
|
||||
export _BUILD_EXE=ninja
|
||||
which ninja
|
||||
ninja --version
|
||||
else
|
||||
# Unix Makefiles = Generates standard UNIX makefiles.
|
||||
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}"
|
||||
if ${BUILDNAME+false}; then
|
||||
_HOSTNAME=`hostname -s`
|
||||
BUILDNAME="${_HOSTNAME}_${BUILD_TYPE}_${LIB_TYPE}_${_COMPILER_NAME}_${_BUILD_EXE}"
|
||||
fi
|
||||
cmake \
|
||||
-G "${BUILD_TOOL}" \
|
||||
-DBUILDNAME:STRING="${BUILDNAME}" \
|
||||
-DCMAKE_CXX_COMPILER:PATH=${CXX} \
|
||||
-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
|
||||
# Final step is to verify that installation succeeds
|
||||
cmake --build . --config ${BUILD_TYPE} --target install
|
||||
|
||||
if [ "${DESTDIR}" != "/usr/local" ]; then
|
||||
${_BUILD_EXE} install
|
||||
fi
|
||||
cd -
|
||||
|
||||
if ${CLEANUP+false}; then
|
||||
echo "Skipping cleanup: build directory will persist."
|
||||
else
|
||||
rm -r "${_BUILD_DIR_NAME}"
|
||||
fi
|
87
.travis_scripts/meson_builder.sh
Executable file
87
.travis_scripts/meson_builder.sh
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env sh
|
||||
# This script can be used on the command line directly to configure several
|
||||
# different build environments.
|
||||
# This is called by `.travis.yml` via Travis CI.
|
||||
# Travis supplies $TRAVIS_OS_NAME.
|
||||
# http://docs.travis-ci.com/user/multi-os/
|
||||
# Our .travis.yml also defines:
|
||||
|
||||
# - BUILD_TYPE=release/debug
|
||||
# - LIB_TYPE=static/shared
|
||||
|
||||
env_set=1
|
||||
if ${BUILD_TYPE+false}; then
|
||||
echo "BUILD_TYPE not set in environment."
|
||||
env_set=0
|
||||
fi
|
||||
if ${LIB_TYPE+false}; then
|
||||
echo "LIB_TYPE not set in environment."
|
||||
env_set=0
|
||||
fi
|
||||
if ${CXX+false}; then
|
||||
echo "CXX not set in environment."
|
||||
env_set=0
|
||||
fi
|
||||
|
||||
|
||||
if [ ${env_set} -eq 0 ]; then
|
||||
echo "USAGE: CXX=$(which clang++) BUILD_TYPE=[release|debug] LIB_TYPE=[static|shared] $0"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " CXX=$(which clang++) BUILD_TYPE=release LIB_TYPE=shared DESTDIR=/tmp/meson_json_cpp $0"
|
||||
echo " CXX=$(which clang++) BUILD_TYPE=debug LIB_TYPE=shared DESTDIR=/tmp/meson_json_cpp $0"
|
||||
echo " CXX=$(which clang++) BUILD_TYPE=release LIB_TYPE=static DESTDIR=/tmp/meson_json_cpp $0"
|
||||
echo " CXX=$(which clang++) BUILD_TYPE=debug LIB_TYPE=static DESTDIR=/tmp/meson_json_cpp $0"
|
||||
|
||||
echo " CXX=$(which g++) BUILD_TYPE=release LIB_TYPE=shared DESTDIR=/tmp/meson_json_cpp $0"
|
||||
echo " CXX=$(which g++) BUILD_TYPE=debug LIB_TYPE=shared DESTDIR=/tmp/meson_json_cpp $0"
|
||||
echo " CXX=$(which g++) BUILD_TYPE=release LIB_TYPE=static DESTDIR=/tmp/meson_json_cpp $0"
|
||||
echo " CXX=$(which g++) BUILD_TYPE=debug LIB_TYPE=static DESTDIR=/tmp/meson_json_cpp $0"
|
||||
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if ${DESTDIR+false}; then
|
||||
DESTDIR="/usr/local"
|
||||
fi
|
||||
|
||||
# -e: fail on error
|
||||
# -v: show commands
|
||||
# -x: show expanded commands
|
||||
set -vex
|
||||
|
||||
|
||||
env | sort
|
||||
|
||||
which python3
|
||||
which meson
|
||||
which ninja
|
||||
echo ${CXX}
|
||||
${CXX} --version
|
||||
python3 --version
|
||||
meson --version
|
||||
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
|
||||
meson --fatal-meson-warnings --werror --buildtype ${BUILD_TYPE} --default-library ${LIB_TYPE} . "${_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
|
||||
ninja install
|
||||
fi
|
||||
cd -
|
||||
|
||||
if ${CLEANUP+false}; then
|
||||
echo "Skipping cleanup: build directory will persist."
|
||||
else
|
||||
rm -r "${_BUILD_DIR_NAME}"
|
||||
fi
|
356
.travis_scripts/run-clang-format.py
Executable file
356
.travis_scripts/run-clang-format.py
Executable file
@@ -0,0 +1,356 @@
|
||||
#!/usr/bin/env python
|
||||
"""A wrapper script around clang-format, suitable for linting multiple files
|
||||
and to use for continuous integration.
|
||||
This is an alternative API for the clang-format command line.
|
||||
It runs over multiple files and directories in parallel.
|
||||
A diff output is produced and a sensible exit code is returned.
|
||||
|
||||
NOTE: pulled from https://github.com/Sarcasm/run-clang-format, which is
|
||||
licensed under the MIT license.
|
||||
"""
|
||||
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import codecs
|
||||
import difflib
|
||||
import fnmatch
|
||||
import io
|
||||
import multiprocessing
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from functools import partial
|
||||
|
||||
try:
|
||||
from subprocess import DEVNULL # py3k
|
||||
except ImportError:
|
||||
DEVNULL = open(os.devnull, "wb")
|
||||
|
||||
|
||||
DEFAULT_EXTENSIONS = 'c,h,C,H,cpp,hpp,cc,hh,c++,h++,cxx,hxx'
|
||||
|
||||
|
||||
class ExitStatus:
|
||||
SUCCESS = 0
|
||||
DIFF = 1
|
||||
TROUBLE = 2
|
||||
|
||||
|
||||
def list_files(files, recursive=False, extensions=None, exclude=None):
|
||||
if extensions is None:
|
||||
extensions = []
|
||||
if exclude is None:
|
||||
exclude = []
|
||||
|
||||
out = []
|
||||
for file in files:
|
||||
if recursive and os.path.isdir(file):
|
||||
for dirpath, dnames, fnames in os.walk(file):
|
||||
fpaths = [os.path.join(dirpath, fname) for fname in fnames]
|
||||
for pattern in exclude:
|
||||
# os.walk() supports trimming down the dnames list
|
||||
# by modifying it in-place,
|
||||
# to avoid unnecessary directory listings.
|
||||
dnames[:] = [
|
||||
x for x in dnames
|
||||
if
|
||||
not fnmatch.fnmatch(os.path.join(dirpath, x), pattern)
|
||||
]
|
||||
fpaths = [
|
||||
x for x in fpaths if not fnmatch.fnmatch(x, pattern)
|
||||
]
|
||||
for f in fpaths:
|
||||
ext = os.path.splitext(f)[1][1:]
|
||||
if ext in extensions:
|
||||
out.append(f)
|
||||
else:
|
||||
out.append(file)
|
||||
return out
|
||||
|
||||
|
||||
def make_diff(file, original, reformatted):
|
||||
return list(
|
||||
difflib.unified_diff(
|
||||
original,
|
||||
reformatted,
|
||||
fromfile='{}\t(original)'.format(file),
|
||||
tofile='{}\t(reformatted)'.format(file),
|
||||
n=3))
|
||||
|
||||
|
||||
class DiffError(Exception):
|
||||
def __init__(self, message, errs=None):
|
||||
super(DiffError, self).__init__(message)
|
||||
self.errs = errs or []
|
||||
|
||||
|
||||
class UnexpectedError(Exception):
|
||||
def __init__(self, message, exc=None):
|
||||
super(UnexpectedError, self).__init__(message)
|
||||
self.formatted_traceback = traceback.format_exc()
|
||||
self.exc = exc
|
||||
|
||||
|
||||
def run_clang_format_diff_wrapper(args, file):
|
||||
try:
|
||||
ret = run_clang_format_diff(args, file)
|
||||
return ret
|
||||
except DiffError:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise UnexpectedError('{}: {}: {}'.format(file, e.__class__.__name__,
|
||||
e), e)
|
||||
|
||||
|
||||
def run_clang_format_diff(args, file):
|
||||
try:
|
||||
with io.open(file, 'r', encoding='utf-8') as f:
|
||||
original = f.readlines()
|
||||
except IOError as exc:
|
||||
raise DiffError(str(exc))
|
||||
invocation = [args.clang_format_executable, file]
|
||||
|
||||
# Use of utf-8 to decode the process output.
|
||||
#
|
||||
# Hopefully, this is the correct thing to do.
|
||||
#
|
||||
# It's done due to the following assumptions (which may be incorrect):
|
||||
# - clang-format will returns the bytes read from the files as-is,
|
||||
# without conversion, and it is already assumed that the files use utf-8.
|
||||
# - if the diagnostics were internationalized, they would use utf-8:
|
||||
# > Adding Translations to Clang
|
||||
# >
|
||||
# > Not possible yet!
|
||||
# > Diagnostic strings should be written in UTF-8,
|
||||
# > the client can translate to the relevant code page if needed.
|
||||
# > Each translation completely replaces the format string
|
||||
# > for the diagnostic.
|
||||
# > -- http://clang.llvm.org/docs/InternalsManual.html#internals-diag-translation
|
||||
#
|
||||
# It's not pretty, due to Python 2 & 3 compatibility.
|
||||
encoding_py3 = {}
|
||||
if sys.version_info[0] >= 3:
|
||||
encoding_py3['encoding'] = 'utf-8'
|
||||
|
||||
try:
|
||||
proc = subprocess.Popen(
|
||||
invocation,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
**encoding_py3)
|
||||
except OSError as exc:
|
||||
raise DiffError(
|
||||
"Command '{}' failed to start: {}".format(
|
||||
subprocess.list2cmdline(invocation), exc
|
||||
)
|
||||
)
|
||||
proc_stdout = proc.stdout
|
||||
proc_stderr = proc.stderr
|
||||
if sys.version_info[0] < 3:
|
||||
# make the pipes compatible with Python 3,
|
||||
# reading lines should output unicode
|
||||
encoding = 'utf-8'
|
||||
proc_stdout = codecs.getreader(encoding)(proc_stdout)
|
||||
proc_stderr = codecs.getreader(encoding)(proc_stderr)
|
||||
# hopefully the stderr pipe won't get full and block the process
|
||||
outs = list(proc_stdout.readlines())
|
||||
errs = list(proc_stderr.readlines())
|
||||
proc.wait()
|
||||
if proc.returncode:
|
||||
raise DiffError(
|
||||
"Command '{}' returned non-zero exit status {}".format(
|
||||
subprocess.list2cmdline(invocation), proc.returncode
|
||||
),
|
||||
errs,
|
||||
)
|
||||
return make_diff(file, original, outs), errs
|
||||
|
||||
|
||||
def bold_red(s):
|
||||
return '\x1b[1m\x1b[31m' + s + '\x1b[0m'
|
||||
|
||||
|
||||
def colorize(diff_lines):
|
||||
def bold(s):
|
||||
return '\x1b[1m' + s + '\x1b[0m'
|
||||
|
||||
def cyan(s):
|
||||
return '\x1b[36m' + s + '\x1b[0m'
|
||||
|
||||
def green(s):
|
||||
return '\x1b[32m' + s + '\x1b[0m'
|
||||
|
||||
def red(s):
|
||||
return '\x1b[31m' + s + '\x1b[0m'
|
||||
|
||||
for line in diff_lines:
|
||||
if line[:4] in ['--- ', '+++ ']:
|
||||
yield bold(line)
|
||||
elif line.startswith('@@ '):
|
||||
yield cyan(line)
|
||||
elif line.startswith('+'):
|
||||
yield green(line)
|
||||
elif line.startswith('-'):
|
||||
yield red(line)
|
||||
else:
|
||||
yield line
|
||||
|
||||
|
||||
def print_diff(diff_lines, use_color):
|
||||
if use_color:
|
||||
diff_lines = colorize(diff_lines)
|
||||
if sys.version_info[0] < 3:
|
||||
sys.stdout.writelines((l.encode('utf-8') for l in diff_lines))
|
||||
else:
|
||||
sys.stdout.writelines(diff_lines)
|
||||
|
||||
|
||||
def print_trouble(prog, message, use_colors):
|
||||
error_text = 'error:'
|
||||
if use_colors:
|
||||
error_text = bold_red(error_text)
|
||||
print("{}: {} {}".format(prog, error_text, message), file=sys.stderr)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
'--clang-format-executable',
|
||||
metavar='EXECUTABLE',
|
||||
help='path to the clang-format executable',
|
||||
default='clang-format')
|
||||
parser.add_argument(
|
||||
'--extensions',
|
||||
help='comma separated list of file extensions (default: {})'.format(
|
||||
DEFAULT_EXTENSIONS),
|
||||
default=DEFAULT_EXTENSIONS)
|
||||
parser.add_argument(
|
||||
'-r',
|
||||
'--recursive',
|
||||
action='store_true',
|
||||
help='run recursively over directories')
|
||||
parser.add_argument('files', metavar='file', nargs='+')
|
||||
parser.add_argument(
|
||||
'-q',
|
||||
'--quiet',
|
||||
action='store_true')
|
||||
parser.add_argument(
|
||||
'-j',
|
||||
metavar='N',
|
||||
type=int,
|
||||
default=0,
|
||||
help='run N clang-format jobs in parallel'
|
||||
' (default number of cpus + 1)')
|
||||
parser.add_argument(
|
||||
'--color',
|
||||
default='auto',
|
||||
choices=['auto', 'always', 'never'],
|
||||
help='show colored diff (default: auto)')
|
||||
parser.add_argument(
|
||||
'-e',
|
||||
'--exclude',
|
||||
metavar='PATTERN',
|
||||
action='append',
|
||||
default=[],
|
||||
help='exclude paths matching the given glob-like pattern(s)'
|
||||
' from recursive search')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# use default signal handling, like diff return SIGINT value on ^C
|
||||
# https://bugs.python.org/issue14229#msg156446
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
try:
|
||||
signal.SIGPIPE
|
||||
except AttributeError:
|
||||
# compatibility, SIGPIPE does not exist on Windows
|
||||
pass
|
||||
else:
|
||||
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
||||
|
||||
colored_stdout = False
|
||||
colored_stderr = False
|
||||
if args.color == 'always':
|
||||
colored_stdout = True
|
||||
colored_stderr = True
|
||||
elif args.color == 'auto':
|
||||
colored_stdout = sys.stdout.isatty()
|
||||
colored_stderr = sys.stderr.isatty()
|
||||
|
||||
version_invocation = [args.clang_format_executable, str("--version")]
|
||||
try:
|
||||
subprocess.check_call(version_invocation, stdout=DEVNULL)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print_trouble(parser.prog, str(e), use_colors=colored_stderr)
|
||||
return ExitStatus.TROUBLE
|
||||
except OSError as e:
|
||||
print_trouble(
|
||||
parser.prog,
|
||||
"Command '{}' failed to start: {}".format(
|
||||
subprocess.list2cmdline(version_invocation), e
|
||||
),
|
||||
use_colors=colored_stderr,
|
||||
)
|
||||
return ExitStatus.TROUBLE
|
||||
|
||||
retcode = ExitStatus.SUCCESS
|
||||
files = list_files(
|
||||
args.files,
|
||||
recursive=args.recursive,
|
||||
exclude=args.exclude,
|
||||
extensions=args.extensions.split(','))
|
||||
|
||||
if not files:
|
||||
return
|
||||
|
||||
njobs = args.j
|
||||
if njobs == 0:
|
||||
njobs = multiprocessing.cpu_count() + 1
|
||||
njobs = min(len(files), njobs)
|
||||
|
||||
if njobs == 1:
|
||||
# execute directly instead of in a pool,
|
||||
# less overhead, simpler stacktraces
|
||||
it = (run_clang_format_diff_wrapper(args, file) for file in files)
|
||||
pool = None
|
||||
else:
|
||||
pool = multiprocessing.Pool(njobs)
|
||||
it = pool.imap_unordered(
|
||||
partial(run_clang_format_diff_wrapper, args), files)
|
||||
while True:
|
||||
try:
|
||||
outs, errs = next(it)
|
||||
except StopIteration:
|
||||
break
|
||||
except DiffError as e:
|
||||
print_trouble(parser.prog, str(e), use_colors=colored_stderr)
|
||||
retcode = ExitStatus.TROUBLE
|
||||
sys.stderr.writelines(e.errs)
|
||||
except UnexpectedError as e:
|
||||
print_trouble(parser.prog, str(e), use_colors=colored_stderr)
|
||||
sys.stderr.write(e.formatted_traceback)
|
||||
retcode = ExitStatus.TROUBLE
|
||||
# stop at the first unexpected error,
|
||||
# something could be very wrong,
|
||||
# don't process all files unnecessarily
|
||||
if pool:
|
||||
pool.terminate()
|
||||
break
|
||||
else:
|
||||
sys.stderr.writelines(errs)
|
||||
if outs == []:
|
||||
continue
|
||||
if not args.quiet:
|
||||
print_diff(outs, use_color=colored_stdout)
|
||||
if retcode == ExitStatus.SUCCESS:
|
||||
retcode = ExitStatus.DIFF
|
||||
return retcode
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
4
.travis_scripts/run-clang-format.sh
Executable file
4
.travis_scripts/run-clang-format.sh
Executable file
@@ -0,0 +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/**/
|
8
.travis_scripts/travis.before_install.linux.sh
Normal file
8
.travis_scripts/travis.before_install.linux.sh
Normal file
@@ -0,0 +1,8 @@
|
||||
set -vex
|
||||
|
||||
# Preinstalled versions of python are dependent on which Ubuntu distribution
|
||||
# you are running. The below version needs to be updated whenever we roll
|
||||
# the Ubuntu version used in Travis.
|
||||
# https://docs.travis-ci.com/user/languages/python/
|
||||
|
||||
pyenv global 3.7.1
|
1
.travis_scripts/travis.before_install.osx.sh
Normal file
1
.travis_scripts/travis.before_install.osx.sh
Normal file
@@ -0,0 +1 @@
|
||||
# NOTHING TO DO HERE
|
10
.travis_scripts/travis.install.linux.sh
Normal file
10
.travis_scripts/travis.install.linux.sh
Normal file
@@ -0,0 +1,10 @@
|
||||
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}
|
1
.travis_scripts/travis.install.osx.sh
Normal file
1
.travis_scripts/travis.install.osx.sh
Normal file
@@ -0,0 +1 @@
|
||||
# NOTHING TO DO HERE
|
4
AUTHORS
4
AUTHORS
@@ -16,12 +16,12 @@ Baruch Siach <baruch@tkos.co.il>
|
||||
Ben Boeckel <mathstuf@gmail.com>
|
||||
Benjamin Knecht <bknecht@logitech.com>
|
||||
Bernd Kuhls <bernd.kuhls@t-online.de>
|
||||
Billy Donahue <billy.donahue@gmail.com>
|
||||
Billy Donahue <billydonahue@google.com>
|
||||
Braden McDorman <bmcdorman@gmail.com>
|
||||
Brandon Myers <bmyers1788@gmail.com>
|
||||
Brendan Drew <brendan.drew@daqri.com>
|
||||
chason <cxchao802@gmail.com>
|
||||
chenguoping <chenguopingdota@163.com>
|
||||
Chen Guoping chenguopingdota@163.com
|
||||
Chris Gilling <cgilling@iparadigms.com>
|
||||
Christopher Dawes <christopher.dawes.1981@googlemail.com>
|
||||
Christopher Dunn <cdunn2001@gmail.com>
|
||||
|
37
BUILD.bazel
37
BUILD.bazel
@@ -1,37 +0,0 @@
|
||||
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"],
|
||||
)
|
146
CMakeLists.txt
146
CMakeLists.txt
@@ -6,7 +6,7 @@
|
||||
# policies that provide successful builds. By setting JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION
|
||||
# to a value greater than the oldest policies, all policies between
|
||||
# JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION and CMAKE_VERSION (used for this build)
|
||||
# are set to their NEW behavior, thereby suppressing policy warnings related to policies
|
||||
# are set to their NEW behaivor, thereby suppressing policy warnings related to policies
|
||||
# between the JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION and CMAKE_VERSION.
|
||||
#
|
||||
# CMake versions greater than the JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION policies will
|
||||
@@ -22,9 +22,6 @@ 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
|
||||
@@ -40,36 +37,63 @@ 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()
|
||||
# ---------------------------------------------------------------------------
|
||||
find_program(CCACHE_EXECUTABLE "ccache" HINTS /usr/local/bin /opt/local/bin)
|
||||
if(CCACHE_EXECUTABLE)
|
||||
message(STATUS "use ccache")
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE)
|
||||
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
|
||||
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()
|
||||
|
||||
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.7 # <major>[.<minor>[.<patch>[.<tweak>]]]
|
||||
LANGUAGES CXX)
|
||||
|
||||
message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||
set(PROJECT_SOVERSION 27)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInSourceBuilds.cmake)
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInBuildInstalls.cmake)
|
||||
# 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)
|
||||
|
||||
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)
|
||||
@@ -78,30 +102,47 @@ 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(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)
|
||||
option(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." OFF)
|
||||
option(BUILD_WITH_CXX_11 "Build jsoncpp_lib with C++11 standard." ON)
|
||||
|
||||
## To compatible with C++0x and C++1x
|
||||
set(CMAKE_MINIMUN_CXX_STANDARD 98)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_COMPILER "/usr/bin/g++")
|
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE CXX_VERSION)
|
||||
if(CXX_VERSION VERSION_GREATER 4.8.0)
|
||||
if(BUILD_WITH_CXX_11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
message(STATUS "Compiled with C++11(or newer) standard!")
|
||||
else()
|
||||
set(CMAKE_CXX_STANDARD 98)
|
||||
message(STATUS "Compiled with C++0x standard!")
|
||||
endif()
|
||||
else()
|
||||
set(CMAKE_CXX_STANDARD 98)
|
||||
message(STATUS "Compiled with C++0x standard!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_CXX_STANDARD)
|
||||
if (BUILD_WITH_CXX_11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
message(STATUS "Compiled with C++1x standard!")
|
||||
else()
|
||||
set(CMAKE_CXX_STANDARD 98)
|
||||
message(STATUS "Compiled with C++0x standard!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Adhere to GNU filesystem layout conventions
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Archive output dir.")
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Library output dir.")
|
||||
set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "PDB (MSVC debug symbol)output dir.")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Executable/dll output dir.")
|
||||
endif()
|
||||
|
||||
include(CheckFunctionExists)
|
||||
check_function_exists(memset_s HAVE_MEMSET_S)
|
||||
if(HAVE_MEMSET_S)
|
||||
add_definitions("-DHAVE_MEMSET_S=1")
|
||||
endif()
|
||||
|
||||
if(JSONCPP_USE_SECURE_MEMORY)
|
||||
add_definitions("-DJSONCPP_USE_SECURE_MEMORY=1")
|
||||
endif()
|
||||
set(JSONCPP_USE_SECURE_MEMORY "0" CACHE STRING "-D...=1 to use memory-wiping allocator for STL")
|
||||
|
||||
configure_file("${PROJECT_SOURCE_DIR}/version.in"
|
||||
"${PROJECT_BINARY_DIR}/version"
|
||||
@@ -127,36 +168,27 @@ 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($<$<CONFIG:Debug>:/W4>)
|
||||
if (JSONCPP_STATIC_WINDOWS_RUNTIME)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# using regular Clang or AppleClang
|
||||
add_compile_options(-Wall -Wconversion -Wshadow)
|
||||
|
||||
if(JSONCPP_WITH_WARNING_AS_ERROR)
|
||||
add_compile_options(-Werror=conversion -Werror=sign-compare)
|
||||
endif()
|
||||
add_compile_options(-Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare)
|
||||
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(-Wpedantic)
|
||||
add_compile_options(-Wall)
|
||||
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)
|
||||
add_compile_options(-Wall -Wconversion -Wshadow -Wextra -Werror=conversion)
|
||||
|
||||
if(JSONCPP_WITH_WARNING_AS_ERROR)
|
||||
add_compile_options(-Werror=conversion)
|
||||
elseif(JSONCPP_WITH_STRICT_ISO)
|
||||
if(JSONCPP_WITH_STRICT_ISO AND NOT JSONCPP_WITH_WARNING_AS_ERROR)
|
||||
add_compile_options(-Wpedantic)
|
||||
endif()
|
||||
endif()
|
||||
@@ -166,11 +198,6 @@ 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"
|
||||
@@ -183,16 +210,11 @@ if(JSONCPP_WITH_CMAKE_PACKAGE)
|
||||
include(CMakePackageConfigHelpers)
|
||||
install(EXPORT jsoncpp
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp
|
||||
FILE jsoncpp-targets.cmake)
|
||||
configure_package_config_file(jsoncppConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp)
|
||||
|
||||
FILE jsoncppConfig.cmake)
|
||||
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
VERSION ${JSONCPP_VERSION}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/jsoncpp-namespaced-targets.cmake
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp)
|
||||
endif()
|
||||
|
||||
|
@@ -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,7 +35,6 @@ 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
|
||||
@@ -77,7 +76,7 @@ See `doxybuild.py --help` for options.
|
||||
To add a test, you need to create two files in test/data:
|
||||
|
||||
* a `TESTNAME.json` file, that contains the input document in JSON format.
|
||||
* a `TESTNAME.expected` file, that contains a flattened representation of the
|
||||
* a `TESTNAME.expected` file, that contains a flatened representation of the
|
||||
input document.
|
||||
|
||||
The `TESTNAME.expected` file format is as follows:
|
||||
@@ -144,9 +143,7 @@ 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.
|
||||
|
||||
|
22
README.md
22
README.md
@@ -1,11 +1,5 @@
|
||||
# JsonCpp
|
||||
|
||||
[](https://bintray.com/theirix/conan-repo/jsoncpp%3Atheirix)
|
||||
[](https://github.com/open-source-parsers/jsoncpp/blob/master/LICENSE)
|
||||
[](http://open-source-parsers.github.io/jsoncpp-docs/doxygen/index.html)
|
||||
[](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.
|
||||
@@ -17,6 +11,13 @@ 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
|
||||
|
||||
@@ -30,14 +31,9 @@ format to store user input files.
|
||||
|
||||
* `1.y.z` is built with C++11.
|
||||
* `0.y.z` can be used with older compilers.
|
||||
* `00.11.z` can be used both in old and new compilers.
|
||||
* `00.11.z` can be used with older compilers , with new features from `1.y.z`
|
||||
* 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
|
||||
|
||||
@@ -48,7 +44,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.
|
||||
|
||||
|
17
SECURITY.md
17
SECURITY.md
@@ -1,17 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
If you have discovered a security vulnerability in this project, please report it
|
||||
privately. **Do not disclose it as a public issue.** This gives us time to work with you
|
||||
to fix the issue before public exposure, reducing the chance that the exploit will be
|
||||
used before a patch is released.
|
||||
|
||||
Please submit the report by filling out
|
||||
[this form](https://github.com/open-source-parsers/jsoncpp/security/advisories/new).
|
||||
|
||||
Please provide the following information in your report:
|
||||
|
||||
- A description of the vulnerability and its impact
|
||||
- How to reproduce the issue
|
||||
|
||||
This project is maintained by volunteers on a reasonable-effort basis. As such,
|
||||
we ask that you give us 90 days to work on a fix before public exposure.
|
@@ -63,7 +63,7 @@ def amalgamate_source(source_top_dir=None,
|
||||
"""
|
||||
print("Amalgamating header...")
|
||||
header = AmalgamationFile(source_top_dir)
|
||||
header.add_text("/// Json-cpp amalgamated header (https://github.com/open-source-parsers/jsoncpp/).")
|
||||
header.add_text("/// Json-cpp amalgamated header (http://jsoncpp.sourceforge.net/).")
|
||||
header.add_text('/// It is intended to be used with #include "%s"' % header_include_path)
|
||||
header.add_file("LICENSE", wrap_in_comment=True)
|
||||
header.add_text("#ifndef JSON_AMALGAMATED_H_INCLUDED")
|
||||
@@ -90,7 +90,7 @@ def amalgamate_source(source_top_dir=None,
|
||||
forward_header_include_path = base + "-forwards" + ext
|
||||
print("Amalgamating forward header...")
|
||||
header = AmalgamationFile(source_top_dir)
|
||||
header.add_text("/// Json-cpp amalgamated forward header (https://github.com/open-source-parsers/jsoncpp/).")
|
||||
header.add_text("/// Json-cpp amalgamated forward header (http://jsoncpp.sourceforge.net/).")
|
||||
header.add_text('/// It is intended to be used with #include "%s"' % forward_header_include_path)
|
||||
header.add_text("/// This header provides forward declaration for all JsonCpp types.")
|
||||
header.add_file("LICENSE", wrap_in_comment=True)
|
||||
@@ -112,7 +112,7 @@ def amalgamate_source(source_top_dir=None,
|
||||
|
||||
print("Amalgamating source...")
|
||||
source = AmalgamationFile(source_top_dir)
|
||||
source.add_text("/// Json-cpp amalgamated source (https://github.com/open-source-parsers/jsoncpp/).")
|
||||
source.add_text("/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/).")
|
||||
source.add_text('/// It is intended to be used with #include "%s"' % header_include_path)
|
||||
source.add_file("LICENSE", wrap_in_comment=True)
|
||||
source.add_text("")
|
||||
|
11
appveyor.yml
11
appveyor.yml
@@ -1,7 +1,6 @@
|
||||
clone_folder: c:\projects\jsoncpp
|
||||
|
||||
environment:
|
||||
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
CMAKE_GENERATOR: Visual Studio 14 2015
|
||||
@@ -14,15 +13,11 @@ environment:
|
||||
|
||||
build_script:
|
||||
- cmake --version
|
||||
# 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%
|
||||
- cd c:\projects\jsoncpp
|
||||
- cmake -G "%CMAKE_GENERATOR%" -DCMAKE_INSTALL_PREFIX:PATH=%CD:\=/%/install -DBUILD_SHARED_LIBS:BOOL=ON .
|
||||
# Use ctest to make a dashboard build:
|
||||
# - ctest -D Experimental(Start|Update|Configure|Build|Test|Coverage|MemCheck|Submit)
|
||||
# NOTE: Testing on windows is not yet finished:
|
||||
# NOTE: Testing on window 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
|
||||
|
@@ -1,23 +0,0 @@
|
||||
# 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()
|
@@ -1,11 +1,9 @@
|
||||
# This is only for jsoncpp developers/contributors.
|
||||
# We use this to sign releases, generate documentation, etc.
|
||||
VER?=$(shell cat version)
|
||||
VER?=$(shell cat version.txt)
|
||||
|
||||
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
|
||||
|
@@ -9,7 +9,7 @@ import shutil
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import html
|
||||
import cgi
|
||||
|
||||
class BuildDesc:
|
||||
def __init__(self, prepend_envs=None, variables=None, build_type=None, generator=None):
|
||||
@@ -195,12 +195,12 @@ def generate_html_report(html_report_path, builds):
|
||||
for variable in variables:
|
||||
build_types = sorted(build_types_by_variable[variable])
|
||||
nb_build_type = len(build_types_by_variable[variable])
|
||||
th_vars.append('<th colspan="%d">%s</th>' % (nb_build_type, html.escape(' '.join(variable))))
|
||||
th_vars.append('<th colspan="%d">%s</th>' % (nb_build_type, cgi.escape(' '.join(variable))))
|
||||
for build_type in build_types:
|
||||
th_build_types.append('<th>%s</th>' % html.escape(build_type))
|
||||
th_build_types.append('<th>%s</th>' % cgi.escape(build_type))
|
||||
tr_builds = []
|
||||
for generator in sorted(builds_by_generator):
|
||||
tds = [ '<td>%s</td>\n' % html.escape(generator) ]
|
||||
tds = [ '<td>%s</td>\n' % cgi.escape(generator) ]
|
||||
for variable in variables:
|
||||
build_types = sorted(build_types_by_variable[variable])
|
||||
for build_type in build_types:
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#include "json/json.h"
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
/** \brief Parse from stream, collect comments and capture error info.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include "json/json.h"
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
/**
|
||||
* \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 = R"({"Age": 20, "Name": "colin"})";
|
||||
const auto rawJsonLength = static_cast<int>(rawJson.length());
|
||||
constexpr bool shouldUseOldWay = false;
|
||||
const std::string rawJson = "{\"Age\": 20, \"Name\": \"colin\"}";
|
||||
const int rawJsonLength = static_cast<int>(rawJson.length());
|
||||
JSONCPP_CONST bool shouldUseOldWay = false;
|
||||
JSONCPP_STRING err;
|
||||
Json::Value root;
|
||||
|
||||
@@ -22,12 +22,13 @@ int main() {
|
||||
reader.parse(rawJson, root);
|
||||
} else {
|
||||
Json::CharReaderBuilder builder;
|
||||
const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
|
||||
Json::CharReader* reader(builder.newCharReader());
|
||||
if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLength, &root,
|
||||
&err)) {
|
||||
std::cout << "error: " << err << std::endl;
|
||||
std::cout << "error" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
delete reader;
|
||||
}
|
||||
const std::string name = root["Name"].asString();
|
||||
const int age = root["Age"].asInt();
|
||||
|
@@ -1,6 +1,5 @@
|
||||
#include "json/json.h"
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
/** \brief Write the Value object to a stream.
|
||||
* Example Usage:
|
||||
* $g++ streamWrite.cpp -ljsoncpp -std=c++11 -o streamWrite
|
||||
@@ -13,11 +12,11 @@
|
||||
int main() {
|
||||
Json::Value root;
|
||||
Json::StreamWriterBuilder builder;
|
||||
const std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
|
||||
Json::StreamWriter* writer(builder.newStreamWriter());
|
||||
|
||||
root["Name"] = "robin";
|
||||
root["Age"] = 20;
|
||||
writer->write(root, &std::cout);
|
||||
|
||||
delete writer;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#include "json/json.h"
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
/** \brief Write a Value object to a string.
|
||||
* Example Usage:
|
||||
@@ -15,7 +16,7 @@
|
||||
int main() {
|
||||
Json::Value root;
|
||||
Json::Value data;
|
||||
constexpr bool shouldUseOldWay = false;
|
||||
JSONCPP_CONST bool shouldUseOldWay = false;
|
||||
root["action"] = "run";
|
||||
data["number"] = 1;
|
||||
root["data"] = data;
|
||||
|
@@ -1,5 +0,0 @@
|
||||
while (<>) {
|
||||
if (/version : '(.+)',/) {
|
||||
print "$1";
|
||||
}
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
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()
|
@@ -1,45 +0,0 @@
|
||||
#
|
||||
# This function will prevent in-source builds
|
||||
function(AssureOutOfSourceBuilds)
|
||||
# make sure the user doesn't play dirty with symlinks
|
||||
get_filename_component(srcdir "${CMAKE_CURRENT_SOURCE_DIR}" REALPATH)
|
||||
get_filename_component(bindir "${CMAKE_CURRENT_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()
|
@@ -6,12 +6,10 @@
|
||||
#ifndef JSON_ALLOCATOR_H_INCLUDED
|
||||
#define JSON_ALLOCATOR_H_INCLUDED
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack()
|
||||
#pragma pack(push, 8)
|
||||
|
||||
namespace Json {
|
||||
template <typename T> class SecureAllocator {
|
||||
@@ -37,18 +35,11 @@ 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(pointer p, size_type n) {
|
||||
// These constructs will not be removed by the compiler during optimization,
|
||||
// unlike memset.
|
||||
#if defined(HAVE_MEMSET_S)
|
||||
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
|
||||
#elif defined(_WIN32)
|
||||
RtlSecureZeroMemory(p, n * sizeof(T));
|
||||
#else
|
||||
std::fill_n(reinterpret_cast<volatile unsigned char*>(p), n, 0);
|
||||
#endif
|
||||
|
||||
void deallocate(volatile pointer p, size_type n) {
|
||||
std::memset(p, 0, n * sizeof(T));
|
||||
// free using "global operator delete"
|
||||
::operator delete(p);
|
||||
}
|
||||
@@ -78,9 +69,7 @@ public:
|
||||
// Boilerplate
|
||||
SecureAllocator() {}
|
||||
template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
|
||||
template <typename U> struct rebind {
|
||||
using other = SecureAllocator<U>;
|
||||
};
|
||||
template <typename U> struct rebind { using other = SecureAllocator<U>; };
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
|
@@ -58,4 +58,10 @@
|
||||
} \
|
||||
} 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
|
||||
|
@@ -5,14 +5,20 @@
|
||||
|
||||
#ifndef JSON_CONFIG_H_INCLUDED
|
||||
#define JSON_CONFIG_H_INCLUDED
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#if JSONCPP_CXX_STD_11
|
||||
#include <cstddef> // typedef ptrdiff_t
|
||||
#include <cstdint> // typedef int64_t, uint64_t
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
// If non-zero, the library uses exceptions to report bad input instead of C
|
||||
// assertion macros. The default is to use exceptions.
|
||||
@@ -50,11 +56,6 @@
|
||||
#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
|
||||
@@ -70,10 +71,41 @@ 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
|
||||
|
||||
// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools.
|
||||
// C++11 should be used directly in JSONCPP.
|
||||
#define JSONCPP_OVERRIDE override
|
||||
#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
|
||||
#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)))
|
||||
@@ -98,36 +130,39 @@ 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 {
|
||||
using Int = int;
|
||||
using UInt = unsigned int;
|
||||
|
||||
typedef int Int;
|
||||
typedef unsigned int UInt;
|
||||
#if defined(JSON_NO_INT64)
|
||||
using LargestInt = int;
|
||||
using LargestUInt = unsigned int;
|
||||
typedef int LargestInt;
|
||||
typedef unsigned int LargestUInt;
|
||||
#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
|
||||
using Int64 = __int64;
|
||||
using UInt64 = unsigned __int64;
|
||||
typedef __int64 Int64;
|
||||
typedef unsigned __int64 UInt64;
|
||||
#else // if defined(_MSC_VER) // Other platforms, use long long
|
||||
using Int64 = int64_t;
|
||||
using UInt64 = uint64_t;
|
||||
typedef int64_t Int64;
|
||||
typedef uint64_t UInt64;
|
||||
#endif // if defined(_MSC_VER)
|
||||
using LargestInt = Int64;
|
||||
using LargestUInt = UInt64;
|
||||
typedef Int64 LargestInt;
|
||||
typedef UInt64 LargestUInt;
|
||||
#define JSON_HAS_INT64
|
||||
#endif // if defined(JSON_NO_INT64)
|
||||
|
||||
#if JSONCPP_CXX_STD_11
|
||||
template <typename T>
|
||||
using Allocator =
|
||||
typename std::conditional<JSONCPP_USE_SECURE_MEMORY, SecureAllocator<T>,
|
||||
typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>,
|
||||
std::allocator<T>>::type;
|
||||
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
|
||||
using IStringStream =
|
||||
@@ -138,13 +173,20 @@ 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).
|
||||
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;
|
||||
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;
|
||||
|
||||
#endif // JSON_CONFIG_H_INCLUDED
|
||||
|
@@ -29,7 +29,7 @@ class CharReaderBuilder;
|
||||
class Features;
|
||||
|
||||
// value.h
|
||||
using ArrayIndex = unsigned int;
|
||||
typedef unsigned int ArrayIndex;
|
||||
class StaticString;
|
||||
class Path;
|
||||
class PathArgument;
|
||||
|
@@ -10,8 +10,7 @@
|
||||
#include "forwards.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack()
|
||||
#pragma pack(push, 8)
|
||||
|
||||
namespace Json {
|
||||
|
||||
@@ -42,17 +41,17 @@ public:
|
||||
Features();
|
||||
|
||||
/// \c true if comments are allowed. Default: \c true.
|
||||
bool allowComments_{true};
|
||||
bool allowComments_;
|
||||
|
||||
/// \c true if root must be either an array or an object value. Default: \c
|
||||
/// false.
|
||||
bool strictRoot_{false};
|
||||
bool strictRoot_;
|
||||
|
||||
/// \c true if dropped null placeholders are allowed. Default: \c false.
|
||||
bool allowDroppedNullPlaceholders_{false};
|
||||
bool allowDroppedNullPlaceholders_;
|
||||
|
||||
/// \c true if numeric object key are allowed. Default: \c false.
|
||||
bool allowNumericKeys_{false};
|
||||
bool allowNumericKeys_;
|
||||
};
|
||||
|
||||
} // namespace Json
|
||||
|
@@ -23,8 +23,7 @@
|
||||
#pragma warning(disable : 4251)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack()
|
||||
#pragma pack(push, 8)
|
||||
|
||||
namespace Json {
|
||||
|
||||
@@ -34,10 +33,11 @@ namespace Json {
|
||||
* \deprecated Use CharReader and CharReaderBuilder.
|
||||
*/
|
||||
|
||||
class JSON_API Reader {
|
||||
class JSONCPP_DEPRECATED(
|
||||
"Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
|
||||
public:
|
||||
using Char = char;
|
||||
using Location = const Char*;
|
||||
typedef char Char;
|
||||
typedef const Char* Location;
|
||||
|
||||
/** \brief An error tagged with where in the JSON text it was encountered.
|
||||
*
|
||||
@@ -51,13 +51,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 <a HREF="http://www.json.org">JSON</a>
|
||||
@@ -187,10 +187,9 @@ private:
|
||||
Location extra_;
|
||||
};
|
||||
|
||||
using Errors = std::deque<ErrorInfo>;
|
||||
typedef std::deque<ErrorInfo> Errors;
|
||||
|
||||
bool readToken(Token& token);
|
||||
bool readTokenSkippingComments(Token& token);
|
||||
void skipSpaces();
|
||||
bool match(const Char* pattern, int patternLength);
|
||||
bool readComment();
|
||||
@@ -211,7 +210,8 @@ private:
|
||||
unsigned int& unicode);
|
||||
bool decodeUnicodeEscapeSequence(Token& token, Location& current,
|
||||
Location end, unsigned int& unicode);
|
||||
bool addError(const String& message, Token& token, Location extra = nullptr);
|
||||
bool addError(const String& message, Token& token,
|
||||
Location extra = JSONCPP_NULL);
|
||||
bool recoverFromError(TokenType skipUntilToken);
|
||||
bool addErrorAndRecover(const String& message, Token& token,
|
||||
TokenType skipUntilToken);
|
||||
@@ -222,35 +222,30 @@ private:
|
||||
int& column) const;
|
||||
String getLocationLineAndColumn(Location location) const;
|
||||
void addComment(Location begin, Location end, CommentPlacement placement);
|
||||
void skipCommentTokens(Token& token);
|
||||
|
||||
static bool containsNewLine(Location begin, Location end);
|
||||
static String normalizeEOL(Location begin, Location end);
|
||||
|
||||
using Nodes = std::stack<Value*>;
|
||||
typedef std::stack<Value*> Nodes;
|
||||
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:
|
||||
struct JSON_API StructuredError {
|
||||
ptrdiff_t offset_start;
|
||||
ptrdiff_t offset_limit;
|
||||
String message;
|
||||
};
|
||||
|
||||
virtual ~CharReader() = default;
|
||||
virtual ~CharReader() {}
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
|
||||
* document. The document must be a UTF-8 encoded string containing the
|
||||
* document to read.
|
||||
@@ -268,35 +263,16 @@ public:
|
||||
* error occurred.
|
||||
*/
|
||||
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
||||
String* errs);
|
||||
|
||||
/** \brief Returns a vector of structured errors encountered while parsing.
|
||||
* Each parse call resets the stored list of errors.
|
||||
*/
|
||||
std::vector<StructuredError> getStructuredErrors() const;
|
||||
String* errs) = 0;
|
||||
|
||||
class JSON_API Factory {
|
||||
public:
|
||||
virtual ~Factory() = default;
|
||||
virtual ~Factory() {}
|
||||
/** \brief Allocate a CharReader via operator new().
|
||||
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
||||
*/
|
||||
virtual CharReader* newCharReader() const = 0;
|
||||
}; // Factory
|
||||
|
||||
protected:
|
||||
class Impl {
|
||||
public:
|
||||
virtual ~Impl() = default;
|
||||
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
||||
String* errs) = 0;
|
||||
virtual std::vector<StructuredError> getStructuredErrors() const = 0;
|
||||
};
|
||||
|
||||
explicit CharReader(std::unique_ptr<Impl> impl) : _impl(std::move(impl)) {}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Impl> _impl;
|
||||
}; // CharReader
|
||||
|
||||
/** \brief Build a CharReader implementation.
|
||||
@@ -349,9 +325,6 @@ 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.
|
||||
@@ -360,9 +333,9 @@ public:
|
||||
Json::Value settings_;
|
||||
|
||||
CharReaderBuilder();
|
||||
~CharReaderBuilder() override;
|
||||
~CharReaderBuilder() JSONCPP_OVERRIDE;
|
||||
|
||||
CharReader* newCharReader() const override;
|
||||
CharReader* newCharReader() const JSONCPP_OVERRIDE;
|
||||
|
||||
/** \return true if 'settings' are legal and consistent;
|
||||
* otherwise, indicate bad settings via 'invalid'.
|
||||
@@ -385,12 +358,6 @@ public:
|
||||
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
|
||||
*/
|
||||
static void strictMode(Json::Value* settings);
|
||||
/** ECMA-404 mode.
|
||||
* \pre 'settings' != NULL (but Json::null is fine)
|
||||
* \remark Defaults:
|
||||
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderECMA404Mode
|
||||
*/
|
||||
static void ecma404Mode(Json::Value* settings);
|
||||
};
|
||||
|
||||
/** Consume entire stream and use its begin/end.
|
||||
|
@@ -3,8 +3,8 @@
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_VALUE_H_INCLUDED
|
||||
#define JSON_VALUE_H_INCLUDED
|
||||
#ifndef JSON_H_INCLUDED
|
||||
#define JSON_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
#include "forwards.h"
|
||||
@@ -13,13 +13,16 @@
|
||||
// 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) && _MSC_VER == 1800
|
||||
#if defined(_MSC_VER)
|
||||
#define JSONCPP_NORETURN __declspec(noreturn)
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define JSONCPP_NORETURN __attribute__((noreturn))
|
||||
#else
|
||||
#define JSONCPP_NORETURN [[noreturn]]
|
||||
#endif
|
||||
#define JSONCPP_NORETURN
|
||||
#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
|
||||
@@ -39,10 +42,15 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#if JSONCPP_CXX_STD_11
|
||||
#else
|
||||
#undef JSONCPP_TEMPLATE_DELETE
|
||||
#define JSONCPP_TEMPLATE_DELETE
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -50,11 +58,10 @@
|
||||
// be used by...
|
||||
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4251 4275)
|
||||
#pragma warning(disable : 4251)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack()
|
||||
#pragma pack(push, 8)
|
||||
|
||||
/** \brief JSON (JavaScript Object Notation).
|
||||
*/
|
||||
@@ -68,8 +75,8 @@ namespace Json {
|
||||
class JSON_API Exception : public std::exception {
|
||||
public:
|
||||
Exception(String msg);
|
||||
~Exception() noexcept override;
|
||||
char const* what() const noexcept override;
|
||||
~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE;
|
||||
char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE;
|
||||
|
||||
protected:
|
||||
String msg_;
|
||||
@@ -147,7 +154,7 @@ enum PrecisionType {
|
||||
*/
|
||||
class JSON_API StaticString {
|
||||
public:
|
||||
explicit StaticString(const char* czstring) : c_str_(czstring) {}
|
||||
JSONCPP_OP_EXPLICIT StaticString(const char* czstring) : c_str_(czstring) {}
|
||||
|
||||
operator const char*() const { return c_str_; }
|
||||
|
||||
@@ -195,21 +202,21 @@ class JSON_API Value {
|
||||
friend class ValueIteratorBase;
|
||||
|
||||
public:
|
||||
using Members = std::vector<String>;
|
||||
using iterator = ValueIterator;
|
||||
using const_iterator = ValueConstIterator;
|
||||
using UInt = Json::UInt;
|
||||
using Int = Json::Int;
|
||||
typedef std::vector<String> Members;
|
||||
typedef ValueIterator iterator;
|
||||
typedef ValueConstIterator const_iterator;
|
||||
typedef Json::UInt UInt;
|
||||
typedef Json::Int Int;
|
||||
#if defined(JSON_HAS_INT64)
|
||||
using UInt64 = Json::UInt64;
|
||||
using Int64 = Json::Int64;
|
||||
typedef Json::UInt64 UInt64;
|
||||
typedef Json::Int64 Int64;
|
||||
#endif // defined(JSON_HAS_INT64)
|
||||
using LargestInt = Json::LargestInt;
|
||||
using LargestUInt = Json::LargestUInt;
|
||||
using ArrayIndex = Json::ArrayIndex;
|
||||
typedef Json::LargestInt LargestInt;
|
||||
typedef Json::LargestUInt LargestUInt;
|
||||
typedef Json::ArrayIndex ArrayIndex;
|
||||
|
||||
// Required for boost integration, e. g. BOOST_TEST
|
||||
using value_type = std::string;
|
||||
typedef std::string value_type;
|
||||
|
||||
#if JSON_USE_NULLREF
|
||||
// Binary compatibility kludges, do not use.
|
||||
@@ -221,34 +228,35 @@ public:
|
||||
static Value const& nullSingleton();
|
||||
|
||||
/// Minimum signed integer value that can be stored in a Json::Value.
|
||||
static constexpr LargestInt minLargestInt =
|
||||
static JSONCPP_CONST LargestInt minLargestInt =
|
||||
LargestInt(~(LargestUInt(-1) / 2));
|
||||
/// Maximum signed integer value that can be stored in a Json::Value.
|
||||
static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2);
|
||||
static JSONCPP_CONST LargestInt maxLargestInt =
|
||||
LargestInt(LargestUInt(-1) / 2);
|
||||
/// Maximum unsigned integer value that can be stored in a Json::Value.
|
||||
static constexpr LargestUInt maxLargestUInt = LargestUInt(-1);
|
||||
static JSONCPP_CONST LargestUInt maxLargestUInt = LargestUInt(-1);
|
||||
|
||||
/// Minimum signed int value that can be stored in a Json::Value.
|
||||
static constexpr Int minInt = Int(~(UInt(-1) / 2));
|
||||
static JSONCPP_CONST Int minInt = Int(~(UInt(-1) / 2));
|
||||
/// Maximum signed int value that can be stored in a Json::Value.
|
||||
static constexpr Int maxInt = Int(UInt(-1) / 2);
|
||||
static JSONCPP_CONST Int maxInt = Int(UInt(-1) / 2);
|
||||
/// Maximum unsigned int value that can be stored in a Json::Value.
|
||||
static constexpr UInt maxUInt = UInt(-1);
|
||||
static JSONCPP_CONST UInt maxUInt = UInt(-1);
|
||||
|
||||
#if defined(JSON_HAS_INT64)
|
||||
/// Minimum signed 64 bits int value that can be stored in a Json::Value.
|
||||
static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2));
|
||||
static JSONCPP_CONST Int64 minInt64 = Int64(~(UInt64(-1) / 2));
|
||||
/// Maximum signed 64 bits int value that can be stored in a Json::Value.
|
||||
static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2);
|
||||
static JSONCPP_CONST Int64 maxInt64 = Int64(UInt64(-1) / 2);
|
||||
/// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
|
||||
static constexpr UInt64 maxUInt64 = UInt64(-1);
|
||||
static JSONCPP_CONST UInt64 maxUInt64 = UInt64(-1);
|
||||
#endif // defined(JSON_HAS_INT64)
|
||||
/// Default precision for real value for string representation.
|
||||
static constexpr UInt defaultRealPrecision = 17;
|
||||
static JSONCPP_CONST 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 constexpr double maxUInt64AsDouble = 18446744073709551615.0;
|
||||
static JSONCPP_CONST 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
|
||||
@@ -264,11 +272,14 @@ private:
|
||||
CZString(ArrayIndex index);
|
||||
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
|
||||
CZString(CZString const& other);
|
||||
CZString(CZString&& other) noexcept;
|
||||
#if JSONCPP_CXX_STD_11
|
||||
CZString(CZString&& other);
|
||||
#endif
|
||||
~CZString();
|
||||
CZString& operator=(const CZString& other);
|
||||
CZString& operator=(CZString&& other) noexcept;
|
||||
|
||||
#if JSONCPP_CXX_STD_11
|
||||
CZString& operator=(CZString&& other);
|
||||
#endif
|
||||
bool operator<(CZString const& other) const;
|
||||
bool operator==(CZString const& other) const;
|
||||
ArrayIndex index() const;
|
||||
@@ -343,15 +354,18 @@ public:
|
||||
Value(const StaticString& value);
|
||||
Value(const String& value);
|
||||
Value(bool value);
|
||||
Value(std::nullptr_t ptr) = delete;
|
||||
Value(const Value& other);
|
||||
Value(Value&& other) noexcept;
|
||||
#if JSONCPP_CXX_STD_11
|
||||
Value(Value&& other);
|
||||
#endif
|
||||
~Value();
|
||||
|
||||
/// \note Overwrite existing comments. To preserve comments, use
|
||||
/// #swapPayload().
|
||||
Value& operator=(const Value& other);
|
||||
Value& operator=(Value&& other) noexcept;
|
||||
#if JSONCPP_CXX_STD_11
|
||||
Value& operator=(Value&& other);
|
||||
#endif
|
||||
|
||||
/// Swap everything.
|
||||
void swap(Value& other);
|
||||
@@ -375,7 +389,7 @@ public:
|
||||
int compare(const Value& other) const;
|
||||
|
||||
const char* asCString() const; ///< Embedded zeroes could cause you trouble!
|
||||
#if JSONCPP_USE_SECURE_MEMORY
|
||||
#if JSONCPP_USING_SECURE_MEMORY
|
||||
unsigned getCStringLength() const; // Allows you to understand the length of
|
||||
// the CString
|
||||
#endif
|
||||
@@ -423,7 +437,7 @@ public:
|
||||
bool empty() const;
|
||||
|
||||
/// Return !isNull()
|
||||
explicit operator bool() const;
|
||||
JSONCPP_OP_EXPLICIT operator bool() const;
|
||||
|
||||
/// Remove all object members and array elements.
|
||||
/// \pre type() is arrayValue, objectValue, or nullValue
|
||||
@@ -437,7 +451,7 @@ public:
|
||||
/// \post type() is arrayValue
|
||||
void resize(ArrayIndex newSize);
|
||||
|
||||
///@{
|
||||
//@{
|
||||
/// Access an array element (zero based index). If the array contains less
|
||||
/// than index element, then null value are inserted in the array so that
|
||||
/// its size is index+1.
|
||||
@@ -445,15 +459,15 @@ public:
|
||||
/// this from the operator[] which takes a string.)
|
||||
Value& operator[](ArrayIndex index);
|
||||
Value& operator[](int index);
|
||||
///@}
|
||||
//@}
|
||||
|
||||
///@{
|
||||
//@{
|
||||
/// Access an array element (zero based index).
|
||||
/// (You may need to say 'value[0u]' to get your compiler to distinguish
|
||||
/// this from the operator[] which takes a string.)
|
||||
const Value& operator[](ArrayIndex index) const;
|
||||
const Value& operator[](int index) const;
|
||||
///@}
|
||||
//@}
|
||||
|
||||
/// If the array contains at least index+1 elements, returns the element
|
||||
/// value, otherwise returns defaultValue.
|
||||
@@ -464,11 +478,15 @@ 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.
|
||||
@@ -513,9 +531,6 @@ public:
|
||||
/// and operator[]const
|
||||
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
|
||||
Value const* find(char const* begin, char const* end) const;
|
||||
/// Most general and efficient version of isMember()const, get()const,
|
||||
/// and operator[]const
|
||||
Value const* find(const String& key) const;
|
||||
/// Most general and efficient version of object-mutators.
|
||||
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
|
||||
/// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
|
||||
@@ -567,15 +582,11 @@ public:
|
||||
|
||||
/// \deprecated Always pass len.
|
||||
JSONCPP_DEPRECATED("Use setComment(String const&) instead.")
|
||||
void setComment(const char* comment, CommentPlacement placement) {
|
||||
setComment(String(comment, strlen(comment)), placement);
|
||||
}
|
||||
void setComment(const char* comment, CommentPlacement placement);
|
||||
/// Comments must be //... or /* ... */
|
||||
void setComment(const char* comment, size_t len, CommentPlacement placement) {
|
||||
setComment(String(comment, len), placement);
|
||||
}
|
||||
void setComment(const char* comment, size_t len, CommentPlacement placement);
|
||||
/// Comments must be //... or /* ... */
|
||||
void setComment(String comment, CommentPlacement placement);
|
||||
void setComment(const String& comment, CommentPlacement placement);
|
||||
bool hasComment(CommentPlacement placement) const;
|
||||
/// Include delimiters and embedded newlines.
|
||||
String getComment(CommentPlacement placement) const;
|
||||
@@ -588,26 +599,6 @@ public:
|
||||
iterator begin();
|
||||
iterator end();
|
||||
|
||||
/// \brief Returns a reference to the first element in the `Value`.
|
||||
/// Requires that this value holds an array or json object, with at least one
|
||||
/// element.
|
||||
const Value& front() const;
|
||||
|
||||
/// \brief Returns a reference to the first element in the `Value`.
|
||||
/// Requires that this value holds an array or json object, with at least one
|
||||
/// element.
|
||||
Value& front();
|
||||
|
||||
/// \brief Returns a reference to the last element in the `Value`.
|
||||
/// Requires that value holds an array or json object, with at least one
|
||||
/// element.
|
||||
const Value& back() const;
|
||||
|
||||
/// \brief Returns a reference to the last element in the `Value`.
|
||||
/// Requires that this value holds an array or json object, with at least one
|
||||
/// element.
|
||||
Value& back();
|
||||
|
||||
// Accessors for the [start, limit) range of bytes within the JSON text from
|
||||
// which this value was parsed, if any.
|
||||
void setOffsetStart(ptrdiff_t start);
|
||||
@@ -657,18 +648,15 @@ private:
|
||||
|
||||
class Comments {
|
||||
public:
|
||||
Comments() = default;
|
||||
Comments() {}
|
||||
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 comment);
|
||||
void set(CommentPlacement slot, String s);
|
||||
|
||||
private:
|
||||
using Array = std::array<String, numberOfCommentPlacement>;
|
||||
std::unique_ptr<Array> ptr_;
|
||||
String ptr_[numberOfCommentPlacement];
|
||||
};
|
||||
Comments comments_;
|
||||
|
||||
@@ -723,8 +711,8 @@ public:
|
||||
private:
|
||||
enum Kind { kindNone = 0, kindIndex, kindKey };
|
||||
String key_;
|
||||
ArrayIndex index_{};
|
||||
Kind kind_{kindNone};
|
||||
ArrayIndex index_;
|
||||
Kind kind_;
|
||||
};
|
||||
|
||||
/** \brief Experimental and untested: represents a "path" to access a node.
|
||||
@@ -753,8 +741,8 @@ public:
|
||||
Value& make(Value& root) const;
|
||||
|
||||
private:
|
||||
using InArgs = std::vector<const PathArgument*>;
|
||||
using Args = std::vector<PathArgument>;
|
||||
typedef std::vector<const PathArgument*> InArgs;
|
||||
typedef std::vector<PathArgument> Args;
|
||||
|
||||
void makePath(const String& path, const InArgs& in);
|
||||
void addPathInArg(const String& path, const InArgs& in,
|
||||
@@ -769,10 +757,10 @@ private:
|
||||
*/
|
||||
class JSON_API ValueIteratorBase {
|
||||
public:
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using size_t = unsigned int;
|
||||
using difference_type = int;
|
||||
using SelfType = ValueIteratorBase;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
typedef unsigned int size_t;
|
||||
typedef int difference_type;
|
||||
typedef ValueIteratorBase SelfType;
|
||||
|
||||
bool operator==(const SelfType& other) const { return isEqual(other); }
|
||||
|
||||
@@ -829,13 +817,14 @@ protected:
|
||||
private:
|
||||
Value::ObjectValues::iterator current_;
|
||||
// Indicates that iterator is for a null value.
|
||||
bool isNull_{true};
|
||||
bool isNull_;
|
||||
|
||||
public:
|
||||
// For some reason, BORLAND needs these at the end, rather
|
||||
// than earlier. No idea why.
|
||||
ValueIteratorBase();
|
||||
explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
|
||||
JSONCPP_OP_EXPLICIT
|
||||
ValueIteratorBase(const Value::ObjectValues::iterator& current);
|
||||
};
|
||||
|
||||
/** \brief const iterator for object and array value.
|
||||
@@ -845,12 +834,12 @@ class JSON_API ValueConstIterator : public ValueIteratorBase {
|
||||
friend class Value;
|
||||
|
||||
public:
|
||||
using value_type = const Value;
|
||||
typedef const Value value_type;
|
||||
// typedef unsigned int size_t;
|
||||
// typedef int difference_type;
|
||||
using reference = const Value&;
|
||||
using pointer = const Value*;
|
||||
using SelfType = ValueConstIterator;
|
||||
typedef const Value& reference;
|
||||
typedef const Value* pointer;
|
||||
typedef ValueConstIterator SelfType;
|
||||
|
||||
ValueConstIterator();
|
||||
ValueConstIterator(ValueIterator const& other);
|
||||
@@ -858,7 +847,8 @@ public:
|
||||
private:
|
||||
/*! \internal Use by Value to create an iterator.
|
||||
*/
|
||||
explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
|
||||
JSONCPP_OP_EXPLICIT
|
||||
ValueConstIterator(const Value::ObjectValues::iterator& current);
|
||||
|
||||
public:
|
||||
SelfType& operator=(const ValueIteratorBase& other);
|
||||
@@ -896,21 +886,22 @@ class JSON_API ValueIterator : public ValueIteratorBase {
|
||||
friend class Value;
|
||||
|
||||
public:
|
||||
using value_type = Value;
|
||||
using size_t = unsigned int;
|
||||
using difference_type = int;
|
||||
using reference = Value&;
|
||||
using pointer = Value*;
|
||||
using SelfType = ValueIterator;
|
||||
typedef Value value_type;
|
||||
typedef unsigned int size_t;
|
||||
typedef int difference_type;
|
||||
typedef Value& reference;
|
||||
typedef Value* pointer;
|
||||
typedef ValueIterator SelfType;
|
||||
|
||||
ValueIterator();
|
||||
explicit ValueIterator(const ValueConstIterator& other);
|
||||
JSONCPP_OP_EXPLICIT ValueIterator(const ValueConstIterator& other);
|
||||
ValueIterator(const ValueIterator& other);
|
||||
|
||||
private:
|
||||
/*! \internal Use by Value to create an iterator.
|
||||
*/
|
||||
explicit ValueIterator(const Value::ObjectValues::iterator& current);
|
||||
JSONCPP_OP_EXPLICIT
|
||||
ValueIterator(const Value::ObjectValues::iterator& current);
|
||||
|
||||
public:
|
||||
SelfType& operator=(const SelfType& other);
|
||||
@@ -942,20 +933,12 @@ public:
|
||||
* because the returned references/pointers can be used
|
||||
* to change state of the base class.
|
||||
*/
|
||||
reference operator*() const { return const_cast<reference>(deref()); }
|
||||
pointer operator->() const { return const_cast<pointer>(&deref()); }
|
||||
reference operator*() { return deref(); }
|
||||
pointer operator->() { return &deref(); }
|
||||
};
|
||||
|
||||
inline void swap(Value& a, Value& b) { a.swap(b); }
|
||||
|
||||
inline const Value& Value::front() const { return *begin(); }
|
||||
|
||||
inline Value& Value::front() { return *begin(); }
|
||||
|
||||
inline const Value& Value::back() const { return *(--end()); }
|
||||
|
||||
inline Value& Value::back() { return *(--end()); }
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#pragma pack(pop)
|
||||
|
@@ -9,18 +9,19 @@
|
||||
// 3. /CMakeLists.txt
|
||||
// IMPORTANT: also update the SOVERSION!!
|
||||
|
||||
#define JSONCPP_VERSION_STRING "1.9.7"
|
||||
#define JSONCPP_VERSION_MAJOR 1
|
||||
#define JSONCPP_VERSION_MINOR 9
|
||||
#define JSONCPP_VERSION_PATCH 7
|
||||
#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_QUALIFIER
|
||||
#define JSONCPP_VERSION_HEXA \
|
||||
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
|
||||
(JSONCPP_VERSION_PATCH << 8))
|
||||
|
||||
#if !defined(JSONCPP_USE_SECURE_MEMORY)
|
||||
#define JSONCPP_USE_SECURE_MEMORY 0
|
||||
#ifdef JSONCPP_USING_SECURE_MEMORY
|
||||
#undef JSONCPP_USING_SECURE_MEMORY
|
||||
#endif
|
||||
#define JSONCPP_USING_SECURE_MEMORY 0
|
||||
// If non-zero, the library zeroes any memory that it has allocated before
|
||||
// it frees its memory.
|
||||
|
||||
|
@@ -20,8 +20,7 @@
|
||||
#pragma warning(disable : 4251)
|
||||
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack()
|
||||
#pragma pack(push, 8)
|
||||
|
||||
namespace Json {
|
||||
|
||||
@@ -111,8 +110,6 @@ 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
|
||||
@@ -122,12 +119,12 @@ public:
|
||||
Json::Value settings_;
|
||||
|
||||
StreamWriterBuilder();
|
||||
~StreamWriterBuilder() override;
|
||||
~StreamWriterBuilder() JSONCPP_OVERRIDE;
|
||||
|
||||
/**
|
||||
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
||||
*/
|
||||
StreamWriter* newStreamWriter() const override;
|
||||
StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE;
|
||||
|
||||
/** \return true if 'settings' are legal and consistent;
|
||||
* otherwise, indicate bad settings via 'invalid'.
|
||||
@@ -148,7 +145,7 @@ public:
|
||||
/** \brief Abstract class for writers.
|
||||
* \deprecated Use StreamWriter. (And really, this is an implementation detail.)
|
||||
*/
|
||||
class JSON_API Writer {
|
||||
class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer {
|
||||
public:
|
||||
virtual ~Writer();
|
||||
|
||||
@@ -168,10 +165,11 @@ public:
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSON_API FastWriter : public Writer {
|
||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter
|
||||
: public Writer {
|
||||
public:
|
||||
FastWriter();
|
||||
~FastWriter() override = default;
|
||||
~FastWriter() JSONCPP_OVERRIDE {}
|
||||
|
||||
void enableYAMLCompatibility();
|
||||
|
||||
@@ -185,15 +183,15 @@ public:
|
||||
void omitEndingLineFeed();
|
||||
|
||||
public: // overridden from Writer
|
||||
String write(const Value& root) override;
|
||||
String write(const Value& root) JSONCPP_OVERRIDE;
|
||||
|
||||
private:
|
||||
void writeValue(const Value& value);
|
||||
|
||||
String document_;
|
||||
bool yamlCompatibilityEnabled_{false};
|
||||
bool dropNullPlaceholders_{false};
|
||||
bool omitEndingLineFeed_{false};
|
||||
bool yamlCompatibilityEnabled_;
|
||||
bool dropNullPlaceholders_;
|
||||
bool omitEndingLineFeed_;
|
||||
};
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
@@ -217,7 +215,7 @@ private:
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputted according to their
|
||||
* If the Value have comments then they are outputed according to their
|
||||
*#CommentPlacement.
|
||||
*
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
@@ -227,17 +225,18 @@ private:
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSON_API StyledWriter : public Writer {
|
||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
|
||||
StyledWriter : public Writer {
|
||||
public:
|
||||
StyledWriter();
|
||||
~StyledWriter() override = default;
|
||||
~StyledWriter() JSONCPP_OVERRIDE {}
|
||||
|
||||
public: // overridden from Writer
|
||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||
* \param root Value to serialize.
|
||||
* \return String containing the JSON document that represents the root value.
|
||||
*/
|
||||
String write(const Value& root) override;
|
||||
String write(const Value& root) JSONCPP_OVERRIDE;
|
||||
|
||||
private:
|
||||
void writeValue(const Value& value);
|
||||
@@ -253,14 +252,14 @@ private:
|
||||
static bool hasCommentForValue(const Value& value);
|
||||
static String normalizeEOL(const String& text);
|
||||
|
||||
using ChildValues = std::vector<String>;
|
||||
typedef std::vector<String> ChildValues;
|
||||
|
||||
ChildValues childValues_;
|
||||
String document_;
|
||||
String indentString_;
|
||||
unsigned int rightMargin_{74};
|
||||
unsigned int indentSize_{3};
|
||||
bool addChildValues_{false};
|
||||
unsigned int rightMargin_;
|
||||
unsigned int indentSize_;
|
||||
bool addChildValues_;
|
||||
};
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
@@ -285,7 +284,7 @@ private:
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputted according to their
|
||||
* If the Value have comments then they are outputed according to their
|
||||
#CommentPlacement.
|
||||
*
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
@@ -295,13 +294,14 @@ private:
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // Deriving from deprecated class
|
||||
#endif
|
||||
class JSON_API StyledStreamWriter {
|
||||
class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
|
||||
StyledStreamWriter {
|
||||
public:
|
||||
/**
|
||||
* \param indentation Each level will be indented by this amount extra.
|
||||
*/
|
||||
StyledStreamWriter(String indentation = "\t");
|
||||
~StyledStreamWriter() = default;
|
||||
~StyledStreamWriter() {}
|
||||
|
||||
public:
|
||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||
@@ -326,12 +326,12 @@ private:
|
||||
static bool hasCommentForValue(const Value& value);
|
||||
static String normalizeEOL(const String& text);
|
||||
|
||||
using ChildValues = std::vector<String>;
|
||||
typedef std::vector<String> ChildValues;
|
||||
|
||||
ChildValues childValues_;
|
||||
OStream* document_;
|
||||
String indentString_;
|
||||
unsigned int rightMargin_{74};
|
||||
unsigned int rightMargin_;
|
||||
String indentation_;
|
||||
bool addChildValues_ : 1;
|
||||
bool indented_ : 1;
|
||||
@@ -348,10 +348,9 @@ 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 = PrecisionType::significantDigits);
|
||||
PrecisionType precisionType = significantDigits);
|
||||
String JSON_API valueToString(bool value);
|
||||
String JSON_API valueToQuotedString(const char* value);
|
||||
String JSON_API valueToQuotedString(const char* value, size_t length);
|
||||
|
||||
/// \brief Output using the StyledStreamWriter.
|
||||
/// \see Json::operator>>()
|
||||
|
@@ -1,9 +0,0 @@
|
||||
if (NOT TARGET JsonCpp::JsonCpp)
|
||||
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 ()
|
||||
endif ()
|
@@ -1,11 +0,0 @@
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(VERSION 3.0...3.26)
|
||||
|
||||
@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)
|
@@ -1,6 +0,0 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
@MESON_SHARED_TARGET@
|
||||
@MESON_STATIC_TARGET@
|
||||
|
||||
include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-namespaced-targets.cmake" )
|
45
meson.build
45
meson.build
@@ -9,13 +9,13 @@ project(
|
||||
# 2. /include/json/version.h
|
||||
# 3. /CMakeLists.txt
|
||||
# IMPORTANT: also update the SOVERSION!!
|
||||
version : '1.9.7',
|
||||
version : '00.11.0',
|
||||
default_options : [
|
||||
'buildtype=release',
|
||||
'cpp_std=c++11',
|
||||
'warning_level=1'],
|
||||
license : 'Public Domain',
|
||||
meson_version : '>= 0.54.0')
|
||||
meson_version : '>= 0.49.0')
|
||||
|
||||
|
||||
jsoncpp_headers = files([
|
||||
@@ -50,7 +50,7 @@ jsoncpp_lib = library(
|
||||
'src/lib_json/json_value.cpp',
|
||||
'src/lib_json/json_writer.cpp',
|
||||
]),
|
||||
soversion : 27,
|
||||
soversion : 23,
|
||||
install : true,
|
||||
include_directories : jsoncpp_include_directories,
|
||||
cpp_args: dll_export_flag)
|
||||
@@ -62,43 +62,6 @@ import('pkgconfig').generate(
|
||||
filebase : 'jsoncpp',
|
||||
description : 'A C++ library for interacting with JSON')
|
||||
|
||||
cmakeconf = configuration_data()
|
||||
cmakeconf.set('MESON_LIB_DIR', get_option('libdir'))
|
||||
cmakeconf.set('MESON_INCLUDE_DIR', get_option('includedir'))
|
||||
|
||||
fs = import('fs')
|
||||
if get_option('default_library') == 'shared'
|
||||
shared_name = fs.name(jsoncpp_lib.full_path())
|
||||
endif
|
||||
if get_option('default_library') == 'static'
|
||||
static_name = fs.name(jsoncpp_lib.full_path())
|
||||
endif
|
||||
if get_option('default_library') == 'both'
|
||||
shared_name = fs.name(jsoncpp_lib.get_shared_lib().full_path())
|
||||
static_name = fs.name(jsoncpp_lib.get_static_lib().full_path())
|
||||
endif
|
||||
|
||||
if get_option('default_library') == 'shared' or get_option('default_library') == 'both'
|
||||
cmakeconf.set('MESON_SHARED_TARGET', '''
|
||||
add_library(jsoncpp_lib IMPORTED SHARED)
|
||||
set_target_properties(jsoncpp_lib PROPERTIES
|
||||
IMPORTED_LOCATION "''' + join_paths('${PACKAGE_PREFIX_DIR}', get_option('libdir'), shared_name) + '''"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "''' + join_paths('${PACKAGE_PREFIX_DIR}', get_option('includedir')) + '")')
|
||||
endif
|
||||
if get_option('default_library') == 'static' or get_option('default_library') == 'both'
|
||||
cmakeconf.set('MESON_STATIC_TARGET', '''
|
||||
add_library(jsoncpp_static IMPORTED STATIC)
|
||||
set_target_properties(jsoncpp_static PROPERTIES
|
||||
IMPORTED_LOCATION "''' + join_paths('${PACKAGE_PREFIX_DIR}', get_option('libdir'), static_name) + '''"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "''' + join_paths('${PACKAGE_PREFIX_DIR}', get_option('includedir')) + '")')
|
||||
endif
|
||||
|
||||
import('cmake').configure_package_config_file(
|
||||
name: 'jsoncpp',
|
||||
input: 'jsoncppConfig.cmake.meson.in',
|
||||
configuration: cmakeconf)
|
||||
install_data('jsoncpp-namespaced-targets.cmake', install_dir : join_paths(get_option('libdir'), 'cmake', jsoncpp_lib.name()))
|
||||
|
||||
# for libraries bundling jsoncpp
|
||||
jsoncpp_dep = declare_dependency(
|
||||
include_directories : jsoncpp_include_directories,
|
||||
@@ -110,7 +73,7 @@ if meson.is_subproject() or not get_option('tests')
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
python = find_program('python3')
|
||||
python = import('python').find_installation('python3')
|
||||
|
||||
jsoncpp_test = executable(
|
||||
'jsoncpp_test', files([
|
||||
|
@@ -1,11 +1,11 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=@CMAKE_INSTALL_PREFIX@
|
||||
libdir=@libdir_for_pc_file@
|
||||
includedir=@includedir_for_pc_file@
|
||||
libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||
|
||||
Name: jsoncpp
|
||||
Description: A C++ library for interacting with JSON
|
||||
Version: @PROJECT_VERSION@
|
||||
Version: @JSONCPP_VERSION@
|
||||
URL: https://github.com/open-source-parsers/jsoncpp
|
||||
Libs: -L${libdir} -ljsoncpp
|
||||
Cflags: -I${includedir}
|
||||
|
@@ -1 +0,0 @@
|
||||
find src -name '*.cpp' -or -name '*.h' | xargs clang-format -i
|
@@ -19,10 +19,8 @@ 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)
|
||||
|
||||
|
@@ -24,7 +24,9 @@ struct Options {
|
||||
Json::String path;
|
||||
Json::Features features;
|
||||
bool parseOnly;
|
||||
using writeFuncType = Json::String (*)(Json::Value const&);
|
||||
|
||||
typedef Json::String (*writeFuncType)(Json::Value const&);
|
||||
|
||||
writeFuncType write;
|
||||
};
|
||||
|
||||
@@ -57,11 +59,11 @@ static Json::String readInputTestFile(const char* path) {
|
||||
if (!file)
|
||||
return "";
|
||||
fseek(file, 0, SEEK_END);
|
||||
auto const size = ftell(file);
|
||||
auto const usize = static_cast<size_t>(size);
|
||||
long const size = ftell(file);
|
||||
size_t const usize = static_cast<size_t>(size);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
auto buffer = new char[size + 1];
|
||||
buffer[size] = 0;
|
||||
char* buffer = new char[usize + 1];
|
||||
buffer[usize] = 0;
|
||||
Json::String text;
|
||||
if (fread(buffer, 1, usize, file) == usize)
|
||||
text = buffer;
|
||||
@@ -111,7 +113,9 @@ 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 (const auto& name : members) {
|
||||
for (Json::Value::Members::const_iterator it = members.begin();
|
||||
it != members.end(); it++) {
|
||||
const Json::String& name = *it;
|
||||
printValueTree(fout, value[name], path + suffix + name);
|
||||
}
|
||||
} break;
|
||||
@@ -138,7 +142,7 @@ static int parseAndSaveValueTree(const Json::String& input,
|
||||
features.allowDroppedNullPlaceholders_;
|
||||
builder.settings_["allowNumericKeys"] = features.allowNumericKeys_;
|
||||
|
||||
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
|
||||
Json::CharReader* reader(builder.newCharReader());
|
||||
Json::String errors;
|
||||
const bool parsingSuccessful =
|
||||
reader->parse(input.data(), input.data() + input.size(), root, &errors);
|
||||
@@ -148,7 +152,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 {
|
||||
@@ -240,12 +244,9 @@ static int parseCommandLine(int argc, const char* argv[], Options* opts) {
|
||||
return printUsage(argv);
|
||||
}
|
||||
int index = 1;
|
||||
if (Json::String(argv[index]) == "--parse-only") {
|
||||
opts->parseOnly = true;
|
||||
++index;
|
||||
}
|
||||
if (Json::String(argv[index]) == "--strict") {
|
||||
if (Json::String(argv[index]) == "--json-checker") {
|
||||
opts->features = Json::Features::strictMode();
|
||||
opts->parseOnly = true;
|
||||
++index;
|
||||
}
|
||||
if (Json::String(argv[index]) == "--json-config") {
|
||||
@@ -338,7 +339,6 @@ int main(int argc, const char* argv[]) {
|
||||
std::cerr << "Unhandled exception:" << std::endl << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
|
@@ -11,10 +11,20 @@ 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()
|
||||
|
||||
if(NOT (HAVE_CLOCALE AND HAVE_LCONV_SIZE AND HAVE_DECIMAL_POINT AND HAVE_LOCALECONV))
|
||||
message(WARNING "Locale functionality is not supported")
|
||||
@@ -40,7 +50,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
|
||||
@@ -55,10 +65,33 @@ 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
|
||||
list(APPEND REQUIRED_FEATURES
|
||||
if(CMAKE_CXX_STANDARD EQUAL "11")
|
||||
target_compile_features(jsoncpp_lib PUBLIC
|
||||
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.
|
||||
@@ -104,102 +137,21 @@ list(APPEND REQUIRED_FEATURES
|
||||
cxx_variadic_macros # Variadic macros, as defined in N1653.
|
||||
cxx_variadic_templates # Variadic templates, as defined in N2242.
|
||||
)
|
||||
|
||||
|
||||
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)
|
||||
set(CMAKE_CXX_STANDARD 98)
|
||||
target_compile_features(jsoncpp_lib PUBLIC)
|
||||
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
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
|
||||
)
|
||||
|
||||
list(APPEND CMAKE_TARGETS ${SHARED_LIB})
|
||||
endif()
|
||||
|
||||
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 also named jsoncpp.lib
|
||||
if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS)
|
||||
if (MSVC OR ("${CMAKE_C_SIMULATE_ID}" STREQUAL "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
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
|
||||
)
|
||||
|
||||
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()
|
||||
|
||||
target_compile_features(${OBJECT_LIB} PUBLIC ${REQUIRED_FEATURES})
|
||||
|
||||
target_include_directories(${OBJECT_LIB} PUBLIC
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
|
||||
)
|
||||
|
||||
list(APPEND CMAKE_TARGETS ${OBJECT_LIB})
|
||||
endif()
|
||||
|
||||
install(TARGETS ${CMAKE_TARGETS} ${INSTALL_EXPORT}
|
||||
install(TARGETS jsoncpp_lib ${INSTALL_EXPORT}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
|
||||
target_include_directories(jsoncpp_lib PUBLIC
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
|
||||
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/json>
|
||||
)
|
||||
endif()
|
||||
|
@@ -10,9 +10,7 @@
|
||||
#include <json/reader.h>
|
||||
#include <json/value.h>
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
@@ -23,6 +21,13 @@
|
||||
#include <utility>
|
||||
|
||||
#include <cstdio>
|
||||
#if __cplusplus >= 201103L
|
||||
|
||||
#if !defined(sscanf)
|
||||
#define sscanf std::sscanf
|
||||
#endif
|
||||
|
||||
#endif //__cplusplus
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
|
||||
@@ -46,14 +51,15 @@ static size_t const stackLimit_g =
|
||||
|
||||
namespace Json {
|
||||
|
||||
using CharReaderPtr = std::unique_ptr<CharReader>;
|
||||
typedef CharReader* CharReaderPtr;
|
||||
|
||||
// Implementation of class Features
|
||||
// ////////////////////////////////
|
||||
|
||||
Features::Features() = default;
|
||||
|
||||
Features Features::all() { return {}; }
|
||||
Features::Features()
|
||||
: allowComments_(true), strictRoot_(false),
|
||||
allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
|
||||
Features Features::all() { return Features(); }
|
||||
|
||||
Features Features::strictMode() {
|
||||
Features features;
|
||||
@@ -68,15 +74,24 @@ Features Features::strictMode() {
|
||||
// ////////////////////////////////
|
||||
|
||||
bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
|
||||
return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
|
||||
for (; begin < end; ++begin)
|
||||
if (*begin == '\n' || *begin == '\r')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Class Reader
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
Reader::Reader() : features_(Features::all()) {}
|
||||
Reader::Reader()
|
||||
: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
|
||||
lastValue_(), commentsBefore_(), features_(Features::all()),
|
||||
collectComments_() {}
|
||||
|
||||
Reader::Reader(const Features& features) : features_(features) {}
|
||||
Reader::Reader(const Features& features)
|
||||
: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
|
||||
lastValue_(), commentsBefore_(), features_(features), collectComments_() {
|
||||
}
|
||||
|
||||
bool Reader::parse(const std::string& document, Value& root,
|
||||
bool collectComments) {
|
||||
@@ -94,7 +109,8 @@ 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::istreambuf_iterator<char>(is), {});
|
||||
String doc;
|
||||
std::getline(is, doc, static_cast<char> EOF);
|
||||
return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
|
||||
}
|
||||
|
||||
@@ -108,8 +124,8 @@ bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
|
||||
end_ = endDoc;
|
||||
collectComments_ = collectComments;
|
||||
current_ = begin_;
|
||||
lastValueEnd_ = nullptr;
|
||||
lastValue_ = nullptr;
|
||||
lastValueEnd_ = JSONCPP_NULL;
|
||||
lastValue_ = JSONCPP_NULL;
|
||||
commentsBefore_.clear();
|
||||
errors_.clear();
|
||||
while (!nodes_.empty())
|
||||
@@ -118,7 +134,7 @@ bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
|
||||
|
||||
bool successful = readValue();
|
||||
Token token;
|
||||
readTokenSkippingComments(token);
|
||||
skipCommentTokens(token);
|
||||
if (collectComments_ && !commentsBefore_.empty())
|
||||
root.setComment(commentsBefore_, commentAfter);
|
||||
if (features_.strictRoot_) {
|
||||
@@ -146,7 +162,7 @@ bool Reader::readValue() {
|
||||
throwRuntimeError("Exceeded stackLimit in readValue().");
|
||||
|
||||
Token token;
|
||||
readTokenSkippingComments(token);
|
||||
skipCommentTokens(token);
|
||||
bool successful = true;
|
||||
|
||||
if (collectComments_ && !commentsBefore_.empty()) {
|
||||
@@ -214,15 +230,15 @@ bool Reader::readValue() {
|
||||
return successful;
|
||||
}
|
||||
|
||||
bool Reader::readTokenSkippingComments(Token& token) {
|
||||
bool success = readToken(token);
|
||||
void Reader::skipCommentTokens(Token& token) {
|
||||
if (features_.allowComments_) {
|
||||
while (success && token.type_ == tokenComment) {
|
||||
success = readToken(token);
|
||||
do {
|
||||
readToken(token);
|
||||
} while (token.type_ == tokenComment);
|
||||
} else {
|
||||
readToken(token);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Reader::readToken(Token& token) {
|
||||
skipSpaces();
|
||||
@@ -363,7 +379,7 @@ void Reader::addComment(Location begin, Location end,
|
||||
assert(collectComments_);
|
||||
const String& normalized = normalizeEOL(begin, end);
|
||||
if (placement == commentAfterOnSameLine) {
|
||||
assert(lastValue_ != nullptr);
|
||||
assert(lastValue_ != JSONCPP_NULL);
|
||||
lastValue_->setComment(normalized, placement);
|
||||
} else {
|
||||
commentsBefore_ += normalized;
|
||||
@@ -435,7 +451,12 @@ bool Reader::readObject(Token& token) {
|
||||
Value init(objectValue);
|
||||
currentValue().swapPayload(init);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
while (readTokenSkippingComments(tokenName)) {
|
||||
while (readToken(tokenName)) {
|
||||
bool initialTokenOk = true;
|
||||
while (tokenName.type_ == tokenComment && initialTokenOk)
|
||||
initialTokenOk = readToken(tokenName);
|
||||
if (!initialTokenOk)
|
||||
break;
|
||||
if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
|
||||
return true;
|
||||
name.clear();
|
||||
@@ -464,11 +485,15 @@ bool Reader::readObject(Token& token) {
|
||||
return recoverFromError(tokenObjectEnd);
|
||||
|
||||
Token comma;
|
||||
if (!readTokenSkippingComments(comma) ||
|
||||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
|
||||
if (!readToken(comma) ||
|
||||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
|
||||
comma.type_ != tokenComment)) {
|
||||
return addErrorAndRecover("Missing ',' or '}' in object declaration",
|
||||
comma, tokenObjectEnd);
|
||||
}
|
||||
bool finalizeTokenOk = true;
|
||||
while (comma.type_ == tokenComment && finalizeTokenOk)
|
||||
finalizeTokenOk = readToken(comma);
|
||||
if (comma.type_ == tokenObjectEnd)
|
||||
return true;
|
||||
}
|
||||
@@ -498,7 +523,10 @@ bool Reader::readArray(Token& token) {
|
||||
|
||||
Token currentToken;
|
||||
// Accept Comment after last item in the array.
|
||||
ok = readTokenSkippingComments(currentToken);
|
||||
ok = readToken(currentToken);
|
||||
while (currentToken.type_ == tokenComment && ok) {
|
||||
ok = readToken(currentToken);
|
||||
}
|
||||
bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
|
||||
currentToken.type_ != tokenArrayEnd);
|
||||
if (!ok || badTokenType) {
|
||||
@@ -540,7 +568,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
|
||||
Char c = *current++;
|
||||
if (c < '0' || c > '9')
|
||||
return decodeDouble(token, decoded);
|
||||
auto digit(static_cast<Value::UInt>(c - '0'));
|
||||
Value::UInt digit(static_cast<Value::UInt>(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
|
||||
@@ -576,16 +604,11 @@ bool Reader::decodeDouble(Token& token) {
|
||||
|
||||
bool Reader::decodeDouble(Token& token, Value& decoded) {
|
||||
double value = 0;
|
||||
IStringStream is(String(token.start_, token.end_));
|
||||
if (!(is >> value)) {
|
||||
if (value == std::numeric_limits<double>::max())
|
||||
value = std::numeric_limits<double>::infinity();
|
||||
else if (value == std::numeric_limits<double>::lowest())
|
||||
value = -std::numeric_limits<double>::infinity();
|
||||
else if (!std::isinf(value))
|
||||
String buffer(token.start_, token.end_);
|
||||
IStringStream is(buffer);
|
||||
if (!(is >> value))
|
||||
return addError(
|
||||
"'" + String(token.start_, token.end_) + "' is not a number.", token);
|
||||
}
|
||||
decoded = value;
|
||||
return true;
|
||||
}
|
||||
@@ -749,7 +772,7 @@ void Reader::getLocationLineAndColumn(Location location, int& line,
|
||||
while (current < location && current != end_) {
|
||||
Char c = *current++;
|
||||
if (c == '\r') {
|
||||
if (current != end_ && *current == '\n')
|
||||
if (*current == '\n')
|
||||
++current;
|
||||
lastLineStart = current;
|
||||
++line;
|
||||
@@ -778,7 +801,9 @@ String Reader::getFormatedErrorMessages() const {
|
||||
|
||||
String Reader::getFormattedErrorMessages() const {
|
||||
String formattedMessage;
|
||||
for (const auto& error : errors_) {
|
||||
for (Errors::const_iterator itError = errors_.begin();
|
||||
itError != errors_.end(); ++itError) {
|
||||
const ErrorInfo& error = *itError;
|
||||
formattedMessage +=
|
||||
"* " + getLocationLineAndColumn(error.token_.start_) + "\n";
|
||||
formattedMessage += " " + error.message_ + "\n";
|
||||
@@ -791,7 +816,9 @@ String Reader::getFormattedErrorMessages() const {
|
||||
|
||||
std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
|
||||
std::vector<Reader::StructuredError> allErrors;
|
||||
for (const auto& error : errors_) {
|
||||
for (Errors::const_iterator itError = errors_.begin();
|
||||
itError != errors_.end(); ++itError) {
|
||||
const ErrorInfo& error = *itError;
|
||||
Reader::StructuredError structured;
|
||||
structured.offset_start = error.token_.start_ - begin_;
|
||||
structured.offset_limit = error.token_.end_ - begin_;
|
||||
@@ -812,7 +839,7 @@ bool Reader::pushError(const Value& value, const String& message) {
|
||||
ErrorInfo info;
|
||||
info.token_ = token;
|
||||
info.message_ = message;
|
||||
info.extra_ = nullptr;
|
||||
info.extra_ = JSONCPP_NULL;
|
||||
errors_.push_back(info);
|
||||
return true;
|
||||
}
|
||||
@@ -855,7 +882,7 @@ public:
|
||||
size_t stackLimit_;
|
||||
}; // OurFeatures
|
||||
|
||||
OurFeatures OurFeatures::all() { return {}; }
|
||||
OurFeatures OurFeatures::all() { return OurFeatures(); }
|
||||
|
||||
// Implementation of class Reader
|
||||
// ////////////////////////////////
|
||||
@@ -864,14 +891,19 @@ OurFeatures OurFeatures::all() { return {}; }
|
||||
// for implementing JSON reading.
|
||||
class OurReader {
|
||||
public:
|
||||
using Char = char;
|
||||
using Location = const Char*;
|
||||
typedef char Char;
|
||||
typedef const Char* Location;
|
||||
struct StructuredError {
|
||||
ptrdiff_t offset_start;
|
||||
ptrdiff_t offset_limit;
|
||||
String message;
|
||||
};
|
||||
|
||||
explicit OurReader(OurFeatures const& features);
|
||||
JSONCPP_OP_EXPLICIT OurReader(OurFeatures const& features);
|
||||
bool parse(const char* beginDoc, const char* endDoc, Value& root,
|
||||
bool collectComments = true);
|
||||
String getFormattedErrorMessages() const;
|
||||
std::vector<CharReader::StructuredError> getStructuredErrors() const;
|
||||
std::vector<StructuredError> getStructuredErrors() const;
|
||||
|
||||
private:
|
||||
OurReader(OurReader const&); // no impl
|
||||
@@ -911,10 +943,9 @@ private:
|
||||
Location extra_;
|
||||
};
|
||||
|
||||
using Errors = std::deque<ErrorInfo>;
|
||||
typedef std::deque<ErrorInfo> Errors;
|
||||
|
||||
bool readToken(Token& token);
|
||||
bool readTokenSkippingComments(Token& token);
|
||||
void skipSpaces();
|
||||
void skipBom(bool skipBom);
|
||||
bool match(const Char* pattern, int patternLength);
|
||||
@@ -937,7 +968,8 @@ private:
|
||||
unsigned int& unicode);
|
||||
bool decodeUnicodeEscapeSequence(Token& token, Location& current,
|
||||
Location end, unsigned int& unicode);
|
||||
bool addError(const String& message, Token& token, Location extra = nullptr);
|
||||
bool addError(const String& message, Token& token,
|
||||
Location extra = JSONCPP_NULL);
|
||||
bool recoverFromError(TokenType skipUntilToken);
|
||||
bool addErrorAndRecover(const String& message, Token& token,
|
||||
TokenType skipUntilToken);
|
||||
@@ -948,35 +980,43 @@ private:
|
||||
int& column) const;
|
||||
String getLocationLineAndColumn(Location location) const;
|
||||
void addComment(Location begin, Location end, CommentPlacement placement);
|
||||
void skipCommentTokens(Token& token);
|
||||
|
||||
static String normalizeEOL(Location begin, Location end);
|
||||
static bool containsNewLine(Location begin, Location end);
|
||||
|
||||
using Nodes = std::stack<Value*>;
|
||||
typedef std::stack<Value*> Nodes;
|
||||
|
||||
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_{};
|
||||
Nodes nodes_;
|
||||
Errors errors_;
|
||||
String document_;
|
||||
Location begin_;
|
||||
Location end_;
|
||||
Location current_;
|
||||
Location lastValueEnd_;
|
||||
Value* lastValue_;
|
||||
bool lastValueHasAComment_;
|
||||
String commentsBefore_;
|
||||
|
||||
OurFeatures const features_;
|
||||
bool collectComments_ = false;
|
||||
bool collectComments_;
|
||||
}; // OurReader
|
||||
|
||||
// complete copy of Read impl, for OurReader
|
||||
|
||||
bool OurReader::containsNewLine(OurReader::Location begin,
|
||||
OurReader::Location end) {
|
||||
return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
|
||||
for (; begin < end; ++begin)
|
||||
if (*begin == '\n' || *begin == '\r')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
OurReader::OurReader(OurFeatures const& features) : features_(features) {}
|
||||
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) {}
|
||||
|
||||
bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
|
||||
bool collectComments) {
|
||||
@@ -988,8 +1028,8 @@ bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
|
||||
end_ = endDoc;
|
||||
collectComments_ = collectComments;
|
||||
current_ = begin_;
|
||||
lastValueEnd_ = nullptr;
|
||||
lastValue_ = nullptr;
|
||||
lastValueEnd_ = JSONCPP_NULL;
|
||||
lastValue_ = JSONCPP_NULL;
|
||||
commentsBefore_.clear();
|
||||
errors_.clear();
|
||||
while (!nodes_.empty())
|
||||
@@ -1001,7 +1041,7 @@ bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
|
||||
bool successful = readValue();
|
||||
nodes_.pop();
|
||||
Token token;
|
||||
readTokenSkippingComments(token);
|
||||
skipCommentTokens(token);
|
||||
if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
|
||||
addError("Extra non-whitespace after JSON value.", token);
|
||||
return false;
|
||||
@@ -1029,7 +1069,7 @@ bool OurReader::readValue() {
|
||||
if (nodes_.size() > features_.stackLimit_)
|
||||
throwRuntimeError("Exceeded stackLimit in readValue().");
|
||||
Token token;
|
||||
readTokenSkippingComments(token);
|
||||
skipCommentTokens(token);
|
||||
bool successful = true;
|
||||
|
||||
if (collectComments_ && !commentsBefore_.empty()) {
|
||||
@@ -1116,15 +1156,15 @@ bool OurReader::readValue() {
|
||||
return successful;
|
||||
}
|
||||
|
||||
bool OurReader::readTokenSkippingComments(Token& token) {
|
||||
bool success = readToken(token);
|
||||
void OurReader::skipCommentTokens(Token& token) {
|
||||
if (features_.allowComments_) {
|
||||
while (success && token.type_ == tokenComment) {
|
||||
success = readToken(token);
|
||||
do {
|
||||
readToken(token);
|
||||
} while (token.type_ == tokenComment);
|
||||
} else {
|
||||
readToken(token);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool OurReader::readToken(Token& token) {
|
||||
skipSpaces();
|
||||
@@ -1152,11 +1192,8 @@ bool OurReader::readToken(Token& token) {
|
||||
if (features_.allowSingleQuotes_) {
|
||||
token.type_ = tokenString;
|
||||
ok = readStringSingleQuote();
|
||||
} else {
|
||||
// If we don't allow single quotes, this is a failure case.
|
||||
ok = false;
|
||||
}
|
||||
break;
|
||||
} // else fall through
|
||||
case '/':
|
||||
token.type_ = tokenComment;
|
||||
ok = readComment();
|
||||
@@ -1250,7 +1287,7 @@ void OurReader::skipSpaces() {
|
||||
void OurReader::skipBom(bool skipBom) {
|
||||
// The default behavior is to skip BOM.
|
||||
if (skipBom) {
|
||||
if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) {
|
||||
if (strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) {
|
||||
begin_ += 3;
|
||||
current_ = begin_;
|
||||
}
|
||||
@@ -1327,7 +1364,7 @@ void OurReader::addComment(Location begin, Location end,
|
||||
assert(collectComments_);
|
||||
const String& normalized = normalizeEOL(begin, end);
|
||||
if (placement == commentAfterOnSameLine) {
|
||||
assert(lastValue_ != nullptr);
|
||||
assert(lastValue_ != JSONCPP_NULL);
|
||||
lastValue_->setComment(normalized, placement);
|
||||
} else {
|
||||
commentsBefore_ += normalized;
|
||||
@@ -1420,7 +1457,12 @@ bool OurReader::readObject(Token& token) {
|
||||
Value init(objectValue);
|
||||
currentValue().swapPayload(init);
|
||||
currentValue().setOffsetStart(token.start_ - begin_);
|
||||
while (readTokenSkippingComments(tokenName)) {
|
||||
while (readToken(tokenName)) {
|
||||
bool initialTokenOk = true;
|
||||
while (tokenName.type_ == tokenComment && initialTokenOk)
|
||||
initialTokenOk = readToken(tokenName);
|
||||
if (!initialTokenOk)
|
||||
break;
|
||||
if (tokenName.type_ == tokenObjectEnd &&
|
||||
(name.empty() ||
|
||||
features_.allowTrailingCommas_)) // empty object or trailing comma
|
||||
@@ -1457,11 +1499,15 @@ bool OurReader::readObject(Token& token) {
|
||||
return recoverFromError(tokenObjectEnd);
|
||||
|
||||
Token comma;
|
||||
if (!readTokenSkippingComments(comma) ||
|
||||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
|
||||
if (!readToken(comma) ||
|
||||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
|
||||
comma.type_ != tokenComment)) {
|
||||
return addErrorAndRecover("Missing ',' or '}' in object declaration",
|
||||
comma, tokenObjectEnd);
|
||||
}
|
||||
bool finalizeTokenOk = true;
|
||||
while (comma.type_ == tokenComment && finalizeTokenOk)
|
||||
finalizeTokenOk = readToken(comma);
|
||||
if (comma.type_ == tokenObjectEnd)
|
||||
return true;
|
||||
}
|
||||
@@ -1495,7 +1541,10 @@ bool OurReader::readArray(Token& token) {
|
||||
|
||||
Token currentToken;
|
||||
// Accept Comment after last item in the array.
|
||||
ok = readTokenSkippingComments(currentToken);
|
||||
ok = readToken(currentToken);
|
||||
while (currentToken.type_ == tokenComment && ok) {
|
||||
ok = readToken(currentToken);
|
||||
}
|
||||
bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
|
||||
currentToken.type_ != tokenArrayEnd);
|
||||
if (!ok || badTokenType) {
|
||||
@@ -1531,32 +1580,36 @@ 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.
|
||||
static_assert(Value::maxLargestInt <= Value::maxLargestUInt,
|
||||
"Int must be smaller than UInt");
|
||||
|
||||
JSONCPP_STATIC_ASSERT(LargestUInt(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.
|
||||
static_assert(Value::minLargestInt <= -Value::maxLargestInt,
|
||||
"The absolute value of minLargestInt must be greater than or "
|
||||
JSONCPP_STATIC_ASSERT(
|
||||
Value::minLargestInt <= -Value::maxLargestInt,
|
||||
"The absolute value of minLargestInt must ve greater than or"
|
||||
"equal to maxLargestInt");
|
||||
static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt,
|
||||
|
||||
JSONCPP_STATIC_ASSERT(
|
||||
Value::minLargestInt / 10 >= -Value::maxLargestInt,
|
||||
"The absolute value of minLargestInt must be only 1 magnitude"
|
||||
"larger than maxLargestInt");
|
||||
|
||||
static constexpr Value::LargestUInt positive_threshold =
|
||||
static JSONCPP_CONST Value::LargestUInt positive_threshold =
|
||||
Value::maxLargestUInt / 10;
|
||||
static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10;
|
||||
static JSONCPP_CONST 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 constexpr auto negative_threshold =
|
||||
static JSONCPP_CONST Value::LargestUInt negative_threshold =
|
||||
Value::LargestUInt(-(Value::minLargestInt / 10));
|
||||
static constexpr auto negative_last_digit =
|
||||
static JSONCPP_CONST Value::UInt negative_last_digit =
|
||||
Value::UInt(-(Value::minLargestInt % 10));
|
||||
|
||||
const Value::LargestUInt threshold =
|
||||
@@ -1570,10 +1623,10 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
|
||||
if (c < '0' || c > '9')
|
||||
return decodeDouble(token, decoded);
|
||||
|
||||
const auto digit(static_cast<Value::UInt>(c - '0'));
|
||||
const Value::UInt digit(static_cast<Value::UInt>(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, meaning value == threshold,
|
||||
// a) we've only just touched the limit, meaing value == threshold,
|
||||
// b) this is the last digit, or
|
||||
// c) it's small enough to fit in that rounding delta, we're okay.
|
||||
// Otherwise treat this number as a double to avoid overflow.
|
||||
@@ -1587,7 +1640,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
|
||||
|
||||
if (isNegative) {
|
||||
// We use the same magnitude assumption here, just in case.
|
||||
const auto last_digit = static_cast<Value::UInt>(value % 10);
|
||||
const Value::UInt last_digit = static_cast<Value::UInt>(value % 10);
|
||||
decoded = -Value::LargestInt(value / 10) * 10 - last_digit;
|
||||
} else if (value <= Value::LargestUInt(Value::maxLargestInt)) {
|
||||
decoded = Value::LargestInt(value);
|
||||
@@ -1610,13 +1663,9 @@ bool OurReader::decodeDouble(Token& token) {
|
||||
|
||||
bool OurReader::decodeDouble(Token& token, Value& decoded) {
|
||||
double value = 0;
|
||||
IStringStream is(String(token.start_, token.end_));
|
||||
const String buffer(token.start_, token.end_);
|
||||
IStringStream is(buffer);
|
||||
if (!(is >> value)) {
|
||||
if (value == std::numeric_limits<double>::max())
|
||||
value = std::numeric_limits<double>::infinity();
|
||||
else if (value == std::numeric_limits<double>::lowest())
|
||||
value = -std::numeric_limits<double>::infinity();
|
||||
else if (!std::isinf(value))
|
||||
return addError(
|
||||
"'" + String(token.start_, token.end_) + "' is not a number.", token);
|
||||
}
|
||||
@@ -1783,7 +1832,7 @@ void OurReader::getLocationLineAndColumn(Location location, int& line,
|
||||
while (current < location && current != end_) {
|
||||
Char c = *current++;
|
||||
if (c == '\r') {
|
||||
if (current != end_ && *current == '\n')
|
||||
if (*current == '\n')
|
||||
++current;
|
||||
lastLineStart = current;
|
||||
++line;
|
||||
@@ -1807,7 +1856,9 @@ String OurReader::getLocationLineAndColumn(Location location) const {
|
||||
|
||||
String OurReader::getFormattedErrorMessages() const {
|
||||
String formattedMessage;
|
||||
for (const auto& error : errors_) {
|
||||
for (Errors::const_iterator itError = errors_.begin();
|
||||
itError != errors_.end(); ++itError) {
|
||||
const ErrorInfo& error = *itError;
|
||||
formattedMessage +=
|
||||
"* " + getLocationLineAndColumn(error.token_.start_) + "\n";
|
||||
formattedMessage += " " + error.message_ + "\n";
|
||||
@@ -1818,11 +1869,12 @@ String OurReader::getFormattedErrorMessages() const {
|
||||
return formattedMessage;
|
||||
}
|
||||
|
||||
std::vector<CharReader::StructuredError>
|
||||
OurReader::getStructuredErrors() const {
|
||||
std::vector<CharReader::StructuredError> allErrors;
|
||||
for (const auto& error : errors_) {
|
||||
CharReader::StructuredError structured;
|
||||
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
|
||||
std::vector<OurReader::StructuredError> allErrors;
|
||||
for (Errors::const_iterator itError = errors_.begin();
|
||||
itError != errors_.end(); ++itError) {
|
||||
const ErrorInfo& error = *itError;
|
||||
OurReader::StructuredError structured;
|
||||
structured.offset_start = error.token_.start_ - begin_;
|
||||
structured.offset_limit = error.token_.end_ - begin_;
|
||||
structured.message = error.message_;
|
||||
@@ -1832,40 +1884,24 @@ OurReader::getStructuredErrors() const {
|
||||
}
|
||||
|
||||
class OurCharReader : public CharReader {
|
||||
bool const collectComments_;
|
||||
OurReader reader_;
|
||||
|
||||
public:
|
||||
OurCharReader(bool collectComments, OurFeatures const& features)
|
||||
: CharReader(
|
||||
std::unique_ptr<OurImpl>(new OurImpl(collectComments, features))) {}
|
||||
|
||||
protected:
|
||||
class OurImpl : public Impl {
|
||||
public:
|
||||
OurImpl(bool collectComments, OurFeatures const& features)
|
||||
: collectComments_(collectComments), reader_(features) {}
|
||||
|
||||
bool parse(char const* beginDoc, char const* endDoc, Value* root,
|
||||
String* errs) override {
|
||||
String* errs) JSONCPP_OVERRIDE {
|
||||
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
|
||||
if (errs) {
|
||||
*errs = reader_.getFormattedErrorMessages();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
std::vector<CharReader::StructuredError>
|
||||
getStructuredErrors() const override {
|
||||
return reader_.getStructuredErrors();
|
||||
}
|
||||
|
||||
private:
|
||||
bool const collectComments_;
|
||||
OurReader reader_;
|
||||
};
|
||||
};
|
||||
|
||||
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
|
||||
CharReaderBuilder::~CharReaderBuilder() = default;
|
||||
CharReaderBuilder::~CharReaderBuilder() {}
|
||||
CharReader* CharReaderBuilder::newCharReader() const {
|
||||
bool collectComments = settings_["collectComments"].asBool();
|
||||
OurFeatures features = OurFeatures::all();
|
||||
@@ -1886,34 +1922,38 @@ CharReader* CharReaderBuilder::newCharReader() const {
|
||||
features.skipBom_ = settings_["skipBom"].asBool();
|
||||
return new OurCharReader(collectComments, features);
|
||||
}
|
||||
|
||||
static void getValidReaderKeys(std::set<String>* valid_keys) {
|
||||
valid_keys->clear();
|
||||
valid_keys->insert("collectComments");
|
||||
valid_keys->insert("allowComments");
|
||||
valid_keys->insert("allowTrailingCommas");
|
||||
valid_keys->insert("strictRoot");
|
||||
valid_keys->insert("allowDroppedNullPlaceholders");
|
||||
valid_keys->insert("allowNumericKeys");
|
||||
valid_keys->insert("allowSingleQuotes");
|
||||
valid_keys->insert("stackLimit");
|
||||
valid_keys->insert("failIfExtra");
|
||||
valid_keys->insert("rejectDupKeys");
|
||||
valid_keys->insert("allowSpecialFloats");
|
||||
valid_keys->insert("skipBom");
|
||||
}
|
||||
bool CharReaderBuilder::validate(Json::Value* invalid) const {
|
||||
static const auto& valid_keys = *new std::set<String>{
|
||||
"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;
|
||||
Json::Value my_invalid;
|
||||
if (!invalid)
|
||||
invalid = &my_invalid; // so we do not need to test for NULL
|
||||
Json::Value& inv = *invalid;
|
||||
std::set<String> 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];
|
||||
}
|
||||
return invalid ? invalid->empty() : true;
|
||||
}
|
||||
|
||||
return inv.empty();
|
||||
}
|
||||
Value& CharReaderBuilder::operator[](const String& key) {
|
||||
return settings_[key];
|
||||
}
|
||||
@@ -1950,32 +1990,6 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
|
||||
(*settings)["skipBom"] = true;
|
||||
//! [CharReaderBuilderDefaults]
|
||||
}
|
||||
// static
|
||||
void CharReaderBuilder::ecma404Mode(Json::Value* settings) {
|
||||
//! [CharReaderBuilderECMA404Mode]
|
||||
(*settings)["allowComments"] = false;
|
||||
(*settings)["allowTrailingCommas"] = false;
|
||||
(*settings)["strictRoot"] = false;
|
||||
(*settings)["allowDroppedNullPlaceholders"] = false;
|
||||
(*settings)["allowNumericKeys"] = false;
|
||||
(*settings)["allowSingleQuotes"] = false;
|
||||
(*settings)["stackLimit"] = 1000;
|
||||
(*settings)["failIfExtra"] = true;
|
||||
(*settings)["rejectDupKeys"] = false;
|
||||
(*settings)["allowSpecialFloats"] = false;
|
||||
(*settings)["skipBom"] = false;
|
||||
//! [CharReaderBuilderECMA404Mode]
|
||||
}
|
||||
|
||||
std::vector<CharReader::StructuredError>
|
||||
CharReader::getStructuredErrors() const {
|
||||
return _impl->getStructuredErrors();
|
||||
}
|
||||
|
||||
bool CharReader::parse(char const* beginDoc, char const* endDoc, Value* root,
|
||||
String* errs) {
|
||||
return _impl->parse(beginDoc, endDoc, root, errs);
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
// global functions
|
||||
@@ -1984,12 +1998,14 @@ bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,
|
||||
String* errs) {
|
||||
OStringStream ssin;
|
||||
ssin << sin.rdbuf();
|
||||
String doc = std::move(ssin).str();
|
||||
String doc = ssin.str();
|
||||
char const* begin = doc.data();
|
||||
char const* end = begin + doc.size();
|
||||
// Note that we do not actually need a null-terminator.
|
||||
CharReaderPtr const reader(fact.newCharReader());
|
||||
return reader->parse(begin, end, root, errs);
|
||||
bool ret = reader->parse(begin, end, root, errs);
|
||||
delete reader;
|
||||
return ret;
|
||||
}
|
||||
|
||||
IStream& operator>>(IStream& sin, Value& root) {
|
||||
|
@@ -71,7 +71,7 @@ enum {
|
||||
};
|
||||
|
||||
// Defines a char buffer for use with uintToString().
|
||||
using UIntToStringBuffer = char[uintToStringBufferSize];
|
||||
typedef char UIntToStringBuffer[uintToStringBufferSize];
|
||||
|
||||
/** Converts an unsigned integer to string.
|
||||
* @param value Unsigned integer to convert to string
|
||||
@@ -116,19 +116,15 @@ template <typename Iter> 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 <typename Iter>
|
||||
Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) {
|
||||
template <typename Iter> Iter fixZerosInTheEnd(Iter begin, Iter end) {
|
||||
for (; begin != end; --end) {
|
||||
if (*(end - 1) != '0') {
|
||||
return end;
|
||||
}
|
||||
// Don't delete the last zero before the decimal point.
|
||||
if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') {
|
||||
if (precision) {
|
||||
if (begin != (end - 1) && *(end - 2) == '.') {
|
||||
return end;
|
||||
}
|
||||
return end - 2;
|
||||
}
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
@@ -48,14 +48,6 @@ int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
|
||||
#define JSON_ASSERT_UNREACHABLE assert(false)
|
||||
|
||||
namespace Json {
|
||||
template <typename T>
|
||||
static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {
|
||||
std::unique_ptr<T> r;
|
||||
if (p) {
|
||||
r = std::unique_ptr<T>(new T(*p));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// This is a walkaround to avoid the static initialization of Value::null.
|
||||
// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
|
||||
@@ -87,8 +79,7 @@ template <typename T, typename U>
|
||||
static inline bool InRange(double d, T min, U max) {
|
||||
// The casts can lose precision, but we are looking only for
|
||||
// an approximate range. Might fail on edge cases though. ~cdunn
|
||||
return d >= static_cast<double>(min) && d <= static_cast<double>(max) &&
|
||||
!(static_cast<U>(d) == min && d != static_cast<double>(min));
|
||||
return d >= static_cast<double>(min) && d <= static_cast<double>(max);
|
||||
}
|
||||
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
||||
static inline double integerToDouble(Json::UInt64 value) {
|
||||
@@ -102,8 +93,7 @@ template <typename T> static inline double integerToDouble(T value) {
|
||||
|
||||
template <typename T, typename U>
|
||||
static inline bool InRange(double d, T min, U max) {
|
||||
return d >= integerToDouble(min) && d <= integerToDouble(max) &&
|
||||
!(static_cast<U>(d) == min && d != integerToDouble(min));
|
||||
return d >= integerToDouble(min) && d <= integerToDouble(max);
|
||||
}
|
||||
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
|
||||
|
||||
@@ -120,8 +110,8 @@ static inline char* duplicateStringValue(const char* value, size_t length) {
|
||||
if (length >= static_cast<size_t>(Value::maxInt))
|
||||
length = Value::maxInt - 1;
|
||||
|
||||
auto newString = static_cast<char*>(malloc(length + 1));
|
||||
if (newString == nullptr) {
|
||||
char* newString = static_cast<char*>(malloc(length + 1));
|
||||
if (newString == JSONCPP_NULL) {
|
||||
throwRuntimeError("in Json::Value::duplicateStringValue(): "
|
||||
"Failed to allocate string value buffer");
|
||||
}
|
||||
@@ -141,8 +131,8 @@ static inline char* duplicateAndPrefixStringValue(const char* value,
|
||||
"in Json::Value::duplicateAndPrefixStringValue(): "
|
||||
"length too big for prefixing");
|
||||
size_t actualLength = sizeof(length) + length + 1;
|
||||
auto newString = static_cast<char*>(malloc(actualLength));
|
||||
if (newString == nullptr) {
|
||||
char* newString = static_cast<char*>(malloc(actualLength));
|
||||
if (newString == JSONCPP_NULL) {
|
||||
throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
|
||||
"Failed to allocate string value buffer");
|
||||
}
|
||||
@@ -165,7 +155,7 @@ inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,
|
||||
/** Free the string duplicated by
|
||||
* duplicateStringValue()/duplicateAndPrefixStringValue().
|
||||
*/
|
||||
#if JSONCPP_USE_SECURE_MEMORY
|
||||
#if JSONCPP_USING_SECURE_MEMORY
|
||||
static inline void releasePrefixedStringValue(char* value) {
|
||||
unsigned length = 0;
|
||||
char const* valueDecoded;
|
||||
@@ -180,10 +170,10 @@ static inline void releaseStringValue(char* value, unsigned length) {
|
||||
memset(value, 0, size);
|
||||
free(value);
|
||||
}
|
||||
#else // !JSONCPP_USE_SECURE_MEMORY
|
||||
#else // !JSONCPP_USING_SECURE_MEMORY
|
||||
static inline void releasePrefixedStringValue(char* value) { free(value); }
|
||||
static inline void releaseStringValue(char* value, unsigned) { free(value); }
|
||||
#endif // JSONCPP_USE_SECURE_MEMORY
|
||||
#endif // JSONCPP_USING_SECURE_MEMORY
|
||||
|
||||
} // namespace Json
|
||||
|
||||
@@ -202,9 +192,9 @@ static inline void releaseStringValue(char* value, unsigned) { free(value); }
|
||||
namespace Json {
|
||||
|
||||
#if JSON_USE_EXCEPTION
|
||||
Exception::Exception(String msg) : msg_(std::move(msg)) {}
|
||||
Exception::~Exception() noexcept = default;
|
||||
char const* Exception::what() const noexcept { return msg_.c_str(); }
|
||||
Exception::Exception(String msg) : msg_(JSONCPP_MOVE(msg)) {}
|
||||
Exception::~Exception() JSONCPP_NOEXCEPT {}
|
||||
char const* Exception::what() const JSONCPP_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) {
|
||||
@@ -235,7 +225,8 @@ 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_(nullptr), index_(index) {}
|
||||
Value::CZString::CZString(ArrayIndex index)
|
||||
: cstr_(JSONCPP_NULL), index_(index) {}
|
||||
|
||||
Value::CZString::CZString(char const* str, unsigned length,
|
||||
DuplicationPolicy allocate)
|
||||
@@ -246,7 +237,8 @@ Value::CZString::CZString(char const* str, unsigned length,
|
||||
}
|
||||
|
||||
Value::CZString::CZString(const CZString& other) {
|
||||
cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr
|
||||
cstr_ =
|
||||
(other.storage_.policy_ != noDuplication && other.cstr_ != JSONCPP_NULL
|
||||
? duplicateStringValue(other.cstr_, other.storage_.length_)
|
||||
: other.cstr_);
|
||||
storage_.policy_ =
|
||||
@@ -260,12 +252,12 @@ Value::CZString::CZString(const CZString& other) {
|
||||
3U;
|
||||
storage_.length_ = other.storage_.length_;
|
||||
}
|
||||
|
||||
Value::CZString::CZString(CZString&& other) noexcept
|
||||
#if JSONCPP_CXX_STD_11
|
||||
Value::CZString::CZString(CZString&& other)
|
||||
: cstr_(other.cstr_), index_(other.index_) {
|
||||
other.cstr_ = nullptr;
|
||||
other.cstr_ = JSONCPP_NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
Value::CZString::~CZString() {
|
||||
if (cstr_ && storage_.policy_ == duplicate) {
|
||||
releaseStringValue(const_cast<char*>(cstr_),
|
||||
@@ -286,14 +278,14 @@ Value::CZString& Value::CZString::operator=(const CZString& other) {
|
||||
index_ = other.index_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value::CZString& Value::CZString::operator=(CZString&& other) noexcept {
|
||||
#if JSONCPP_CXX_STD_11
|
||||
Value::CZString& Value::CZString::operator=(CZString&& other) {
|
||||
cstr_ = other.cstr_;
|
||||
index_ = other.index_;
|
||||
other.cstr_ = nullptr;
|
||||
other.cstr_ = JSONCPP_NULL;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif
|
||||
bool Value::CZString::operator<(const CZString& other) const {
|
||||
if (!cstr_)
|
||||
return index_ < other.index_;
|
||||
@@ -402,7 +394,7 @@ Value::Value(double value) {
|
||||
|
||||
Value::Value(const char* value) {
|
||||
initBasic(stringValue, true);
|
||||
JSON_ASSERT_MESSAGE(value != nullptr,
|
||||
JSON_ASSERT_MESSAGE(value != JSONCPP_NULL,
|
||||
"Null Value Passed to Value Constructor");
|
||||
value_.string_ = duplicateAndPrefixStringValue(
|
||||
value, static_cast<unsigned>(strlen(value)));
|
||||
@@ -434,11 +426,12 @@ Value::Value(const Value& other) {
|
||||
dupPayload(other);
|
||||
dupMeta(other);
|
||||
}
|
||||
|
||||
Value::Value(Value&& other) noexcept {
|
||||
#if JSONCPP_CXX_STD_11
|
||||
Value::Value(Value&& other) {
|
||||
initBasic(nullValue);
|
||||
swap(other);
|
||||
}
|
||||
#endif
|
||||
|
||||
Value::~Value() {
|
||||
releasePayload();
|
||||
@@ -449,11 +442,12 @@ Value& Value::operator=(const Value& other) {
|
||||
Value(other).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value& Value::operator=(Value&& other) noexcept {
|
||||
#if JSONCPP_CXX_STD_11
|
||||
Value& Value::operator=(Value&& other) {
|
||||
other.swap(*this);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Value::swapPayload(Value& other) {
|
||||
std::swap(bits_, other.bits_);
|
||||
@@ -505,8 +499,9 @@ bool Value::operator<(const Value& other) const {
|
||||
case booleanValue:
|
||||
return value_.bool_ < other.value_.bool_;
|
||||
case stringValue: {
|
||||
if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
|
||||
return other.value_.string_ != nullptr;
|
||||
if ((value_.string_ == JSONCPP_NULL) ||
|
||||
(other.value_.string_ == JSONCPP_NULL)) {
|
||||
return other.value_.string_ != JSONCPP_NULL;
|
||||
}
|
||||
unsigned this_len;
|
||||
unsigned other_len;
|
||||
@@ -527,8 +522,8 @@ bool Value::operator<(const Value& other) const {
|
||||
}
|
||||
case arrayValue:
|
||||
case objectValue: {
|
||||
auto thisSize = value_.map_->size();
|
||||
auto otherSize = other.value_.map_->size();
|
||||
long unsigned int thisSize = value_.map_->size();
|
||||
long unsigned int otherSize = other.value_.map_->size();
|
||||
if (thisSize != otherSize)
|
||||
return thisSize < otherSize;
|
||||
return (*value_.map_) < (*other.value_.map_);
|
||||
@@ -560,7 +555,8 @@ bool Value::operator==(const Value& other) const {
|
||||
case booleanValue:
|
||||
return value_.bool_ == other.value_.bool_;
|
||||
case stringValue: {
|
||||
if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
|
||||
if ((value_.string_ == JSONCPP_NULL) ||
|
||||
(other.value_.string_ == JSONCPP_NULL)) {
|
||||
return (value_.string_ == other.value_.string_);
|
||||
}
|
||||
unsigned this_len;
|
||||
@@ -592,8 +588,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_ == nullptr)
|
||||
return nullptr;
|
||||
if (value_.string_ == JSONCPP_NULL)
|
||||
return JSONCPP_NULL;
|
||||
unsigned this_len;
|
||||
char const* this_str;
|
||||
decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
|
||||
@@ -601,7 +597,7 @@ const char* Value::asCString() const {
|
||||
return this_str;
|
||||
}
|
||||
|
||||
#if JSONCPP_USE_SECURE_MEMORY
|
||||
#if JSONCPP_USING_SECURE_MEMORY
|
||||
unsigned Value::getCStringLength() const {
|
||||
JSON_ASSERT_MESSAGE(type() == stringValue,
|
||||
"in Json::Value::asCString(): requires stringValue");
|
||||
@@ -618,7 +614,7 @@ unsigned Value::getCStringLength() const {
|
||||
bool Value::getString(char const** begin, char const** end) const {
|
||||
if (type() != stringValue)
|
||||
return false;
|
||||
if (value_.string_ == nullptr)
|
||||
if (value_.string_ == JSONCPP_NULL)
|
||||
return false;
|
||||
unsigned length;
|
||||
decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
|
||||
@@ -632,7 +628,7 @@ String Value::asString() const {
|
||||
case nullValue:
|
||||
return "";
|
||||
case stringValue: {
|
||||
if (value_.string_ == nullptr)
|
||||
if (value_.string_ == JSONCPP_NULL)
|
||||
return "";
|
||||
unsigned this_len;
|
||||
char const* this_str;
|
||||
@@ -684,7 +680,7 @@ Value::UInt Value::asUInt() const {
|
||||
JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
|
||||
return UInt(value_.uint_);
|
||||
case realValue:
|
||||
JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt),
|
||||
JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
|
||||
"double out of UInt range");
|
||||
return UInt(value_.real_);
|
||||
case nullValue:
|
||||
@@ -707,11 +703,6 @@ Value::Int64 Value::asInt64() const {
|
||||
JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
|
||||
return Int64(value_.uint_);
|
||||
case realValue:
|
||||
// If the double value is in proximity to minInt64, it will be rounded to
|
||||
// minInt64. The correct value in this scenario is indeterminable
|
||||
JSON_ASSERT_MESSAGE(
|
||||
value_.real_ != minInt64,
|
||||
"Double value is minInt64, precise value cannot be determined");
|
||||
JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
|
||||
"double out of Int64 range");
|
||||
return Int64(value_.real_);
|
||||
@@ -733,7 +724,7 @@ Value::UInt64 Value::asUInt64() const {
|
||||
case uintValue:
|
||||
return UInt64(value_.uint_);
|
||||
case realValue:
|
||||
JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt64),
|
||||
JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
|
||||
"double out of UInt64 range");
|
||||
return UInt64(value_.real_);
|
||||
case nullValue:
|
||||
@@ -820,7 +811,7 @@ bool Value::asBool() const {
|
||||
return value_.uint_ != 0;
|
||||
case realValue: {
|
||||
// According to JavaScript language zero or NaN is regarded as false
|
||||
const auto value_classification = std::fpclassify(value_.real_);
|
||||
const int value_classification = std::fpclassify(value_.real_);
|
||||
return value_classification != FP_ZERO && value_classification != FP_NAN;
|
||||
}
|
||||
default:
|
||||
@@ -844,7 +835,7 @@ bool Value::isConvertibleTo(ValueType other) const {
|
||||
type() == booleanValue || type() == nullValue;
|
||||
case uintValue:
|
||||
return isUInt() ||
|
||||
(type() == realValue && InRange(value_.real_, 0u, maxUInt)) ||
|
||||
(type() == realValue && InRange(value_.real_, 0, maxUInt)) ||
|
||||
type() == booleanValue || type() == nullValue;
|
||||
case realValue:
|
||||
return isNumeric() || type() == booleanValue || type() == nullValue;
|
||||
@@ -919,8 +910,7 @@ void Value::resize(ArrayIndex newSize) {
|
||||
if (newSize == 0)
|
||||
clear();
|
||||
else if (newSize > oldSize)
|
||||
for (ArrayIndex i = oldSize; i < newSize; ++i)
|
||||
(*this)[i];
|
||||
this->operator[](newSize - 1);
|
||||
else {
|
||||
for (ArrayIndex index = newSize; index < oldSize; ++index) {
|
||||
value_.map_->erase(index);
|
||||
@@ -936,7 +926,7 @@ Value& Value::operator[](ArrayIndex index) {
|
||||
if (type() == nullValue)
|
||||
*this = Value(arrayValue);
|
||||
CZString key(index);
|
||||
auto it = value_.map_->lower_bound(key);
|
||||
ObjectValues::iterator it = value_.map_->lower_bound(key);
|
||||
if (it != value_.map_->end() && (*it).first == key)
|
||||
return (*it).second;
|
||||
|
||||
@@ -975,7 +965,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;
|
||||
}
|
||||
@@ -1050,7 +1040,7 @@ Value& Value::resolveReference(const char* key) {
|
||||
*this = Value(objectValue);
|
||||
CZString actualKey(key, static_cast<unsigned>(strlen(key)),
|
||||
CZString::noDuplication); // NOTE!
|
||||
auto it = value_.map_->lower_bound(actualKey);
|
||||
ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
|
||||
if (it != value_.map_->end() && (*it).first == actualKey)
|
||||
return (*it).second;
|
||||
|
||||
@@ -1069,7 +1059,7 @@ Value& Value::resolveReference(char const* key, char const* end) {
|
||||
*this = Value(objectValue);
|
||||
CZString actualKey(key, static_cast<unsigned>(end - key),
|
||||
CZString::duplicateOnCopy);
|
||||
auto it = value_.map_->lower_bound(actualKey);
|
||||
ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
|
||||
if (it != value_.map_->end() && (*it).first == actualKey)
|
||||
return (*it).second;
|
||||
|
||||
@@ -1091,17 +1081,14 @@ 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 nullptr;
|
||||
return JSONCPP_NULL;
|
||||
CZString actualKey(begin, static_cast<unsigned>(end - begin),
|
||||
CZString::noDuplication);
|
||||
ObjectValues::const_iterator it = value_.map_->find(actualKey);
|
||||
if (it == value_.map_->end())
|
||||
return nullptr;
|
||||
return JSONCPP_NULL;
|
||||
return &(*it).second;
|
||||
}
|
||||
Value const* Value::find(const String& key) const {
|
||||
return find(key.data(), key.data() + key.length());
|
||||
}
|
||||
Value* Value::demand(char const* begin, char const* end) {
|
||||
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
|
||||
"in Json::Value::demand(begin, end): requires "
|
||||
@@ -1115,7 +1102,7 @@ const Value& Value::operator[](const char* key) const {
|
||||
return *found;
|
||||
}
|
||||
Value const& Value::operator[](const String& key) const {
|
||||
Value const* found = find(key);
|
||||
Value const* found = find(key.data(), key.data() + key.length());
|
||||
if (!found)
|
||||
return nullSingleton();
|
||||
return *found;
|
||||
@@ -1133,8 +1120,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");
|
||||
@@ -1143,12 +1130,19 @@ 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();
|
||||
@@ -1156,12 +1150,11 @@ bool Value::insert(ArrayIndex index, Value&& newValue) {
|
||||
return false;
|
||||
}
|
||||
for (ArrayIndex i = length; i > index; i--) {
|
||||
(*this)[i] = std::move((*this)[i - 1]);
|
||||
(*this)[i] = JSONCPP_MOVE((*this)[i - 1]);
|
||||
}
|
||||
(*this)[index] = std::move(newValue);
|
||||
(*this)[index] = JSONCPP_MOVE(newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
Value Value::get(char const* begin, char const* end,
|
||||
Value const& defaultValue) const {
|
||||
Value const* found = find(begin, end);
|
||||
@@ -1180,11 +1173,11 @@ bool Value::removeMember(const char* begin, const char* end, Value* removed) {
|
||||
}
|
||||
CZString actualKey(begin, static_cast<unsigned>(end - begin),
|
||||
CZString::noDuplication);
|
||||
auto it = value_.map_->find(actualKey);
|
||||
ObjectValues::iterator it = value_.map_->find(actualKey);
|
||||
if (it == value_.map_->end())
|
||||
return false;
|
||||
if (removed)
|
||||
*removed = std::move(it->second);
|
||||
*removed = JSONCPP_MOVE(it->second);
|
||||
value_.map_->erase(it);
|
||||
return true;
|
||||
}
|
||||
@@ -1210,12 +1203,12 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
|
||||
return false;
|
||||
}
|
||||
CZString key(index);
|
||||
auto it = value_.map_->find(key);
|
||||
ObjectValues::iterator it = value_.map_->find(key);
|
||||
if (it == value_.map_->end()) {
|
||||
return false;
|
||||
}
|
||||
if (removed)
|
||||
*removed = std::move(it->second);
|
||||
*removed = it->second;
|
||||
ArrayIndex oldSize = size();
|
||||
// shift left all items left, into the place of the "removed"
|
||||
for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
|
||||
@@ -1224,14 +1217,14 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
|
||||
}
|
||||
// erase the last one ("leftover")
|
||||
CZString keyLast(oldSize - 1);
|
||||
auto itLast = value_.map_->find(keyLast);
|
||||
ObjectValues::iterator 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 nullptr != value;
|
||||
return JSONCPP_NULL != value;
|
||||
}
|
||||
bool Value::isMember(char const* key) const {
|
||||
return isMember(key, key + strlen(key));
|
||||
@@ -1318,12 +1311,8 @@ bool Value::isInt64() const {
|
||||
// Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
|
||||
// double, so double(maxInt64) will be rounded up to 2^63. Therefore we
|
||||
// require the value to be strictly less than the limit.
|
||||
// minInt64 is -2^63 which can be represented as a double, but since double
|
||||
// values in its proximity are also rounded to -2^63, we require the value
|
||||
// to be strictly greater than the limit to avoid returning 'true' for
|
||||
// values that are not in the range
|
||||
return value_.real_ > double(minInt64) && value_.real_ < double(maxInt64) &&
|
||||
IsIntegral(value_.real_);
|
||||
return value_.real_ >= double(minInt64) &&
|
||||
value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1361,11 +1350,7 @@ bool Value::isIntegral() const {
|
||||
// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
|
||||
// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
|
||||
// require the value to be strictly less than the limit.
|
||||
// minInt64 is -2^63 which can be represented as a double, but since double
|
||||
// values in its proximity are also rounded to -2^63, we require the value
|
||||
// to be strictly greater than the limit to avoid returning 'true' for
|
||||
// values that are not in the range
|
||||
return value_.real_ > double(minInt64) &&
|
||||
return value_.real_ >= double(minInt64) &&
|
||||
value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
|
||||
#else
|
||||
return value_.real_ >= minInt && value_.real_ <= maxUInt &&
|
||||
@@ -1389,51 +1374,44 @@ bool Value::isArray() const { return type() == arrayValue; }
|
||||
|
||||
bool Value::isObject() const { return type() == objectValue; }
|
||||
|
||||
Value::Comments::Comments(const Comments& that)
|
||||
: ptr_{cloneUnique(that.ptr_)} {}
|
||||
|
||||
Value::Comments::Comments(Comments&& that) noexcept
|
||||
: ptr_{std::move(that.ptr_)} {}
|
||||
|
||||
Value::Comments::Comments(const Comments& that) {
|
||||
for (size_t i = 0; i < numberOfCommentPlacement; i++) {
|
||||
ptr_[i] = that.ptr_[i];
|
||||
}
|
||||
}
|
||||
Value::Comments& Value::Comments::operator=(const Comments& that) {
|
||||
ptr_ = cloneUnique(that.ptr_);
|
||||
for (size_t i = 0; i < numberOfCommentPlacement; i++) {
|
||||
ptr_[i] = that.ptr_[i];
|
||||
}
|
||||
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_ && !(*ptr_)[slot].empty();
|
||||
return !ptr_[slot].empty();
|
||||
}
|
||||
|
||||
String Value::Comments::get(CommentPlacement slot) const {
|
||||
if (!ptr_)
|
||||
return {};
|
||||
return (*ptr_)[slot];
|
||||
}
|
||||
String Value::Comments::get(CommentPlacement slot) const { return ptr_[slot]; }
|
||||
|
||||
void Value::Comments::set(CommentPlacement slot, String comment) {
|
||||
if (slot >= CommentPlacement::numberOfCommentPlacement)
|
||||
return;
|
||||
if (!ptr_)
|
||||
ptr_ = std::unique_ptr<Array>(new Array());
|
||||
(*ptr_)[slot] = std::move(comment);
|
||||
// check comments array boundry.
|
||||
if (slot < numberOfCommentPlacement) {
|
||||
ptr_[slot] = comment;
|
||||
}
|
||||
}
|
||||
|
||||
void Value::setComment(String comment, CommentPlacement placement) {
|
||||
if (!comment.empty() && (comment.back() == '\n')) {
|
||||
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')) {
|
||||
// Always discard trailing newline, to aid indentation.
|
||||
comment.pop_back();
|
||||
len -= 1;
|
||||
}
|
||||
JSON_ASSERT_MESSAGE(
|
||||
comment.empty() || comment[0] == '/',
|
||||
"in Json::Value::setComment(): Comments must start with /");
|
||||
comments_.set(placement, std::move(comment));
|
||||
comments_.set(placement, String(comment, len));
|
||||
}
|
||||
void Value::setComment(const String& comment, CommentPlacement placement) {
|
||||
setComment(comment.c_str(), comment.length(), placement);
|
||||
}
|
||||
|
||||
bool Value::hasComment(CommentPlacement placement) const {
|
||||
return comments_.has(placement);
|
||||
}
|
||||
@@ -1470,7 +1448,7 @@ Value::const_iterator Value::begin() const {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return {};
|
||||
return const_iterator();
|
||||
}
|
||||
|
||||
Value::const_iterator Value::end() const {
|
||||
@@ -1483,7 +1461,7 @@ Value::const_iterator Value::end() const {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return {};
|
||||
return const_iterator();
|
||||
}
|
||||
|
||||
Value::iterator Value::begin() {
|
||||
@@ -1515,14 +1493,15 @@ Value::iterator Value::end() {
|
||||
// class PathArgument
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
PathArgument::PathArgument() = default;
|
||||
PathArgument::PathArgument() {}
|
||||
|
||||
PathArgument::PathArgument(ArrayIndex index)
|
||||
: index_(index), kind_(kindIndex) {}
|
||||
|
||||
PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {}
|
||||
|
||||
PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {}
|
||||
PathArgument::PathArgument(String key)
|
||||
: key_(JSONCPP_MOVE(key)), kind_(kindKey) {}
|
||||
|
||||
// class Path
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
@@ -1543,7 +1522,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();
|
||||
auto itInArg = in.begin();
|
||||
InArgs::const_iterator itInArg = in.begin();
|
||||
while (current != end) {
|
||||
if (*current == '[') {
|
||||
++current;
|
||||
@@ -1589,7 +1568,9 @@ void Path::invalidPath(const String& /*path*/, int /*location*/) {
|
||||
|
||||
const Value& Path::resolve(const Value& root) const {
|
||||
const Value* node = &root;
|
||||
for (const auto& arg : args_) {
|
||||
for (Args::const_iterator itArg = args_.begin(); itArg != args_.end();
|
||||
++itArg) {
|
||||
const PathArgument& arg = *itArg;
|
||||
if (arg.kind_ == PathArgument::kindIndex) {
|
||||
if (!node->isArray() || !node->isValidIndex(arg.index_)) {
|
||||
// Error: unable to resolve path (array value expected at position... )
|
||||
@@ -1614,7 +1595,9 @@ const Value& Path::resolve(const Value& root) const {
|
||||
|
||||
Value Path::resolve(const Value& root, const Value& defaultValue) const {
|
||||
const Value* node = &root;
|
||||
for (const auto& arg : args_) {
|
||||
for (Args::const_iterator itArg = args_.begin(); itArg != args_.end();
|
||||
++itArg) {
|
||||
const PathArgument& arg = *itArg;
|
||||
if (arg.kind_ == PathArgument::kindIndex) {
|
||||
if (!node->isArray() || !node->isValidIndex(arg.index_))
|
||||
return defaultValue;
|
||||
@@ -1632,7 +1615,9 @@ Value Path::resolve(const Value& root, const Value& defaultValue) const {
|
||||
|
||||
Value& Path::make(Value& root) const {
|
||||
Value* node = &root;
|
||||
for (const auto& arg : args_) {
|
||||
for (Args::const_iterator itArg = args_.begin(); itArg != args_.end();
|
||||
++itArg) {
|
||||
const PathArgument& arg = *itArg;
|
||||
if (arg.kind_ == PathArgument::kindIndex) {
|
||||
if (!node->isArray()) {
|
||||
// Error: node is not an array at position ...
|
||||
|
@@ -15,7 +15,7 @@ namespace Json {
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueIteratorBase::ValueIteratorBase() : current_() {}
|
||||
ValueIteratorBase::ValueIteratorBase() : current_(), isNull_(true) {}
|
||||
|
||||
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 = nullptr;
|
||||
return nullptr;
|
||||
*end = JSONCPP_NULL;
|
||||
return JSONCPP_NULL;
|
||||
}
|
||||
*end = cname + (*current_).first.length();
|
||||
return cname;
|
||||
@@ -113,7 +113,7 @@ char const* ValueIteratorBase::memberName(char const** end) const {
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueConstIterator::ValueConstIterator() = default;
|
||||
ValueConstIterator::ValueConstIterator() {}
|
||||
|
||||
ValueConstIterator::ValueConstIterator(
|
||||
const Value::ObjectValues::iterator& current)
|
||||
@@ -136,7 +136,7 @@ operator=(const ValueIteratorBase& other) {
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueIterator::ValueIterator() = default;
|
||||
ValueIterator::ValueIterator() {}
|
||||
|
||||
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
|
||||
: ValueIteratorBase(current) {}
|
||||
@@ -146,7 +146,8 @@ ValueIterator::ValueIterator(const ValueConstIterator& other)
|
||||
throwRuntimeError("ConstIterator to Iterator should never be allowed.");
|
||||
}
|
||||
|
||||
ValueIterator::ValueIterator(const ValueIterator& other) = default;
|
||||
ValueIterator::ValueIterator(const ValueIterator& other)
|
||||
: ValueIteratorBase(other) {}
|
||||
|
||||
ValueIterator& ValueIterator::operator=(const SelfType& other) {
|
||||
copy(other);
|
||||
|
@@ -7,11 +7,7 @@
|
||||
#include "json_tool.h"
|
||||
#include <json/writer.h>
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
@@ -19,6 +15,67 @@
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
#if !defined(isnan)
|
||||
#define isnan std::isnan
|
||||
#endif
|
||||
|
||||
#if !defined(isfinite)
|
||||
#define isfinite std::isfinite
|
||||
#endif
|
||||
|
||||
#else
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if !defined(isnan)
|
||||
#include <float.h>
|
||||
#define isnan _isnan
|
||||
#endif
|
||||
|
||||
#if !defined(isfinite)
|
||||
#include <float.h>
|
||||
#define isfinite _finite
|
||||
#endif
|
||||
|
||||
#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
|
||||
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
|
||||
#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
|
||||
|
||||
#endif //_MSC_VER
|
||||
|
||||
#if defined(__sun) && defined(__SVR4) // Solaris
|
||||
#if !defined(isfinite)
|
||||
#include <ieeefp.h>
|
||||
#define isfinite finite
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__hpux)
|
||||
#if !defined(isfinite)
|
||||
#if defined(__ia64) && !defined(finite)
|
||||
#define isfinite(x) \
|
||||
((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x)))
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(isnan)
|
||||
// IEEE standard states that NaN values will not compare to themselves
|
||||
#define isnan(x) (x != x)
|
||||
#endif
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
#if !defined(isfinite)
|
||||
#define isfinite finite
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Disable warning about strdup being deprecated.
|
||||
#pragma warning(disable : 4996)
|
||||
@@ -26,7 +83,7 @@
|
||||
|
||||
namespace Json {
|
||||
|
||||
using StreamWriterPtr = std::unique_ptr<StreamWriter>;
|
||||
typedef StreamWriter* StreamWriterPtr;
|
||||
|
||||
String valueToString(LargestInt value) {
|
||||
UIntToStringBuffer buffer;
|
||||
@@ -66,22 +123,21 @@ String valueToString(double value, bool useSpecialFloats,
|
||||
// Print into the buffer. We need not request the alternative representation
|
||||
// that always has a decimal point because JSON doesn't distinguish the
|
||||
// concepts of reals and integers.
|
||||
if (!std::isfinite(value)) {
|
||||
if (std::isnan(value))
|
||||
return useSpecialFloats ? "NaN" : "null";
|
||||
if (value < 0)
|
||||
return useSpecialFloats ? "-Infinity" : "-1e+9999";
|
||||
return useSpecialFloats ? "Infinity" : "1e+9999";
|
||||
if (!isfinite(value)) {
|
||||
static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"},
|
||||
{"null", "-1e+9999", "1e+9999"}};
|
||||
return reps[useSpecialFloats ? 0 : 1]
|
||||
[isnan(value) ? 0 : (value < 0) ? 1 : 2];
|
||||
}
|
||||
|
||||
String buffer(size_t(36), '\0');
|
||||
while (true) {
|
||||
int len = jsoncpp_snprintf(
|
||||
&*buffer.begin(), buffer.size(),
|
||||
(precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f",
|
||||
int len =
|
||||
jsoncpp_snprintf(&*buffer.begin(), buffer.size(),
|
||||
(precisionType == significantDigits) ? "%.*g" : "%.*f",
|
||||
precision, value);
|
||||
assert(len >= 0);
|
||||
auto wouldPrint = static_cast<size_t>(len);
|
||||
size_t wouldPrint = static_cast<size_t>(len);
|
||||
if (wouldPrint >= buffer.size()) {
|
||||
buffer.resize(wouldPrint + 1);
|
||||
continue;
|
||||
@@ -92,18 +148,16 @@ 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
|
||||
@@ -115,12 +169,17 @@ String valueToString(double value, unsigned int precision,
|
||||
|
||||
String valueToString(bool value) { return value ? "true" : "false"; }
|
||||
|
||||
static bool doesAnyCharRequireEscaping(char const* s, size_t n) {
|
||||
static bool isAnyCharRequiredQuoting(char const* s, size_t n) {
|
||||
assert(s || !n);
|
||||
|
||||
return std::any_of(s, s + n, [](unsigned char c) {
|
||||
return c == '\\' || c == '"' || c < 0x20 || c > 0x7F;
|
||||
});
|
||||
char const* const end = s + n;
|
||||
for (char const* cur = s; cur < end; ++cur) {
|
||||
if (*cur == '\\' || *cur == '\"' ||
|
||||
static_cast<unsigned char>(*cur) < ' ' ||
|
||||
static_cast<unsigned char>(*cur) >= 0x80)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned int utf8ToCodepoint(const char*& s, const char* e) {
|
||||
@@ -202,20 +261,12 @@ static String toHex16Bit(unsigned int x) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static void appendRaw(String& result, unsigned ch) {
|
||||
result += static_cast<char>(ch);
|
||||
}
|
||||
|
||||
static void appendHex(String& result, unsigned ch) {
|
||||
result.append("\\u").append(toHex16Bit(ch));
|
||||
}
|
||||
|
||||
static String valueToQuotedStringN(const char* value, size_t length,
|
||||
static String valueToQuotedStringN(const char* value, unsigned length,
|
||||
bool emitUTF8 = false) {
|
||||
if (value == nullptr)
|
||||
if (value == JSONCPP_NULL)
|
||||
return "";
|
||||
|
||||
if (!doesAnyCharRequireEscaping(value, length))
|
||||
if (!isAnyCharRequiredQuoting(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.
|
||||
@@ -258,26 +309,29 @@ static String valueToQuotedStringN(const char* value, size_t length,
|
||||
// sequence from occurring.
|
||||
default: {
|
||||
if (emitUTF8) {
|
||||
unsigned codepoint = static_cast<unsigned char>(*c);
|
||||
if (codepoint < 0x20) {
|
||||
appendHex(result, codepoint);
|
||||
result += *c;
|
||||
} else {
|
||||
appendRaw(result, codepoint);
|
||||
}
|
||||
} else {
|
||||
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));
|
||||
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<char>(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);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
@@ -288,23 +342,19 @@ static String valueToQuotedStringN(const char* value, size_t length,
|
||||
}
|
||||
|
||||
String valueToQuotedString(const char* value) {
|
||||
return valueToQuotedStringN(value, strlen(value));
|
||||
}
|
||||
|
||||
String valueToQuotedString(const char* value, size_t length) {
|
||||
return valueToQuotedStringN(value, length);
|
||||
return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
|
||||
}
|
||||
|
||||
// Class Writer
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
Writer::~Writer() = default;
|
||||
Writer::~Writer() {}
|
||||
|
||||
// Class FastWriter
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
FastWriter::FastWriter()
|
||||
|
||||
= default;
|
||||
: yamlCompatibilityEnabled_(false), dropNullPlaceholders_(false),
|
||||
omitEndingLineFeed_(false) {}
|
||||
|
||||
void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; }
|
||||
|
||||
@@ -341,7 +391,7 @@ void FastWriter::writeValue(const Value& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
document_ += valueToQuotedStringN(str, static_cast<size_t>(end - str));
|
||||
document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));
|
||||
break;
|
||||
}
|
||||
case booleanValue:
|
||||
@@ -360,11 +410,13 @@ void FastWriter::writeValue(const Value& value) {
|
||||
case objectValue: {
|
||||
Value::Members members(value.getMemberNames());
|
||||
document_ += '{';
|
||||
for (auto it = members.begin(); it != members.end(); ++it) {
|
||||
for (Value::Members::const_iterator it = members.begin();
|
||||
it != members.end(); ++it) {
|
||||
const String& name = *it;
|
||||
if (it != members.begin())
|
||||
document_ += ',';
|
||||
document_ += valueToQuotedStringN(name.data(), name.length());
|
||||
document_ += valueToQuotedStringN(name.data(),
|
||||
static_cast<unsigned>(name.length()));
|
||||
document_ += yamlCompatibilityEnabled_ ? ": " : ":";
|
||||
writeValue(value[name]);
|
||||
}
|
||||
@@ -376,7 +428,8 @@ void FastWriter::writeValue(const Value& value) {
|
||||
// Class StyledWriter
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
StyledWriter::StyledWriter() = default;
|
||||
StyledWriter::StyledWriter()
|
||||
: rightMargin_(74), indentSize_(3), addChildValues_() {}
|
||||
|
||||
String StyledWriter::write(const Value& root) {
|
||||
document_.clear();
|
||||
@@ -409,7 +462,7 @@ void StyledWriter::writeValue(const Value& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
|
||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
|
||||
else
|
||||
pushValue("");
|
||||
break;
|
||||
@@ -427,12 +480,12 @@ void StyledWriter::writeValue(const Value& value) {
|
||||
else {
|
||||
writeWithIndent("{");
|
||||
indent();
|
||||
auto it = members.begin();
|
||||
Value::Members::const_iterator it = members.begin();
|
||||
for (;;) {
|
||||
const String& name = *it;
|
||||
const Value& childValue = value[name];
|
||||
writeCommentBeforeValue(childValue);
|
||||
writeWithIndent(valueToQuotedString(name.c_str(), name.size()));
|
||||
writeWithIndent(valueToQuotedString(name.c_str()));
|
||||
document_ += " : ";
|
||||
writeValue(childValue);
|
||||
if (++it == members.end()) {
|
||||
@@ -450,7 +503,7 @@ void StyledWriter::writeValue(const Value& value) {
|
||||
}
|
||||
|
||||
void StyledWriter::writeArrayValue(const Value& value) {
|
||||
size_t size = value.size();
|
||||
unsigned size = value.size();
|
||||
if (size == 0)
|
||||
pushValue("[]");
|
||||
else {
|
||||
@@ -459,7 +512,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
|
||||
writeWithIndent("[");
|
||||
indent();
|
||||
bool hasChildValue = !childValues_.empty();
|
||||
ArrayIndex index = 0;
|
||||
unsigned index = 0;
|
||||
for (;;) {
|
||||
const Value& childValue = value[index];
|
||||
writeCommentBeforeValue(childValue);
|
||||
@@ -482,7 +535,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
|
||||
{
|
||||
assert(childValues_.size() == size);
|
||||
document_ += "[ ";
|
||||
for (size_t index = 0; index < size; ++index) {
|
||||
for (unsigned index = 0; index < size; ++index) {
|
||||
if (index > 0)
|
||||
document_ += ", ";
|
||||
document_ += childValues_[index];
|
||||
@@ -589,8 +642,9 @@ bool StyledWriter::hasCommentForValue(const Value& value) {
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
StyledStreamWriter::StyledStreamWriter(String indentation)
|
||||
: document_(nullptr), indentation_(std::move(indentation)),
|
||||
addChildValues_(), indented_(false) {}
|
||||
: document_(JSONCPP_NULL), rightMargin_(74),
|
||||
indentation_(JSONCPP_MOVE(indentation)), addChildValues_(),
|
||||
indented_(false) {}
|
||||
|
||||
void StyledStreamWriter::write(OStream& out, const Value& root) {
|
||||
document_ = &out;
|
||||
@@ -604,7 +658,7 @@ void StyledStreamWriter::write(OStream& out, const Value& root) {
|
||||
writeValue(root);
|
||||
writeCommentAfterValueOnSameLine(root);
|
||||
*document_ << "\n";
|
||||
document_ = nullptr; // Forget the stream, for safety.
|
||||
document_ = JSONCPP_NULL; // Forget the stream, for safety.
|
||||
}
|
||||
|
||||
void StyledStreamWriter::writeValue(const Value& value) {
|
||||
@@ -627,7 +681,7 @@ void StyledStreamWriter::writeValue(const Value& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
|
||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
|
||||
else
|
||||
pushValue("");
|
||||
break;
|
||||
@@ -645,12 +699,12 @@ void StyledStreamWriter::writeValue(const Value& value) {
|
||||
else {
|
||||
writeWithIndent("{");
|
||||
indent();
|
||||
auto it = members.begin();
|
||||
Value::Members::const_iterator it = members.begin();
|
||||
for (;;) {
|
||||
const String& name = *it;
|
||||
const Value& childValue = value[name];
|
||||
writeCommentBeforeValue(childValue);
|
||||
writeWithIndent(valueToQuotedString(name.c_str(), name.size()));
|
||||
writeWithIndent(valueToQuotedString(name.c_str()));
|
||||
*document_ << " : ";
|
||||
writeValue(childValue);
|
||||
if (++it == members.end()) {
|
||||
@@ -823,7 +877,7 @@ struct BuiltStyledStreamWriter : public StreamWriter {
|
||||
String endingLineFeedSymbol, bool useSpecialFloats,
|
||||
bool emitUTF8, unsigned int precision,
|
||||
PrecisionType precisionType);
|
||||
int write(Value const& root, OStream* sout) override;
|
||||
int write(Value const& root, OStream* sout) JSONCPP_OVERRIDE;
|
||||
|
||||
private:
|
||||
void writeValue(Value const& value);
|
||||
@@ -838,7 +892,7 @@ private:
|
||||
void writeCommentAfterValueOnSameLine(Value const& root);
|
||||
static bool hasCommentForValue(const Value& value);
|
||||
|
||||
using ChildValues = std::vector<String>;
|
||||
typedef std::vector<String> ChildValues;
|
||||
|
||||
ChildValues childValues_;
|
||||
String indentString_;
|
||||
@@ -859,9 +913,10 @@ 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_(std::move(indentation)), cs_(cs),
|
||||
colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)),
|
||||
endingLineFeedSymbol_(std::move(endingLineFeedSymbol)),
|
||||
: rightMargin_(74), indentation_(JSONCPP_MOVE(indentation)), cs_(cs),
|
||||
colonSymbol_(JSONCPP_MOVE(colonSymbol)),
|
||||
nullSymbol_(JSONCPP_MOVE(nullSymbol)),
|
||||
endingLineFeedSymbol_(JSONCPP_MOVE(endingLineFeedSymbol)),
|
||||
addChildValues_(false), indented_(false),
|
||||
useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8),
|
||||
precision_(precision), precisionType_(precisionType) {}
|
||||
@@ -877,7 +932,7 @@ int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) {
|
||||
writeValue(root);
|
||||
writeCommentAfterValueOnSameLine(root);
|
||||
*sout_ << endingLineFeedSymbol_;
|
||||
sout_ = nullptr;
|
||||
sout_ = JSONCPP_NULL;
|
||||
return 0;
|
||||
}
|
||||
void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
||||
@@ -901,8 +956,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
||||
char const* end;
|
||||
bool ok = value.getString(&str, &end);
|
||||
if (ok)
|
||||
pushValue(
|
||||
valueToQuotedStringN(str, static_cast<size_t>(end - str), emitUTF8_));
|
||||
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str),
|
||||
emitUTF8_));
|
||||
else
|
||||
pushValue("");
|
||||
break;
|
||||
@@ -920,13 +975,13 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
|
||||
else {
|
||||
writeWithIndent("{");
|
||||
indent();
|
||||
auto it = members.begin();
|
||||
Value::Members::const_iterator it = members.begin();
|
||||
for (;;) {
|
||||
String const& name = *it;
|
||||
Value const& childValue = value[name];
|
||||
writeCommentBeforeValue(childValue);
|
||||
writeWithIndent(
|
||||
valueToQuotedStringN(name.data(), name.length(), emitUTF8_));
|
||||
writeWithIndent(valueToQuotedStringN(
|
||||
name.data(), static_cast<unsigned>(name.length()), emitUTF8_));
|
||||
*sout_ << colonSymbol_;
|
||||
writeValue(childValue);
|
||||
if (++it == members.end()) {
|
||||
@@ -1096,11 +1151,11 @@ bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
|
||||
///////////////
|
||||
// StreamWriter
|
||||
|
||||
StreamWriter::StreamWriter() : sout_(nullptr) {}
|
||||
StreamWriter::~StreamWriter() = default;
|
||||
StreamWriter::Factory::~Factory() = default;
|
||||
StreamWriter::StreamWriter() : sout_(JSONCPP_NULL) {}
|
||||
StreamWriter::~StreamWriter() {}
|
||||
StreamWriter::Factory::~Factory() {}
|
||||
StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); }
|
||||
StreamWriterBuilder::~StreamWriterBuilder() = default;
|
||||
StreamWriterBuilder::~StreamWriterBuilder() {}
|
||||
StreamWriter* StreamWriterBuilder::newStreamWriter() const {
|
||||
const String indentation = settings_["indentation"].asString();
|
||||
const String cs_str = settings_["commentStyle"].asString();
|
||||
@@ -1120,9 +1175,9 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const {
|
||||
}
|
||||
PrecisionType precisionType(significantDigits);
|
||||
if (pt_str == "significant") {
|
||||
precisionType = PrecisionType::significantDigits;
|
||||
precisionType = significantDigits;
|
||||
} else if (pt_str == "decimal") {
|
||||
precisionType = PrecisionType::decimalPlaces;
|
||||
precisionType = decimalPlaces;
|
||||
} else {
|
||||
throwRuntimeError("precisionType must be 'significant' or 'decimal'");
|
||||
}
|
||||
@@ -1143,30 +1198,34 @@ StreamWriter* StreamWriterBuilder::newStreamWriter() const {
|
||||
endingLineFeedSymbol, usf, emitUTF8, pre,
|
||||
precisionType);
|
||||
}
|
||||
|
||||
static void getValidWriterKeys(std::set<String>* valid_keys) {
|
||||
valid_keys->clear();
|
||||
valid_keys->insert("indentation");
|
||||
valid_keys->insert("commentStyle");
|
||||
valid_keys->insert("enableYAMLCompatibility");
|
||||
valid_keys->insert("dropNullPlaceholders");
|
||||
valid_keys->insert("useSpecialFloats");
|
||||
valid_keys->insert("emitUTF8");
|
||||
valid_keys->insert("precision");
|
||||
valid_keys->insert("precisionType");
|
||||
}
|
||||
bool StreamWriterBuilder::validate(Json::Value* invalid) const {
|
||||
static const auto& valid_keys = *new std::set<String>{
|
||||
"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;
|
||||
Json::Value my_invalid;
|
||||
if (!invalid)
|
||||
invalid = &my_invalid; // so we do not need to test for NULL
|
||||
Json::Value& inv = *invalid;
|
||||
std::set<String> 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];
|
||||
}
|
||||
return invalid ? invalid->empty() : true;
|
||||
}
|
||||
|
||||
return inv.empty();
|
||||
}
|
||||
Value& StreamWriterBuilder::operator[](const String& key) {
|
||||
return settings_[key];
|
||||
}
|
||||
@@ -1188,13 +1247,15 @@ String writeString(StreamWriter::Factory const& factory, Value const& root) {
|
||||
OStringStream sout;
|
||||
StreamWriterPtr const writer(factory.newStreamWriter());
|
||||
writer->write(root, &sout);
|
||||
return std::move(sout).str();
|
||||
delete writer;
|
||||
return sout.str();
|
||||
}
|
||||
|
||||
OStream& operator<<(OStream& sout, Value const& root) {
|
||||
StreamWriterBuilder builder;
|
||||
StreamWriterPtr const writer(builder.newStreamWriter());
|
||||
writer->write(root, &sout);
|
||||
delete writer;
|
||||
return sout;
|
||||
}
|
||||
|
||||
|
@@ -15,10 +15,8 @@ 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)
|
||||
|
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "fuzz.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <json/config.h>
|
||||
#include <json/json.h>
|
||||
#include <memory>
|
||||
@@ -41,14 +40,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);
|
||||
|
||||
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
|
||||
|
||||
Json::CharReader* reader(builder.newCharReader());
|
||||
Json::Value root;
|
||||
const auto data_str = reinterpret_cast<const char*>(data);
|
||||
const char* data_str = reinterpret_cast<const char*>(data);
|
||||
try {
|
||||
reader->parse(data_str, data_str + size, &root, nullptr);
|
||||
reader->parse(data_str, data_str + size, &root, JSONCPP_NULL);
|
||||
} catch (Json::Exception const&) {
|
||||
}
|
||||
delete reader;
|
||||
// Whether it succeeded or not doesn't matter.
|
||||
return 0;
|
||||
}
|
||||
|
@@ -73,10 +73,11 @@ namespace JsonTest {
|
||||
// class TestResult
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
TestResult::TestResult() {
|
||||
TestResult::TestResult()
|
||||
: predicateId_(1), lastUsedPredicateId_(0), messageTarget_(JSONCPP_NULL) {
|
||||
// The root predicate has id 0
|
||||
rootPredicateNode_.id_ = 0;
|
||||
rootPredicateNode_.next_ = nullptr;
|
||||
rootPredicateNode_.next_ = JSONCPP_NULL;
|
||||
predicateStackTail_ = &rootPredicateNode_;
|
||||
}
|
||||
|
||||
@@ -88,7 +89,7 @@ TestResult& TestResult::addFailure(const char* file, unsigned int line,
|
||||
/// added.
|
||||
unsigned int nestingLevel = 0;
|
||||
PredicateContext* lastNode = rootPredicateNode_.next_;
|
||||
for (; lastNode != nullptr; lastNode = lastNode->next_) {
|
||||
for (; lastNode != JSONCPP_NULL; lastNode = lastNode->next_) {
|
||||
if (lastNode->id_ > lastUsedPredicateId_) // new PredicateContext
|
||||
{
|
||||
lastUsedPredicateId_ = lastNode->id_;
|
||||
@@ -121,17 +122,18 @@ void TestResult::addFailureInfo(const char* file, unsigned int line,
|
||||
|
||||
TestResult& TestResult::popPredicateContext() {
|
||||
PredicateContext* lastNode = &rootPredicateNode_;
|
||||
while (lastNode->next_ != nullptr && lastNode->next_->next_ != nullptr) {
|
||||
while (lastNode->next_ != JSONCPP_NULL &&
|
||||
lastNode->next_->next_ != JSONCPP_NULL) {
|
||||
lastNode = lastNode->next_;
|
||||
}
|
||||
// Set message target to popped failure
|
||||
PredicateContext* tail = lastNode->next_;
|
||||
if (tail != nullptr && tail->failure_ != nullptr) {
|
||||
if (tail != JSONCPP_NULL && tail->failure_ != JSONCPP_NULL) {
|
||||
messageTarget_ = tail->failure_;
|
||||
}
|
||||
// Remove tail from list
|
||||
predicateStackTail_ = lastNode;
|
||||
lastNode->next_ = nullptr;
|
||||
lastNode->next_ = JSONCPP_NULL;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -147,7 +149,9 @@ void TestResult::printFailure(bool printTestName) const {
|
||||
}
|
||||
|
||||
// Print in reverse to display the callstack in the right order
|
||||
for (const auto& failure : failures_) {
|
||||
for (Failures::const_iterator it = failures_.begin(); it != failures_.end();
|
||||
++it) {
|
||||
const Failure& failure = *it;
|
||||
Json::String indent(failure.nestingLevel_ * 2, ' ');
|
||||
if (failure.file_) {
|
||||
printf("%s%s(%u): ", indent.c_str(), failure.file_, failure.line_);
|
||||
@@ -181,7 +185,7 @@ Json::String TestResult::indentText(const Json::String& text,
|
||||
}
|
||||
|
||||
TestResult& TestResult::addToLastFailure(const Json::String& message) {
|
||||
if (messageTarget_ != nullptr) {
|
||||
if (messageTarget_ != JSONCPP_NULL) {
|
||||
messageTarget_->message_ += message;
|
||||
}
|
||||
return *this;
|
||||
@@ -202,9 +206,9 @@ TestResult& TestResult::operator<<(bool value) {
|
||||
// class TestCase
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
TestCase::TestCase() = default;
|
||||
TestCase::TestCase() : result_(JSONCPP_NULL) {}
|
||||
|
||||
TestCase::~TestCase() = default;
|
||||
TestCase::~TestCase() {}
|
||||
|
||||
void TestCase::run(TestResult& result) {
|
||||
result_ = &result;
|
||||
@@ -214,7 +218,7 @@ void TestCase::run(TestResult& result) {
|
||||
// class Runner
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
Runner::Runner() = default;
|
||||
Runner::Runner() {}
|
||||
|
||||
Runner& Runner::add(TestCaseFactory factory) {
|
||||
tests_.push_back(factory);
|
||||
@@ -268,7 +272,8 @@ bool Runner::runAllTest(bool printSummary) const {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
for (auto& result : failures) {
|
||||
for (size_t index = 0; index < failures.size(); ++index) {
|
||||
TestResult& result = failures[index];
|
||||
result.printFailure(count > 1);
|
||||
}
|
||||
|
||||
@@ -410,7 +415,7 @@ Json::String ToJsonString(const char* toConvert) {
|
||||
|
||||
Json::String ToJsonString(Json::String in) { return in; }
|
||||
|
||||
#if JSONCPP_USE_SECURE_MEMORY
|
||||
#if JSONCPP_USING_SECURE_MEMORY
|
||||
Json::String ToJsonString(std::string in) {
|
||||
return Json::String(in.data(), in.data() + in.length());
|
||||
}
|
||||
|
@@ -42,7 +42,7 @@ public:
|
||||
/// Must be a POD to allow inline initialisation without stepping
|
||||
/// into the debugger.
|
||||
struct PredicateContext {
|
||||
using Id = unsigned int;
|
||||
typedef unsigned int Id;
|
||||
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_{1};
|
||||
PredicateContext::Id predicateId_;
|
||||
|
||||
/// \internal Implementation detail for predicate macros
|
||||
PredicateContext* predicateStackTail_;
|
||||
@@ -70,11 +70,11 @@ public:
|
||||
|
||||
/// Adds an assertion failure.
|
||||
TestResult& addFailure(const char* file, unsigned int line,
|
||||
const char* expr = nullptr);
|
||||
const char* expr = JSONCPP_NULL);
|
||||
|
||||
/// Removes the last PredicateContext added to the predicate stack
|
||||
/// chained list.
|
||||
/// Next messages will be targeted at the PredicateContext that was removed.
|
||||
/// Next messages will be targed at the PredicateContext that was removed.
|
||||
TestResult& popPredicateContext();
|
||||
|
||||
bool failed() const;
|
||||
@@ -84,7 +84,9 @@ public:
|
||||
// Generic operator that will work with anything ostream can deal with.
|
||||
template <typename T> TestResult& operator<<(const T& value) {
|
||||
Json::OStringStream oss;
|
||||
oss << std::setprecision(16) << std::hexfloat << value;
|
||||
oss.precision(16);
|
||||
oss.setf(std::ios_base::floatfield);
|
||||
oss << value;
|
||||
return addToLastFailure(oss.str());
|
||||
}
|
||||
|
||||
@@ -102,13 +104,13 @@ private:
|
||||
static Json::String indentText(const Json::String& text,
|
||||
const Json::String& indent);
|
||||
|
||||
using Failures = std::deque<Failure>;
|
||||
typedef std::deque<Failure> Failures;
|
||||
Failures failures_;
|
||||
Json::String name_;
|
||||
PredicateContext rootPredicateNode_;
|
||||
PredicateContext::Id lastUsedPredicateId_{0};
|
||||
PredicateContext::Id lastUsedPredicateId_;
|
||||
/// Failure which is the target of the messages added using operator <<
|
||||
Failure* messageTarget_{nullptr};
|
||||
Failure* messageTarget_;
|
||||
};
|
||||
|
||||
class TestCase {
|
||||
@@ -122,14 +124,14 @@ public:
|
||||
virtual const char* testName() const = 0;
|
||||
|
||||
protected:
|
||||
TestResult* result_{nullptr};
|
||||
TestResult* result_;
|
||||
|
||||
private:
|
||||
virtual void runTestCase() = 0;
|
||||
};
|
||||
|
||||
/// Function pointer type for TestCase factory
|
||||
using TestCaseFactory = TestCase* (*)();
|
||||
typedef TestCase* (*TestCaseFactory)();
|
||||
|
||||
class Runner {
|
||||
public:
|
||||
@@ -159,8 +161,8 @@ public:
|
||||
static void printUsage(const char* appName);
|
||||
|
||||
private: // prevents copy construction and assignment
|
||||
Runner(const Runner& other) = delete;
|
||||
Runner& operator=(const Runner& other) = delete;
|
||||
Runner(const Runner& other) JSONCPP_CTOR_DELETE;
|
||||
Runner& operator=(const Runner& other) JSONCPP_CTOR_DELETE;
|
||||
|
||||
private:
|
||||
void listTests() const;
|
||||
@@ -168,7 +170,7 @@ private:
|
||||
static void preventDialogOnCrash();
|
||||
|
||||
private:
|
||||
using Factories = std::deque<TestCaseFactory>;
|
||||
typedef std::deque<TestCaseFactory> Factories;
|
||||
Factories tests_;
|
||||
};
|
||||
|
||||
@@ -185,7 +187,7 @@ TestResult& checkEqual(TestResult& result, T expected, U actual,
|
||||
|
||||
Json::String ToJsonString(const char* toConvert);
|
||||
Json::String ToJsonString(Json::String in);
|
||||
#if JSONCPP_USE_SECURE_MEMORY
|
||||
#if JSONCPP_USING_SECURE_MEMORY
|
||||
Json::String ToJsonString(std::string in);
|
||||
#endif
|
||||
|
||||
@@ -251,8 +253,10 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected,
|
||||
} \
|
||||
\
|
||||
public: /* overridden from TestCase */ \
|
||||
const char* testName() const override { return #FixtureType "/" #name; } \
|
||||
void runTestCase() override; \
|
||||
const char* testName() const JSONCPP_OVERRIDE { \
|
||||
return #FixtureType "/" #name; \
|
||||
} \
|
||||
void runTestCase() JSONCPP_OVERRIDE; \
|
||||
}; \
|
||||
\
|
||||
void Test##FixtureType##name::runTestCase()
|
||||
@@ -276,8 +280,10 @@ TestResult& checkStringEqual(TestResult& result, const Json::String& expected,
|
||||
} \
|
||||
\
|
||||
public: /* overridden from TestCase */ \
|
||||
const char* testName() const override { return #FixtureType "/" #name; } \
|
||||
void runTestCase() override; \
|
||||
const char* testName() const JSONCPP_OVERRIDE { \
|
||||
return #FixtureType "/" #name; \
|
||||
} \
|
||||
void runTestCase() JSONCPP_OVERRIDE; \
|
||||
}; \
|
||||
\
|
||||
static bool test##FixtureType##name##collect = \
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
{'//this is bad JSON.'}
|
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"a": "aaa",
|
||||
"b": "bbb" // comments not allowed in strict mode
|
||||
}
|
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"a": "aaa", // comments not allowed in strict mode
|
||||
"b": "bbb"
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"array" : [1, 2, 3 /* comments not allowed in strict mode */]
|
||||
}
|
@@ -1 +0,0 @@
|
||||
{"one": 1 /* } */ { "two" : 2 }
|
@@ -1,3 +0,0 @@
|
||||
.=[]
|
||||
.[0]=-inf
|
||||
.[1]=inf
|
@@ -1 +0,0 @@
|
||||
[-1e+9999, 1e+9999]
|
@@ -97,17 +97,14 @@ def runAllTests(jsontest_executable_path, input_dir = None,
|
||||
valgrind_path = use_valgrind and VALGRIND_CMD or ''
|
||||
for input_path in tests + test_jsonchecker:
|
||||
expect_failure = os.path.basename(input_path).startswith('fail')
|
||||
is_json_checker_test = input_path in test_jsonchecker
|
||||
is_parse_only = is_json_checker_test or expect_failure
|
||||
is_strict_test = ('_strict_' in os.path.basename(input_path)) or is_json_checker_test
|
||||
is_json_checker_test = (input_path in test_jsonchecker) or expect_failure
|
||||
print('TESTING:', input_path, end=' ')
|
||||
options = is_parse_only and '--parse-only' or ''
|
||||
options += is_strict_test and ' --strict' or ''
|
||||
options = is_json_checker_test and '--json-checker' or ''
|
||||
options += ' --json-writer %s'%writerClass
|
||||
cmd = '%s%s %s "%s"' % ( valgrind_path, jsontest_executable_path, options,
|
||||
input_path)
|
||||
status, process_output = getStatusOutput(cmd)
|
||||
if is_parse_only:
|
||||
if is_json_checker_test:
|
||||
if expect_failure:
|
||||
if not status:
|
||||
print('FAILED')
|
||||
|
Reference in New Issue
Block a user