Compare commits

..

No commits in common. "master" and "1.9.4" have entirely different histories.

71 changed files with 1081 additions and 1161 deletions

View File

@ -1,4 +1,4 @@
BasedOnStyle: LLVM BasedOnStyle: LLVM
DerivePointerAlignment: false DerivePointerAlignment: false
PointerAlignment: Left PointerAlignment: Left
SpacesBeforeTrailingComments: 1

View File

@ -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 }}

View File

@ -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

View File

@ -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 }}

5
.gitignore vendored
View File

@ -10,7 +10,6 @@
/libs/ /libs/
/doc/doxyfile /doc/doxyfile
/dist/ /dist/
/.cache/
# MSVC project files: # MSVC project files:
*.sln *.sln
@ -31,7 +30,6 @@
CMakeFiles/ CMakeFiles/
/pkg-config/jsoncpp.pc /pkg-config/jsoncpp.pc
jsoncpp_lib_static.dir/ jsoncpp_lib_static.dir/
compile_commands.json
# In case someone runs cmake in the root-dir: # In case someone runs cmake in the root-dir:
/CMakeCache.txt /CMakeCache.txt
@ -52,6 +50,3 @@ compile_commands.json
# DS_Store # DS_Store
.DS_Store .DS_Store
# temps
/version

71
.travis.yml Normal file
View File

@ -0,0 +1,71 @@
# 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
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
# 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 cmake 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
before_install:
- pip install --user cpp-coveralls
script: ./.travis_scripts/cmake_builder.sh
after_success:
- coveralls --include src/lib_json --include include
notifications:
email: false

130
.travis_scripts/cmake_builder.sh Executable file
View File

@ -0,0 +1,130 @@
#!/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 [ "${LIB_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
_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} \
../
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

View File

@ -0,0 +1,83 @@
#!/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}"
./.travis_scripts/run-clang-format.sh
meson --fatal-meson-warnings --werror --buildtype ${BUILD_TYPE} --default-library ${LIB_TYPE} . "${_BUILD_DIR_NAME}"
ninja -v -j 2 -C "${_BUILD_DIR_NAME}"
cd "${_BUILD_DIR_NAME}"
meson 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

View 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())

View 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/**/

View 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

View File

@ -0,0 +1 @@
# NOTHING TO DO HERE

View 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}

View File

@ -0,0 +1 @@
# NOTHING TO DO HERE

View File

@ -16,7 +16,7 @@ Baruch Siach <baruch@tkos.co.il>
Ben Boeckel <mathstuf@gmail.com> Ben Boeckel <mathstuf@gmail.com>
Benjamin Knecht <bknecht@logitech.com> Benjamin Knecht <bknecht@logitech.com>
Bernd Kuhls <bernd.kuhls@t-online.de> Bernd Kuhls <bernd.kuhls@t-online.de>
Billy Donahue <billy.donahue@gmail.com> Billy Donahue <billydonahue@google.com>
Braden McDorman <bmcdorman@gmail.com> Braden McDorman <bmcdorman@gmail.com>
Brandon Myers <bmyers1788@gmail.com> Brandon Myers <bmyers1788@gmail.com>
Brendan Drew <brendan.drew@daqri.com> Brendan Drew <brendan.drew@daqri.com>

View File

@ -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"],
)

View File

@ -6,7 +6,7 @@
# policies that provide successful builds. By setting JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION # policies that provide successful builds. By setting JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION
# to a value greater than the oldest policies, all policies between # to a value greater than the oldest policies, all policies between
# JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION and CMAKE_VERSION (used for this build) # 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. # between the JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION and CMAKE_VERSION.
# #
# CMake versions greater than the JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION policies will # 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}") set(JSONCPP_CMAKE_POLICY_VERSION "${JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION}")
endif() endif()
cmake_policy(VERSION ${JSONCPP_CMAKE_POLICY_VERSION}) 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 # Now enumerate specific policies newer than JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION
# that may need to be individually set to NEW/OLD # that may need to be individually set to NEW/OLD
@ -54,6 +51,16 @@ endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 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()
project(jsoncpp project(jsoncpp
# Note: version must be updated in three places when doing a release. This # Note: version must be updated in three places when doing a release. This
# annoying process ensures that amalgamate, CMake, and meson all report the # annoying process ensures that amalgamate, CMake, and meson all report the
@ -62,14 +69,11 @@ project(jsoncpp
# 2. ./include/json/version.h # 2. ./include/json/version.h
# 3. ./CMakeLists.txt # 3. ./CMakeLists.txt
# IMPORTANT: also update the PROJECT_SOVERSION!! # IMPORTANT: also update the PROJECT_SOVERSION!!
VERSION 1.9.7 # <major>[.<minor>[.<patch>[.<tweak>]]] VERSION 1.9.4 # <major>[.<minor>[.<patch>[.<tweak>]]]
LANGUAGES CXX) LANGUAGES CXX)
message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
set(PROJECT_SOVERSION 27) set(PROJECT_SOVERSION 24)
include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInSourceBuilds.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/include/PreventInBuildInstalls.cmake)
option(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" ON) option(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" ON)
option(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON) option(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON)
@ -78,7 +82,6 @@ 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_PKGCONFIG_SUPPORT "Generate and install .pc files" ON)
option(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" ON) option(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" ON)
option(JSONCPP_WITH_EXAMPLE "Compile JsonCpp example" OFF) option(JSONCPP_WITH_EXAMPLE "Compile JsonCpp example" OFF)
option(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_SHARED_LIBS "Build jsoncpp_lib as a shared library." ON)
option(BUILD_STATIC_LIBS "Build jsoncpp_lib as a static 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_OBJECT_LIBS "Build jsoncpp_lib as a object library." ON)
@ -86,22 +89,12 @@ option(BUILD_OBJECT_LIBS "Build jsoncpp_lib as a object library." ON)
# Adhere to GNU filesystem layout conventions # Adhere to GNU filesystem layout conventions
include(GNUInstallDirs) 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_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_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_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.")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Executable/dll output dir.")
endif()
include(CheckFunctionExists) set(JSONCPP_USE_SECURE_MEMORY "0" CACHE STRING "-D...=1 to use memory-wiping allocator for STL")
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()
configure_file("${PROJECT_SOURCE_DIR}/version.in" configure_file("${PROJECT_SOURCE_DIR}/version.in"
"${PROJECT_BINARY_DIR}/version" "${PROJECT_BINARY_DIR}/version"
@ -127,18 +120,11 @@ if(MSVC)
# Only enabled in debug because some old versions of VS STL generate # Only enabled in debug because some old versions of VS STL generate
# unreachable code warning when compiled in release configuration. # unreachable code warning when compiled in release configuration.
add_compile_options($<$<CONFIG:Debug>:/W4>) add_compile_options($<$<CONFIG:Debug>:/W4>)
if (JSONCPP_STATIC_WINDOWS_RUNTIME)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
endif() endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# using regular Clang or AppleClang # using regular Clang or AppleClang
add_compile_options(-Wall -Wconversion -Wshadow) add_compile_options(-Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare)
if(JSONCPP_WITH_WARNING_AS_ERROR)
add_compile_options(-Werror=conversion -Werror=sign-compare)
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# using GCC # using GCC
add_compile_options(-Wall -Wconversion -Wshadow -Wextra) add_compile_options(-Wall -Wconversion -Wshadow -Wextra)
@ -152,11 +138,9 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
endif() endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
# using Intel compiler # 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) if(JSONCPP_WITH_STRICT_ISO AND NOT JSONCPP_WITH_WARNING_AS_ERROR)
add_compile_options(-Werror=conversion)
elseif(JSONCPP_WITH_STRICT_ISO)
add_compile_options(-Wpedantic) add_compile_options(-Wpedantic)
endif() endif()
endif() endif()
@ -183,16 +167,11 @@ if(JSONCPP_WITH_CMAKE_PACKAGE)
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
install(EXPORT jsoncpp install(EXPORT jsoncpp
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp
FILE jsoncpp-targets.cmake) FILE jsoncppConfig.cmake)
configure_package_config_file(jsoncppConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp)
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake" write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake"
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion) COMPATIBILITY SameMajorVersion)
install(FILES install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake
${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfig.cmake
${CMAKE_CURRENT_SOURCE_DIR}/jsoncpp-namespaced-targets.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp) DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp)
endif() endif()

View File

@ -19,7 +19,7 @@ If you wish to install to a directory other than /usr/local, set an environment
DESTDIR=/path/to/install/dir DESTDIR=/path/to/install/dir
Then, Then,
```sh
cd jsoncpp/ cd jsoncpp/
BUILD_TYPE=debug BUILD_TYPE=debug
#BUILD_TYPE=release #BUILD_TYPE=release
@ -35,7 +35,6 @@ Then,
#meson test --no-rebuild --print-errorlogs #meson test --no-rebuild --print-errorlogs
sudo ninja install sudo ninja install
```
## Building and testing with other build systems ## Building and testing with other build systems
See https://github.com/open-source-parsers/jsoncpp/wiki/Building 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: 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.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. input document.
The `TESTNAME.expected` file format is as follows: 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: 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 ninja -v -C build-${LIB_TYPE}/ clang-format
``` ```
For convenience, you can also run the `reformat.sh` script located in the root directory.

View File

@ -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.

View File

@ -63,7 +63,7 @@ def amalgamate_source(source_top_dir=None,
""" """
print("Amalgamating header...") print("Amalgamating header...")
header = AmalgamationFile(source_top_dir) 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_text('/// It is intended to be used with #include "%s"' % header_include_path)
header.add_file("LICENSE", wrap_in_comment=True) header.add_file("LICENSE", wrap_in_comment=True)
header.add_text("#ifndef JSON_AMALGAMATED_H_INCLUDED") 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 forward_header_include_path = base + "-forwards" + ext
print("Amalgamating forward header...") print("Amalgamating forward header...")
header = AmalgamationFile(source_top_dir) 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('/// 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_text("/// This header provides forward declaration for all JsonCpp types.")
header.add_file("LICENSE", wrap_in_comment=True) header.add_file("LICENSE", wrap_in_comment=True)
@ -112,7 +112,7 @@ def amalgamate_source(source_top_dir=None,
print("Amalgamating source...") print("Amalgamating source...")
source = AmalgamationFile(source_top_dir) 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_text('/// It is intended to be used with #include "%s"' % header_include_path)
source.add_file("LICENSE", wrap_in_comment=True) source.add_file("LICENSE", wrap_in_comment=True)
source.add_text("") source.add_text("")

View File

@ -1,7 +1,6 @@
clone_folder: c:\projects\jsoncpp clone_folder: c:\projects\jsoncpp
environment: environment:
matrix: matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
CMAKE_GENERATOR: Visual Studio 14 2015 CMAKE_GENERATOR: Visual Studio 14 2015
@ -14,15 +13,11 @@ environment:
build_script: build_script:
- cmake --version - cmake --version
# The build script starts in root. - cd c:\projects\jsoncpp
- set JSONCPP_FOLDER=%cd% - cmake -G "%CMAKE_GENERATOR%" -DCMAKE_INSTALL_PREFIX:PATH=%CD:\=/%/install -DBUILD_SHARED_LIBS:BOOL=ON .
- set JSONCPP_BUILD_FOLDER=%JSONCPP_FOLDER%\build\release
- mkdir -p %JSONCPP_BUILD_FOLDER%
- cd %JSONCPP_BUILD_FOLDER%
- cmake -G "%CMAKE_GENERATOR%" -DCMAKE_INSTALL_PREFIX:PATH=%CD:\=/%/install -DBUILD_SHARED_LIBS:BOOL=ON %JSONCPP_FOLDER%
# Use ctest to make a dashboard build: # Use ctest to make a dashboard build:
# - ctest -D Experimental(Start|Update|Configure|Build|Test|Coverage|MemCheck|Submit) # - 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 ExperimentalTest -D ExperimentalSubmit
- ctest -C Release -D ExperimentalStart -D ExperimentalConfigure -D ExperimentalBuild -D ExperimentalSubmit - ctest -C Release -D ExperimentalStart -D ExperimentalConfigure -D ExperimentalBuild -D ExperimentalSubmit
# Final step is to verify that installation succeeds # Final step is to verify that installation succeeds

View File

@ -1,11 +1,9 @@
# This is only for jsoncpp developers/contributors. # This is only for jsoncpp developers/contributors.
# We use this to sign releases, generate documentation, etc. # We use this to sign releases, generate documentation, etc.
VER?=$(shell cat version) VER?=$(shell cat version.txt)
default: default:
@echo "VER=${VER}" @echo "VER=${VER}"
update-version:
perl get_version.pl meson.build >| version
sign: jsoncpp-${VER}.tar.gz sign: jsoncpp-${VER}.tar.gz
gpg --armor --detach-sign $< gpg --armor --detach-sign $<
gpg --verify $<.asc gpg --verify $<.asc

View File

@ -9,7 +9,7 @@ import shutil
import string import string
import subprocess import subprocess
import sys import sys
import html import cgi
class BuildDesc: class BuildDesc:
def __init__(self, prepend_envs=None, variables=None, build_type=None, generator=None): 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: for variable in variables:
build_types = sorted(build_types_by_variable[variable]) build_types = sorted(build_types_by_variable[variable])
nb_build_type = len(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: 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 = [] tr_builds = []
for generator in sorted(builds_by_generator): 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: for variable in variables:
build_types = sorted(build_types_by_variable[variable]) build_types = sorted(build_types_by_variable[variable])
for build_type in build_types: for build_type in build_types:

View File

@ -1,6 +1,5 @@
#include "json/json.h" #include "json/json.h"
#include <iostream> #include <iostream>
#include <memory>
/** /**
* \brief Parse a raw string into Value object using the CharReaderBuilder * \brief Parse a raw string into Value object using the CharReaderBuilder
* class, or the legacy Reader class. * class, or the legacy Reader class.
@ -25,7 +24,7 @@ int main() {
const std::unique_ptr<Json::CharReader> reader(builder.newCharReader()); const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLength, &root, if (!reader->parse(rawJson.c_str(), rawJson.c_str() + rawJsonLength, &root,
&err)) { &err)) {
std::cout << "error: " << err << std::endl; std::cout << "error" << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }

View File

@ -1,6 +1,5 @@
#include "json/json.h" #include "json/json.h"
#include <iostream> #include <iostream>
#include <memory>
/** \brief Write the Value object to a stream. /** \brief Write the Value object to a stream.
* Example Usage: * Example Usage:
* $g++ streamWrite.cpp -ljsoncpp -std=c++11 -o streamWrite * $g++ streamWrite.cpp -ljsoncpp -std=c++11 -o streamWrite

View File

@ -1,5 +0,0 @@
while (<>) {
if (/version : '(.+)',/) {
print "$1";
}
}

View File

@ -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()

View File

@ -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()

View File

@ -6,12 +6,10 @@
#ifndef JSON_ALLOCATOR_H_INCLUDED #ifndef JSON_ALLOCATOR_H_INCLUDED
#define JSON_ALLOCATOR_H_INCLUDED #define JSON_ALLOCATOR_H_INCLUDED
#include <algorithm>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#pragma pack(push) #pragma pack(push, 8)
#pragma pack()
namespace Json { namespace Json {
template <typename T> class SecureAllocator { template <typename T> class SecureAllocator {
@ -37,18 +35,11 @@ public:
* Release memory which was allocated for N items at pointer P. * Release memory which was allocated for N items at pointer P.
* *
* The memory block is filled with zeroes before being released. * 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) { void deallocate(volatile pointer p, size_type n) {
// These constructs will not be removed by the compiler during optimization, std::memset(p, 0, n * sizeof(T));
// 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
// free using "global operator delete" // free using "global operator delete"
::operator delete(p); ::operator delete(p);
} }
@ -78,9 +69,7 @@ public:
// Boilerplate // Boilerplate
SecureAllocator() {} SecureAllocator() {}
template <typename U> SecureAllocator(const SecureAllocator<U>&) {} template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
template <typename U> struct rebind { template <typename U> struct rebind { using other = SecureAllocator<U>; };
using other = SecureAllocator<U>;
};
}; };
template <typename T, typename U> template <typename T, typename U>

View File

@ -127,7 +127,7 @@ using LargestUInt = UInt64;
template <typename T> template <typename T>
using Allocator = using Allocator =
typename std::conditional<JSONCPP_USE_SECURE_MEMORY, SecureAllocator<T>, typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>,
std::allocator<T>>::type; std::allocator<T>>::type;
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>; using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
using IStringStream = using IStringStream =

View File

@ -10,8 +10,7 @@
#include "forwards.h" #include "forwards.h"
#endif // if !defined(JSON_IS_AMALGAMATION) #endif // if !defined(JSON_IS_AMALGAMATION)
#pragma pack(push) #pragma pack(push, 8)
#pragma pack()
namespace Json { namespace Json {

View File

@ -23,8 +23,7 @@
#pragma warning(disable : 4251) #pragma warning(disable : 4251)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma pack(push) #pragma pack(push, 8)
#pragma pack()
namespace Json { namespace Json {
@ -34,7 +33,8 @@ namespace Json {
* \deprecated Use CharReader and CharReaderBuilder. * \deprecated Use CharReader and CharReaderBuilder.
*/ */
class JSON_API Reader { class JSONCPP_DEPRECATED(
"Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
public: public:
using Char = char; using Char = char;
using Location = const Char*; using Location = const Char*;
@ -51,13 +51,13 @@ public:
}; };
/** \brief Constructs a Reader allowing all features for parsing. /** \brief Constructs a Reader allowing all features for parsing.
* \deprecated Use CharReader and CharReaderBuilder.
*/ */
JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
Reader(); Reader();
/** \brief Constructs a Reader allowing the specified feature set for parsing. /** \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); Reader(const Features& features);
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
@ -190,7 +190,6 @@ private:
using Errors = std::deque<ErrorInfo>; using Errors = std::deque<ErrorInfo>;
bool readToken(Token& token); bool readToken(Token& token);
bool readTokenSkippingComments(Token& token);
void skipSpaces(); void skipSpaces();
bool match(const Char* pattern, int patternLength); bool match(const Char* pattern, int patternLength);
bool readComment(); bool readComment();
@ -222,6 +221,7 @@ private:
int& column) const; int& column) const;
String getLocationLineAndColumn(Location location) const; String getLocationLineAndColumn(Location location) const;
void addComment(Location begin, Location end, CommentPlacement placement); void addComment(Location begin, Location end, CommentPlacement placement);
void skipCommentTokens(Token& token);
static bool containsNewLine(Location begin, Location end); static bool containsNewLine(Location begin, Location end);
static String normalizeEOL(Location begin, Location end); static String normalizeEOL(Location begin, Location end);
@ -244,12 +244,6 @@ private:
*/ */
class JSON_API CharReader { class JSON_API CharReader {
public: public:
struct JSON_API StructuredError {
ptrdiff_t offset_start;
ptrdiff_t offset_limit;
String message;
};
virtual ~CharReader() = default; virtual ~CharReader() = default;
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
* document. The document must be a UTF-8 encoded string containing the * document. The document must be a UTF-8 encoded string containing the
@ -268,12 +262,7 @@ public:
* error occurred. * error occurred.
*/ */
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root, virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs); String* errs) = 0;
/** \brief Returns a vector of structured errors encountered while parsing.
* Each parse call resets the stored list of errors.
*/
std::vector<StructuredError> getStructuredErrors() const;
class JSON_API Factory { class JSON_API Factory {
public: public:
@ -283,21 +272,7 @@ public:
*/ */
virtual CharReader* newCharReader() const = 0; virtual CharReader* newCharReader() const = 0;
}; // Factory }; // Factory
}; // CharReader
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. /** \brief Build a CharReader implementation.
* *
@ -349,9 +324,6 @@ public:
* - `"allowSpecialFloats": false or true` * - `"allowSpecialFloats": false or true`
* - If true, special float values (NaNs and infinities) are allowed and * - If true, special float values (NaNs and infinities) are allowed and
* their values are lossfree restorable. * 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 * You can examine 'settings_` yourself to see the defaults. You can also
* write and read them just like any JSON Value. * write and read them just like any JSON Value.
@ -385,12 +357,6 @@ public:
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
*/ */
static void strictMode(Json::Value* settings); 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. /** Consume entire stream and use its begin/end.

View File

@ -3,8 +3,8 @@
// recognized in your jurisdiction. // recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_VALUE_H_INCLUDED #ifndef JSON_H_INCLUDED
#define JSON_VALUE_H_INCLUDED #define JSON_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION) #if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h" #include "forwards.h"
@ -39,10 +39,6 @@
#endif #endif
#endif #endif
#if __cplusplus >= 201703L
#define JSONCPP_HAS_STRING_VIEW 1
#endif
#include <array> #include <array>
#include <exception> #include <exception>
#include <map> #include <map>
@ -50,19 +46,14 @@
#include <string> #include <string>
#include <vector> #include <vector>
#ifdef JSONCPP_HAS_STRING_VIEW
#include <string_view>
#endif
// Disable warning C4251: <data member>: <type> needs to have dll-interface to // Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by... // be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4251 4275) #pragma warning(disable : 4251)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma pack(push) #pragma pack(push, 8)
#pragma pack()
/** \brief JSON (JavaScript Object Notation). /** \brief JSON (JavaScript Object Notation).
*/ */
@ -272,10 +263,10 @@ private:
CZString(ArrayIndex index); CZString(ArrayIndex index);
CZString(char const* str, unsigned length, DuplicationPolicy allocate); CZString(char const* str, unsigned length, DuplicationPolicy allocate);
CZString(CZString const& other); CZString(CZString const& other);
CZString(CZString&& other) noexcept; CZString(CZString&& other);
~CZString(); ~CZString();
CZString& operator=(const CZString& other); CZString& operator=(const CZString& other);
CZString& operator=(CZString&& other) noexcept; CZString& operator=(CZString&& other);
bool operator<(CZString const& other) const; bool operator<(CZString const& other) const;
bool operator==(CZString const& other) const; bool operator==(CZString const& other) const;
@ -350,19 +341,16 @@ public:
*/ */
Value(const StaticString& value); Value(const StaticString& value);
Value(const String& value); Value(const String& value);
#ifdef JSONCPP_HAS_STRING_VIEW
Value(std::string_view value);
#endif
Value(bool value); Value(bool value);
Value(std::nullptr_t ptr) = delete; Value(std::nullptr_t ptr) = delete;
Value(const Value& other); Value(const Value& other);
Value(Value&& other) noexcept; Value(Value&& other);
~Value(); ~Value();
/// \note Overwrite existing comments. To preserve comments, use /// \note Overwrite existing comments. To preserve comments, use
/// #swapPayload(). /// #swapPayload().
Value& operator=(const Value& other); Value& operator=(const Value& other);
Value& operator=(Value&& other) noexcept; Value& operator=(Value&& other);
/// Swap everything. /// Swap everything.
void swap(Value& other); void swap(Value& other);
@ -386,7 +374,7 @@ public:
int compare(const Value& other) const; int compare(const Value& other) const;
const char* asCString() const; ///< Embedded zeroes could cause you trouble! 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 unsigned getCStringLength() const; // Allows you to understand the length of
// the CString // the CString
#endif #endif
@ -395,12 +383,6 @@ public:
* \return false if !string. (Seg-fault if str or end are NULL.) * \return false if !string. (Seg-fault if str or end are NULL.)
*/ */
bool getString(char const** begin, char const** end) const; bool getString(char const** begin, char const** end) const;
#ifdef JSONCPP_HAS_STRING_VIEW
/** Get string_view of string-value.
* \return false if !string. (Seg-fault if str is NULL.)
*/
bool getString(std::string_view* str) const;
#endif
Int asInt() const; Int asInt() const;
UInt asUInt() const; UInt asUInt() const;
#if defined(JSON_HAS_INT64) #if defined(JSON_HAS_INT64)
@ -454,7 +436,7 @@ public:
/// \post type() is arrayValue /// \post type() is arrayValue
void resize(ArrayIndex newSize); void resize(ArrayIndex newSize);
///@{ //@{
/// Access an array element (zero based index). If the array contains less /// 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 /// than index element, then null value are inserted in the array so that
/// its size is index+1. /// its size is index+1.
@ -462,15 +444,15 @@ public:
/// this from the operator[] which takes a string.) /// this from the operator[] which takes a string.)
Value& operator[](ArrayIndex index); Value& operator[](ArrayIndex index);
Value& operator[](int index); Value& operator[](int index);
///@} //@}
///@{ //@{
/// Access an array element (zero based index). /// Access an array element (zero based index).
/// (You may need to say 'value[0u]' to get your compiler to distinguish /// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.) /// this from the operator[] which takes a string.)
const Value& operator[](ArrayIndex index) const; const Value& operator[](ArrayIndex index) const;
const Value& operator[](int index) const; const Value& operator[](int index) const;
///@} //@}
/// If the array contains at least index+1 elements, returns the element /// If the array contains at least index+1 elements, returns the element
/// value, otherwise returns defaultValue. /// value, otherwise returns defaultValue.
@ -487,15 +469,6 @@ public:
bool insert(ArrayIndex index, const Value& newValue); bool insert(ArrayIndex index, const Value& newValue);
bool insert(ArrayIndex index, Value&& newValue); bool insert(ArrayIndex index, Value&& newValue);
#ifdef JSONCPP_HAS_STRING_VIEW
/// Access an object value by name, create a null member if it does not exist.
/// \param key may contain embedded nulls.
Value& operator[](std::string_view key);
/// Access an object value by name, returns null if there is no member with
/// that name.
/// \param key may contain embedded nulls.
const Value& operator[](std::string_view key) const;
#else
/// Access an object value by name, create a null member if it does not exist. /// Access an object value by name, create a null member if it does not exist.
/// \note Because of our implementation, keys are limited to 2^30 -1 chars. /// \note Because of our implementation, keys are limited to 2^30 -1 chars.
/// Exceeding that will cause an exception. /// Exceeding that will cause an exception.
@ -510,7 +483,6 @@ public:
/// that name. /// that name.
/// \param key may contain embedded nulls. /// \param key may contain embedded nulls.
const Value& operator[](const String& key) const; const Value& operator[](const String& key) const;
#endif
/** \brief Access an object value by name, create a null member if it does not /** \brief Access an object value by name, create a null member if it does not
* exist. * exist.
* *
@ -524,54 +496,22 @@ public:
* \endcode * \endcode
*/ */
Value& operator[](const StaticString& key); Value& operator[](const StaticString& key);
#ifdef JSONCPP_HAS_STRING_VIEW
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
Value get(std::string_view key, const Value& defaultValue) const;
#else
/// Return the member named key if it exist, defaultValue otherwise. /// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy /// \note deep copy
Value get(const char* key, const Value& defaultValue) const; Value get(const char* key, const Value& defaultValue) const;
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
/// \param key may contain embedded nulls.
Value get(const String& key, const Value& defaultValue) const;
#endif
/// Return the member named key if it exist, defaultValue otherwise. /// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy /// \note deep copy
/// \note key may contain embedded nulls. /// \note key may contain embedded nulls.
Value get(const char* begin, const char* end, Value get(const char* begin, const char* end,
const Value& defaultValue) const; const Value& defaultValue) const;
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
/// \param key may contain embedded nulls.
Value get(const String& key, const Value& defaultValue) const;
/// Most general and efficient version of isMember()const, get()const, /// Most general and efficient version of isMember()const, get()const,
/// and operator[]const /// and operator[]const
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
Value const* find(char const* begin, char const* end) const; 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;
/// Calls find and only returns a valid pointer if the type is found
template <typename T, bool (T::*TMemFn)() const>
Value const* findValue(const String& key) const {
Value const* found = find(key);
if (!found || !(found->*TMemFn)())
return nullptr;
return found;
}
Value const* findNull(const String& key) const;
Value const* findBool(const String& key) const;
Value const* findInt(const String& key) const;
Value const* findInt64(const String& key) const;
Value const* findUInt(const String& key) const;
Value const* findUInt64(const String& key) const;
Value const* findIntegral(const String& key) const;
Value const* findDouble(const String& key) const;
Value const* findNumeric(const String& key) const;
Value const* findString(const String& key) const;
Value const* findArray(const String& key) const;
Value const* findObject(const String& key) const;
/// Most general and efficient version of object-mutators. /// Most general and efficient version of object-mutators.
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 /// \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. /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
@ -581,28 +521,20 @@ public:
/// Do nothing if it did not exist. /// Do nothing if it did not exist.
/// \pre type() is objectValue or nullValue /// \pre type() is objectValue or nullValue
/// \post type() is unchanged /// \post type() is unchanged
#if JSONCPP_HAS_STRING_VIEW
void removeMember(std::string_view key);
#else
void removeMember(const char* key); void removeMember(const char* key);
/// Same as removeMember(const char*) /// Same as removeMember(const char*)
/// \param key may contain embedded nulls. /// \param key may contain embedded nulls.
void removeMember(const String& key); void removeMember(const String& key);
#endif /// Same as removeMember(const char* begin, const char* end, Value* removed),
/// but 'key' is null-terminated.
bool removeMember(const char* key, Value* removed);
/** \brief Remove the named map member. /** \brief Remove the named map member.
* *
* Update 'removed' iff removed. * Update 'removed' iff removed.
* \param key may contain embedded nulls. * \param key may contain embedded nulls.
* \return true iff removed (no exceptions) * \return true iff removed (no exceptions)
*/ */
#if JSONCPP_HAS_STRING_VIEW
bool removeMember(std::string_view key, Value* removed);
#else
bool removeMember(String const& key, Value* removed); bool removeMember(String const& key, Value* removed);
/// Same as removeMember(const char* begin, const char* end, Value* removed),
/// but 'key' is null-terminated.
bool removeMember(const char* key, Value* removed);
#endif
/// Same as removeMember(String const& key, Value* removed) /// Same as removeMember(String const& key, Value* removed)
bool removeMember(const char* begin, const char* end, Value* removed); bool removeMember(const char* begin, const char* end, Value* removed);
/** \brief Remove the indexed array element. /** \brief Remove the indexed array element.
@ -613,18 +545,12 @@ public:
*/ */
bool removeIndex(ArrayIndex index, Value* removed); bool removeIndex(ArrayIndex index, Value* removed);
#ifdef JSONCPP_HAS_STRING_VIEW
/// Return true if the object has a member named key.
/// \param key may contain embedded nulls.
bool isMember(std::string_view key) const;
#else
/// Return true if the object has a member named key. /// Return true if the object has a member named key.
/// \note 'key' must be null-terminated. /// \note 'key' must be null-terminated.
bool isMember(const char* key) const; bool isMember(const char* key) const;
/// Return true if the object has a member named key. /// Return true if the object has a member named key.
/// \param key may contain embedded nulls. /// \param key may contain embedded nulls.
bool isMember(const String& key) const; bool isMember(const String& key) const;
#endif
/// Same as isMember(String const& key)const /// Same as isMember(String const& key)const
bool isMember(const char* begin, const char* end) const; bool isMember(const char* begin, const char* end) const;
@ -658,26 +584,6 @@ public:
iterator begin(); iterator begin();
iterator end(); 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 // Accessors for the [start, limit) range of bytes within the JSON text from
// which this value was parsed, if any. // which this value was parsed, if any.
void setOffsetStart(ptrdiff_t start); void setOffsetStart(ptrdiff_t start);
@ -729,9 +635,9 @@ private:
public: public:
Comments() = default; Comments() = default;
Comments(const Comments& that); Comments(const Comments& that);
Comments(Comments&& that) noexcept; Comments(Comments&& that);
Comments& operator=(const Comments& that); Comments& operator=(const Comments& that);
Comments& operator=(Comments&& that) noexcept; Comments& operator=(Comments&& that);
bool has(CommentPlacement slot) const; bool has(CommentPlacement slot) const;
String get(CommentPlacement slot) const; String get(CommentPlacement slot) const;
void set(CommentPlacement slot, String comment); void set(CommentPlacement slot, String comment);
@ -1012,20 +918,12 @@ public:
* because the returned references/pointers can be used * because the returned references/pointers can be used
* to change state of the base class. * to change state of the base class.
*/ */
reference operator*() const { return const_cast<reference>(deref()); } reference operator*() { return deref(); }
pointer operator->() const { return const_cast<pointer>(&deref()); } pointer operator->() { return &deref(); }
}; };
inline void swap(Value& a, Value& b) { a.swap(b); } 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 } // namespace Json
#pragma pack(pop) #pragma pack(pop)

View File

@ -9,18 +9,19 @@
// 3. /CMakeLists.txt // 3. /CMakeLists.txt
// IMPORTANT: also update the SOVERSION!! // IMPORTANT: also update the SOVERSION!!
#define JSONCPP_VERSION_STRING "1.9.7" #define JSONCPP_VERSION_STRING "1.9.4"
#define JSONCPP_VERSION_MAJOR 1 #define JSONCPP_VERSION_MAJOR 1
#define JSONCPP_VERSION_MINOR 9 #define JSONCPP_VERSION_MINOR 9
#define JSONCPP_VERSION_PATCH 7 #define JSONCPP_VERSION_PATCH 3
#define JSONCPP_VERSION_QUALIFIER #define JSONCPP_VERSION_QUALIFIER
#define JSONCPP_VERSION_HEXA \ #define JSONCPP_VERSION_HEXA \
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
(JSONCPP_VERSION_PATCH << 8)) (JSONCPP_VERSION_PATCH << 8))
#if !defined(JSONCPP_USE_SECURE_MEMORY) #ifdef JSONCPP_USING_SECURE_MEMORY
#define JSONCPP_USE_SECURE_MEMORY 0 #undef JSONCPP_USING_SECURE_MEMORY
#endif #endif
#define JSONCPP_USING_SECURE_MEMORY 0
// If non-zero, the library zeroes any memory that it has allocated before // If non-zero, the library zeroes any memory that it has allocated before
// it frees its memory. // it frees its memory.

View File

@ -20,8 +20,7 @@
#pragma warning(disable : 4251) #pragma warning(disable : 4251)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) #endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma pack(push) #pragma pack(push, 8)
#pragma pack()
namespace Json { namespace Json {
@ -64,7 +63,7 @@ public:
*/ */
virtual StreamWriter* newStreamWriter() const = 0; virtual StreamWriter* newStreamWriter() const = 0;
}; // Factory }; // Factory
}; // StreamWriter }; // StreamWriter
/** \brief Write into stringstream, then return string, for convenience. /** \brief Write into stringstream, then return string, for convenience.
* A StreamWriter will be created from the factory, used, and then deleted. * A StreamWriter will be created from the factory, used, and then deleted.
@ -111,8 +110,6 @@ public:
* - Number of precision digits for formatting of real values. * - Number of precision digits for formatting of real values.
* - "precisionType": "significant"(default) or "decimal" * - "precisionType": "significant"(default) or "decimal"
* - Type of precision for formatting of real values. * - 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 * You can examine 'settings_` yourself
* to see the defaults. You can also write and read them just like any * to see the defaults. You can also write and read them just like any
@ -148,7 +145,7 @@ public:
/** \brief Abstract class for writers. /** \brief Abstract class for writers.
* \deprecated Use StreamWriter. (And really, this is an implementation detail.) * \deprecated Use StreamWriter. (And really, this is an implementation detail.)
*/ */
class JSON_API Writer { class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer {
public: public:
virtual ~Writer(); virtual ~Writer();
@ -168,7 +165,8 @@ public:
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class #pragma warning(disable : 4996) // Deriving from deprecated class
#endif #endif
class JSON_API FastWriter : public Writer { class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter
: public Writer {
public: public:
FastWriter(); FastWriter();
~FastWriter() override = default; ~FastWriter() override = default;
@ -217,7 +215,7 @@ private:
* - otherwise, it the values do not fit on one line, or the array contains * - 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. * 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. *#CommentPlacement.
* *
* \sa Reader, Value, Value::setComment() * \sa Reader, Value, Value::setComment()
@ -227,7 +225,8 @@ private:
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class #pragma warning(disable : 4996) // Deriving from deprecated class
#endif #endif
class JSON_API StyledWriter : public Writer { class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
StyledWriter : public Writer {
public: public:
StyledWriter(); StyledWriter();
~StyledWriter() override = default; ~StyledWriter() override = default;
@ -285,7 +284,7 @@ private:
* - otherwise, it the values do not fit on one line, or the array contains * - 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. * 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. #CommentPlacement.
* *
* \sa Reader, Value, Value::setComment() * \sa Reader, Value, Value::setComment()
@ -295,7 +294,8 @@ private:
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class #pragma warning(disable : 4996) // Deriving from deprecated class
#endif #endif
class JSON_API StyledStreamWriter { class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
StyledStreamWriter {
public: public:
/** /**
* \param indentation Each level will be indented by this amount extra. * \param indentation Each level will be indented by this amount extra.
@ -351,7 +351,6 @@ String JSON_API valueToString(
PrecisionType precisionType = PrecisionType::significantDigits); PrecisionType precisionType = PrecisionType::significantDigits);
String JSON_API valueToString(bool value); String JSON_API valueToString(bool value);
String JSON_API valueToQuotedString(const char* value); String JSON_API valueToQuotedString(const char* value);
String JSON_API valueToQuotedString(const char* value, size_t length);
/// \brief Output using the StyledStreamWriter. /// \brief Output using the StyledStreamWriter.
/// \see Json::operator>>() /// \see Json::operator>>()

View File

@ -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 ()

View File

@ -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)

View File

@ -1,6 +0,0 @@
@PACKAGE_INIT@
@MESON_SHARED_TARGET@
@MESON_STATIC_TARGET@
include ( "${CMAKE_CURRENT_LIST_DIR}/jsoncpp-namespaced-targets.cmake" )

View File

@ -9,13 +9,13 @@ project(
# 2. /include/json/version.h # 2. /include/json/version.h
# 3. /CMakeLists.txt # 3. /CMakeLists.txt
# IMPORTANT: also update the SOVERSION!! # IMPORTANT: also update the SOVERSION!!
version : '1.9.7', version : '1.9.4',
default_options : [ default_options : [
'buildtype=release', 'buildtype=release',
'cpp_std=c++11', 'cpp_std=c++11',
'warning_level=1'], 'warning_level=1'],
license : 'Public Domain', license : 'Public Domain',
meson_version : '>= 0.54.0') meson_version : '>= 0.49.0')
jsoncpp_headers = files([ jsoncpp_headers = files([
@ -50,7 +50,7 @@ jsoncpp_lib = library(
'src/lib_json/json_value.cpp', 'src/lib_json/json_value.cpp',
'src/lib_json/json_writer.cpp', 'src/lib_json/json_writer.cpp',
]), ]),
soversion : 27, soversion : 24,
install : true, install : true,
include_directories : jsoncpp_include_directories, include_directories : jsoncpp_include_directories,
cpp_args: dll_export_flag) cpp_args: dll_export_flag)
@ -62,43 +62,6 @@ import('pkgconfig').generate(
filebase : 'jsoncpp', filebase : 'jsoncpp',
description : 'A C++ library for interacting with JSON') 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 # for libraries bundling jsoncpp
jsoncpp_dep = declare_dependency( jsoncpp_dep = declare_dependency(
include_directories : jsoncpp_include_directories, include_directories : jsoncpp_include_directories,
@ -110,7 +73,7 @@ if meson.is_subproject() or not get_option('tests')
subdir_done() subdir_done()
endif endif
python = find_program('python3') python = import('python').find_installation()
jsoncpp_test = executable( jsoncpp_test = executable(
'jsoncpp_test', files([ 'jsoncpp_test', files([

View File

@ -5,7 +5,7 @@ includedir=@includedir_for_pc_file@
Name: jsoncpp Name: jsoncpp
Description: A C++ library for interacting with JSON Description: A C++ library for interacting with JSON
Version: @PROJECT_VERSION@ Version: @JSONCPP_VERSION@
URL: https://github.com/open-source-parsers/jsoncpp URL: https://github.com/open-source-parsers/jsoncpp
Libs: -L${libdir} -ljsoncpp Libs: -L${libdir} -ljsoncpp
Cflags: -I${includedir} Cflags: -I${includedir}

View File

@ -1 +0,0 @@
find src -name '*.cpp' -or -name '*.h' | xargs clang-format -i

View File

@ -240,12 +240,9 @@ static int parseCommandLine(int argc, const char* argv[], Options* opts) {
return printUsage(argv); return printUsage(argv);
} }
int index = 1; int index = 1;
if (Json::String(argv[index]) == "--parse-only") { if (Json::String(argv[index]) == "--json-checker") {
opts->parseOnly = true;
++index;
}
if (Json::String(argv[index]) == "--strict") {
opts->features = Json::Features::strictMode(); opts->features = Json::Features::strictMode();
opts->parseOnly = true;
++index; ++index;
} }
if (Json::String(argv[index]) == "--json-config") { if (Json::String(argv[index]) == "--json-config") {
@ -338,7 +335,6 @@ int main(int argc, const char* argv[]) {
std::cerr << "Unhandled exception:" << std::endl << e.what() << std::endl; std::cerr << "Unhandled exception:" << std::endl << e.what() << std::endl;
return 1; return 1;
} }
return 0;
} }
#if defined(__GNUC__) #if defined(__GNUC__)

View File

@ -11,10 +11,20 @@ include(CheckCXXSymbolExists)
check_include_file_cxx(clocale HAVE_CLOCALE) check_include_file_cxx(clocale HAVE_CLOCALE)
check_cxx_symbol_exists(localeconv clocale HAVE_LOCALECONV) check_cxx_symbol_exists(localeconv clocale HAVE_LOCALECONV)
set(CMAKE_EXTRA_INCLUDE_FILES clocale) if(CMAKE_VERSION VERSION_LESS 3.0.0)
check_type_size(lconv LCONV_SIZE LANGUAGE CXX) # The "LANGUAGE CXX" parameter is not supported in CMake versions below 3,
unset(CMAKE_EXTRA_INCLUDE_FILES) # so the C compiler and header has to be used.
check_struct_has_member(lconv decimal_point clocale HAVE_DECIMAL_POINT LANGUAGE CXX) 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)) if(NOT (HAVE_CLOCALE AND HAVE_LCONV_SIZE AND HAVE_DECIMAL_POINT AND HAVE_LOCALECONV))
message(WARNING "Locale functionality is not supported") message(WARNING "Locale functionality is not supported")
@ -119,7 +129,7 @@ if(BUILD_SHARED_LIBS)
OUTPUT_NAME jsoncpp OUTPUT_NAME jsoncpp
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_SOVERSION} SOVERSION ${PROJECT_SOVERSION}
POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS} POSITION_INDEPENDENT_CODE ON
) )
# Set library's runtime search path on OSX # Set library's runtime search path on OSX
@ -129,10 +139,13 @@ if(BUILD_SHARED_LIBS)
target_compile_features(${SHARED_LIB} PUBLIC ${REQUIRED_FEATURES}) target_compile_features(${SHARED_LIB} PUBLIC ${REQUIRED_FEATURES})
target_include_directories(${SHARED_LIB} PUBLIC if(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> target_include_directories(${SHARED_LIB} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
) $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/json>
)
endif()
list(APPEND CMAKE_TARGETS ${SHARED_LIB}) list(APPEND CMAKE_TARGETS ${SHARED_LIB})
endif() endif()
@ -141,13 +154,9 @@ if(BUILD_STATIC_LIBS)
set(STATIC_LIB ${PROJECT_NAME}_static) set(STATIC_LIB ${PROJECT_NAME}_static)
add_library(${STATIC_LIB} STATIC ${PUBLIC_HEADERS} ${JSONCPP_SOURCES}) add_library(${STATIC_LIB} STATIC ${PUBLIC_HEADERS} ${JSONCPP_SOURCES})
# avoid name clashes on windows as the shared import lib is also named jsoncpp.lib # avoid name clashes on windows as the shared import lib is alse named jsoncpp.lib
if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS) if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS)
if (MSVC OR ("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC")) set(STATIC_SUFFIX "_static")
set(STATIC_SUFFIX "_static")
else()
set(STATIC_SUFFIX "")
endif()
endif() endif()
set_target_properties(${STATIC_LIB} PROPERTIES set_target_properties(${STATIC_LIB} PROPERTIES
@ -162,10 +171,13 @@ if(BUILD_STATIC_LIBS)
target_compile_features(${STATIC_LIB} PUBLIC ${REQUIRED_FEATURES}) target_compile_features(${STATIC_LIB} PUBLIC ${REQUIRED_FEATURES})
target_include_directories(${STATIC_LIB} PUBLIC if(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> target_include_directories(${STATIC_LIB} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
) $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/json>
)
endif()
list(APPEND CMAKE_TARGETS ${STATIC_LIB}) list(APPEND CMAKE_TARGETS ${STATIC_LIB})
endif() endif()
@ -178,7 +190,7 @@ if(BUILD_OBJECT_LIBS)
OUTPUT_NAME jsoncpp OUTPUT_NAME jsoncpp
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_SOVERSION} SOVERSION ${PROJECT_SOVERSION}
POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS} POSITION_INDEPENDENT_CODE ON
) )
# Set library's runtime search path on OSX # Set library's runtime search path on OSX
@ -188,10 +200,13 @@ if(BUILD_OBJECT_LIBS)
target_compile_features(${OBJECT_LIB} PUBLIC ${REQUIRED_FEATURES}) target_compile_features(${OBJECT_LIB} PUBLIC ${REQUIRED_FEATURES})
target_include_directories(${OBJECT_LIB} PUBLIC if(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> target_include_directories(${OBJECT_LIB} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
) $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/json>
)
endif()
list(APPEND CMAKE_TARGETS ${OBJECT_LIB}) list(APPEND CMAKE_TARGETS ${OBJECT_LIB})
endif() endif()

View File

@ -12,7 +12,6 @@
#endif // if !defined(JSON_IS_AMALGAMATION) #endif // if !defined(JSON_IS_AMALGAMATION)
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cmath>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <istream> #include <istream>
@ -23,6 +22,13 @@
#include <utility> #include <utility>
#include <cstdio> #include <cstdio>
#if __cplusplus >= 201103L
#if !defined(sscanf)
#define sscanf std::sscanf
#endif
#endif //__cplusplus
#if defined(_MSC_VER) #if defined(_MSC_VER)
#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) #if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
@ -46,7 +52,11 @@ static size_t const stackLimit_g =
namespace Json { namespace Json {
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
using CharReaderPtr = std::unique_ptr<CharReader>; using CharReaderPtr = std::unique_ptr<CharReader>;
#else
using CharReaderPtr = std::auto_ptr<CharReader>;
#endif
// Implementation of class Features // Implementation of class Features
// //////////////////////////////// // ////////////////////////////////
@ -94,7 +104,8 @@ bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
// Since String is reference-counted, this at least does not // Since String is reference-counted, this at least does not
// create an extra copy. // 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); return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
} }
@ -118,7 +129,7 @@ bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
bool successful = readValue(); bool successful = readValue();
Token token; Token token;
readTokenSkippingComments(token); skipCommentTokens(token);
if (collectComments_ && !commentsBefore_.empty()) if (collectComments_ && !commentsBefore_.empty())
root.setComment(commentsBefore_, commentAfter); root.setComment(commentsBefore_, commentAfter);
if (features_.strictRoot_) { if (features_.strictRoot_) {
@ -146,7 +157,7 @@ bool Reader::readValue() {
throwRuntimeError("Exceeded stackLimit in readValue()."); throwRuntimeError("Exceeded stackLimit in readValue().");
Token token; Token token;
readTokenSkippingComments(token); skipCommentTokens(token);
bool successful = true; bool successful = true;
if (collectComments_ && !commentsBefore_.empty()) { if (collectComments_ && !commentsBefore_.empty()) {
@ -214,14 +225,14 @@ bool Reader::readValue() {
return successful; return successful;
} }
bool Reader::readTokenSkippingComments(Token& token) { void Reader::skipCommentTokens(Token& token) {
bool success = readToken(token);
if (features_.allowComments_) { if (features_.allowComments_) {
while (success && token.type_ == tokenComment) { do {
success = readToken(token); readToken(token);
} } while (token.type_ == tokenComment);
} else {
readToken(token);
} }
return success;
} }
bool Reader::readToken(Token& token) { bool Reader::readToken(Token& token) {
@ -435,7 +446,12 @@ bool Reader::readObject(Token& token) {
Value init(objectValue); Value init(objectValue);
currentValue().swapPayload(init); currentValue().swapPayload(init);
currentValue().setOffsetStart(token.start_ - begin_); 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 if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
return true; return true;
name.clear(); name.clear();
@ -464,11 +480,15 @@ bool Reader::readObject(Token& token) {
return recoverFromError(tokenObjectEnd); return recoverFromError(tokenObjectEnd);
Token comma; Token comma;
if (!readTokenSkippingComments(comma) || if (!readToken(comma) ||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) { (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
comma.type_ != tokenComment)) {
return addErrorAndRecover("Missing ',' or '}' in object declaration", return addErrorAndRecover("Missing ',' or '}' in object declaration",
comma, tokenObjectEnd); comma, tokenObjectEnd);
} }
bool finalizeTokenOk = true;
while (comma.type_ == tokenComment && finalizeTokenOk)
finalizeTokenOk = readToken(comma);
if (comma.type_ == tokenObjectEnd) if (comma.type_ == tokenObjectEnd)
return true; return true;
} }
@ -498,7 +518,10 @@ bool Reader::readArray(Token& token) {
Token currentToken; Token currentToken;
// Accept Comment after last item in the array. // 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 && bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
currentToken.type_ != tokenArrayEnd); currentToken.type_ != tokenArrayEnd);
if (!ok || badTokenType) { if (!ok || badTokenType) {
@ -576,16 +599,11 @@ bool Reader::decodeDouble(Token& token) {
bool Reader::decodeDouble(Token& token, Value& decoded) { bool Reader::decodeDouble(Token& token, Value& decoded) {
double value = 0; double value = 0;
IStringStream is(String(token.start_, token.end_)); String buffer(token.start_, token.end_);
if (!(is >> value)) { IStringStream is(buffer);
if (value == std::numeric_limits<double>::max()) if (!(is >> value))
value = std::numeric_limits<double>::infinity(); return addError(
else if (value == std::numeric_limits<double>::lowest()) "'" + String(token.start_, token.end_) + "' is not a number.", token);
value = -std::numeric_limits<double>::infinity();
else if (!std::isinf(value))
return addError(
"'" + String(token.start_, token.end_) + "' is not a number.", token);
}
decoded = value; decoded = value;
return true; return true;
} }
@ -749,7 +767,7 @@ void Reader::getLocationLineAndColumn(Location location, int& line,
while (current < location && current != end_) { while (current < location && current != end_) {
Char c = *current++; Char c = *current++;
if (c == '\r') { if (c == '\r') {
if (current != end_ && *current == '\n') if (*current == '\n')
++current; ++current;
lastLineStart = current; lastLineStart = current;
++line; ++line;
@ -866,12 +884,17 @@ class OurReader {
public: public:
using Char = char; using Char = char;
using Location = const Char*; using Location = const Char*;
struct StructuredError {
ptrdiff_t offset_start;
ptrdiff_t offset_limit;
String message;
};
explicit OurReader(OurFeatures const& features); explicit OurReader(OurFeatures const& features);
bool parse(const char* beginDoc, const char* endDoc, Value& root, bool parse(const char* beginDoc, const char* endDoc, Value& root,
bool collectComments = true); bool collectComments = true);
String getFormattedErrorMessages() const; String getFormattedErrorMessages() const;
std::vector<CharReader::StructuredError> getStructuredErrors() const; std::vector<StructuredError> getStructuredErrors() const;
private: private:
OurReader(OurReader const&); // no impl OurReader(OurReader const&); // no impl
@ -914,7 +937,6 @@ private:
using Errors = std::deque<ErrorInfo>; using Errors = std::deque<ErrorInfo>;
bool readToken(Token& token); bool readToken(Token& token);
bool readTokenSkippingComments(Token& token);
void skipSpaces(); void skipSpaces();
void skipBom(bool skipBom); void skipBom(bool skipBom);
bool match(const Char* pattern, int patternLength); bool match(const Char* pattern, int patternLength);
@ -948,6 +970,7 @@ private:
int& column) const; int& column) const;
String getLocationLineAndColumn(Location location) const; String getLocationLineAndColumn(Location location) const;
void addComment(Location begin, Location end, CommentPlacement placement); void addComment(Location begin, Location end, CommentPlacement placement);
void skipCommentTokens(Token& token);
static String normalizeEOL(Location begin, Location end); static String normalizeEOL(Location begin, Location end);
static bool containsNewLine(Location begin, Location end); static bool containsNewLine(Location begin, Location end);
@ -1001,7 +1024,7 @@ bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
bool successful = readValue(); bool successful = readValue();
nodes_.pop(); nodes_.pop();
Token token; Token token;
readTokenSkippingComments(token); skipCommentTokens(token);
if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) { if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
addError("Extra non-whitespace after JSON value.", token); addError("Extra non-whitespace after JSON value.", token);
return false; return false;
@ -1029,7 +1052,7 @@ bool OurReader::readValue() {
if (nodes_.size() > features_.stackLimit_) if (nodes_.size() > features_.stackLimit_)
throwRuntimeError("Exceeded stackLimit in readValue()."); throwRuntimeError("Exceeded stackLimit in readValue().");
Token token; Token token;
readTokenSkippingComments(token); skipCommentTokens(token);
bool successful = true; bool successful = true;
if (collectComments_ && !commentsBefore_.empty()) { if (collectComments_ && !commentsBefore_.empty()) {
@ -1116,14 +1139,14 @@ bool OurReader::readValue() {
return successful; return successful;
} }
bool OurReader::readTokenSkippingComments(Token& token) { void OurReader::skipCommentTokens(Token& token) {
bool success = readToken(token);
if (features_.allowComments_) { if (features_.allowComments_) {
while (success && token.type_ == tokenComment) { do {
success = readToken(token); readToken(token);
} } while (token.type_ == tokenComment);
} else {
readToken(token);
} }
return success;
} }
bool OurReader::readToken(Token& token) { bool OurReader::readToken(Token& token) {
@ -1420,7 +1443,12 @@ bool OurReader::readObject(Token& token) {
Value init(objectValue); Value init(objectValue);
currentValue().swapPayload(init); currentValue().swapPayload(init);
currentValue().setOffsetStart(token.start_ - begin_); 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 && if (tokenName.type_ == tokenObjectEnd &&
(name.empty() || (name.empty() ||
features_.allowTrailingCommas_)) // empty object or trailing comma features_.allowTrailingCommas_)) // empty object or trailing comma
@ -1457,11 +1485,15 @@ bool OurReader::readObject(Token& token) {
return recoverFromError(tokenObjectEnd); return recoverFromError(tokenObjectEnd);
Token comma; Token comma;
if (!readTokenSkippingComments(comma) || if (!readToken(comma) ||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) { (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
comma.type_ != tokenComment)) {
return addErrorAndRecover("Missing ',' or '}' in object declaration", return addErrorAndRecover("Missing ',' or '}' in object declaration",
comma, tokenObjectEnd); comma, tokenObjectEnd);
} }
bool finalizeTokenOk = true;
while (comma.type_ == tokenComment && finalizeTokenOk)
finalizeTokenOk = readToken(comma);
if (comma.type_ == tokenObjectEnd) if (comma.type_ == tokenObjectEnd)
return true; return true;
} }
@ -1495,7 +1527,10 @@ bool OurReader::readArray(Token& token) {
Token currentToken; Token currentToken;
// Accept Comment after last item in the array. // 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 && bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
currentToken.type_ != tokenArrayEnd); currentToken.type_ != tokenArrayEnd);
if (!ok || badTokenType) { if (!ok || badTokenType) {
@ -1573,7 +1608,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
const auto digit(static_cast<Value::UInt>(c - '0')); const auto digit(static_cast<Value::UInt>(c - '0'));
if (value >= threshold) { if (value >= threshold) {
// We've hit or exceeded the max value divided by 10 (rounded down). If // We've hit or exceeded the max value divided by 10 (rounded down). If
// a) we've only just touched the limit, meaning value == threshold, // a) we've only just touched the limit, meaing value == threshold,
// b) this is the last digit, or // b) this is the last digit, or
// c) it's small enough to fit in that rounding delta, we're okay. // c) it's small enough to fit in that rounding delta, we're okay.
// Otherwise treat this number as a double to avoid overflow. // Otherwise treat this number as a double to avoid overflow.
@ -1610,15 +1645,11 @@ bool OurReader::decodeDouble(Token& token) {
bool OurReader::decodeDouble(Token& token, Value& decoded) { bool OurReader::decodeDouble(Token& token, Value& decoded) {
double value = 0; double value = 0;
IStringStream is(String(token.start_, token.end_)); const String buffer(token.start_, token.end_);
IStringStream is(buffer);
if (!(is >> value)) { if (!(is >> value)) {
if (value == std::numeric_limits<double>::max()) return addError(
value = std::numeric_limits<double>::infinity(); "'" + String(token.start_, token.end_) + "' is not a number.", token);
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);
} }
decoded = value; decoded = value;
return true; return true;
@ -1783,7 +1814,7 @@ void OurReader::getLocationLineAndColumn(Location location, int& line,
while (current < location && current != end_) { while (current < location && current != end_) {
Char c = *current++; Char c = *current++;
if (c == '\r') { if (c == '\r') {
if (current != end_ && *current == '\n') if (*current == '\n')
++current; ++current;
lastLineStart = current; lastLineStart = current;
++line; ++line;
@ -1818,11 +1849,10 @@ String OurReader::getFormattedErrorMessages() const {
return formattedMessage; return formattedMessage;
} }
std::vector<CharReader::StructuredError> std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
OurReader::getStructuredErrors() const { std::vector<OurReader::StructuredError> allErrors;
std::vector<CharReader::StructuredError> allErrors;
for (const auto& error : errors_) { for (const auto& error : errors_) {
CharReader::StructuredError structured; OurReader::StructuredError structured;
structured.offset_start = error.token_.start_ - begin_; structured.offset_start = error.token_.start_ - begin_;
structured.offset_limit = error.token_.end_ - begin_; structured.offset_limit = error.token_.end_ - begin_;
structured.message = error.message_; structured.message = error.message_;
@ -1832,36 +1862,20 @@ OurReader::getStructuredErrors() const {
} }
class OurCharReader : public CharReader { class OurCharReader : public CharReader {
bool const collectComments_;
OurReader reader_;
public: public:
OurCharReader(bool collectComments, OurFeatures const& features) OurCharReader(bool collectComments, OurFeatures const& features)
: CharReader( : collectComments_(collectComments), reader_(features) {}
std::unique_ptr<OurImpl>(new OurImpl(collectComments, features))) {} bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) override {
protected: bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
class OurImpl : public Impl { if (errs) {
public: *errs = reader_.getFormattedErrorMessages();
OurImpl(bool collectComments, OurFeatures const& features)
: collectComments_(collectComments), reader_(features) {}
bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) override {
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
if (errs) {
*errs = reader_.getFormattedErrorMessages();
}
return ok;
} }
return ok;
std::vector<CharReader::StructuredError> }
getStructuredErrors() const override {
return reader_.getStructuredErrors();
}
private:
bool const collectComments_;
OurReader reader_;
};
}; };
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
@ -1907,7 +1921,7 @@ bool CharReaderBuilder::validate(Json::Value* invalid) const {
if (valid_keys.count(key)) if (valid_keys.count(key))
continue; continue;
if (invalid) if (invalid)
(*invalid)[key] = *si; (*invalid)[std::move(key)] = *si;
else else
return false; return false;
} }
@ -1950,32 +1964,6 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
(*settings)["skipBom"] = true; (*settings)["skipBom"] = true;
//! [CharReaderBuilderDefaults] //! [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 // global functions
@ -1984,7 +1972,7 @@ bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,
String* errs) { String* errs) {
OStringStream ssin; OStringStream ssin;
ssin << sin.rdbuf(); ssin << sin.rdbuf();
String doc = std::move(ssin).str(); String doc = ssin.str();
char const* begin = doc.data(); char const* begin = doc.data();
char const* end = begin + doc.size(); char const* end = begin + doc.size();
// Note that we do not actually need a null-terminator. // Note that we do not actually need a null-terminator.

View File

@ -116,18 +116,14 @@ template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {
* Return iterator that would be the new end of the range [begin,end), if we * 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 '.'. * were to delete zeros in the end of string, but not the last zero before '.'.
*/ */
template <typename Iter> template <typename Iter> Iter fixZerosInTheEnd(Iter begin, Iter end) {
Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) {
for (; begin != end; --end) { for (; begin != end; --end) {
if (*(end - 1) != '0') { if (*(end - 1) != '0') {
return end; return end;
} }
// Don't delete the last zero before the decimal point. // Don't delete the last zero before the decimal point.
if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') { if (begin != (end - 1) && *(end - 2) == '.') {
if (precision) { return end;
return end;
}
return end - 2;
} }
} }
return end; return end;

View File

@ -17,10 +17,6 @@
#include <sstream> #include <sstream>
#include <utility> #include <utility>
#ifdef JSONCPP_HAS_STRING_VIEW
#include <string_view>
#endif
// Provide implementation equivalent of std::snprintf for older _MSC compilers // Provide implementation equivalent of std::snprintf for older _MSC compilers
#if defined(_MSC_VER) && _MSC_VER < 1900 #if defined(_MSC_VER) && _MSC_VER < 1900
#include <stdarg.h> #include <stdarg.h>
@ -91,8 +87,7 @@ template <typename T, typename U>
static inline bool InRange(double d, T min, U max) { static inline bool InRange(double d, T min, U max) {
// The casts can lose precision, but we are looking only for // The casts can lose precision, but we are looking only for
// an approximate range. Might fail on edge cases though. ~cdunn // an approximate range. Might fail on edge cases though. ~cdunn
return d >= static_cast<double>(min) && d <= static_cast<double>(max) && return d >= static_cast<double>(min) && d <= static_cast<double>(max);
!(static_cast<U>(d) == min && d != static_cast<double>(min));
} }
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
static inline double integerToDouble(Json::UInt64 value) { static inline double integerToDouble(Json::UInt64 value) {
@ -106,8 +101,7 @@ template <typename T> static inline double integerToDouble(T value) {
template <typename T, typename U> template <typename T, typename U>
static inline bool InRange(double d, T min, U max) { static inline bool InRange(double d, T min, U max) {
return d >= integerToDouble(min) && d <= integerToDouble(max) && return d >= integerToDouble(min) && d <= integerToDouble(max);
!(static_cast<U>(d) == min && d != integerToDouble(min));
} }
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
@ -169,7 +163,7 @@ inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,
/** Free the string duplicated by /** Free the string duplicated by
* duplicateStringValue()/duplicateAndPrefixStringValue(). * duplicateStringValue()/duplicateAndPrefixStringValue().
*/ */
#if JSONCPP_USE_SECURE_MEMORY #if JSONCPP_USING_SECURE_MEMORY
static inline void releasePrefixedStringValue(char* value) { static inline void releasePrefixedStringValue(char* value) {
unsigned length = 0; unsigned length = 0;
char const* valueDecoded; char const* valueDecoded;
@ -184,10 +178,10 @@ static inline void releaseStringValue(char* value, unsigned length) {
memset(value, 0, size); memset(value, 0, size);
free(value); free(value);
} }
#else // !JSONCPP_USE_SECURE_MEMORY #else // !JSONCPP_USING_SECURE_MEMORY
static inline void releasePrefixedStringValue(char* value) { free(value); } static inline void releasePrefixedStringValue(char* value) { free(value); }
static inline void releaseStringValue(char* value, unsigned) { free(value); } static inline void releaseStringValue(char* value, unsigned) { free(value); }
#endif // JSONCPP_USE_SECURE_MEMORY #endif // JSONCPP_USING_SECURE_MEMORY
} // namespace Json } // namespace Json
@ -265,7 +259,7 @@ Value::CZString::CZString(const CZString& other) {
storage_.length_ = other.storage_.length_; storage_.length_ = other.storage_.length_;
} }
Value::CZString::CZString(CZString&& other) noexcept Value::CZString::CZString(CZString&& other)
: cstr_(other.cstr_), index_(other.index_) { : cstr_(other.cstr_), index_(other.index_) {
other.cstr_ = nullptr; other.cstr_ = nullptr;
} }
@ -291,7 +285,7 @@ Value::CZString& Value::CZString::operator=(const CZString& other) {
return *this; return *this;
} }
Value::CZString& Value::CZString::operator=(CZString&& other) noexcept { Value::CZString& Value::CZString::operator=(CZString&& other) {
cstr_ = other.cstr_; cstr_ = other.cstr_;
index_ = other.index_; index_ = other.index_;
other.cstr_ = nullptr; other.cstr_ = nullptr;
@ -424,14 +418,6 @@ Value::Value(const String& value) {
value.data(), static_cast<unsigned>(value.length())); value.data(), static_cast<unsigned>(value.length()));
} }
#ifdef JSONCPP_HAS_STRING_VIEW
Value::Value(std::string_view value) {
initBasic(stringValue, true);
value_.string_ = duplicateAndPrefixStringValue(
value.data(), static_cast<unsigned>(value.length()));
}
#endif
Value::Value(const StaticString& value) { Value::Value(const StaticString& value) {
initBasic(stringValue); initBasic(stringValue);
value_.string_ = const_cast<char*>(value.c_str()); value_.string_ = const_cast<char*>(value.c_str());
@ -447,7 +433,7 @@ Value::Value(const Value& other) {
dupMeta(other); dupMeta(other);
} }
Value::Value(Value&& other) noexcept { Value::Value(Value&& other) {
initBasic(nullValue); initBasic(nullValue);
swap(other); swap(other);
} }
@ -462,7 +448,7 @@ Value& Value::operator=(const Value& other) {
return *this; return *this;
} }
Value& Value::operator=(Value&& other) noexcept { Value& Value::operator=(Value&& other) {
other.swap(*this); other.swap(*this);
return *this; return *this;
} }
@ -613,7 +599,7 @@ const char* Value::asCString() const {
return this_str; return this_str;
} }
#if JSONCPP_USE_SECURE_MEMORY #if JSONCPP_USING_SECURE_MEMORY
unsigned Value::getCStringLength() const { unsigned Value::getCStringLength() const {
JSON_ASSERT_MESSAGE(type() == stringValue, JSON_ASSERT_MESSAGE(type() == stringValue,
"in Json::Value::asCString(): requires stringValue"); "in Json::Value::asCString(): requires stringValue");
@ -639,21 +625,6 @@ bool Value::getString(char const** begin, char const** end) const {
return true; return true;
} }
#ifdef JSONCPP_HAS_STRING_VIEW
bool Value::getString(std::string_view* str) const {
if (type() != stringValue)
return false;
if (value_.string_ == nullptr)
return false;
const char* begin;
unsigned length;
decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
&begin);
*str = std::string_view(begin, length);
return true;
}
#endif
String Value::asString() const { String Value::asString() const {
switch (type()) { switch (type()) {
case nullValue: case nullValue:
@ -711,7 +682,7 @@ Value::UInt Value::asUInt() const {
JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
return UInt(value_.uint_); return UInt(value_.uint_);
case realValue: case realValue:
JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt), JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
"double out of UInt range"); "double out of UInt range");
return UInt(value_.real_); return UInt(value_.real_);
case nullValue: case nullValue:
@ -734,11 +705,6 @@ Value::Int64 Value::asInt64() const {
JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
return Int64(value_.uint_); return Int64(value_.uint_);
case realValue: 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), JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
"double out of Int64 range"); "double out of Int64 range");
return Int64(value_.real_); return Int64(value_.real_);
@ -760,7 +726,7 @@ Value::UInt64 Value::asUInt64() const {
case uintValue: case uintValue:
return UInt64(value_.uint_); return UInt64(value_.uint_);
case realValue: case realValue:
JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt64), JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
"double out of UInt64 range"); "double out of UInt64 range");
return UInt64(value_.real_); return UInt64(value_.real_);
case nullValue: case nullValue:
@ -871,7 +837,7 @@ bool Value::isConvertibleTo(ValueType other) const {
type() == booleanValue || type() == nullValue; type() == booleanValue || type() == nullValue;
case uintValue: case uintValue:
return isUInt() || return isUInt() ||
(type() == realValue && InRange(value_.real_, 0u, maxUInt)) || (type() == realValue && InRange(value_.real_, 0, maxUInt)) ||
type() == booleanValue || type() == nullValue; type() == booleanValue || type() == nullValue;
case realValue: case realValue:
return isNumeric() || type() == booleanValue || type() == nullValue; return isNumeric() || type() == booleanValue || type() == nullValue;
@ -946,8 +912,7 @@ void Value::resize(ArrayIndex newSize) {
if (newSize == 0) if (newSize == 0)
clear(); clear();
else if (newSize > oldSize) else if (newSize > oldSize)
for (ArrayIndex i = oldSize; i < newSize; ++i) this->operator[](newSize - 1);
(*this)[i];
else { else {
for (ArrayIndex index = newSize; index < oldSize; ++index) { for (ArrayIndex index = newSize; index < oldSize; ++index) {
value_.map_->erase(index); value_.map_->erase(index);
@ -1126,64 +1091,12 @@ Value const* Value::find(char const* begin, char const* end) const {
return nullptr; return nullptr;
return &(*it).second; return &(*it).second;
} }
Value const* Value::find(const String& key) const {
return find(key.data(), key.data() + key.length());
}
Value const* Value::findNull(const String& key) const {
return findValue<Value, &Value::isNull>(key);
}
Value const* Value::findBool(const String& key) const {
return findValue<Value, &Value::isBool>(key);
}
Value const* Value::findInt(const String& key) const {
return findValue<Value, &Value::isInt>(key);
}
Value const* Value::findInt64(const String& key) const {
return findValue<Value, &Value::isInt64>(key);
}
Value const* Value::findUInt(const String& key) const {
return findValue<Value, &Value::isUInt>(key);
}
Value const* Value::findUInt64(const String& key) const {
return findValue<Value, &Value::isUInt64>(key);
}
Value const* Value::findIntegral(const String& key) const {
return findValue<Value, &Value::isIntegral>(key);
}
Value const* Value::findDouble(const String& key) const {
return findValue<Value, &Value::isDouble>(key);
}
Value const* Value::findNumeric(const String& key) const {
return findValue<Value, &Value::isNumeric>(key);
}
Value const* Value::findString(const String& key) const {
return findValue<Value, &Value::isString>(key);
}
Value const* Value::findArray(const String& key) const {
return findValue<Value, &Value::isArray>(key);
}
Value const* Value::findObject(const String& key) const {
return findValue<Value, &Value::isObject>(key);
}
Value* Value::demand(char const* begin, char const* end) { Value* Value::demand(char const* begin, char const* end) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
"in Json::Value::demand(begin, end): requires " "in Json::Value::demand(begin, end): requires "
"objectValue or nullValue"); "objectValue or nullValue");
return &resolveReference(begin, end); return &resolveReference(begin, end);
} }
#ifdef JSONCPP_HAS_STRING_VIEW
const Value& Value::operator[](std::string_view key) const {
Value const* found = find(key.data(), key.data() + key.length());
if (!found)
return nullSingleton();
return *found;
}
Value& Value::operator[](std::string_view key) {
return resolveReference(key.data(), key.data() + key.length());
}
#else
const Value& Value::operator[](const char* key) const { const Value& Value::operator[](const char* key) const {
Value const* found = find(key, key + strlen(key)); Value const* found = find(key, key + strlen(key));
if (!found) if (!found)
@ -1191,7 +1104,7 @@ const Value& Value::operator[](const char* key) const {
return *found; return *found;
} }
Value const& Value::operator[](const String& key) const { 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) if (!found)
return nullSingleton(); return nullSingleton();
return *found; return *found;
@ -1204,7 +1117,6 @@ Value& Value::operator[](const char* key) {
Value& Value::operator[](const String& key) { Value& Value::operator[](const String& key) {
return resolveReference(key.data(), key.data() + key.length()); return resolveReference(key.data(), key.data() + key.length());
} }
#endif
Value& Value::operator[](const StaticString& key) { Value& Value::operator[](const StaticString& key) {
return resolveReference(key.c_str()); return resolveReference(key.c_str());
@ -1244,18 +1156,12 @@ Value Value::get(char const* begin, char const* end,
Value const* found = find(begin, end); Value const* found = find(begin, end);
return !found ? defaultValue : *found; return !found ? defaultValue : *found;
} }
#ifdef JSONCPP_HAS_STRING_VIEW
Value Value::get(std::string_view key, const Value& defaultValue) const {
return get(key.data(), key.data() + key.length(), defaultValue);
}
#else
Value Value::get(char const* key, Value const& defaultValue) const { Value Value::get(char const* key, Value const& defaultValue) const {
return get(key, key + strlen(key), defaultValue); return get(key, key + strlen(key), defaultValue);
} }
Value Value::get(String const& key, Value const& defaultValue) const { Value Value::get(String const& key, Value const& defaultValue) const {
return get(key.data(), key.data() + key.length(), defaultValue); return get(key.data(), key.data() + key.length(), defaultValue);
} }
#endif
bool Value::removeMember(const char* begin, const char* end, Value* removed) { bool Value::removeMember(const char* begin, const char* end, Value* removed) {
if (type() != objectValue) { if (type() != objectValue) {
@ -1271,31 +1177,12 @@ bool Value::removeMember(const char* begin, const char* end, Value* removed) {
value_.map_->erase(it); value_.map_->erase(it);
return true; return true;
} }
#ifdef JSONCPP_HAS_STRING_VIEW
bool Value::removeMember(std::string_view key, Value* removed) {
return removeMember(key.data(), key.data() + key.length(), removed);
}
#else
bool Value::removeMember(const char* key, Value* removed) { bool Value::removeMember(const char* key, Value* removed) {
return removeMember(key, key + strlen(key), removed); return removeMember(key, key + strlen(key), removed);
} }
bool Value::removeMember(String const& key, Value* removed) { bool Value::removeMember(String const& key, Value* removed) {
return removeMember(key.data(), key.data() + key.length(), removed); return removeMember(key.data(), key.data() + key.length(), removed);
} }
#endif
#ifdef JSONCPP_HAS_STRING_VIEW
void Value::removeMember(std::string_view key) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
"in Json::Value::removeMember(): requires objectValue");
if (type() == nullValue)
return;
CZString actualKey(key.data(), unsigned(key.length()),
CZString::noDuplication);
value_.map_->erase(actualKey);
}
#else
void Value::removeMember(const char* key) { void Value::removeMember(const char* key) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
"in Json::Value::removeMember(): requires objectValue"); "in Json::Value::removeMember(): requires objectValue");
@ -1306,7 +1193,6 @@ void Value::removeMember(const char* key) {
value_.map_->erase(actualKey); value_.map_->erase(actualKey);
} }
void Value::removeMember(const String& key) { removeMember(key.c_str()); } void Value::removeMember(const String& key) { removeMember(key.c_str()); }
#endif
bool Value::removeIndex(ArrayIndex index, Value* removed) { bool Value::removeIndex(ArrayIndex index, Value* removed) {
if (type() != arrayValue) { if (type() != arrayValue) {
@ -1318,7 +1204,7 @@ bool Value::removeIndex(ArrayIndex index, Value* removed) {
return false; return false;
} }
if (removed) if (removed)
*removed = std::move(it->second); *removed = it->second;
ArrayIndex oldSize = size(); ArrayIndex oldSize = size();
// shift left all items left, into the place of the "removed" // shift left all items left, into the place of the "removed"
for (ArrayIndex i = index; i < (oldSize - 1); ++i) { for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
@ -1336,18 +1222,12 @@ bool Value::isMember(char const* begin, char const* end) const {
Value const* value = find(begin, end); Value const* value = find(begin, end);
return nullptr != value; return nullptr != value;
} }
#ifdef JSONCPP_HAS_STRING_VIEW
bool Value::isMember(std::string_view key) const {
return isMember(key.data(), key.data() + key.length());
}
#else
bool Value::isMember(char const* key) const { bool Value::isMember(char const* key) const {
return isMember(key, key + strlen(key)); return isMember(key, key + strlen(key));
} }
bool Value::isMember(String const& key) const { bool Value::isMember(String const& key) const {
return isMember(key.data(), key.data() + key.length()); return isMember(key.data(), key.data() + key.length());
} }
#endif
Value::Members Value::getMemberNames() const { Value::Members Value::getMemberNames() const {
JSON_ASSERT_MESSAGE( JSON_ASSERT_MESSAGE(
@ -1427,12 +1307,8 @@ bool Value::isInt64() const {
// Note that maxInt64 (= 2^63 - 1) is not exactly representable as a // 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 // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
// require the value to be strictly less than the limit. // require the value to be strictly less than the limit.
// minInt64 is -2^63 which can be represented as a double, but since double return value_.real_ >= double(minInt64) &&
// values in its proximity are also rounded to -2^63, we require the value value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
// 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_);
default: default:
break; break;
} }
@ -1470,11 +1346,7 @@ bool Value::isIntegral() const {
// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a // 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 // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
// require the value to be strictly less than the limit. // require the value to be strictly less than the limit.
// minInt64 is -2^63 which can be represented as a double, but since double return value_.real_ >= double(minInt64) &&
// 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_ < maxUInt64AsDouble && IsIntegral(value_.real_); value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
#else #else
return value_.real_ >= minInt && value_.real_ <= maxUInt && return value_.real_ >= minInt && value_.real_ <= maxUInt &&
@ -1501,15 +1373,14 @@ bool Value::isObject() const { return type() == objectValue; }
Value::Comments::Comments(const Comments& that) Value::Comments::Comments(const Comments& that)
: ptr_{cloneUnique(that.ptr_)} {} : ptr_{cloneUnique(that.ptr_)} {}
Value::Comments::Comments(Comments&& that) noexcept Value::Comments::Comments(Comments&& that) : ptr_{std::move(that.ptr_)} {}
: ptr_{std::move(that.ptr_)} {}
Value::Comments& Value::Comments::operator=(const Comments& that) { Value::Comments& Value::Comments::operator=(const Comments& that) {
ptr_ = cloneUnique(that.ptr_); ptr_ = cloneUnique(that.ptr_);
return *this; return *this;
} }
Value::Comments& Value::Comments::operator=(Comments&& that) noexcept { Value::Comments& Value::Comments::operator=(Comments&& that) {
ptr_ = std::move(that.ptr_); ptr_ = std::move(that.ptr_);
return *this; return *this;
} }
@ -1525,11 +1396,13 @@ String Value::Comments::get(CommentPlacement slot) const {
} }
void Value::Comments::set(CommentPlacement slot, String comment) { void Value::Comments::set(CommentPlacement slot, String comment) {
if (slot >= CommentPlacement::numberOfCommentPlacement) if (!ptr_) {
return;
if (!ptr_)
ptr_ = std::unique_ptr<Array>(new Array()); ptr_ = std::unique_ptr<Array>(new Array());
(*ptr_)[slot] = std::move(comment); }
// check comments array boundry.
if (slot < CommentPlacement::numberOfCommentPlacement) {
(*ptr_)[slot] = std::move(comment);
}
} }
void Value::setComment(String comment, CommentPlacement placement) { void Value::setComment(String comment, CommentPlacement placement) {
@ -1537,8 +1410,9 @@ void Value::setComment(String comment, CommentPlacement placement) {
// Always discard trailing newline, to aid indentation. // Always discard trailing newline, to aid indentation.
comment.pop_back(); comment.pop_back();
} }
JSON_ASSERT(!comment.empty());
JSON_ASSERT_MESSAGE( JSON_ASSERT_MESSAGE(
comment.empty() || comment[0] == '/', comment[0] == '\0' || comment[0] == '/',
"in Json::Value::setComment(): Comments must start with /"); "in Json::Value::setComment(): Comments must start with /");
comments_.set(placement, std::move(comment)); comments_.set(placement, std::move(comment));
} }

View File

@ -10,8 +10,6 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <cctype> #include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring> #include <cstring>
#include <iomanip> #include <iomanip>
#include <memory> #include <memory>
@ -19,6 +17,67 @@
#include <sstream> #include <sstream>
#include <utility> #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) #if defined(_MSC_VER)
// Disable warning about strdup being deprecated. // Disable warning about strdup being deprecated.
#pragma warning(disable : 4996) #pragma warning(disable : 4996)
@ -26,7 +85,11 @@
namespace Json { namespace Json {
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
using StreamWriterPtr = std::unique_ptr<StreamWriter>; using StreamWriterPtr = std::unique_ptr<StreamWriter>;
#else
using StreamWriterPtr = std::auto_ptr<StreamWriter>;
#endif
String valueToString(LargestInt value) { String valueToString(LargestInt value) {
UIntToStringBuffer buffer; UIntToStringBuffer buffer;
@ -66,12 +129,11 @@ String valueToString(double value, bool useSpecialFloats,
// Print into the buffer. We need not request the alternative representation // Print into the buffer. We need not request the alternative representation
// that always has a decimal point because JSON doesn't distinguish the // that always has a decimal point because JSON doesn't distinguish the
// concepts of reals and integers. // concepts of reals and integers.
if (!std::isfinite(value)) { if (!isfinite(value)) {
if (std::isnan(value)) static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"},
return useSpecialFloats ? "NaN" : "null"; {"null", "-1e+9999", "1e+9999"}};
if (value < 0) return reps[useSpecialFloats ? 0 : 1]
return useSpecialFloats ? "-Infinity" : "-1e+9999"; [isnan(value) ? 0 : (value < 0) ? 1 : 2];
return useSpecialFloats ? "Infinity" : "1e+9999";
} }
String buffer(size_t(36), '\0'); String buffer(size_t(36), '\0');
@ -92,18 +154,16 @@ String valueToString(double value, bool useSpecialFloats,
buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
// strip the zero padding from the right
if (precisionType == 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 // try to ensure we preserve the fact that this was given to us as a double on
// input // input
if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) { if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {
buffer += ".0"; 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; return buffer;
} }
} // namespace } // namespace
@ -210,7 +270,7 @@ static void appendHex(String& result, unsigned ch) {
result.append("\\u").append(toHex16Bit(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) { bool emitUTF8 = false) {
if (value == nullptr) if (value == nullptr)
return ""; return "";
@ -288,11 +348,7 @@ static String valueToQuotedStringN(const char* value, size_t length,
} }
String valueToQuotedString(const char* value) { String valueToQuotedString(const char* value) {
return valueToQuotedStringN(value, strlen(value)); return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
}
String valueToQuotedString(const char* value, size_t length) {
return valueToQuotedStringN(value, length);
} }
// Class Writer // Class Writer
@ -341,7 +397,7 @@ void FastWriter::writeValue(const Value& value) {
char const* end; char const* end;
bool ok = value.getString(&str, &end); bool ok = value.getString(&str, &end);
if (ok) if (ok)
document_ += valueToQuotedStringN(str, static_cast<size_t>(end - str)); document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));
break; break;
} }
case booleanValue: case booleanValue:
@ -364,7 +420,8 @@ void FastWriter::writeValue(const Value& value) {
const String& name = *it; const String& name = *it;
if (it != members.begin()) if (it != members.begin())
document_ += ','; document_ += ',';
document_ += valueToQuotedStringN(name.data(), name.length()); document_ += valueToQuotedStringN(name.data(),
static_cast<unsigned>(name.length()));
document_ += yamlCompatibilityEnabled_ ? ": " : ":"; document_ += yamlCompatibilityEnabled_ ? ": " : ":";
writeValue(value[name]); writeValue(value[name]);
} }
@ -409,7 +466,7 @@ void StyledWriter::writeValue(const Value& value) {
char const* end; char const* end;
bool ok = value.getString(&str, &end); bool ok = value.getString(&str, &end);
if (ok) if (ok)
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str))); pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
else else
pushValue(""); pushValue("");
break; break;
@ -432,7 +489,7 @@ void StyledWriter::writeValue(const Value& value) {
const String& name = *it; const String& name = *it;
const Value& childValue = value[name]; const Value& childValue = value[name];
writeCommentBeforeValue(childValue); writeCommentBeforeValue(childValue);
writeWithIndent(valueToQuotedString(name.c_str(), name.size())); writeWithIndent(valueToQuotedString(name.c_str()));
document_ += " : "; document_ += " : ";
writeValue(childValue); writeValue(childValue);
if (++it == members.end()) { if (++it == members.end()) {
@ -450,7 +507,7 @@ void StyledWriter::writeValue(const Value& value) {
} }
void StyledWriter::writeArrayValue(const Value& value) { void StyledWriter::writeArrayValue(const Value& value) {
size_t size = value.size(); unsigned size = value.size();
if (size == 0) if (size == 0)
pushValue("[]"); pushValue("[]");
else { else {
@ -459,7 +516,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
writeWithIndent("["); writeWithIndent("[");
indent(); indent();
bool hasChildValue = !childValues_.empty(); bool hasChildValue = !childValues_.empty();
ArrayIndex index = 0; unsigned index = 0;
for (;;) { for (;;) {
const Value& childValue = value[index]; const Value& childValue = value[index];
writeCommentBeforeValue(childValue); writeCommentBeforeValue(childValue);
@ -482,7 +539,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
{ {
assert(childValues_.size() == size); assert(childValues_.size() == size);
document_ += "[ "; document_ += "[ ";
for (size_t index = 0; index < size; ++index) { for (unsigned index = 0; index < size; ++index) {
if (index > 0) if (index > 0)
document_ += ", "; document_ += ", ";
document_ += childValues_[index]; document_ += childValues_[index];
@ -627,7 +684,7 @@ void StyledStreamWriter::writeValue(const Value& value) {
char const* end; char const* end;
bool ok = value.getString(&str, &end); bool ok = value.getString(&str, &end);
if (ok) if (ok)
pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str))); pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
else else
pushValue(""); pushValue("");
break; break;
@ -650,7 +707,7 @@ void StyledStreamWriter::writeValue(const Value& value) {
const String& name = *it; const String& name = *it;
const Value& childValue = value[name]; const Value& childValue = value[name];
writeCommentBeforeValue(childValue); writeCommentBeforeValue(childValue);
writeWithIndent(valueToQuotedString(name.c_str(), name.size())); writeWithIndent(valueToQuotedString(name.c_str()));
*document_ << " : "; *document_ << " : ";
writeValue(childValue); writeValue(childValue);
if (++it == members.end()) { if (++it == members.end()) {
@ -901,8 +958,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
char const* end; char const* end;
bool ok = value.getString(&str, &end); bool ok = value.getString(&str, &end);
if (ok) if (ok)
pushValue( pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str),
valueToQuotedStringN(str, static_cast<size_t>(end - str), emitUTF8_)); emitUTF8_));
else else
pushValue(""); pushValue("");
break; break;
@ -925,8 +982,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
String const& name = *it; String const& name = *it;
Value const& childValue = value[name]; Value const& childValue = value[name];
writeCommentBeforeValue(childValue); writeCommentBeforeValue(childValue);
writeWithIndent( writeWithIndent(valueToQuotedStringN(
valueToQuotedStringN(name.data(), name.length(), emitUTF8_)); name.data(), static_cast<unsigned>(name.length()), emitUTF8_));
*sout_ << colonSymbol_; *sout_ << colonSymbol_;
writeValue(childValue); writeValue(childValue);
if (++it == members.end()) { if (++it == members.end()) {
@ -1160,7 +1217,7 @@ bool StreamWriterBuilder::validate(Json::Value* invalid) const {
if (valid_keys.count(key)) if (valid_keys.count(key))
continue; continue;
if (invalid) if (invalid)
(*invalid)[key] = *si; (*invalid)[std::move(key)] = *si;
else else
return false; return false;
} }
@ -1188,7 +1245,7 @@ String writeString(StreamWriter::Factory const& factory, Value const& root) {
OStringStream sout; OStringStream sout;
StreamWriterPtr const writer(factory.newStreamWriter()); StreamWriterPtr const writer(factory.newStreamWriter());
writer->write(root, &sout); writer->write(root, &sout);
return std::move(sout).str(); return sout.str();
} }
OStream& operator<<(OStream& sout, Value const& root) { OStream& operator<<(OStream& sout, Value const& root) {

View File

@ -410,7 +410,7 @@ Json::String ToJsonString(const char* toConvert) {
Json::String ToJsonString(Json::String in) { return in; } Json::String ToJsonString(Json::String in) { return in; }
#if JSONCPP_USE_SECURE_MEMORY #if JSONCPP_USING_SECURE_MEMORY
Json::String ToJsonString(std::string in) { Json::String ToJsonString(std::string in) {
return Json::String(in.data(), in.data() + in.length()); return Json::String(in.data(), in.data() + in.length());
} }

View File

@ -74,7 +74,7 @@ public:
/// Removes the last PredicateContext added to the predicate stack /// Removes the last PredicateContext added to the predicate stack
/// chained list. /// 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(); TestResult& popPredicateContext();
bool failed() const; bool failed() const;
@ -185,7 +185,7 @@ TestResult& checkEqual(TestResult& result, T expected, U actual,
Json::String ToJsonString(const char* toConvert); Json::String ToJsonString(const char* toConvert);
Json::String ToJsonString(Json::String in); Json::String ToJsonString(Json::String in);
#if JSONCPP_USE_SECURE_MEMORY #if JSONCPP_USING_SECURE_MEMORY
Json::String ToJsonString(std::string in); Json::String ToJsonString(std::string in);
#endif #endif

View File

@ -12,7 +12,6 @@
#include "fuzz.h" #include "fuzz.h"
#include "jsontest.h" #include "jsontest.h"
#include <algorithm>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <functional> #include <functional>
@ -25,7 +24,6 @@
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector>
using CharReaderPtr = std::unique_ptr<Json::CharReader>; using CharReaderPtr = std::unique_ptr<Json::CharReader>;
@ -76,8 +74,6 @@ struct ValueTest : JsonTest::TestCase {
Json::Value float_{0.00390625f}; Json::Value float_{0.00390625f};
Json::Value array1_; Json::Value array1_;
Json::Value object1_; Json::Value object1_;
Json::Value object2_;
Json::Value object3_;
Json::Value emptyString_{""}; Json::Value emptyString_{""};
Json::Value string1_{"a"}; Json::Value string1_{"a"};
Json::Value string_{"sometext with space"}; Json::Value string_{"sometext with space"};
@ -87,34 +83,6 @@ struct ValueTest : JsonTest::TestCase {
ValueTest() { ValueTest() {
array1_.append(1234); array1_.append(1234);
object1_["id"] = 1234; object1_["id"] = 1234;
// object2 with matching values
object2_["null"] = Json::nullValue;
object2_["bool"] = true;
object2_["int"] = Json::Int{Json::Value::maxInt};
object2_["int64"] = Json::Int64{Json::Value::maxInt64};
object2_["uint"] = Json::UInt{Json::Value::maxUInt};
object2_["uint64"] = Json::UInt64{Json::Value::maxUInt64};
object2_["integral"] = 1234;
object2_["double"] = 1234.56789;
object2_["numeric"] = 0.12345f;
object2_["string"] = "string";
object2_["array"] = Json::arrayValue;
object2_["object"] = Json::objectValue;
// object3 with not matching values
object3_["object"] = Json::nullValue;
object3_["null"] = true;
object3_["bool"] = Json::Int{Json::Value::maxInt};
object3_["int"] = "not_an_int";
object3_["int64"] = "not_an_int64";
object3_["uint"] = "not_an_uint";
object3_["uin64"] = "not_an_uint64";
object3_["integral"] = 1234.56789;
object3_["double"] = false;
object3_["numeric"] = "string";
object3_["string"] = Json::arrayValue;
object3_["array"] = Json::objectValue;
} }
struct IsCheck { struct IsCheck {
@ -250,76 +218,11 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, objects) {
JSONTEST_ASSERT(foundId != nullptr); JSONTEST_ASSERT(foundId != nullptr);
JSONTEST_ASSERT_EQUAL(Json::Value(1234), *foundId); JSONTEST_ASSERT_EQUAL(Json::Value(1234), *foundId);
const std::string stringIdKey = "id";
const Json::Value* stringFoundId = object1_.find(stringIdKey);
JSONTEST_ASSERT(stringFoundId != nullptr);
JSONTEST_ASSERT_EQUAL(Json::Value(1234), *stringFoundId);
const char unknownIdKey[] = "unknown id"; const char unknownIdKey[] = "unknown id";
const Json::Value* foundUnknownId = const Json::Value* foundUnknownId =
object1_.find(unknownIdKey, unknownIdKey + strlen(unknownIdKey)); object1_.find(unknownIdKey, unknownIdKey + strlen(unknownIdKey));
JSONTEST_ASSERT_EQUAL(nullptr, foundUnknownId); JSONTEST_ASSERT_EQUAL(nullptr, foundUnknownId);
const std::string stringUnknownIdKey = "unknown id";
const Json::Value* stringFoundUnknownId = object1_.find(stringUnknownIdKey);
JSONTEST_ASSERT_EQUAL(nullptr, stringFoundUnknownId);
// Access through find<Type>()
const Json::Value* nullFound = object2_.findNull("null");
JSONTEST_ASSERT(nullFound != nullptr);
JSONTEST_ASSERT_EQUAL(Json::nullValue, *nullFound);
JSONTEST_ASSERT(object3_.findNull("null") == nullptr);
const Json::Value* boolFound = object2_.findBool("bool");
JSONTEST_ASSERT(boolFound != nullptr);
JSONTEST_ASSERT_EQUAL(true, *boolFound);
JSONTEST_ASSERT(object3_.findBool("bool") == nullptr);
const Json::Value* intFound = object2_.findInt("int");
JSONTEST_ASSERT(intFound != nullptr);
JSONTEST_ASSERT_EQUAL(Json::Int{Json::Value::maxInt}, *intFound);
JSONTEST_ASSERT(object3_.findInt("int") == nullptr);
const Json::Value* int64Found = object2_.findInt64("int64");
JSONTEST_ASSERT(int64Found != nullptr);
JSONTEST_ASSERT_EQUAL(Json::Int64{Json::Value::maxInt64}, *int64Found);
JSONTEST_ASSERT(object3_.findInt64("int64") == nullptr);
const Json::Value* uintFound = object2_.findUInt("uint");
JSONTEST_ASSERT(uintFound != nullptr);
JSONTEST_ASSERT_EQUAL(Json::UInt{Json::Value::maxUInt}, *uintFound);
JSONTEST_ASSERT(object3_.findUInt("uint") == nullptr);
const Json::Value* uint64Found = object2_.findUInt64("uint64");
JSONTEST_ASSERT(uint64Found != nullptr);
JSONTEST_ASSERT_EQUAL(Json::UInt64{Json::Value::maxUInt64}, *uint64Found);
JSONTEST_ASSERT(object3_.findUInt64("uint64") == nullptr);
const Json::Value* integralFound = object2_.findIntegral("integral");
JSONTEST_ASSERT(integralFound != nullptr);
JSONTEST_ASSERT_EQUAL(1234, *integralFound);
JSONTEST_ASSERT(object3_.findIntegral("integral") == nullptr);
const Json::Value* doubleFound = object2_.findDouble("double");
JSONTEST_ASSERT(doubleFound != nullptr);
JSONTEST_ASSERT_EQUAL(1234.56789, *doubleFound);
JSONTEST_ASSERT(object3_.findDouble("double") == nullptr);
const Json::Value* numericFound = object2_.findNumeric("numeric");
JSONTEST_ASSERT(numericFound != nullptr);
JSONTEST_ASSERT_EQUAL(0.12345f, *numericFound);
JSONTEST_ASSERT(object3_.findNumeric("numeric") == nullptr);
const Json::Value* stringFound = object2_.findString("string");
JSONTEST_ASSERT(stringFound != nullptr);
JSONTEST_ASSERT_EQUAL(std::string{"string"}, *stringFound);
JSONTEST_ASSERT(object3_.findString("string") == nullptr);
const Json::Value* arrayFound = object2_.findArray("array");
JSONTEST_ASSERT(arrayFound != nullptr);
JSONTEST_ASSERT_EQUAL(Json::arrayValue, *arrayFound);
JSONTEST_ASSERT(object3_.findArray("array") == nullptr);
// Access through demand() // Access through demand()
const char yetAnotherIdKey[] = "yet another id"; const char yetAnotherIdKey[] = "yet another id";
const Json::Value* foundYetAnotherId = const Json::Value* foundYetAnotherId =
@ -405,14 +308,10 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, arrays) {
const Json::Value& constArray = array1_; const Json::Value& constArray = array1_;
JSONTEST_ASSERT_EQUAL(Json::Value(1234), constArray[index0]); JSONTEST_ASSERT_EQUAL(Json::Value(1234), constArray[index0]);
JSONTEST_ASSERT_EQUAL(Json::Value(1234), constArray[0]); JSONTEST_ASSERT_EQUAL(Json::Value(1234), constArray[0]);
JSONTEST_ASSERT_EQUAL(Json::Value(1234), constArray.front());
JSONTEST_ASSERT_EQUAL(Json::Value(1234), constArray.back());
// Access through non-const reference // Access through non-const reference
JSONTEST_ASSERT_EQUAL(Json::Value(1234), array1_[index0]); JSONTEST_ASSERT_EQUAL(Json::Value(1234), array1_[index0]);
JSONTEST_ASSERT_EQUAL(Json::Value(1234), array1_[0]); JSONTEST_ASSERT_EQUAL(Json::Value(1234), array1_[0]);
JSONTEST_ASSERT_EQUAL(Json::Value(1234), array1_.front());
JSONTEST_ASSERT_EQUAL(Json::Value(1234), array1_.back());
array1_[2] = Json::Value(17); array1_[2] = Json::Value(17);
JSONTEST_ASSERT_EQUAL(Json::Value(), array1_[1]); JSONTEST_ASSERT_EQUAL(Json::Value(), array1_[1]);
@ -448,19 +347,6 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, resizeArray) {
JSONTEST_ASSERT_EQUAL(array.size(), 0); JSONTEST_ASSERT_EQUAL(array.size(), 0);
} }
} }
JSONTEST_FIXTURE_LOCAL(ValueTest, resizePopulatesAllMissingElements) {
Json::ArrayIndex n = 10;
Json::Value v;
v.resize(n);
JSONTEST_ASSERT_EQUAL(n, v.size());
JSONTEST_ASSERT_EQUAL(n, std::distance(v.begin(), v.end()));
JSONTEST_ASSERT_EQUAL(v.front(), Json::Value{});
JSONTEST_ASSERT_EQUAL(v.back(), Json::Value{});
for (const Json::Value& e : v)
JSONTEST_ASSERT_EQUAL(e, Json::Value{});
}
JSONTEST_FIXTURE_LOCAL(ValueTest, getArrayValue) { JSONTEST_FIXTURE_LOCAL(ValueTest, getArrayValue) {
Json::Value array; Json::Value array;
for (Json::ArrayIndex i = 0; i < 5; i++) for (Json::ArrayIndex i = 0; i < 5; i++)
@ -507,8 +393,6 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, arrayInsertAtRandomIndex) {
JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[0]); // check append JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[0]); // check append
JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[1]); JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[1]);
JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[2]); JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[2]);
JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array.front());
JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array.back());
// insert lvalue at the head // insert lvalue at the head
JSONTEST_ASSERT(array.insert(0, str1)); JSONTEST_ASSERT(array.insert(0, str1));
@ -516,8 +400,6 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, arrayInsertAtRandomIndex) {
JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[1]); JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[1]);
JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[2]); JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[2]);
JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[3]); JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[3]);
JSONTEST_ASSERT_EQUAL(Json::Value("index3"), array.front());
JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array.back());
// checking address // checking address
for (Json::ArrayIndex i = 0; i < 3; i++) { for (Json::ArrayIndex i = 0; i < 3; i++) {
JSONTEST_ASSERT_EQUAL(vec[i], &array[i]); JSONTEST_ASSERT_EQUAL(vec[i], &array[i]);
@ -530,8 +412,6 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, arrayInsertAtRandomIndex) {
JSONTEST_ASSERT_EQUAL(Json::Value("index4"), array[2]); JSONTEST_ASSERT_EQUAL(Json::Value("index4"), array[2]);
JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[3]); JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[3]);
JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[4]); JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[4]);
JSONTEST_ASSERT_EQUAL(Json::Value("index3"), array.front());
JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array.back());
// checking address // checking address
for (Json::ArrayIndex i = 0; i < 4; i++) { for (Json::ArrayIndex i = 0; i < 4; i++) {
JSONTEST_ASSERT_EQUAL(vec[i], &array[i]); JSONTEST_ASSERT_EQUAL(vec[i], &array[i]);
@ -545,8 +425,6 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, arrayInsertAtRandomIndex) {
JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[3]); JSONTEST_ASSERT_EQUAL(Json::Value("index1"), array[3]);
JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[4]); JSONTEST_ASSERT_EQUAL(Json::Value("index2"), array[4]);
JSONTEST_ASSERT_EQUAL(Json::Value("index5"), array[5]); JSONTEST_ASSERT_EQUAL(Json::Value("index5"), array[5]);
JSONTEST_ASSERT_EQUAL(Json::Value("index3"), array.front());
JSONTEST_ASSERT_EQUAL(Json::Value("index5"), array.back());
// checking address // checking address
for (Json::ArrayIndex i = 0; i < 5; i++) { for (Json::ArrayIndex i = 0; i < 5; i++) {
JSONTEST_ASSERT_EQUAL(vec[i], &array[i]); JSONTEST_ASSERT_EQUAL(vec[i], &array[i]);
@ -1277,13 +1155,15 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, integers) {
JSONTEST_ASSERT_EQUAL(true, val.asBool()); JSONTEST_ASSERT_EQUAL(true, val.asBool());
JSONTEST_ASSERT_STRING_EQUAL("-9223372036854775808", val.asString()); JSONTEST_ASSERT_STRING_EQUAL("-9223372036854775808", val.asString());
// int64 min (floating point constructor). Since double values in proximity of // int64 min (floating point constructor). Note that kint64min *is* exactly
// kint64min are rounded to kint64min, we don't check for conversion to int64. // representable as a double.
val = Json::Value(double(kint64min)); val = Json::Value(double(kint64min));
JSONTEST_ASSERT_EQUAL(Json::realValue, val.type()); JSONTEST_ASSERT_EQUAL(Json::realValue, val.type());
checks = IsCheck(); checks = IsCheck();
checks.isInt64_ = true;
checks.isIntegral_ = true;
checks.isDouble_ = true; checks.isDouble_ = true;
checks.isNumeric_ = true; checks.isNumeric_ = true;
JSONTEST_ASSERT_PRED(checkIs(val, checks)); JSONTEST_ASSERT_PRED(checkIs(val, checks));
@ -1292,6 +1172,8 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, integers) {
JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue)); JSONTEST_ASSERT(!val.isConvertibleTo(Json::intValue));
JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue)); JSONTEST_ASSERT(!val.isConvertibleTo(Json::uintValue));
JSONTEST_ASSERT_EQUAL(kint64min, val.asInt64());
JSONTEST_ASSERT_EQUAL(kint64min, val.asLargestInt());
JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asDouble()); JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asDouble());
JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asFloat()); JSONTEST_ASSERT_EQUAL(-9223372036854775808.0, val.asFloat());
JSONTEST_ASSERT_EQUAL(true, val.asBool()); JSONTEST_ASSERT_EQUAL(true, val.asBool());
@ -2123,34 +2005,6 @@ JSONTEST_FIXTURE_LOCAL(ValueTest, precision) {
result = Json::writeString(b, v); result = Json::writeString(b, v);
JSONTEST_ASSERT_STRING_EQUAL(expected, result); JSONTEST_ASSERT_STRING_EQUAL(expected, result);
b.settings_["precision"] = 0;
b.settings_["precisionType"] = "decimal";
v = 123.56345694873740545068;
expected = "124";
result = Json::writeString(b, v);
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
b.settings_["precision"] = 1;
b.settings_["precisionType"] = "decimal";
v = 1230.001;
expected = "1230.0";
result = Json::writeString(b, v);
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
b.settings_["precision"] = 0;
b.settings_["precisionType"] = "decimal";
v = 1230.001;
expected = "1230";
result = Json::writeString(b, v);
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
b.settings_["precision"] = 0;
b.settings_["precisionType"] = "decimal";
v = 1231.5;
expected = "1232";
result = Json::writeString(b, v);
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
b.settings_["precision"] = 10; b.settings_["precision"] = 10;
b.settings_["precisionType"] = "decimal"; b.settings_["precisionType"] = "decimal";
v = 0.23300000; v = 0.23300000;
@ -3723,12 +3577,12 @@ JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) {
for (const auto& td : test_data) { for (const auto& td : test_data) {
bool ok = reader->parse(&*td.in.begin(), &*td.in.begin() + td.in.size(), bool ok = reader->parse(&*td.in.begin(), &*td.in.begin() + td.in.size(),
&root, &errs); &root, &errs);
// clang-format off JSONTEST_ASSERT(td.ok == ok) << "line:" << td.line << "\n"
JSONTEST_ASSERT(td.ok == ok) << << " expected: {"
"line:" << td.line << "\n " << << "ok:" << td.ok << ", in:\'" << td.in << "\'"
"expected: {ok:" << td.ok << ", in:\'" << td.in << "\'}\n " << << "}\n"
"actual: {ok:" << ok << "}\n"; << " actual: {"
// clang-format on << "ok:" << ok << "}\n";
} }
{ {
@ -4008,36 +3862,6 @@ JSONTEST_FIXTURE_LOCAL(FuzzTest, fuzzDoesntCrash) {
example.size())); example.size()));
} }
struct ParseWithStructuredErrorsTest : JsonTest::TestCase {
void testErrors(
const std::string& doc, bool success,
const std::vector<Json::CharReader::StructuredError>& expectedErrors) {
Json::CharReaderBuilder b;
CharReaderPtr reader(b.newCharReader());
Json::Value root;
JSONTEST_ASSERT_EQUAL(
reader->parse(doc.data(), doc.data() + doc.length(), &root, nullptr),
success);
auto actualErrors = reader->getStructuredErrors();
JSONTEST_ASSERT_EQUAL(expectedErrors.size(), actualErrors.size());
for (std::size_t i = 0; i < actualErrors.size(); i++) {
const auto& a = actualErrors[i];
const auto& e = expectedErrors[i];
JSONTEST_ASSERT_EQUAL(a.offset_start, e.offset_start);
JSONTEST_ASSERT_EQUAL(a.offset_limit, e.offset_limit);
JSONTEST_ASSERT_STRING_EQUAL(a.message, e.message);
}
}
};
JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, success) {
testErrors("{}", true, {});
}
JSONTEST_FIXTURE_LOCAL(ParseWithStructuredErrorsTest, singleError) {
testErrors("{ 1 : 2 }", false, {{2, 3, "Missing '}' or object member name"}});
}
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
JsonTest::Runner runner; JsonTest::Runner runner;
@ -4092,15 +3916,6 @@ JSONTEST_FIXTURE_LOCAL(MemberTemplateIs, BehavesSameAsNamedIs) {
} }
} }
class VersionTest : public JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(VersionTest, VersionNumbersMatch) {
std::ostringstream vstr;
vstr << JSONCPP_VERSION_MAJOR << '.' << JSONCPP_VERSION_MINOR << '.'
<< JSONCPP_VERSION_PATCH;
JSONTEST_ASSERT_EQUAL(vstr.str(), std::string(JSONCPP_VERSION_STRING));
}
#if defined(__GNUC__) #if defined(__GNUC__)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif

View File

@ -1,4 +0,0 @@
{
"a": "aaa",
"b": "bbb" // comments not allowed in strict mode
}

View File

@ -1,4 +0,0 @@
{
"a": "aaa", // comments not allowed in strict mode
"b": "bbb"
}

View File

@ -1,3 +0,0 @@
{
"array" : [1, 2, 3 /* comments not allowed in strict mode */]
}

View File

@ -1 +0,0 @@
{"one": 1 /* } */ { "two" : 2 }

View File

@ -1,3 +0,0 @@
.=[]
.[0]=-inf
.[1]=inf

View File

@ -1 +0,0 @@
[-1e+9999, 1e+9999]

View File

@ -97,17 +97,14 @@ def runAllTests(jsontest_executable_path, input_dir = None,
valgrind_path = use_valgrind and VALGRIND_CMD or '' valgrind_path = use_valgrind and VALGRIND_CMD or ''
for input_path in tests + test_jsonchecker: for input_path in tests + test_jsonchecker:
expect_failure = os.path.basename(input_path).startswith('fail') expect_failure = os.path.basename(input_path).startswith('fail')
is_json_checker_test = input_path in test_jsonchecker is_json_checker_test = (input_path in test_jsonchecker) or expect_failure
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
print('TESTING:', input_path, end=' ') print('TESTING:', input_path, end=' ')
options = is_parse_only and '--parse-only' or '' options = is_json_checker_test and '--json-checker' or ''
options += is_strict_test and ' --strict' or ''
options += ' --json-writer %s'%writerClass options += ' --json-writer %s'%writerClass
cmd = '%s%s %s "%s"' % ( valgrind_path, jsontest_executable_path, options, cmd = '%s%s %s "%s"' % ( valgrind_path, jsontest_executable_path, options,
input_path) input_path)
status, process_output = getStatusOutput(cmd) status, process_output = getStatusOutput(cmd)
if is_parse_only: if is_json_checker_test:
if expect_failure: if expect_failure:
if not status: if not status:
print('FAILED') print('FAILED')