1 Commits

Author SHA1 Message Date
Eric Hawicz
fa7308b3de Run travis builds using iOS flags, to attempt to reproduce Issue #808. 2023-07-30 10:23:21 -04:00
68 changed files with 226 additions and 4262 deletions

View File

@@ -1,228 +0,0 @@
name: meson
on: [push, pull_request]
concurrency:
group: ${{github.workflow}}-${{github.head_ref}}
cancel-in-progress: true
jobs:
Linux-GCC:
runs-on: ubuntu-22.04
strategy:
matrix:
cc: ['9', '13']
steps:
- uses: actions/checkout@v4
- uses: egor-tensin/setup-gcc@v1
with:
version: ${{matrix.cc}}
- name: Install packages
run: |
python3 -m pip install meson ninja
- name: Compile and Test
run: |
meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dbuildtype=debug
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
Linux-Clang:
runs-on: ubuntu-22.04
strategy:
matrix:
cc: ['9', '22']
steps:
- uses: actions/checkout@v4
- uses: egor-tensin/setup-clang@v1
- name: Install packages
run: |
python3 -m pip install meson ninja
- name: Compile and Test
run: |
meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dbuildtype=debug
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
VisualStudio:
runs-on: windows-latest
strategy:
matrix:
platform: ['x64', 'x86']
steps:
- uses: actions/checkout@v4
- name: Install packages
run: |
python -m pip install meson ninja
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{matrix.platform}}
- name: Compile and Test
env:
CFLAGS: '/analyze'
run: |
meson setup "${{github.workspace}}/build" --wrap-mode=forcefallback -Dwarning_level=3 -Dbuildtype=debug
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
VisualStudio-clang-cl:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Install packages
run: |
python -m pip install meson ninja
- uses: ilammy/msvc-dev-cmd@v1
- name: Compile and Test
env:
CC: clang-cl
run: |
meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dbuildtype=debug
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
MSYS2:
runs-on: windows-latest
strategy:
matrix:
platform: ['UCRT64', 'CLANG64']
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
with:
msystem: ${{matrix.platform}}
pacboy: >-
cc:p
cmake:p
meson:p
ninja:p
pkgconf:p
- name: Compile and Test
run: |
meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dbuildtype=debug
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
Cygwin:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
with:
msystem: 'MSYS'
install: >-
gcc
meson
ninja
- name: Compile and Test
run: |
meson setup build -Dwarning_level=3 -Dcpp_std=gnu++20 -Dbuildtype=debug
meson compile -C build --verbose
meson test -C build --verbose
MacOS:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install packages
run: |
brew install meson
- name: Compile and Test
run: |
meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dbuildtype=debug
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
DragonflyBSD:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: vmactions/dragonflybsd-vm@v1
with:
prepare: |
pkg install -y ninja meson pkgconf
run: |
meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dbuildtype=debug
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
FreeBSD:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: vmactions/freebsd-vm@v1
with:
prepare: |
pkg install -y ninja meson pkgconf
run: |
meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dbuildtype=debug
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
NetBSD:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: vmactions/netbsd-vm@v1
with:
prepare: |
/usr/sbin/pkg_add meson pkgconf
run: |
meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dbuildtype=debug
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
OmniOS:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: vmactions/omnios-vm@v1
with:
prepare: |
pkg install gcc14 meson-313 ninja pkg-config python-313
run: |
/usr/lib/python3.13/bin/meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dbuildtype=debug
/usr/lib/python3.13/bin/meson compile -C "${{github.workspace}}/build" --verbose
/usr/lib/python3.13/bin/meson test -C "${{github.workspace}}/build" --verbose
OpenBSD:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: vmactions/openbsd-vm@v1
with:
prepare: |
pkg_add ninja meson pkgconf
run: |
meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dbuildtype=debug
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose
Alpine:
runs-on: ubuntu-latest
strategy:
matrix:
platform: ['x86_64', 'x86', 'armhf', 'armv7', 'aarch64', 'ppc64le', 'riscv64', 's390x']
defaults:
run:
shell: alpine.sh {0}
steps:
- uses: actions/checkout@v4
- uses: jirutka/setup-alpine@v1
with:
branch: edge
arch: ${{matrix.platform}}
packages: >
build-base pkgconf meson samurai
- name: Compile and Test
run: |
meson setup "${{github.workspace}}/build" -Dwarning_level=3 -Dbuildtype=debug
meson compile -C "${{github.workspace}}/build" --verbose
meson test -C "${{github.workspace}}/build" --verbose

1
.gitignore vendored
View File

@@ -10,7 +10,6 @@
*.save *.save
*.autosav *.autosav
*.autosave *.autosave
.DS_Store
# Tests # Tests
/tests/Makefile /tests/Makefile

View File

@@ -2,146 +2,22 @@ language: cpp
matrix: matrix:
include: include:
# ubuntu xenial 16.04
# gcc 5 is the default on xenial
- os: linux
dist: xenial
compiler: gcc
addons:
apt:
packages:
- valgrind
- cppcheck
- doxygen
- cmake
env: CHECK="true"
# ubuntu bionic 18.04
# gcc 7 is the default on bionic
- os: linux
dist: bionic
compiler: gcc
addons:
apt:
packages:
- valgrind
- cppcheck
- doxygen
- cmake
env: CHECK="true"
# ubuntu focal fossa 20.04
# gcc 9 is the default on bionic
- os: linux
dist: focal
compiler: gcc
addons:
apt:
packages:
- valgrind
- cppcheck
- doxygen
- cmake
env: CHECK="true"
# clang
# xenial
- os: linux
dist: xenial
compiler: clang
addons:
apt:
sources:
- llvm-toolchain-xenial-6.0
packages:
- clang-6.0
- cmake
env: MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0"
# clang-7 is the default on focal, xenial and bionic
- os: linux
dist: focal
compiler: clang
addons:
apt:
packages:
- valgrind
- cppcheck
- doxygen
- cmake
env: CHECK="true"
# osx # osx
- os: osx - os: osx
osx_image: xcode13.4 osx_image: xcode13.4
env: XCODE="true" CHECK="true" env: XCODE="true" CHECK="true"
# run coveralls
- os: linux
dist: xenial
compiler: gcc
addons:
apt:
packages:
- lcov
env: CHECK="true"
before_install:
- sudo gem install coveralls-lcov
- echo $CC
- echo $LANG
- echo $LC_ALL
- set -e
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
eval "${MATRIX_EVAL}";
if [ -n "$MATRIX_EVAL" ] && [ "$TRAVIS_COMPILER" != "clang" ]; then
sudo apt-get install -y $CC;
fi;
fi
before_script:
- export CFLAGS="-fprofile-arcs -ftest-coverage"
- mkdir build && cd build && cmake ..
script:
- make
- make test
after_success:
- cd ..
- lcov -d build/ -b . -c -o build/all_coverage.info
- lcov -r build/all_coverage.info '/usr/*' '*CMakeFiles*' '*fuzz*' '*test*' -o build/coverage.info
- coveralls-lcov --verbose build/coverage.info
# allow_failures:
# - os: osx
before_install: before_install:
- echo $CC - echo $CC
- echo $LANG - echo $LANG
- echo $LC_ALL - echo $LC_ALL
- set -e
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
eval "${MATRIX_EVAL}";
if [ -n "$MATRIX_EVAL" ] && [ "$TRAVIS_COMPILER" != "clang" ]; then
sudo apt-get install -y $CC;
fi;
fi
before_script: before_script:
# XXX osx on travis doesn't work w/ set -e, so turn it off :( # XXX osx on travis doesn't work w/ set -e, so turn it off :(
- set +e - set +e
- mkdir -p build || echo "Failed to mkdir build" - mkdir -p build || echo "Failed to mkdir build"
- cd build || echo "Failed to cd build" - cd build || echo "Failed to cd build"
- cmake .. || echo "Failed to run cmake" - cmake -B_builds -GXcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0 -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=NO -DCMAKE_IOS_INSTALL_COMBINED=YES .. || { echo "Failed to run cmake" ; exit 1 ; }
script: script:
- make - cmake --build _builds --config Release --target json-c-static -- -sdk iphonesimulator
# when using bionic, Travis seems to ignore the "addons" section, so installing the packages with apt-get...
- if [ -n "$CHECK" ]; then
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew install doxygen;
else
if [ "$TRAVIS_DIST" = "bionic" ]; then
sudo apt-get install -y valgrind cppcheck doxygen;
fi;
fi;
make distcheck;
if type cppcheck &> /dev/null ; then cppcheck --error-exitcode=1 --quiet *.h *.c tests/ ; fi;
fi

33
AUTHORS
View File

@@ -1,40 +1,25 @@
Alan Coopersmith <alan.coopersmith@oracle.com> Alan Coopersmith <alan.coopersmith@oracle.com>
Alan Urmancheev <108410815+alurm@users.noreply.github.com>
Alexander Dahl <post@lespocky.de> Alexander Dahl <post@lespocky.de>
Alexandru Ardelean <ardeleanalex@gmail.com> Alexandru Ardelean <ardeleanalex@gmail.com>
An7ar35 <eadavison@protonmail.com>
andy5995 <andy400-dev@yahoo.com> andy5995 <andy400-dev@yahoo.com>
Anton Lundin <glance@ac2.se>
Aram Poghosyan <Aram.Poghosyan@teamviewer.com> Aram Poghosyan <Aram.Poghosyan@teamviewer.com>
Awildidiot <69577313+0xfadead@users.noreply.github.com>
Björn Esser <besser82@fedoraproject.org> Björn Esser <besser82@fedoraproject.org>
BonsaY <bonsay@posteo.de> BonsaY <bonsay@posteo.de>
Bruno Haible <bruno@clisp.org>
Cameron Armstrong <cameronscottarmstrong@gmail.com>
Careles <zhancheng1996@gmail.com>
changyong guo <guo1487@163.com> changyong guo <guo1487@163.com>
chenguoping <chenguopingdota@163.com> chenguoping <chenguopingdota@163.com>
Chris Lamb <lamby@debian.org> Chris Lamb <lamby@debian.org>
Christopher Head <chead@chead.ca> Christopher Head <chead@chead.ca>
Chris Wolfe <chriswwolfe@gmail.com> Chris Wolfe <chriswwolfe@gmail.com>
C. Watford (christopher.watford@gmail.com) C. Watford (christopher.watford@gmail.com)
Daniel Danzberger <daniel@dd-wrt.com>
Darjan Krijan <darjan_krijan@gmx.de> Darjan Krijan <darjan_krijan@gmx.de>
David McCann <mccannd@uk.ibm.com> David McCann <mccannd@uk.ibm.com>
DeX77 <dex@dragonslave.de> DeX77 <dex@dragonslave.de>
Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com>
dota17 <chenguopingdota@163.com> dota17 <chenguopingdota@163.com>
Eric Haszlakiewicz <erh+git@nimenees.com> Eric Haszlakiewicz <erh+git@nimenees.com>
Eric Hawicz <erh+git@nimenees.com> Eric Hawicz <erh+git@nimenees.com>
Evan Si <evsi@amazon.com>
Even Rouault <even.rouault@spatialys.com> Even Rouault <even.rouault@spatialys.com>
evo <149657734+evo-i@users.noreply.github.com>
Fabrice Fontaine <fontaine.fabrice@gmail.com>
Federico Francescon <federico.francescon@higeco.com>
Gianluigi Tiesi <sherpya@netfarm.it> Gianluigi Tiesi <sherpya@netfarm.it>
grdowns <grdowns@microsoft.com> grdowns <grdowns@microsoft.com>
Guilhem Saurel <guilhem.saurel@laas.fr>
HansolChoe <hansol614@gmail.com>
Hex052 <elijahiff@gmail.com> Hex052 <elijahiff@gmail.com>
hofnarr <hofnarr@hofnarr.fi> hofnarr <hofnarr@hofnarr.fi>
ihsinme <61293369+ihsinme@users.noreply.github.com> ihsinme <61293369+ihsinme@users.noreply.github.com>
@@ -42,8 +27,6 @@ Ivan Romanov <drizt@land.ru>
Jaap Keuter <jaap.keuter@xs4all.nl> Jaap Keuter <jaap.keuter@xs4all.nl>
Jakov Smolic <jakov.smolic@sartura.hr> Jakov Smolic <jakov.smolic@sartura.hr>
janczer <menshikov.ivn@gmail.com> janczer <menshikov.ivn@gmail.com>
Ján Tomko <jtomko@redhat.com>
JC (Jonathan Chen) <jc@dijonkitchen.org>
Jehan <jehan@girinstud.io> Jehan <jehan@girinstud.io>
Jehiah Czebotar <jehiah@gmail.com> Jehiah Czebotar <jehiah@gmail.com>
Jonathan Wiens <j.wiens@teles.com> Jonathan Wiens <j.wiens@teles.com>
@@ -51,21 +34,15 @@ Jose Bollo <jose.bollo@iot.bzh>
José Bollo <jose.bollo@iot.bzh> José Bollo <jose.bollo@iot.bzh>
Juuso Alasuutari <juuso.alasuutari@gmail.com> Juuso Alasuutari <juuso.alasuutari@gmail.com>
Keith Holman <keith.holman@windriver.com> Keith Holman <keith.holman@windriver.com>
Khem Raj <raj.khem@gmail.com>
Kizuna-Meraki <z9@kizunameraki.de> Kizuna-Meraki <z9@kizunameraki.de>
Lakshmi-Surekha <Lakshmi.Kovvuri@ibm.com>
Leon Gross <leon.gross@rub.de> Leon Gross <leon.gross@rub.de>
Liang, Gao <liang.gao@intel.com> Liang, Gao <liang.gao@intel.com>
Luca Mannella <luca.mannella@studenti.polito.it>
Marc <34656315+MarcT512@users.noreply.github.com> Marc <34656315+MarcT512@users.noreply.github.com>
Matthias Gatto <matthias.gatto@protonmail.com>
max <mpano91@gmail.com> max <mpano91@gmail.com>
Micah Snyder <micasnyd@cisco.com> Micah Snyder <micasnyd@cisco.com>
Michael Clark <michael@metaparadigm.com> Michael Clark <michael@metaparadigm.com>
Michele Locati <michele@locati.it>
myd7349 <myd7349@gmail.com> myd7349 <myd7349@gmail.com>
Pascal Cuoq <cuoq@trust-in-soft.com> Pascal Cuoq <cuoq@trust-in-soft.com>
Pavel Zwerschke <pavelzw@gmail.com>
Pawday <pawday@mail.ru> Pawday <pawday@mail.ru>
Philosoph228 <philosoph228@gmail.com> Philosoph228 <philosoph228@gmail.com>
Pierce Lopez <pierce.lopez@gmail.com> Pierce Lopez <pierce.lopez@gmail.com>
@@ -73,22 +50,12 @@ Po-Chuan Hsieh <sunpoet@sunpoet.net>
Ramiro Polla <ramiro.polla@gmail.com> Ramiro Polla <ramiro.polla@gmail.com>
Rikard Falkeborn <rikard.falkeborn@gmail.com> Rikard Falkeborn <rikard.falkeborn@gmail.com>
Robert Bielik <robert.bielik@dirac.com> Robert Bielik <robert.bielik@dirac.com>
Robert Pang <robertpang@google.com>
Robert <roby_p97@yahoo.com> Robert <roby_p97@yahoo.com>
Rolf Eike Beer <eb@emlix.com>
Rosen Penev <rosenp@gmail.com> Rosen Penev <rosenp@gmail.com>
Rubasri Kalidas <rubasri.kalidas@intel.com> Rubasri Kalidas <rubasri.kalidas@intel.com>
Sergey Sharshunov <s.sharshunov@gmail.com>
Shane F. Carr <shane@unicode.org>
Simon McVittie <smcv@collabora.com> Simon McVittie <smcv@collabora.com>
Simon Resch <simon.resch@code-intelligence.de>
Simon Sobisch <simonsobisch@web.de>
ssrlive <30760636+ssrlive@users.noreply.github.com> ssrlive <30760636+ssrlive@users.noreply.github.com>
Timothée Ravier <tim@siosm.fr>
Tobias Nießen <tniessen@users.noreply.github.com> Tobias Nießen <tniessen@users.noreply.github.com>
Tobias Stoeckmann <tobias@stoeckmann.org> Tobias Stoeckmann <tobias@stoeckmann.org>
Tudor Brindus <me@tbrindus.ca> Tudor Brindus <me@tbrindus.ca>
Tyler Erickson <tyler.erickson@seagate.com>
Tyler Erickson <vonericsen@gmail.com>
Unmanned Player <36690541+unmanned-player@users.noreply.github.com> Unmanned Player <36690541+unmanned-player@users.noreply.github.com>
Yurii Rashkovskii <yrashk@gmail.com>

View File

@@ -3,11 +3,24 @@
# and many OpenWRT packages require, much newer CMake packages. # and many OpenWRT packages require, much newer CMake packages.
# We're stopping before 3.10 because that version starts requiring # We're stopping before 3.10 because that version starts requiring
# c++11, which isn't available on e.g HPUX. # c++11, which isn't available on e.g HPUX.
cmake_minimum_required(VERSION 3.9...3.12) cmake_minimum_required(VERSION 3.9)
# The project() command manages VERSION variables.
cmake_policy(SET CMP0048 NEW)
# JSON-C library is C only project. # JSON-C library is C only project.
# PROJECT_VERSION{,_MAJOR,_MINOR,_PATCH} set by project(): # PROJECT_VERSION{,_MAJOR,_MINOR,_PATCH} set by project():
project(json-c LANGUAGES C VERSION 0.18.99) project(json-c LANGUAGES C VERSION 0.16.99)
# Targets may not link directly to themselves.
cmake_policy(SET CMP0038 NEW)
# MACOSX_RPATH is enabled by default.
# We set it explicitly to avoid the warning
cmake_policy(SET CMP0042 NEW)
# Only interpret if() arguments as variables or keywords when unquoted.
cmake_policy(SET CMP0054 NEW)
# set default build type if not specified by user # set default build type if not specified by user
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
@@ -16,6 +29,13 @@ endif()
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
# Include file check macros honor CMAKE_REQUIRED_LIBRARIES
# i.e. the check_include_file() calls will include -lm when checking.
# New in version 3.12.
if(POLICY CMP0075)
cmake_policy(SET CMP0075 NEW)
endif()
include(CTest) include(CTest)
# Set some packaging variables. # Set some packaging variables.
@@ -45,6 +65,10 @@ include(CMakePackageConfigHelpers)
option(BUILD_SHARED_LIBS "Default to building shared libraries" ON) option(BUILD_SHARED_LIBS "Default to building shared libraries" ON)
option(BUILD_STATIC_LIBS "Default to building static libraries" ON) option(BUILD_STATIC_LIBS "Default to building static libraries" ON)
if (BUILD_SHARED_LIBS)
add_definitions(-D JSON_C_DLL)
endif()
# Generate a release merge and test it to verify the correctness of republishing the package. # Generate a release merge and test it to verify the correctness of republishing the package.
ADD_CUSTOM_TARGET(distcheck ADD_CUSTOM_TARGET(distcheck
COMMAND make package_source COMMAND make package_source
@@ -64,70 +88,14 @@ option(ENABLE_RDRAND "Enable RDRAND Hardware RNG Hash Seed."
option(ENABLE_THREADING "Enable partial threading support." OFF) option(ENABLE_THREADING "Enable partial threading support." OFF)
option(OVERRIDE_GET_RANDOM_SEED "Override json_c_get_random_seed() with custom code." OFF) option(OVERRIDE_GET_RANDOM_SEED "Override json_c_get_random_seed() with custom code." OFF)
option(DISABLE_EXTRA_LIBS "Avoid linking against extra libraries, such as libbsd." OFF) option(DISABLE_EXTRA_LIBS "Avoid linking against extra libraries, such as libbsd." OFF)
option(DISABLE_JSON_POINTER "Disable JSON pointer (RFC6901) and JSON patch support." OFF) option(DISABLE_JSON_POINTER "Disable JSON pointer (RFC6901) support." OFF)
option(DISABLE_JSON_PATCH "Disable JSON patch (RFC6902) support." OFF)
option(NEWLOCALE_NEEDS_FREELOCALE "Work around newlocale bugs in old FreeBSD and macOS by calling freelocale" OFF)
option(BUILD_APPS "Default to building apps" ON)
# macOS (Darwin) has the same newlocale() bug as older FreeBSD versions:
# newlocale() does not free the locale object passed to it, causing memory leaks.
# See: https://github.com/json-c/json-c/issues/668
if(APPLE AND NOT NEWLOCALE_NEEDS_FREELOCALE)
message(STATUS "macOS detected: enabling NEWLOCALE_NEEDS_FREELOCALE to prevent memory leaks")
set(NEWLOCALE_NEEDS_FREELOCALE ON CACHE BOOL "macOS needs freelocale workaround" FORCE)
endif()
if (AMIGA) if (UNIX OR MINGW OR CYGWIN)
set(DISABLE_THREAD_LOCAL_STORAGE ON)
set(ENABLE_THREADING OFF)
set(BUILD_SHARED_LIBS OFF)
set(BUILD_APPS OFF)
set(DISABLE_STATIC_FPIC ON)
if ($ENV{CROSS_PFX} STREQUAL "m68k-amigaos")
set(AMIGA_M68K ON)
set(BUILD_TESTING OFF)
if (${M68K_CRT} STREQUAL "newlib")
set(NEWLIB ON)
elseif(${M68K_CRT} STREQUAL "clib2")
set(CLIB2 ON)
elseif(${M68K_CRT} STREQUAL "ixemul")
set(IXEMUL ON)
elseif(${M68K_CRT} STREQUAL "nix20")
set(NIX20 ON)
elseif(${M68K_CRT} STREQUAL "nix13")
set(NIX13 ON)
else()
set(NEWLIB ON)
endif()
message(STATUS "Building for Motorola 68k AmigaOS using CRT: ${M68K_CRT}")
elseif ($ENV{CROSS_PFX} STREQUAL "ppc-amigaos")
set(AMIGA_PPC ON)
message(STATUS "Building for PowerPC AmigaOS")
elseif($ENV{CROSS_PFX} STREQUAL "ppc-morphos")
set(MORPHOS ON)
if (NOIXEMUL)
message(STATUS "Building for PowerPC MorphOS without ixemul")
set(DISABLE_WERROR ON)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -noixemul")
else()
message(STATUS "Building for PowerPC MorphOS with ixemul")
endif()
else()
message(FATAL_ERROR "Unsupported AmigaOS target")
endif()
else()
message(STATUS "Building for ${CMAKE_SYSTEM_NAME}")
endif()
if (UNIX OR MINGW OR CYGWIN OR AMIGA)
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
endif() endif()
if (BUILD_SHARED_LIBS) if (UNIX)
add_definitions(-D JSON_C_DLL)
endif()
if (UNIX OR AMIGA)
list(APPEND CMAKE_REQUIRED_LIBRARIES m) list(APPEND CMAKE_REQUIRED_LIBRARIES m)
endif() endif()
@@ -172,30 +140,17 @@ check_include_file(sys/random.h HAVE_SYS_RANDOM_H)
check_include_file(sys/stat.h HAVE_SYS_STAT_H) check_include_file(sys/stat.h HAVE_SYS_STAT_H)
check_include_file(xlocale.h HAVE_XLOCALE_H) check_include_file(xlocale.h HAVE_XLOCALE_H)
# Set json-c specific vars to stamp into json_config.h if (HAVE_INTTYPES_H)
# Set a json-c specific var to stamp into json_config.h
# in a way that hopefully won't conflict with other # in a way that hopefully won't conflict with other
# projects that use json-c. # projects that use json-c.
if (HAVE_INTTYPES_H)
set(JSON_C_HAVE_INTTYPES_H 1) set(JSON_C_HAVE_INTTYPES_H 1)
endif() endif()
if (HAVE_STDINT_H)
set(JSON_C_HAVE_STDINT_H 1)
endif()
check_symbol_exists(_isnan "float.h" HAVE_DECL__ISNAN) check_symbol_exists(_isnan "float.h" HAVE_DECL__ISNAN)
check_symbol_exists(_finite "float.h" HAVE_DECL__FINITE) check_symbol_exists(_finite "float.h" HAVE_DECL__FINITE)
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") if ((MSVC AND NOT (MSVC_VERSION LESS 1800)) OR MINGW OR CYGWIN OR UNIX)
# Detect clang-cl.exe, it is Clang but with MSVC compatible command line arguments
execute_process (COMMAND ${CMAKE_C_COMPILER} -? ERROR_QUIET OUTPUT_QUIET RESULT_VARIABLE _clang_result)
if (_clang_result EQUAL 0)
set(CLANG_CL TRUE)
else()
set(CLANG_CL FALSE)
endif()
endif()
if ((MSVC AND NOT (MSVC_VERSION LESS 1800)) OR MINGW OR CYGWIN OR UNIX OR AMIGA OR CLANG_CL)
check_symbol_exists(INFINITY "math.h" HAVE_DECL_INFINITY) check_symbol_exists(INFINITY "math.h" HAVE_DECL_INFINITY)
check_symbol_exists(isinf "math.h" HAVE_DECL_ISINF) check_symbol_exists(isinf "math.h" HAVE_DECL_ISINF)
check_symbol_exists(isnan "math.h" HAVE_DECL_ISNAN) check_symbol_exists(isnan "math.h" HAVE_DECL_ISNAN)
@@ -203,15 +158,14 @@ if ((MSVC AND NOT (MSVC_VERSION LESS 1800)) OR MINGW OR CYGWIN OR UNIX OR AMIGA
endif() endif()
check_symbol_exists(_doprnt "stdio.h" HAVE_DOPRNT) check_symbol_exists(_doprnt "stdio.h" HAVE_DOPRNT)
if (UNIX OR MINGW OR CYGWIN OR AMIGA) if (UNIX OR MINGW OR CYGWIN)
check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF) check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF)
endif() endif()
check_symbol_exists(vasprintf "stdio.h" HAVE_VASPRINTF) check_symbol_exists(vasprintf "stdio.h" HAVE_VASPRINTF)
check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF) check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF)
check_symbol_exists(vprintf "stdio.h" HAVE_VPRINTF) check_symbol_exists(vprintf "stdio.h" HAVE_VPRINTF)
if (NOT AMIGA_M68K)
check_symbol_exists(arc4random "stdlib.h" HAVE_ARC4RANDOM) check_symbol_exists(arc4random "stdlib.h" HAVE_ARC4RANDOM)
endif()
if (NOT HAVE_ARC4RANDOM AND DISABLE_EXTRA_LIBS STREQUAL "OFF") if (NOT HAVE_ARC4RANDOM AND DISABLE_EXTRA_LIBS STREQUAL "OFF")
check_include_file(bsd/stdlib.h HAVE_BSD_STDLIB_H) check_include_file(bsd/stdlib.h HAVE_BSD_STDLIB_H)
if (HAVE_BSD_STDLIB_H) if (HAVE_BSD_STDLIB_H)
@@ -233,18 +187,13 @@ endif()
if (HAVE_LOCALE_H) if (HAVE_LOCALE_H)
check_symbol_exists(setlocale "locale.h" HAVE_SETLOCALE) check_symbol_exists(setlocale "locale.h" HAVE_SETLOCALE)
check_symbol_exists(uselocale "locale.h" HAVE_USELOCALE) check_symbol_exists(uselocale "locale.h" HAVE_USELOCALE)
if (NOT NIX20 AND NOT NIX13)
# libnix does not fully support this yet
check_symbol_exists(duplocale "locale.h" HAVE_DUPLOCALE)
endif()
endif() endif()
# uClibc *intentionally* crashes in duplocale(), at least as of: # uClibc *intentionally* crashes in duplocale(), at least as of:
# https://github.com/ffainelli/uClibc/blob/266bdc1/libc/misc/locale/locale.c#L1322 # https://github.com/ffainelli/uClibc/blob/266bdc1/libc/misc/locale/locale.c#L1322
# So, if it looks like we're compiling for a system like that just disable # So, if it looks like we're compiling for a system like that just disable
# locale handling entirely. # locale handling entirely.
execute_process (COMMAND ${CMAKE_C_COMPILER} -dumpmachine ERROR_QUIET OUTPUT_VARIABLE CMAKE_GNU_C_MACHINE) exec_program(${CMAKE_C_COMPILER} ARGS -dumpmachine OUTPUT_VARIABLE CMAKE_GNU_C_MACHINE)
if (CMAKE_GNU_C_MACHINE MATCHES "uclibc") if (CMAKE_GNU_C_MACHINE MATCHES "uclibc")
message(STATUS "Detected uClibc compiler, disabling locale handling") message(STATUS "Detected uClibc compiler, disabling locale handling")
set(HAVE_SETLOCALE 0) set(HAVE_SETLOCALE 0)
@@ -340,29 +289,11 @@ message(STATUS "Wrote ${PROJECT_BINARY_DIR}/config.h")
configure_file(${PROJECT_SOURCE_DIR}/cmake/json_config.h.in ${PROJECT_BINARY_DIR}/json_config.h) configure_file(${PROJECT_SOURCE_DIR}/cmake/json_config.h.in ${PROJECT_BINARY_DIR}/json_config.h)
message(STATUS "Wrote ${PROJECT_BINARY_DIR}/json_config.h") message(STATUS "Wrote ${PROJECT_BINARY_DIR}/json_config.h")
if (NOT DEFINED CMAKE_C_COMPILER_FRONTEND_VARIANT OR "${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "") # only available in cmake 3.14+ if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
set(CMAKE_C_COMPILER_FRONTEND_VARIANT "MSVC")
elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_C_COMPILER_FRONTEND_VARIANT "GNU")
elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
if (CLANG_CL)
set(CMAKE_C_COMPILER_FRONTEND_VARIANT "MSVC")
else()
set(CMAKE_C_COMPILER_FRONTEND_VARIANT "GNU")
message(STATUS, "clang result is NOT 0")
endif()
endif()
endif()
if ("${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections")
if ("${DISABLE_WERROR}" STREQUAL "OFF") if ("${DISABLE_WERROR}" STREQUAL "OFF")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
endif() endif()
if (AMIGA_M68K)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fbaserel")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-qual") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-qual")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=deprecated-declarations") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=deprecated-declarations")
@@ -374,12 +305,7 @@ if ("${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER
endif() endif()
add_definitions(-D_GNU_SOURCE) add_definitions(-D_GNU_SOURCE)
elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
if ("${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "Clang")
# Remove this for 1.0 when we can bump the ABI and actually fix these warnings.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-shorten-64-to-32")
endif()
elseif ("${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "MSVC")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /DEBUG") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /DEBUG")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4100") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4100")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4996") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4996")
@@ -390,7 +316,7 @@ elseif ("${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "MSVC")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4701") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4701")
endif() endif()
if (NOT ("${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "MSVC")) if (NOT ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC"))
check_c_source_compiles( check_c_source_compiles(
" "
/* uClibc toolchains without threading barf when _REENTRANT is defined */ /* uClibc toolchains without threading barf when _REENTRANT is defined */
@@ -470,7 +396,6 @@ set(JSON_C_PUBLIC_HEADERS
set(JSON_C_HEADERS set(JSON_C_HEADERS
${JSON_C_PUBLIC_HEADERS} ${JSON_C_PUBLIC_HEADERS}
${PROJECT_SOURCE_DIR}/json_object_private.h ${PROJECT_SOURCE_DIR}/json_object_private.h
${PROJECT_SOURCE_DIR}/json_pointer_private.h
${PROJECT_SOURCE_DIR}/random_seed.h ${PROJECT_SOURCE_DIR}/random_seed.h
${PROJECT_SOURCE_DIR}/strerror_override.h ${PROJECT_SOURCE_DIR}/strerror_override.h
${PROJECT_SOURCE_DIR}/math_compat.h ${PROJECT_SOURCE_DIR}/math_compat.h
@@ -494,26 +419,12 @@ set(JSON_C_SOURCES
${PROJECT_SOURCE_DIR}/strerror_override.c ${PROJECT_SOURCE_DIR}/strerror_override.c
) )
set(JSON_C_RESOURCES)
if (BUILD_SHARED_LIBS AND WIN32)
enable_language(RC)
set(JSON_C_RESOURCES ${JSON_C_RESOURCES} ${PROJECT_SOURCE_DIR}/libjson.rc)
endif()
if (NOT DISABLE_JSON_POINTER) if (NOT DISABLE_JSON_POINTER)
set(JSON_C_PUBLIC_HEADERS ${JSON_C_PUBLIC_HEADERS} ${PROJECT_SOURCE_DIR}/json_pointer.h) set(JSON_C_PUBLIC_HEADERS ${JSON_C_PUBLIC_HEADERS} ${PROJECT_SOURCE_DIR}/json_pointer.h)
set(JSON_C_SOURCES ${JSON_C_SOURCES} ${PROJECT_SOURCE_DIR}/json_pointer.c) set(JSON_C_SOURCES ${JSON_C_SOURCES} ${PROJECT_SOURCE_DIR}/json_pointer.c)
set(JSON_H_JSON_POINTER "#include \"json_pointer.h\"") set(JSON_H_JSON_POINTER "#include \"json_pointer.h\"")
if (NOT DISABLE_JSON_PATCH)
set(JSON_C_PUBLIC_HEADERS ${JSON_C_PUBLIC_HEADERS} ${PROJECT_SOURCE_DIR}/json_patch.h)
set(JSON_C_SOURCES ${JSON_C_SOURCES} ${PROJECT_SOURCE_DIR}/json_patch.c)
set(JSON_H_JSON_PATCH "#include \"json_patch.h\"")
endif()
else() else()
set(JSON_H_JSON_POINTER "") set(JSON_H_JSON_POINTER "")
set(JSON_H_JSON_PATCH "")
endif() endif()
configure_file(json.h.cmakein ${PROJECT_BINARY_DIR}/json.h @ONLY) configure_file(json.h.cmakein ${PROJECT_BINARY_DIR}/json.h @ONLY)
@@ -540,10 +451,9 @@ endif()
add_library(${PROJECT_NAME} add_library(${PROJECT_NAME}
${JSON_C_SOURCES} ${JSON_C_SOURCES}
${JSON_C_HEADERS} ${JSON_C_HEADERS}
${JSON_C_RESOURCES}
) )
set_target_properties(${PROJECT_NAME} PROPERTIES set_target_properties(${PROJECT_NAME} PROPERTIES
VERSION 5.4.0 VERSION 5.2.0
SOVERSION 5) SOVERSION 5)
list(APPEND CMAKE_TARGETS ${PROJECT_NAME}) list(APPEND CMAKE_TARGETS ${PROJECT_NAME})
# If json-c is used as subroject it set to target correct interface -I flags and allow # If json-c is used as subroject it set to target correct interface -I flags and allow
@@ -616,6 +526,7 @@ install(
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
) )
if (UNIX OR MINGW OR CYGWIN)
SET(prefix ${CMAKE_INSTALL_PREFIX}) SET(prefix ${CMAKE_INSTALL_PREFIX})
# exec_prefix is prefix by default and CMake does not have the # exec_prefix is prefix by default and CMake does not have the
# concept. # concept.
@@ -643,6 +554,7 @@ install(
configure_file(json-c.pc.in json-c.pc @ONLY) configure_file(json-c.pc.in json-c.pc @ONLY)
set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_LIBDIR}/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_LIBDIR}/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files")
install(FILES ${PROJECT_BINARY_DIR}/json-c.pc DESTINATION "${INSTALL_PKGCONFIG_DIR}") install(FILES ${PROJECT_BINARY_DIR}/json-c.pc DESTINATION "${INSTALL_PKGCONFIG_DIR}")
endif ()
install(FILES ${JSON_C_PUBLIC_HEADERS} DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/json-c) install(FILES ${JSON_C_PUBLIC_HEADERS} DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/json-c)
@@ -652,9 +564,10 @@ if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING AND
add_subdirectory(tests) add_subdirectory(tests)
endif() endif()
if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_APPS) if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
# skip apps when we're included in someone else's build # skip apps when we're included in someone else's build
if (NOT MSVC) # cmd line apps don't built on Windows currently. if (NOT MSVC) # cmd line apps don't built on Windows currently.
add_subdirectory(apps) add_subdirectory(apps)
endif() endif()
endif() endif()

View File

@@ -1,87 +1,14 @@
0.19 (up to commit 8948568, 2026-01-18) 0.17 (future release)
======================================== ========================================
Deprecated and removed features: Deprecated and removed features:
-------------------------------- --------------------------------
* none * ...
New features New features
------------ ------------
* Add support for Commodore Amiga and MorphOS * ...
* Allow builds with CMake 4 - sync minimum version across all CMakeLists.txt files
* Update openssl command to work for newer versions of openssl.
* Add support for building json-c with meson
* Support MSVC in packages that use GNU Autoconf.
* Add VERSIONINFO to libjson-c.dll
* Make json_tokener_free(NULL) a no-op, to simplify cleanup paths.
* Explicitly handle NaN values when converting to int
* Set errno=RANGE in json_object_get_int/int64/uint64() when the source value can't be represented in the target type.
* Make json_parse a bit more useful by adding -u (validate UTF8) and -P (specify arbitrary tokener parse flags), and read from stdin if no filename is provided.
* Fix the apps/json_parse "-s" (strict) option so it actually does something, and default to non-strict.
Significant changes and bug fixes
---------------------------------
* Issue #867 - also disallow control characters in keys in JSON_TOKENER_STRICT mode
* Issue #875: cast to unsigned char so bytes above 0x7f aren't interpreted as negative, which was causing the strict-mode control characters check to incorrectly trigger.
* Issue #881: don't allow json_tokener_new_ex() with a depth < 1
* Fix linkhash breaking -std=c89
* Fixing Cmake build when using clang-cl, avoids errors about redefining existing symbols
* Fix AIX build failure - Add CMake detection for getopt.h
* Fix bug involving supplemental code points that look like high surrogates
* Fix runtime issue with test_util_file.c in Windows (add O_BINARY)
* Fix macro WIN32_LEAN_AND_MEAN redefined
0.18 (up to commit 6bfab90, 2024-09-15)
========================================
Deprecated and removed features:
--------------------------------
* Clean up pre-3.9 CMake support in CMakeLists.txt
New features
------------
* Build pkg-config for msvc as well
Significant changes and bug fixes
---------------------------------
* Critical fix for binary compatibility with 0.16: Move the
json_tokener_error_memory entry to the end of enum json_tokener_error.
* Issue #829: attempt to detect clang-cl.exe and pass MSVC-compatile command
line arguments.
* PR #831 - rename WIN32 to _WIN32
* PR #839 - Fix gcc 5 "may be used uninitialized" failure in json_pointer.c
* PR #849 - random_seed.c: add a Coverity Scan suppression
* Issue #854: Set error=json_tokener_error_memory in
json_tokener_parser_verbose() when allocating the tokener fails.
* Issue #857: fix a few places where json_tokener should have been returning
json_tokener_error_memory but wasn't.
* Handle yet another out-of-memory condition in json_tokener, duplocate can
return NULL.
* Various fixes in the fuzzers
* A few minor doc fixes
***
0.17 (up to commit 077661f, 2023-08-08)
========================================
Known Bugs
----------
* DO NOT USE THE 0.17 RELEASE: json_tokener_error_memory in misplaced in the
json_tokener_error enum, leading to binary compatibility issues.
Deprecated and removed features:
--------------------------------
* None
New features
------------
* json_patch: add first implementation only with patch application
* Add --disable-static and --disable-dynamic options to the cmake-configure script.
* Add -DBUILD_APPS=NO option to disable app build
* Minimum cmake version is now 3.9
Significant changes and bug fixes Significant changes and bug fixes
--------------------------------- ---------------------------------
@@ -92,17 +19,7 @@ Significant changes and bug fixes
* When parsing with JSON_TOKENER_STRICT set, integer overflow/underflow * When parsing with JSON_TOKENER_STRICT set, integer overflow/underflow
now result in a json_tokener_error_parse_number. Without that flag now result in a json_tokener_error_parse_number. Without that flag
values are capped at INT64_MIN/UINT64_MAX. values are capped at INT64_MIN/UINT64_MAX.
* Fix memory leak with emtpy strings in json_object_set_string
* json_object_from_fd_ex: fail if file is too large (>=INT_MAX bytes)
* Add back json_number_chars, but only because it's part of the public API.
* Entirely drop mode bits from open(O_RDONLY) to avoid warnings on certain
platforms.
* Specify dependent libraries, including -lbsd, in a more consistent way so
linking against a static json-c works better
* Fix a variety of build problems and add & improve tests
* Update RFC reference to https://www.rfc-editor.org/rfc/rfc8259
***
0.16 (up to commit 66dcdf5, 2022-04-13) 0.16 (up to commit 66dcdf5, 2022-04-13)
======================================== ========================================

View File

@@ -1,6 +1,6 @@
\mainpage \mainpage
json-c `json-c`
======== ========
1. [Overview and Build Status](#overview) 1. [Overview and Build Status](#overview)
@@ -12,12 +12,10 @@ json-c
5. [Testing](#testing) 5. [Testing](#testing)
6. [Building with `vcpkg`](#buildvcpkg) 6. [Building with `vcpkg`](#buildvcpkg)
7. [Building for Android](#android) 7. [Building for Android](#android)
8. [Building for Commodore Amiga or MorphOS](#amiga) 7. [Linking to libjson-c](#linking)
9. [Linking to libjson-c](#linking) 8. [Using json-c](#using)
10. [Using json-c](#using)
<a name="overview"></a> JSON-C - A JSON implementation in C <a name="overview"></a>
JSON-C - A JSON implementation in C
----------------------------------- -----------------------------------
JSON-C implements a reference counting object model that allows you to easily JSON-C implements a reference counting object model that allows you to easily
@@ -31,8 +29,7 @@ if you already have json-c installed and ready to use.
Home page for json-c: https://github.com/json-c/json-c/wiki Home page for json-c: https://github.com/json-c/json-c/wiki
<a name="gettinghelp"></a> Getting Help <a name="gettinghelp"></a>
Getting Help
------------ ------------
If you have questions about using json-c, please start a thread on If you have questions about using json-c, please start a thread on
@@ -50,8 +47,7 @@ features or large changes of any kind, please first start a discussion
on the [forums](https://groups.google.com/forum/#!forum/json-c). on the [forums](https://groups.google.com/forum/#!forum/json-c).
<a name="buildunix"></a> Building on Unix with `git`, `gcc` and `cmake` <a name="buildunix"></a>
Building on Unix with `git`, `gcc` and `cmake`
-------------------------------------------------- --------------------------------------------------
If you already have json-c installed, see [Linking to `libjson-c`](#linking) If you already have json-c installed, see [Linking to `libjson-c`](#linking)
@@ -64,8 +60,7 @@ Build Status
Test Status Test Status
* [Coveralls](https://coveralls.io/github/json-c/json-c?branch=master) [![Coverage Status](https://coveralls.io/repos/github/json-c/json-c/badge.svg?branch=master)](https://coveralls.io/github/json-c/json-c?branch=master) * [Coveralls](https://coveralls.io/github/json-c/json-c?branch=master) [![Coverage Status](https://coveralls.io/repos/github/json-c/json-c/badge.svg?branch=master)](https://coveralls.io/github/json-c/json-c?branch=master)
<a name="installprereq"></a> ### Prerequisites: <a name="installprereq"></a>
### Prerequisites:
- `gcc`, `clang`, or another C compiler - `gcc`, `clang`, or another C compiler
@@ -85,8 +80,7 @@ sudo apt install doxygen # optional
sudo apt install valgrind # optional sudo apt install valgrind # optional
``` ```
<a name="buildcmds"></a> ### Build instructions: <a name="buildcmds"></a>
### Build instructions:
`json-c` GitHub repo: https://github.com/json-c/json-c `json-c` GitHub repo: https://github.com/json-c/json-c
@@ -122,8 +116,7 @@ google-chrome doc/html/index.html
``` ```
<a name="CMake"></a> CMake Options <a name="CMake"></a>
CMake Options
-------------------- --------------------
The json-c library is built with [CMake](https://cmake.org/cmake-tutorial/), The json-c library is built with [CMake](https://cmake.org/cmake-tutorial/),
@@ -195,8 +188,7 @@ cmake-configure can take a few options.
| disable-werror | Avoid treating compiler warnings as fatal errors | | disable-werror | Avoid treating compiler warnings as fatal errors |
<a name="testing"></a> Testing: <a name="testing"></a>
Testing:
---------- ----------
By default, if valgrind is available running tests uses it. By default, if valgrind is available running tests uses it.
@@ -232,8 +224,7 @@ JSONC_TEST_TRACE=1 make test
and check the log files again. and check the log files again.
<a name="buildvcpkg"></a> Building on Unix and Windows with `vcpkg` <a name="buildvcpkg"></a>
Building on Unix and Windows with `vcpkg`
-------------------------------------------------- --------------------------------------------------
You can download and install JSON-C using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager: You can download and install JSON-C using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
@@ -246,8 +237,7 @@ You can download and install JSON-C using the [vcpkg](https://github.com/Microso
The JSON-C port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. The JSON-C port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
<a name="android"></a> Building for Android <a name="android">
Building for Android
---------------------- ----------------------
Building on Android is now particularly well supported, but there Building on Android is now particularly well supported, but there
@@ -271,65 +261,7 @@ cmake \
make install make install
``` ```
<a name="amiga"></a> Linking to `libjson-c` <a name="linking">
Building for Commodore Amiga or MorphOS
----------------------
Building for Commodore Amiga is supported for both Motorola 68k (AmigaOS 3) and PowerPC (AmigaOS 4) architectures. MorphOS on compatible PowerPC hardware is also supported. You can set up a cross compiler locally, however it is much easier to use the already preconfigured Amiga development environment wtthin a Docker container.
Install Docker on your machine if you don't already have it. You can download Docker Desktop for Windows/macOS/Linux [here](https://www.docker.com/products/docker-desktop/).
### To build for Motorola 68k Amiga:
```
mkdir build
docker run --rm \
-v ${PWD}:/work \
-e USER=$( id -u ) -e GROUP=$( id -g ) \
-it sacredbanana/amiga-compiler:m68k-amigaos bash
cd build
cmake -DM68K_CRT=newlib ..
make
```
libjson-c.a will get created in the build directory.
You can change newlib to nix20, nix13, ixemul or clib2 if you would like to build the library suited for libnix or clib2 instead. Newlib is default.
### To build for PowerPC Amiga:
```
mkdir build
docker run --rm \
-v ${PWD}:/work \
-e USER=$( id -u ) -e GROUP=$( id -g ) \
-it sacredbanana/amiga-compiler:ppc-amigaos bash
cd build
cmake ..
make
```
libjson-c.a will get created in the build directory.
### To build for PowerPC MorphOS:
```
mkdir build
docker run --rm \
-v ${PWD}:/work \
-e USER=$( id -u ) -e GROUP=$( id -g ) \
-it sacredbanana/amiga-compiler:ppc-morphos bash
cd build
cmake -DNOIXEMUL=1 ..
make
```
If you are making an application that absolutely requires ixemul, then remove the `-DNOIXEMUL=1`.
libjson-c.a will get created in the build directory.
<a name="linking"></a>
Linking to `libjson-c`
---------------------- ----------------------
If your system has `pkgconfig`, If your system has `pkgconfig`,
@@ -366,8 +298,7 @@ cd build
cmake -DCMAKE_PREFIX_PATH=/path/to/json_c/install/lib64/cmake .. cmake -DCMAKE_PREFIX_PATH=/path/to/json_c/install/lib64/cmake ..
``` ```
<a name="using"></a> Using json-c <a name="using">
Using json-c
------------ ------------
To use json-c you can either include json.h, or preferably, one of the To use json-c you can either include json.h, or preferably, one of the

View File

@@ -16,7 +16,6 @@
changes (added/removed/updated funcs, etc...), and detect backwards compat changes (added/removed/updated funcs, etc...), and detect backwards compat
issues. issues.
* https://github.com/lvc/abi-compliance-checker * https://github.com/lvc/abi-compliance-checker
* See also `abi-check.sh`
* If the new release is not backwards compatible, then this is a MAJOR release. * If the new release is not backwards compatible, then this is a MAJOR release.
* Mention removed features in ChangeLog * Mention removed features in ChangeLog
* Consider re-adding backwards compatible support, through symbol * Consider re-adding backwards compatible support, through symbol
@@ -41,15 +40,9 @@
## Release creation ## Release creation
Start creating the new release: Start creating the new release:
release=0.16
PREV=$(git tag | tail -1)
PREV=${PREV#json-c-}
PREV=${PREV%-*}
release=0.$((${PREV#*.} + 1))
cd ~
git clone https://github.com/json-c/json-c json-c-${release} git clone https://github.com/json-c/json-c json-c-${release}
rm -rf distcheck
mkdir distcheck mkdir distcheck
cd distcheck cd distcheck
# Note, the build directory *must* be entirely separate from # Note, the build directory *must* be entirely separate from
@@ -61,7 +54,8 @@ Start creating the new release:
Make any fixes/changes *before* branching. Make any fixes/changes *before* branching.
cd json-c-${release} cd json-c-${release}
git checkout -b json-c-${release} git branch json-c-${release}
git checkout json-c-${release}
------------ ------------
@@ -141,10 +135,12 @@ Use ${release}.99 to indicate a version "newer" than anything on the branch:
Update the version in json_c_version.h Update the version in json_c_version.h
Update the version in CMakeLists.txt Update the version in CMakeLists.txt
Update the set_target_properties() line in CmakeLists.txt to match the release branch. Update RELEASE_CHECKLIST.txt, set release=${release}+1
Add a new empty section to the json-c.sym file, for ${release}+1 Add a new empty section to the json-c.sym file, for ${release}+1
Update the set_target_properties() line in CmakeLists.txt to match the release branch.
git commit -a -m "Update the master branch to version ${release}.99" git commit -a -m "Update the master branch to version ${release}.99"
git push git push
@@ -177,12 +173,11 @@ Update the gh-pages branch with new docs:
Update checksums on wiki page. Update checksums on wiki page.
cd .. cd ..
openssl sha1 -sha256 json-c*gz openssl sha -sha256 json-c*gz
openssl md5 json-c*gz openssl md5 json-c*gz
Copy and paste this output into the wiki page at: Copy and paste this output into the wiki page at:
* https://github.com/json-c/json-c/wiki https://github.com/json-c/json-c/wiki
* https://github.com/json-c/json-c/wiki/Old-Releases
------------ ------------

View File

@@ -1,50 +0,0 @@
#!/bin/sh
set -e
# The 0.17 release is broken
prev=0.18
release=0.19
# ... clone json-c, abi-compliance-checker, abi-dumper
if [ "$1" != "--skip-build" ] ; then
mkdir build
cd build
CFLAGS=-Og cmake -DCMAKE_INSTALL_PREFIX=~/json-c-installs/json-c-${release} ..
make && make test && make install
fi
# Assume the old version has already been built
cd ~/abi-compliance-checker
mkxml()
{
ver="$1"
if [ ! -e ../json-c-installs/json-c-${ver}/lib64 ] ; then
ln -s lib ../json-c-installs/json-c-${ver}/lib64
fi
cat <<EOF > json-c-${ver}.xml
<foo>
<version>
${ver}
</version>
<headers>
../json-c-installs/json-c-${ver}/include/json-c
</headers>
<libs>
../json-c-installs/json-c-${ver}/lib64/libjson-c.so
</libs>
</foo>
EOF
}
mkxml ${release}
mkxml ${prev}
perl abi-compliance-checker.pl -lib json-c -dump json-c-${prev}.xml -dump-path ./ABI-${prev}.dump
perl abi-compliance-checker.pl -lib json-c -dump json-c-${release}.xml -dump-path ./ABI-${release}.dump
perl abi-compliance-checker.pl -l json-c -old ABI-${prev}.dump -new ABI-${release}.dump
echo "look in compat_reports/json-c/..."

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.9...3.12) # see ../CMakeLists.txt for why cmake_minimum_required(VERSION 2.8) # see ../CMakeLists.txt for why 2.8
if(POLICY CMP0075) if(POLICY CMP0075)
cmake_policy(SET CMP0075 NEW) cmake_policy(SET CMP0075 NEW)
@@ -94,9 +94,6 @@ endif() # end "standalone mode" block
# --------------------------------- # ---------------------------------
# Check whether getopt.h exists
check_include_file(getopt.h HAVE_GETOPT_H)
check_include_file(sys/resource.h HAVE_SYS_RESOURCE_H) # for getrusage check_include_file(sys/resource.h HAVE_SYS_RESOURCE_H) # for getrusage
if (HAVE_SYS_RESOURCE_H) if (HAVE_SYS_RESOURCE_H)
check_symbol_exists(getrusage "sys/resource.h" HAVE_GETRUSAGE) check_symbol_exists(getrusage "sys/resource.h" HAVE_GETRUSAGE)

View File

@@ -1,9 +1,7 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -40,8 +38,6 @@
static int formatted_output = JSON_C_TO_STRING_SPACED; static int formatted_output = JSON_C_TO_STRING_SPACED;
static int show_output = 1; static int show_output = 1;
static int strict_mode = 0; static int strict_mode = 0;
static int validate_utf8 = 0;
static int tokener_flags = 0;
static int color = 0; static int color = 0;
static const char *fname = NULL; static const char *fname = NULL;
@@ -78,21 +74,11 @@ static int parseit(int fd, int (*callback)(struct json_object *))
fprintf(stderr, "unable to allocate json_tokener: %s\n", strerror(errno)); fprintf(stderr, "unable to allocate json_tokener: %s\n", strerror(errno));
return 1; return 1;
} }
if (strict_mode) json_tokener_set_flags(tok, JSON_TOKENER_STRICT
{
tokener_flags |= JSON_TOKENER_STRICT;
#ifdef JSON_TOKENER_ALLOW_TRAILING_CHARS #ifdef JSON_TOKENER_ALLOW_TRAILING_CHARS
tokener_flags |= JSON_TOKENER_ALLOW_TRAILING_CHARS; | JSON_TOKENER_ALLOW_TRAILING_CHARS
#endif #endif
} );
if (validate_utf8)
{
tokener_flags |= JSON_TOKENER_VALIDATE_UTF8;
}
if (tokener_flags)
{
json_tokener_set_flags(tok, tokener_flags);
}
// XXX push this into some kind of json_tokener_parse_fd API? // XXX push this into some kind of json_tokener_parse_fd API?
// json_object_from_fd isn't flexible enough, and mirroring // json_object_from_fd isn't flexible enough, and mirroring
@@ -171,15 +157,13 @@ static void usage(const char *argv0, int exitval, const char *errmsg)
fp = stderr; fp = stderr;
if (errmsg != NULL) if (errmsg != NULL)
fprintf(fp, "ERROR: %s\n\n", errmsg); fprintf(fp, "ERROR: %s\n\n", errmsg);
fprintf(fp, "Usage: %s [-f|-F <arg>] [-n] [-s] [-u] [filename]\n", argv0); fprintf(fp, "Usage: %s [-f|-F <arg>] [-n] [-s]\n", argv0);
fprintf(fp, " -f - Format the output to stdout with JSON_C_TO_STRING_PRETTY (default is JSON_C_TO_STRING_SPACED)\n"); fprintf(fp, " -f - Format the output to stdout with JSON_C_TO_STRING_PRETTY (default is JSON_C_TO_STRING_SPACED)\n");
fprintf(fp, " -F - Format the output to stdout with <arg>, e.g. 0 for JSON_C_TO_STRING_PLAIN\n"); fprintf(fp, " -F - Format the output to stdout with <arg>, e.g. 0 for JSON_C_TO_STRING_PLAIN\n");
fprintf(fp, " -n - No output\n"); fprintf(fp, " -n - No output\n");
fprintf(fp, " -c - Set JSON_C_TO_STRING_COLOR to colorize the output\n"); fprintf(fp, " -c - color\n");
fprintf(fp, " -P - Initialize tokener flags to the given value\n"); fprintf(fp, " -s - Parse in strict mode, flags:\n");
fprintf(fp, " -s - Parse in strict mode, add flags:\n");
fprintf(fp, " JSON_TOKENER_STRICT|JSON_TOKENER_ALLOW_TRAILING_CHARS\n"); fprintf(fp, " JSON_TOKENER_STRICT|JSON_TOKENER_ALLOW_TRAILING_CHARS\n");
fprintf(fp, " -u - Add the JSON_TOKENER_VALIDATE_UTF8 flag when parsing\n");
fprintf(fp, " Diagnostic information will be emitted to stderr\n"); fprintf(fp, " Diagnostic information will be emitted to stderr\n");
fprintf(fp, "\nWARNING WARNING WARNING\n"); fprintf(fp, "\nWARNING WARNING WARNING\n");
@@ -191,28 +175,26 @@ int main(int argc, char **argv)
{ {
int opt; int opt;
while ((opt = getopt(argc, argv, "cfF:hnP:su")) != -1) while ((opt = getopt(argc, argv, "fF:hnsc")) != -1)
{ {
switch (opt) switch (opt)
{ {
case 'c': color = JSON_C_TO_STRING_COLOR; break;
case 'f': formatted_output = JSON_C_TO_STRING_PRETTY; break; case 'f': formatted_output = JSON_C_TO_STRING_PRETTY; break;
case 'F': formatted_output = atoi(optarg); break; case 'F': formatted_output = atoi(optarg); break;
case 'n': show_output = 0; break; case 'n': show_output = 0; break;
case 'P': tokener_flags = atoi(optarg); break;
case 's': strict_mode = 1; break; case 's': strict_mode = 1; break;
case 'u': validate_utf8 = 1; break; case 'c': color = JSON_C_TO_STRING_COLOR; break;
case 'h': usage(argv[0], 0, NULL); case 'h': usage(argv[0], 0, NULL);
default: /* '?' */ usage(argv[0], EXIT_FAILURE, "Unknown arguments"); default: /* '?' */ usage(argv[0], EXIT_FAILURE, "Unknown arguments");
} }
} }
int fd = STDIN_FILENO; if (optind >= argc)
fname = "stdin";
if (argc > optind && strcmp(argv[optind], "-") != 0)
{ {
fname = argv[optind]; usage(argv[0], EXIT_FAILURE, "Expected argument after options");
fd = open(fname, O_RDONLY, 0);
} }
fname = argv[optind];
int fd = open(argv[optind], O_RDONLY, 0);
showmem(); showmem();
if (parseit(fd, showobj) != 0) if (parseit(fd, showobj) != 0)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);

View File

@@ -1,27 +0,0 @@
appconf_data = configuration_data()
# Check for json_tokener_get_parse_end symbol
appconf_data.set('HAVE_JSON_TOKENER_GET_PARSE_END',
cc.has_function('json_tokener_get_parse_end', prefix: '#include <json_tokener.h>') ? 1 : 0
)
# Check for getrusage if sys/resource.h is available
appconf_data.set('HAVE_SYS_RESOURCE_H', cc.has_header('sys/resource.h') ? 1 : 0, description: 'Define to 1 if you have the <sys/resource.h> header file.')
if appconf_data.get('HAVE_SYS_RESOURCE_H') == 1
appconf_data.set('HAVE_GETRUSAGE',
cc.has_function('getrusage', prefix: '#include <sys/resource.h>') ? 1 : 0, description: 'Define if you have the `getrusage` function. ')
else
appconf_data.set('HAVE_GETRUSAGE', 0, description: 'Define if you have the `getrusage` function. ')
endif
# Generate apps_config.h
configure_file(
output: 'apps_config.h',
configuration: appconf_data
)
# Build json_parse executable
executable('json_parse', 'json_parse.c',
dependencies: [jsonc_dep],
install: false
)

View File

@@ -125,27 +125,6 @@ int array_list_shrink(struct array_list *arr, size_t empty_slots)
return 0; return 0;
} }
int array_list_insert_idx(struct array_list *arr, size_t idx, void *data)
{
size_t move_amount;
if (idx >= arr->length)
return array_list_put_idx(arr, idx, data);
/* we're at full size, what size_t can support */
if (arr->length == SIZE_T_MAX)
return -1;
if (array_list_expand_internal(arr, arr->length + 1))
return -1;
move_amount = (arr->length - idx) * sizeof(void *);
memmove(arr->array + idx + 1, arr->array + idx, move_amount);
arr->array[idx] = data;
arr->length++;
return 0;
}
//static inline int _array_list_put_idx(struct array_list *arr, size_t idx, void *data) //static inline int _array_list_put_idx(struct array_list *arr, size_t idx, void *data)
int array_list_put_idx(struct array_list *arr, size_t idx, void *data) int array_list_put_idx(struct array_list *arr, size_t idx, void *data)
{ {

View File

@@ -62,8 +62,6 @@ extern void array_list_free(struct array_list *al);
extern void *array_list_get_idx(struct array_list *al, size_t i); extern void *array_list_get_idx(struct array_list *al, size_t i);
extern int array_list_insert_idx(struct array_list *al, size_t i, void *data);
extern int array_list_put_idx(struct array_list *al, size_t i, void *data); extern int array_list_put_idx(struct array_list *al, size_t i, void *data);
extern int array_list_add(struct array_list *al, void *data); extern int array_list_add(struct array_list *al, void *data);

View File

@@ -137,12 +137,6 @@
/* Define to 1 if you have the `uselocale' function. */ /* Define to 1 if you have the `uselocale' function. */
#cmakedefine HAVE_USELOCALE #cmakedefine HAVE_USELOCALE
/* Define to 1 if you have the `duplocale' function. */
#cmakedefine HAVE_DUPLOCALE
/* Define to 1 if newlocale() needs freelocale() called on it's `base` argument */
#cmakedefine NEWLOCALE_NEEDS_FREELOCALE
/* Define to 1 if you have the `vasprintf' function. */ /* Define to 1 if you have the `vasprintf' function. */
#cmakedefine HAVE_VASPRINTF #cmakedefine HAVE_VASPRINTF

View File

@@ -1,5 +1,2 @@
/* Define to 1 if you have the <inttypes.h> header file. */ /* Define to 1 if you have the <inttypes.h> header file. */
#cmakedefine JSON_C_HAVE_INTTYPES_H @JSON_C_HAVE_INTTYPES_H@ #cmakedefine JSON_C_HAVE_INTTYPES_H @JSON_C_HAVE_INTTYPES_H@
/* Define to 1 if you have the <stdint.h> header file. */
#cmakedefine JSON_C_HAVE_STDINT_H @JSON_C_HAVE_STDINT_H@

View File

@@ -1,27 +0,0 @@
#include <fuzzer/FuzzedDataProvider.h>
#include "json.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
FuzzedDataProvider fdp(data, size);
json_object *my_array = json_object_new_array();
for (int i = 0; i < 3; ++i) {
json_object *jso = json_tokener_parse(fdp.ConsumeRandomLengthString(10).c_str());
if (jso == NULL) {
continue;
}
json_object_array_add(my_array, jso);
}
json_object_array_insert_idx(my_array, fdp.ConsumeIntegralInRange<size_t>(0, 10),
json_object_new_int(fdp.ConsumeIntegral<int>()));
json_object_array_get_idx(my_array, fdp.ConsumeIntegralInRange<size_t>(0, 10));
json_object_array_put_idx(my_array, fdp.ConsumeIntegralInRange<size_t>(0, 10),
json_object_new_int(fdp.ConsumeIntegral<int>()));
json_object_array_del_idx(my_array, fdp.ConsumeIntegralInRange<size_t>(0, 10),
fdp.ConsumeIntegralInRange<size_t>(0, 10));
json_object_array_shrink(my_array, fdp.ConsumeIntegralInRange<size_t>(0, 10));
json_object_array_sort(my_array, [](const void *a, const void *b) { return 0; });
json_object_array_length(my_array);
json_object_put(my_array);
return 0;
}

View File

@@ -1,21 +0,0 @@
"{"
"}"
","
"["
"]"
","
":"
"e"
"e+"
"e-"
"E"
"E+"
"E-"
"\""
"null"
"1"
"1.234"
"3e4"
"NaN"
"Infinity"
"-Infinity"

View File

@@ -1,44 +0,0 @@
#include <fuzzer/FuzzedDataProvider.h>
#include "json.h"
#include "json_visit.h"
// Function to test json_c_visit
static int emit_object(json_object *jso, int flags, json_object *parent_jso, const char *jso_key,
size_t *jso_index, void *userarg) {
return JSON_C_VISIT_RETURN_CONTINUE;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
FuzzedDataProvider fdp(data, size);
json_object *jso = json_tokener_parse(fdp.ConsumeRandomLengthString(20).c_str());
json_object_get_boolean(jso);
json_object_get_double(jso);
json_object_get_int(jso);
json_object_get_int64(jso);
json_object_get_uint64(jso);
json_object_get_string(jso);
json_object_get_string_len(jso);
json_object_get_object(jso);
json_object_get_array(jso);
json_object_get_type(jso);
json_c_visit(jso, 0, emit_object, NULL);
json_object_set_int(jso, fdp.ConsumeIntegral<int>());
json_object_set_int64(jso, fdp.ConsumeIntegral<int64_t>());
json_object_set_uint64(jso, fdp.ConsumeIntegral<uint64_t>());
json_object_set_double(jso, fdp.ConsumeFloatingPoint<double>());
json_object_set_string(jso, fdp.ConsumeRandomLengthString(10).c_str());
json_object_set_boolean(jso, fdp.ConsumeBool());
std::string str = fdp.ConsumeRandomLengthString(10);
json_object_set_string_len(jso, str.c_str(), str.size());
json_object *dst = NULL;
json_object_deep_copy(jso, &dst, json_c_shallow_copy_default);
json_object_put(dst);
json_object_put(jso);
return 0;
}

View File

@@ -1,21 +0,0 @@
"{"
"}"
","
"["
"]"
","
":"
"e"
"e+"
"e-"
"E"
"E+"
"E-"
"\""
"null"
"1"
"1.234"
"3e4"
"NaN"
"Infinity"
"-Infinity"

View File

@@ -1,53 +0,0 @@
#include <fuzzer/FuzzedDataProvider.h>
#include "json.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
FuzzedDataProvider fdp(data, size);
struct json_tokener *tokener =
json_tokener_new_ex(fdp.ConsumeIntegralInRange<int>(1, JSON_TOKENER_DEFAULT_DEPTH));
int flags = 0;
if (fdp.ConsumeBool()) {
flags |= JSON_TOKENER_VALIDATE_UTF8;
}
if (fdp.ConsumeBool()) {
flags |= JSON_TOKENER_ALLOW_TRAILING_CHARS;
}
if (fdp.ConsumeBool()) {
flags |= JSON_TOKENER_STRICT;
}
json_tokener_set_flags(tokener, flags);
std::string path = fdp.ConsumeRandomLengthString(5);
std::string sub_json_str = fdp.ConsumeRandomLengthString(10);
bool use_format_string = fdp.ConsumeBool();
std::string json_str = fdp.ConsumeRemainingBytesAsString();
struct json_object *jo1 = json_tokener_parse_ex(tokener, json_str.c_str(), json_str.size());
struct json_object *sub_json = json_tokener_parse(sub_json_str.c_str());
if (sub_json == NULL) {
sub_json = json_object_new_object();
}
struct json_object *jo2 = NULL;
if (use_format_string) {
json_pointer_getf(jo1, &jo2, "%s", path.c_str());
if (json_pointer_setf(&jo1, sub_json, "%s", path.c_str()))
{
json_object_put(sub_json);
}
} else {
json_pointer_get(jo1, path.c_str(), &jo2);
if (json_pointer_set(&jo1, path.c_str(), sub_json))
{
json_object_put(sub_json);
}
}
// Clean up the main JSON object
json_object_put(jo1);
json_tokener_free(tokener);
return 0;
}

View File

@@ -1,21 +0,0 @@
"{"
"}"
","
"["
"]"
","
":"
"e"
"e+"
"e-"
"E"
"E+"
"E-"
"\""
"null"
"1"
"1.234"
"3e4"
"NaN"
"Infinity"
"-Infinity"

View File

@@ -8,13 +8,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
json_tokener *tok = json_tokener_new(); json_tokener *tok = json_tokener_new();
json_object *obj = json_tokener_parse_ex(tok, data1, size); json_object *obj = json_tokener_parse_ex(tok, data1, size);
if (json_object_is_type(obj, json_type_object)) { json_object_object_foreach(jobj, key, val) {
json_object_object_foreach(obj, key, val) {
(void)json_object_get_type(val); (void)json_object_get_type(val);
(void)json_object_get_string(val); (void)json_object_get_string(val);
} }
} (void)json_object_to_json_string(obj, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED);
(void)json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED);
json_object_put(obj); json_object_put(obj);
json_tokener_free(tok); json_tokener_free(tok);

View File

@@ -16,6 +16,3 @@
"1" "1"
"1.234" "1.234"
"3e4" "3e4"
"NaN"
"Infinity"
"-Infinity"

View File

@@ -1,88 +0,0 @@
This list was created with:
```
PREV=2022-04-13
NOW=2023-08-12
curl "https://api.github.com/search/issues?q=repo%3Ajson-c%2Fjson-c+closed%3A>${PREV}+created%3A<${NOW}&sort=created&order=asc&per_page=100&page=1" > issues1.out
jq -r '.items[] | "[" + .title + "](" + .url + ")" | tostring' issues?.out > issues.md
sed -e's,^\[ *\(.*\)\](https://api.github.com/.*/\([0-9].*\)),* [Issue #\2](https://github.com/json-c/json-c/issues/\2) - \1,' -i issues.md
cat issues.md >> issues_closed_for_0.17.md
```
* [Issue #191](https://github.com/json-c/json-c/issues/191) - Override int64 to only display uint64 strings
* [Issue #537](https://github.com/json-c/json-c/issues/537) - Replace '\0' only when parsing key, not change data in value.
* [Issue #570](https://github.com/json-c/json-c/issues/570) - Figure out what needs to be done with Android.configure.mk
* [Issue #587](https://github.com/json-c/json-c/issues/587) - Store the hashValue to avoid repeating the hash calculation during the hash resize.
* [Issue #612](https://github.com/json-c/json-c/issues/612) - json-c-0.11: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ...
* [Issue #620](https://github.com/json-c/json-c/issues/620) - Introduce json_object_new_string_{ext,noalloc}().
* [Issue #624](https://github.com/json-c/json-c/issues/624) - json-c-0.14: Detect broken RDRAND during initialization.
* [Issue #625](https://github.com/json-c/json-c/issues/625) - json-c-0.13.x: Detect broken RDRAND during initialization.
* [Issue #668](https://github.com/json-c/json-c/issues/668) - Memory usage regression due to newlocal() on older FreeBSD releases
* [Issue #676](https://github.com/json-c/json-c/issues/676) - dereferencing type-punned pointer might break strict-aliasing rules [-Werror=strict-aliasing]
* [Issue #677](https://github.com/json-c/json-c/issues/677) - Naming conflict when using both json-c and jansson
* [Issue #679](https://github.com/json-c/json-c/issues/679) - Let json-c be used with obsolete compilers
* [Issue #681](https://github.com/json-c/json-c/issues/681) - json_tokener_parse_ex: `null` (4 bytes) only parses as valid JSON when passed with null terminator (5 bytes). Documentation issue?
* [Issue #686](https://github.com/json-c/json-c/issues/686) - Remove dependency on libM::getrandom
* [Issue #687](https://github.com/json-c/json-c/issues/687) - Does not build on Apple Silicon M1
* [Issue #688](https://github.com/json-c/json-c/issues/688) - json-c-0.15-nodoc.tar.gz build fails
* [Issue #702](https://github.com/json-c/json-c/issues/702) - json_patch: add first implementation only with patch application
* [Issue #704](https://github.com/json-c/json-c/issues/704) - add json_object_array_insert_idx() + test-cases + fix json_pointer doc-strings
* [Issue #705](https://github.com/json-c/json-c/issues/705) - segmentation fault on json-c parsing methods in cross compiled target
* [Issue #721](https://github.com/json-c/json-c/issues/721) - cmake test fails with building json-c with icc
* [Issue #730](https://github.com/json-c/json-c/issues/730) - Need a comparison with other JSON libraries in C
* [Issue #733](https://github.com/json-c/json-c/issues/733) - Official release? 1.0?
* [Issue #756](https://github.com/json-c/json-c/issues/756) - Question: Is there any way to build this with Gnu Make?
* [Issue #757](https://github.com/json-c/json-c/issues/757) - json_object_from_fd_ex: fail if file is too large
* [Issue #759](https://github.com/json-c/json-c/issues/759) - json_tokener_parse_ex: handle out of memory errors
* [Issue #766](https://github.com/json-c/json-c/issues/766) - Some people have trouble with undefined references to arc4random
* [Issue #767](https://github.com/json-c/json-c/issues/767) - How to create a character array using json-c
* [Issue #768](https://github.com/json-c/json-c/issues/768) - commits from May 30, 2022 killed my docker build process
* [Issue #769](https://github.com/json-c/json-c/issues/769) - Issue #768
* [Issue #770](https://github.com/json-c/json-c/issues/770) - json_parse.c:170:13: error: this statement may fall through
* [Issue #771](https://github.com/json-c/json-c/issues/771) - fix fallthough warning
* [Issue #772](https://github.com/json-c/json-c/issues/772) - add JSON_C_TO_STRING_COLOR option
* [Issue #773](https://github.com/json-c/json-c/issues/773) - problem with u_int64_t
* [Issue #774](https://github.com/json-c/json-c/issues/774) - The function add_compile_options was added to CMake version 2.8.12 and later but your minimum is 2.8 which will not work
* [Issue #775](https://github.com/json-c/json-c/issues/775) - list(TRANSFORM ...) is not available prior to CMake 3.12.
* [Issue #776](https://github.com/json-c/json-c/issues/776) - Fix typo
* [Issue #777](https://github.com/json-c/json-c/issues/777) - Don't try to change locale when libc only supports the C locale
* [Issue #778](https://github.com/json-c/json-c/issues/778) - Do not insert newlines when converting empty arrays to json string and JSON_C_TO_STRING_PRETTY is used
* [Issue #779](https://github.com/json-c/json-c/issues/779) - Fix compiling for Android
* [Issue #780](https://github.com/json-c/json-c/issues/780) - Memory Leak when setting empty strings when c_string.pdata is used
* [Issue #781](https://github.com/json-c/json-c/issues/781) - Fix memory leak with emtpy strings in json_object_set_string
* [Issue #782](https://github.com/json-c/json-c/issues/782) - Fix typos found by codespell
* [Issue #783](https://github.com/json-c/json-c/issues/783) - Fix build with clang-15+
* [Issue #784](https://github.com/json-c/json-c/issues/784) - get_time_seed(): silence warning emitted by Coverity Scan static analyzer
* [Issue #786](https://github.com/json-c/json-c/issues/786) - ghpages update was not published for json-c-0.16
* [Issue #787](https://github.com/json-c/json-c/issues/787) - -static linker flag result in building failed
* [Issue #788](https://github.com/json-c/json-c/issues/788) - Clear sensitive information.
* [Issue #789](https://github.com/json-c/json-c/issues/789) - Unnecessary struct declaration and unsafe function usage
* [Issue #790](https://github.com/json-c/json-c/issues/790) - Small update to README file
* [Issue #791](https://github.com/json-c/json-c/issues/791) - json_object_object_foreach not ISO-C compliant
* [Issue #792](https://github.com/json-c/json-c/issues/792) - ` json_object_get_int` does not set `EINVAL` on invalid string
* [Issue #794](https://github.com/json-c/json-c/issues/794) - replaced
* [Issue #796](https://github.com/json-c/json-c/issues/796) - Added Test for get int functions
* [Issue #797](https://github.com/json-c/json-c/issues/797) - make uninstall
* [Issue #798](https://github.com/json-c/json-c/issues/798) - API to deal with enums is missing
* [Issue #799](https://github.com/json-c/json-c/issues/799) - json_object_put: Assertion `jso->_ref_count > 0' failed.
* [Issue #800](https://github.com/json-c/json-c/issues/800) - String converted to scientific notation
* [Issue #801](https://github.com/json-c/json-c/issues/801) - #error You do not have strncasecmp on your system.
* [Issue #802](https://github.com/json-c/json-c/issues/802) - Problem: modern CMake warns about version 2.8
* [Issue #803](https://github.com/json-c/json-c/issues/803) - Problem: confusing error message in snprintf_compat.h
* [Issue #804](https://github.com/json-c/json-c/issues/804) - Problem: cmake 3.25.1 warns about CMP0042 not being set
* [Issue #806](https://github.com/json-c/json-c/issues/806) - The problem is libjson-c.dylib incompatible with OS version
* [Issue #807](https://github.com/json-c/json-c/issues/807) - json simple parse syntax
* [Issue #808](https://github.com/json-c/json-c/issues/808) - iOS Build using cmake fails due to 64 to 32bits conversion precision loss
* [Issue #809](https://github.com/json-c/json-c/issues/809) - Feature request json_object_new_uint()
* [Issue #810](https://github.com/json-c/json-c/issues/810) - docs: update to Internet Standard reference
* [Issue #811](https://github.com/json-c/json-c/issues/811) - dependence on execution character set
* [Issue #812](https://github.com/json-c/json-c/issues/812) - Duplicate symbol when compiling with clang-cl
* [Issue #813](https://github.com/json-c/json-c/issues/813) - Build apps only in project itself.
* [Issue #814](https://github.com/json-c/json-c/issues/814) - Code execution order
* [Issue #816](https://github.com/json-c/json-c/issues/816) - Hi I need to generate libjson-c.so.3 and libjson-c.so.3.0.1, please help with steps
* [Issue #818](https://github.com/json-c/json-c/issues/818) - error: a function declaration without a prototype is deprecated in all versions of C
* [Issue #819](https://github.com/json-c/json-c/issues/819) - build with intel 2023 fails on vasprintf
* [Issue #820](https://github.com/json-c/json-c/issues/820) - ISO C forbids in
* [Issue #821](https://github.com/json-c/json-c/issues/821) - Any release planing for 0.17?
* [Issue #822](https://github.com/json-c/json-c/issues/822) - Added option to disable app build
* [Issue #823](https://github.com/json-c/json-c/issues/823) - Symbol not found during linking stage of libjson-c.so

View File

@@ -1,52 +0,0 @@
This list was created with:
```
PREV=2023-08-12
NOW=2024-09-15
curl "https://api.github.com/search/issues?q=repo%3Ajson-c%2Fjson-c+closed%3A>${PREV}+created%3A<${NOW}&sort=created&order=asc&per_page=100&page=1" > issues1.out
jq -r '.items[] | "[" + .title + "](" + .url + ")" | tostring' issues?.out > issues.md
sed -e's,^\[ *\(.*\)\](https://api.github.com/.*/\([0-9].*\)),* [Issue #\2](https://github.com/json-c/json-c/issues/\2) - \1,' -i issues.md
cat issues.md >> issues_closed_for_0.18.md
```
* [Issue #826](https://github.com/json-c/json-c/issues/826) - CMake: remove needless policy setting
* [Issue #827](https://github.com/json-c/json-c/issues/827) - Resolve build issue in tokener_parse_ex_fuzzer.c
* [Issue #828](https://github.com/json-c/json-c/issues/828) - Put arc4random check under DISABLE_EXTRA_LIBS=OFF in CMakeLists.txt.
* [Issue #829](https://github.com/json-c/json-c/issues/829) - Cannot build with clang-cl
* [Issue #830](https://github.com/json-c/json-c/issues/830) - I am looking whether this CVE - CVE-2021-32292 is impacted by json-c version v0.13.1or not ?
* [Issue #831](https://github.com/json-c/json-c/issues/831) - rename WIN32 to _WIN32
* [Issue #833](https://github.com/json-c/json-c/issues/833) - memory leak issue in 0.13
* [Issue #834](https://github.com/json-c/json-c/issues/834) - fix error des of 'error_memory'
* [Issue #835](https://github.com/json-c/json-c/issues/835) - fix error des of 'error_memory'
* [Issue #836](https://github.com/json-c/json-c/issues/836) - Null pointer dereference in tokener_parse_ex_fuzzer.cc
* [Issue #837](https://github.com/json-c/json-c/issues/837) - Add type checking for parsed objects in tokener_parse_ex_fuzzer
* [Issue #838](https://github.com/json-c/json-c/issues/838) - Cannot link properly using cmake
* [Issue #839](https://github.com/json-c/json-c/issues/839) - json_pointer.c: initialize idx
* [Issue #840](https://github.com/json-c/json-c/issues/840) - Memory leak when enable HAVE_SETLOCALE and HAVE_USELOCALE
* [Issue #841](https://github.com/json-c/json-c/issues/841) - Random crash in json_tokener_parse
* [Issue #842](https://github.com/json-c/json-c/issues/842) - Assignment bug in json_pointer.c
* [Issue #843](https://github.com/json-c/json-c/issues/843) - _WIN32 should be used, not WIN32 in source code ifdefs.
* [Issue #844](https://github.com/json-c/json-c/issues/844) - Doxygen: mis-wording in `json_object_put`
* [Issue #845](https://github.com/json-c/json-c/issues/845) - [CMP0153](https://cmake.org/cmake/help/latest/policy/CMP0153.html)
* [Issue #846](https://github.com/json-c/json-c/issues/846) - CMP0153
* [Issue #848](https://github.com/json-c/json-c/issues/848) - json_object_from_file caused calloc SIGSEGV
* [Issue #849](https://github.com/json-c/json-c/issues/849) - random_seed.c: add a Coverity Scan suppression
* [Issue #850](https://github.com/json-c/json-c/issues/850) - Missing return description
* [Issue #851](https://github.com/json-c/json-c/issues/851) - Allow NULL in json_object_new_string() and json_object_new_string_len()
* [Issue #852](https://github.com/json-c/json-c/issues/852) - docs: micro typo in json_object_put doc
* [Issue #853](https://github.com/json-c/json-c/issues/853) - json_tokener_parse_verbose does not set the error indicator when it fails to allocate the tokener
* [Issue #854](https://github.com/json-c/json-c/issues/854) - json_tokener_parse_verbose sets the error indicator to a wrong value when there is a memory allocation failure
* [Issue #856](https://github.com/json-c/json-c/issues/856) - Using libjson-c.so or compiling from source seg faults on json_tokener_parse_ex in alpine docker container
* [Issue #857](https://github.com/json-c/json-c/issues/857) - json_tokener_parse_verbose sets the error indicator to a wrong value when there is a memory allocation failure
* [Issue #858](https://github.com/json-c/json-c/issues/858) - json_tokener.h: json_tokener_parse_verbose: fix typo
* [Issue #859](https://github.com/json-c/json-c/issues/859) - Develop
* [Issue #860](https://github.com/json-c/json-c/issues/860) - Develop
* [Issue #861](https://github.com/json-c/json-c/issues/861) - Handle yet another out-of-memory condition.
* [Issue #862](https://github.com/json-c/json-c/issues/862) - Missing `json-c-targets.cmake` during build cmake build step
* [Issue #863](https://github.com/json-c/json-c/issues/863) - build ios simulator error
* [Issue #864](https://github.com/json-c/json-c/issues/864) - Build pkg-config for msvc as well
* [Issue #865](https://github.com/json-c/json-c/issues/865) - Assertion usage
* [Issue #866](https://github.com/json-c/json-c/issues/866) - Added github actions
* [Issue #868](https://github.com/json-c/json-c/issues/868) - I meet compile error in harmony
* [Issue #869](https://github.com/json-c/json-c/issues/869) - At a high level how are jsons parses? Are they terminated by the new line?
* [Issue #870](https://github.com/json-c/json-c/issues/870) - Non-Compliant features should be optional (and disabled)

View File

@@ -1,91 +0,0 @@
This list was created with:
```
PREV=2024-09-15
NOW=2026-01-19
curl "https://api.github.com/search/issues?q=repo%3Ajson-c%2Fjson-c+closed%3A>${PREV}+created%3A<${NOW}&sort=created&order=asc&per_page=100&page=1" > issues1.out
jq -r '.items[] | "[" + .title + "](" + .url + ")" | tostring' issues?.out > issues.md
sed -e's,^\[ *\(.*\)\](https://api.github.com/.*/\([0-9].*\)),* [Issue #\2](https://github.com/json-c/json-c/issues/\2) - \1,' -i issues.md
cat issues.md >> issues_closed_for_0.19.md
```
* [Issue #826](https://github.com/json-c/json-c/issues/826) - CMake: remove needless policy setting
* [Issue #827](https://github.com/json-c/json-c/issues/827) - Resolve build issue in tokener_parse_ex_fuzzer.c
* [Issue #828](https://github.com/json-c/json-c/issues/828) - Put arc4random check under DISABLE_EXTRA_LIBS=OFF in CMakeLists.txt.
* [Issue #829](https://github.com/json-c/json-c/issues/829) - Cannot build with clang-cl
* [Issue #830](https://github.com/json-c/json-c/issues/830) - I am looking whether this CVE - CVE-2021-32292 is impacted by json-c version v0.13.1or not ?
* [Issue #831](https://github.com/json-c/json-c/issues/831) - rename WIN32 to _WIN32
* [Issue #833](https://github.com/json-c/json-c/issues/833) - memory leak issue in 0.13
* [Issue #834](https://github.com/json-c/json-c/issues/834) - fix error des of 'error_memory'
* [Issue #835](https://github.com/json-c/json-c/issues/835) - fix error des of 'error_memory'
* [Issue #836](https://github.com/json-c/json-c/issues/836) - Null pointer dereference in tokener_parse_ex_fuzzer.cc
* [Issue #837](https://github.com/json-c/json-c/issues/837) - Add type checking for parsed objects in tokener_parse_ex_fuzzer
* [Issue #838](https://github.com/json-c/json-c/issues/838) - Cannot link properly using cmake
* [Issue #839](https://github.com/json-c/json-c/issues/839) - json_pointer.c: initialize idx
* [Issue #840](https://github.com/json-c/json-c/issues/840) - Memory leak when enable HAVE_SETLOCALE and HAVE_USELOCALE
* [Issue #841](https://github.com/json-c/json-c/issues/841) - Random crash in json_tokener_parse
* [Issue #842](https://github.com/json-c/json-c/issues/842) - Assignment bug in json_pointer.c
* [Issue #843](https://github.com/json-c/json-c/issues/843) - _WIN32 should be used, not WIN32 in source code ifdefs.
* [Issue #844](https://github.com/json-c/json-c/issues/844) - Doxygen: mis-wording in `json_object_put`
* [Issue #845](https://github.com/json-c/json-c/issues/845) - [CMP0153](https://cmake.org/cmake/help/latest/policy/CMP0153.html)
* [Issue #846](https://github.com/json-c/json-c/issues/846) - CMP0153
* [Issue #848](https://github.com/json-c/json-c/issues/848) - json_object_from_file caused calloc SIGSEGV
* [Issue #849](https://github.com/json-c/json-c/issues/849) - random_seed.c: add a Coverity Scan suppression
* [Issue #850](https://github.com/json-c/json-c/issues/850) - Missing return description
* [Issue #851](https://github.com/json-c/json-c/issues/851) - Allow NULL in json_object_new_string() and json_object_new_string_len()
* [Issue #852](https://github.com/json-c/json-c/issues/852) - docs: micro typo in json_object_put doc
* [Issue #853](https://github.com/json-c/json-c/issues/853) - json_tokener_parse_verbose does not set the error indicator when it fails to allocate the tokener
* [Issue #854](https://github.com/json-c/json-c/issues/854) - json_tokener_parse_verbose sets the error indicator to a wrong value when there is a memory allocation failure
* [Issue #856](https://github.com/json-c/json-c/issues/856) - Using libjson-c.so or compiling from source seg faults on json_tokener_parse_ex in alpine docker container
* [Issue #857](https://github.com/json-c/json-c/issues/857) - json_tokener_parse_verbose sets the error indicator to a wrong value when there is a memory allocation failure
* [Issue #858](https://github.com/json-c/json-c/issues/858) - json_tokener.h: json_tokener_parse_verbose: fix typo
* [Issue #859](https://github.com/json-c/json-c/issues/859) - Develop
* [Issue #860](https://github.com/json-c/json-c/issues/860) - Develop
* [Issue #861](https://github.com/json-c/json-c/issues/861) - Handle yet another out-of-memory condition.
* [Issue #862](https://github.com/json-c/json-c/issues/862) - Missing `json-c-targets.cmake` during build cmake build step
* [Issue #863](https://github.com/json-c/json-c/issues/863) - build ios simulator error
* [Issue #864](https://github.com/json-c/json-c/issues/864) - Build pkg-config for msvc as well
* [Issue #865](https://github.com/json-c/json-c/issues/865) - Assertion usage
* [Issue #866](https://github.com/json-c/json-c/issues/866) - Added github actions
* [Issue #868](https://github.com/json-c/json-c/issues/868) - I meet compile error in harmony
* [Issue #869](https://github.com/json-c/json-c/issues/869) - At a high level how are jsons parses? Are they terminated by the new line?
* [Issue #870](https://github.com/json-c/json-c/issues/870) - Non-Compliant features should be optional (and disabled)
* [Issue #825](https://github.com/json-c/json-c/issues/825) - Add support for WASI
* [Issue #847](https://github.com/json-c/json-c/issues/847) - Add support for Commodore Amiga
* [Issue #867](https://github.com/json-c/json-c/issues/867) - Parsing of control characters
* [Issue #872](https://github.com/json-c/json-c/issues/872) - fix linkhash breaking -std=c89
* [Issue #873](https://github.com/json-c/json-c/issues/873) - Correct year in changelog for 0.18 release
* [Issue #874](https://github.com/json-c/json-c/issues/874) - comparison with infinity
* [Issue #875](https://github.com/json-c/json-c/issues/875) - Unicode characters seem to be rejected with JSON_TOKENER_STRICT
* [Issue #876](https://github.com/json-c/json-c/issues/876) - json_object_from_fd(_ex) doesn't work with a socket descriptor
* [Issue #877](https://github.com/json-c/json-c/issues/877) - Fix underline bug in README
* [Issue #878](https://github.com/json-c/json-c/issues/878) - Fix underline bug in README
* [Issue #879](https://github.com/json-c/json-c/issues/879) - Handle NULL gracefully in json_tokener_free
* [Issue #880](https://github.com/json-c/json-c/issues/880) - Undefined behavior when coercing NaN value to int
* [Issue #881](https://github.com/json-c/json-c/issues/881) - Tokener with depth=0 causes segmentation fault
* [Issue #882](https://github.com/json-c/json-c/issues/882) - Explicitly handle NaN values when converting to integer
* [Issue #883](https://github.com/json-c/json-c/issues/883) - Add fuzz tests for json_object/point/array apis
* [Issue #884](https://github.com/json-c/json-c/issues/884) - fix macro WIN32_LEAN_AND_MEAN redefined
* [Issue #886](https://github.com/json-c/json-c/issues/886) - Linking to json-c using cmake's find_package error
* [Issue #887](https://github.com/json-c/json-c/issues/887) - Can json-c accept invalid JSON strings?
* [Issue #888](https://github.com/json-c/json-c/issues/888) - Allow build with cmake 4.0.0
* [Issue #891](https://github.com/json-c/json-c/issues/891) - Cmake cant build only static library
* [Issue #892](https://github.com/json-c/json-c/issues/892) - JSON_TOKENER_STRICT rejects U+00BA : MASCULINE ORDINAL INDICATOR
* [Issue #893](https://github.com/json-c/json-c/issues/893) - Fix bug involving supplemental code points that look like high surrogates
* [Issue #894](https://github.com/json-c/json-c/issues/894) - json_object_to_json_string_* trims string to 32767 characters
* [Issue #895](https://github.com/json-c/json-c/issues/895) - CMake: sync minimum version
* [Issue #897](https://github.com/json-c/json-c/issues/897) - error: calloc sizes specified with sizeof in the earlier argument and not in the later argument
* [Issue #898](https://github.com/json-c/json-c/issues/898) - bug: Fixing Cmake build when using clang-cl
* [Issue #899](https://github.com/json-c/json-c/issues/899) - Meson support
* [Issue #900](https://github.com/json-c/json-c/issues/900) - meson cleanups
* [Issue #901](https://github.com/json-c/json-c/issues/901) - miscellanious gitignore updates
* [Issue #904](https://github.com/json-c/json-c/issues/904) - Include getopt.h header file if the platform is not AIX.
* [Issue #905](https://github.com/json-c/json-c/issues/905) - Fix typo
* [Issue #906](https://github.com/json-c/json-c/issues/906) - json-c: fix calloc argument order to avoid GCC14 -Wcalloc-transposed-args in arraylist.c and json_object.c
* [Issue #907](https://github.com/json-c/json-c/issues/907) - tests/CMakeLists: Allow build with CMake 4
* [Issue #908](https://github.com/json-c/json-c/issues/908) - [json-c-0.18] tests/CMakeLists: Allow build with CMake 4
* [Issue #909](https://github.com/json-c/json-c/issues/909) - compilation error with MSVC in packages that use GNU Autoconf
* [Issue #910](https://github.com/json-c/json-c/issues/910) - Support MSVC in packages that use GNU Autoconf.
* [Issue #911](https://github.com/json-c/json-c/issues/911) - Building libjson-c DLL for Windows under Cygwin: why it's named cygjson-c?
* [Issue #912](https://github.com/json-c/json-c/issues/912) - libjson-c.dll is missing VERSIONINFO
* [Issue #913](https://github.com/json-c/json-c/issues/913) - Add VERSIONINFO to libjson-c.dll

View File

@@ -167,23 +167,11 @@ JSONC_0.15 {
} JSONC_0.14; } JSONC_0.14;
JSONC_0.16 { JSONC_0.16 {
# No new symbols in 0.16 # global:
# ...new symbols here...
} JSONC_0.15; } JSONC_0.15;
JSONC_0.17 { JSONC_0.17 {
global:
json_object_array_insert_idx;
json_patch_apply;
# array_list_insert_idx is intentionally not exported
} JSONC_0.16;
JSONC_0.18 {
# global: # global:
} JSONC_0.17; # ...new symbols here...
} JSONC_0.16;
JSONC_0.19 {
global:
json_pointer_set_with_limit_index;
json_pointer_set_with_cb;
json_object_array_put_with_idx_limit_cb;
} JSONC_0.18;

View File

@@ -26,7 +26,6 @@ extern "C" {
#include "json_c_version.h" #include "json_c_version.h"
#include "json_object.h" #include "json_object.h"
#include "json_object_iterator.h" #include "json_object_iterator.h"
@JSON_H_JSON_PATCH@
@JSON_H_JSON_POINTER@ @JSON_H_JSON_POINTER@
#include "json_tokener.h" #include "json_tokener.h"
#include "json_util.h" #include "json_util.h"

View File

@@ -17,11 +17,11 @@ extern "C" {
#endif #endif
#define JSON_C_MAJOR_VERSION 0 #define JSON_C_MAJOR_VERSION 0
#define JSON_C_MINOR_VERSION 18 #define JSON_C_MINOR_VERSION 16
#define JSON_C_MICRO_VERSION 99 #define JSON_C_MICRO_VERSION 99
#define JSON_C_VERSION_NUM \ #define JSON_C_VERSION_NUM \
((JSON_C_MAJOR_VERSION << 16) | (JSON_C_MINOR_VERSION << 8) | JSON_C_MICRO_VERSION) ((JSON_C_MAJOR_VERSION << 16) | (JSON_C_MINOR_VERSION << 8) | JSON_C_MICRO_VERSION)
#define JSON_C_VERSION "0.18.99" #define JSON_C_VERSION "0.16.99"
#ifndef JSON_EXPORT #ifndef JSON_EXPORT
#if defined(_MSC_VER) && defined(JSON_C_DLL) #if defined(_MSC_VER) && defined(JSON_C_DLL)

View File

@@ -13,15 +13,7 @@
#include <inttypes.h> #include <inttypes.h>
#else #else
#ifdef JSON_C_HAVE_STDINT_H
#include <stdint.h> #include <stdint.h>
#else
/* Really only valid for old MS compilers, VS2008 and earlier: */
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#endif
#define PRId64 "I64d" #define PRId64 "I64d"
#define SCNd64 "I64d" #define SCNd64 "I64d"
@@ -29,7 +21,7 @@ typedef unsigned __int64 uint64_t;
#endif #endif
#if defined(_MSC_VER) && !defined(ssize_t) #if defined(_MSC_VER)
#include <BaseTsd.h> #include <BaseTsd.h>
typedef SSIZE_T ssize_t; typedef SSIZE_T ssize_t;
#endif #endif

View File

@@ -53,7 +53,6 @@
#endif #endif
#endif #endif
const char *json_number_chars = "0123456789.+-eE"; /* Unused, but part of public API, drop for 1.0 */
const char *json_hex_chars = "0123456789abcdefABCDEF"; const char *json_hex_chars = "0123456789abcdefABCDEF";
static void json_object_generic_delete(struct json_object *jso); static void json_object_generic_delete(struct json_object *jso);
@@ -721,7 +720,6 @@ int32_t json_object_get_int(const struct json_object *jso)
int64_t cint64 = 0; int64_t cint64 = 0;
double cdouble; double cdouble;
enum json_type o_type; enum json_type o_type;
errno = 0;
if (!jso) if (!jso)
return 0; return 0;
@@ -757,34 +755,17 @@ int32_t json_object_get_int(const struct json_object *jso)
{ {
case json_type_int: case json_type_int:
/* Make sure we return the correct values for out of range numbers. */ /* Make sure we return the correct values for out of range numbers. */
if (cint64 < INT32_MIN) if (cint64 <= INT32_MIN)
{
errno = ERANGE;
return INT32_MIN; return INT32_MIN;
} if (cint64 >= INT32_MAX)
if (cint64 > INT32_MAX)
{
errno = ERANGE;
return INT32_MAX; return INT32_MAX;
}
return (int32_t)cint64; return (int32_t)cint64;
case json_type_double: case json_type_double:
cdouble = JC_DOUBLE_C(jso)->c_double; cdouble = JC_DOUBLE_C(jso)->c_double;
if (cdouble < INT32_MIN) if (cdouble <= INT32_MIN)
{
errno = ERANGE;
return INT32_MIN; return INT32_MIN;
} if (cdouble >= INT32_MAX)
if (cdouble > INT32_MAX)
{
errno = ERANGE;
return INT32_MAX; return INT32_MAX;
}
if (isnan(cdouble))
{
errno = EINVAL;
return INT32_MIN;
}
return (int32_t)cdouble; return (int32_t)cdouble;
case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; case json_type_boolean: return JC_BOOL_C(jso)->c_boolean;
default: return 0; default: return 0;
@@ -819,7 +800,6 @@ struct json_object *json_object_new_uint64(uint64_t i)
int64_t json_object_get_int64(const struct json_object *jso) int64_t json_object_get_int64(const struct json_object *jso)
{ {
int64_t cint; int64_t cint;
errno = 0;
if (!jso) if (!jso)
return 0; return 0;
@@ -832,11 +812,8 @@ int64_t json_object_get_int64(const struct json_object *jso)
{ {
case json_object_int_type_int64: return jsoint->cint.c_int64; case json_object_int_type_int64: return jsoint->cint.c_int64;
case json_object_int_type_uint64: case json_object_int_type_uint64:
if (jsoint->cint.c_uint64 > INT64_MAX) if (jsoint->cint.c_uint64 >= INT64_MAX)
{
errno = ERANGE;
return INT64_MAX; return INT64_MAX;
}
return (int64_t)jsoint->cint.c_uint64; return (int64_t)jsoint->cint.c_uint64;
default: json_abort("invalid cint_type"); default: json_abort("invalid cint_type");
} }
@@ -844,21 +821,10 @@ int64_t json_object_get_int64(const struct json_object *jso)
case json_type_double: case json_type_double:
// INT64_MAX can't be exactly represented as a double // INT64_MAX can't be exactly represented as a double
// so cast to tell the compiler it's ok to round up. // so cast to tell the compiler it's ok to round up.
if (JC_DOUBLE_C(jso)->c_double > (double)INT64_MAX) if (JC_DOUBLE_C(jso)->c_double >= (double)INT64_MAX)
{
errno = ERANGE;
return INT64_MAX; return INT64_MAX;
} if (JC_DOUBLE_C(jso)->c_double <= INT64_MIN)
if (JC_DOUBLE_C(jso)->c_double < (double)INT64_MIN)
{
errno = ERANGE;
return INT64_MIN; return INT64_MIN;
}
if (isnan(JC_DOUBLE_C(jso)->c_double))
{
errno = EINVAL;
return INT64_MIN;
}
return (int64_t)JC_DOUBLE_C(jso)->c_double; return (int64_t)JC_DOUBLE_C(jso)->c_double;
case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; case json_type_boolean: return JC_BOOL_C(jso)->c_boolean;
case json_type_string: case json_type_string:
@@ -872,7 +838,6 @@ int64_t json_object_get_int64(const struct json_object *jso)
uint64_t json_object_get_uint64(const struct json_object *jso) uint64_t json_object_get_uint64(const struct json_object *jso)
{ {
uint64_t cuint; uint64_t cuint;
errno = 0;
if (!jso) if (!jso)
return 0; return 0;
@@ -885,10 +850,7 @@ uint64_t json_object_get_uint64(const struct json_object *jso)
{ {
case json_object_int_type_int64: case json_object_int_type_int64:
if (jsoint->cint.c_int64 < 0) if (jsoint->cint.c_int64 < 0)
{
errno = ERANGE;
return 0; return 0;
}
return (uint64_t)jsoint->cint.c_int64; return (uint64_t)jsoint->cint.c_int64;
case json_object_int_type_uint64: return jsoint->cint.c_uint64; case json_object_int_type_uint64: return jsoint->cint.c_uint64;
default: json_abort("invalid cint_type"); default: json_abort("invalid cint_type");
@@ -897,21 +859,10 @@ uint64_t json_object_get_uint64(const struct json_object *jso)
case json_type_double: case json_type_double:
// UINT64_MAX can't be exactly represented as a double // UINT64_MAX can't be exactly represented as a double
// so cast to tell the compiler it's ok to round up. // so cast to tell the compiler it's ok to round up.
if (JC_DOUBLE_C(jso)->c_double > (double)UINT64_MAX) if (JC_DOUBLE_C(jso)->c_double >= (double)UINT64_MAX)
{
errno = ERANGE;
return UINT64_MAX; return UINT64_MAX;
}
if (JC_DOUBLE_C(jso)->c_double < 0) if (JC_DOUBLE_C(jso)->c_double < 0)
{
errno = ERANGE;
return 0; return 0;
}
if (isnan(JC_DOUBLE_C(jso)->c_double))
{
errno = EINVAL;
return 0;
}
return (uint64_t)JC_DOUBLE_C(jso)->c_double; return (uint64_t)JC_DOUBLE_C(jso)->c_double;
case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; case json_type_boolean: return JC_BOOL_C(jso)->c_boolean;
case json_type_string: case json_type_string:
@@ -1568,12 +1519,6 @@ int json_object_array_add(struct json_object *jso, struct json_object *val)
return array_list_add(JC_ARRAY(jso)->c_array, val); return array_list_add(JC_ARRAY(jso)->c_array, val);
} }
int json_object_array_insert_idx(struct json_object *jso, size_t idx, struct json_object *val)
{
assert(json_object_get_type(jso) == json_type_array);
return array_list_insert_idx(JC_ARRAY(jso)->c_array, idx, val);
}
int json_object_array_put_idx(struct json_object *jso, size_t idx, struct json_object *val) int json_object_array_put_idx(struct json_object *jso, size_t idx, struct json_object *val)
{ {
assert(json_object_get_type(jso) == json_type_array); assert(json_object_get_type(jso) == json_type_array);

View File

@@ -172,10 +172,10 @@ JSON_EXPORT struct json_object *json_object_get(struct json_object *obj);
* is a member of (unless you know you've called `json_object_get(obj)` to * is a member of (unless you know you've called `json_object_get(obj)` to
* explicitly increment the refcount). * explicitly increment the refcount).
* *
* NULL may be passed, in which case this is a no-op. * NULL may be passed, which which case this is a no-op.
* *
* @param obj the json_object instance * @param obj the json_object instance
* @returns 1 if the object was freed, 0 if only the refcount was decremented * @returns 1 if the object was freed.
* @see json_object_get() * @see json_object_get()
*/ */
JSON_EXPORT int json_object_put(struct json_object *obj); JSON_EXPORT int json_object_put(struct json_object *obj);
@@ -191,7 +191,6 @@ JSON_EXPORT int json_object_put(struct json_object *obj);
json_type_object, json_type_object,
json_type_array, json_type_array,
json_type_string json_type_string
* @returns 1 if the object is of the specified type, 0 otherwise
*/ */
JSON_EXPORT int json_object_is_type(const struct json_object *obj, enum json_type type); JSON_EXPORT int json_object_is_type(const struct json_object *obj, enum json_type type);
@@ -459,9 +458,9 @@ JSON_EXPORT struct json_object *json_object_object_get(const struct json_object
* associated with the given field name. * associated with the given field name.
* *
* It is safe to pass a NULL value. * It is safe to pass a NULL value.
* @returns 1 if the key exists, 0 otherwise * @returns whether or not the key exists
*/ */
JSON_EXPORT int json_object_object_get_ex(const struct json_object *obj, const char *key, JSON_EXPORT json_bool json_object_object_get_ex(const struct json_object *obj, const char *key,
struct json_object **value); struct json_object **value);
/** Delete the given json_object field /** Delete the given json_object field
@@ -561,7 +560,7 @@ JSON_EXPORT struct array_list *json_object_get_array(const struct json_object *o
/** Get the length of a json_object of type json_type_array /** Get the length of a json_object of type json_type_array
* @param obj the json_object instance * @param obj the json_object instance
* @returns the length of the array * @returns an int
*/ */
JSON_EXPORT size_t json_object_array_length(const struct json_object *obj); JSON_EXPORT size_t json_object_array_length(const struct json_object *obj);
@@ -623,25 +622,6 @@ JSON_EXPORT int json_object_array_add(struct json_object *obj, struct json_objec
JSON_EXPORT int json_object_array_put_idx(struct json_object *obj, size_t idx, JSON_EXPORT int json_object_array_put_idx(struct json_object *obj, size_t idx,
struct json_object *val); struct json_object *val);
/** Insert an element at a specified index in an array (a json_object of type json_type_array)
*
* The reference count will *not* be incremented. This is to make adding
* fields to objects in code more compact. If you want to retain a reference
* to an added object you must wrap the passed object with json_object_get
*
* The array size will be automatically be expanded to the size of the
* index if the index is larger than the current size.
* If the index is within the existing array limits, then the element will be
* inserted and all elements will be shifted. This is the only difference between
* this function and json_object_array_put_idx().
*
* @param obj the json_object instance
* @param idx the index to insert the element at
* @param val the json_object to be added
*/
JSON_EXPORT int json_object_array_insert_idx(struct json_object *obj, size_t idx,
struct json_object *val);
/** Get the element at specified index of array `obj` (which must be a json_object of type json_type_array) /** Get the element at specified index of array `obj` (which must be a json_object of type json_type_array)
* *
* *No* reference counts will be changed, and ownership of the returned * *No* reference counts will be changed, and ownership of the returned
@@ -739,12 +719,9 @@ JSON_EXPORT struct json_object *json_object_new_uint64(uint64_t i);
/** Get the int value of a json_object /** Get the int value of a json_object
* *
* The type is coerced to a int if the passed object is not a int. * The type is coerced to a int if the passed object is not a int.
* double objects will return their integer conversion except for NaN values * double objects will return their integer conversion. Strings will be
* which return INT32_MIN and the errno is set to EINVAL. * parsed as an integer. If no conversion exists then 0 is returned
* Strings will be parsed as an integer. If no conversion exists then 0 is * and errno is set to EINVAL. null is equivalent to 0 (no error values set)
* returned and errno is set to EINVAL. null is equivalent to 0 (no error values
* set).
* Sets errno to ERANGE if the value exceeds the range of int.
* *
* Note that integers are stored internally as 64-bit values. * Note that integers are stored internally as 64-bit values.
* If the value of too big or too small to fit into 32-bit, INT32_MAX or * If the value of too big or too small to fit into 32-bit, INT32_MAX or
@@ -786,12 +763,8 @@ JSON_EXPORT int json_object_int_inc(struct json_object *obj, int64_t val);
/** Get the int value of a json_object /** Get the int value of a json_object
* *
* The type is coerced to a int64 if the passed object is not a int64. * The type is coerced to a int64 if the passed object is not a int64.
* double objects will return their int64 conversion except for NaN values * double objects will return their int64 conversion. Strings will be
* which return INT64_MIN and the errno is set to EINVAL. * parsed as an int64. If no conversion exists then 0 is returned.
* Strings will be parsed as an int64. If no conversion exists then 0 is
* returned and errno is set to EINVAL. null is equivalent to 0 (no error values
* set).
* Sets errno to ERANGE if the value exceeds the range of int64.
* *
* NOTE: Set errno to 0 directly before a call to this function to determine * NOTE: Set errno to 0 directly before a call to this function to determine
* whether or not conversion was successful (it does not clear the value for * whether or not conversion was successful (it does not clear the value for
@@ -805,12 +778,8 @@ JSON_EXPORT int64_t json_object_get_int64(const struct json_object *obj);
/** Get the uint value of a json_object /** Get the uint value of a json_object
* *
* The type is coerced to a uint64 if the passed object is not a uint64. * The type is coerced to a uint64 if the passed object is not a uint64.
* double objects will return their uint64 conversion except for NaN values * double objects will return their uint64 conversion. Strings will be
* which return 0 and the errno is set to EINVAL. * parsed as an uint64. If no conversion exists then 0 is returned.
* Strings will be parsed as an uint64. If no conversion exists then 0 is
* returned and errno is set to EINVAL. null is equivalent to 0 (no error values
* set).
* Sets errno to ERANGE if the value exceeds the range of uint64.
* *
* NOTE: Set errno to 0 directly before a call to this function to determine * NOTE: Set errno to 0 directly before a call to this function to determine
* whether or not conversion was successful (it does not clear the value for * whether or not conversion was successful (it does not clear the value for
@@ -1054,7 +1023,7 @@ JSON_EXPORT struct json_object *json_object_new_null(void);
* *
* @param obj1 the first json_object instance * @param obj1 the first json_object instance
* @param obj2 the second json_object instance * @param obj2 the second json_object instance
* @returns 1 if both objects are equal, 0 otherwise * @returns whether both objects are equal or not
*/ */
JSON_EXPORT int json_object_equal(struct json_object *obj1, struct json_object *obj2); JSON_EXPORT int json_object_equal(struct json_object *obj1, struct json_object *obj2);

View File

@@ -28,7 +28,7 @@ struct json_object;
#include <unistd.h> #include <unistd.h>
#endif /* HAVE_UNISTD_H */ #endif /* HAVE_UNISTD_H */
#if defined(_MSC_VER) && !defined(ssize_t) #ifdef _MSC_VER
#include <BaseTsd.h> #include <BaseTsd.h>
typedef SSIZE_T ssize_t; typedef SSIZE_T ssize_t;
#endif #endif

View File

@@ -1,334 +0,0 @@
/*
* Copyright (c) 2021 Alexandru Ardelean.
* Copyright (c) 2023 Eric Hawicz
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "json_patch.h"
#include "json_object_private.h"
#include "json_pointer_private.h"
#include <limits.h>
#ifndef SIZE_T_MAX
#if SIZEOF_SIZE_T == SIZEOF_INT
#define SIZE_T_MAX UINT_MAX
#elif SIZEOF_SIZE_T == SIZEOF_LONG
#define SIZE_T_MAX ULONG_MAX
#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG
#define SIZE_T_MAX ULLONG_MAX
#else
#error Unable to determine size of size_t
#endif
#endif
#define _set_err(_errval, _errmsg) do { \
patch_error->errno_code = (_errval); \
patch_error->errmsg = (_errmsg); \
errno = 0; /* To avoid confusion */ \
} while (0)
#define _set_err_from_ptrget(_errval, _fieldname) do { \
patch_error->errno_code = (_errval); \
patch_error->errmsg = (_errval) == ENOENT ? \
"Did not find element referenced by " _fieldname " field" : \
"Invalid " _fieldname " field"; \
errno = 0; /* To avoid confusion */ \
} while(0)
/**
* JavaScript Object Notation (JSON) Patch
* RFC 6902 - https://tools.ietf.org/html/rfc6902
*/
static int json_patch_apply_test(struct json_object **res,
struct json_object *patch_elem,
const char *path, struct json_patch_error *patch_error)
{
struct json_object *value1, *value2;
if (!json_object_object_get_ex(patch_elem, "value", &value1)) {
_set_err(EINVAL, "Patch object does not contain a 'value' field");
return -1;
}
if (json_pointer_get(*res, path, &value2))
{
_set_err_from_ptrget(errno, "path");
return -1;
}
if (!json_object_equal(value1, value2)) {
_set_err(ENOENT, "Value of element referenced by 'path' field did not match 'value' field");
return -1;
}
return 0;
}
static int __json_patch_apply_remove(struct json_pointer_get_result *jpres)
{
if (json_object_is_type(jpres->parent, json_type_array)) {
return json_object_array_del_idx(jpres->parent, jpres->index_in_parent, 1);
} else if (jpres->parent && jpres->key_in_parent) {
json_object_object_del(jpres->parent, jpres->key_in_parent);
return 0;
} else {
// We're removing the root object
(void)json_object_put(jpres->obj);
jpres->obj = NULL;
return 0;
}
}
static int json_patch_apply_remove(struct json_object **res, const char *path, struct json_patch_error *patch_error)
{
struct json_pointer_get_result jpres;
int rc;
if (json_pointer_get_internal(*res, path, &jpres))
{
_set_err_from_ptrget(errno, "path");
return -1;
}
rc = __json_patch_apply_remove(&jpres);
if (rc < 0)
_set_err(EINVAL, "Unable to remove path referenced by 'path' field");
// This means we removed and freed the root object, i.e. *res
if (jpres.parent == NULL)
*res = NULL;
return rc;
}
// callback for json_pointer_set_with_cb()
// key is ignored because this callback is only for arrays
static int json_object_array_insert_idx_cb(struct json_object *parent, const char *key, size_t idx,
struct json_object *value, void *priv)
{
int rc;
int *add = priv;
if (idx > json_object_array_length(parent))
{
// Note: will propagate back out through json_pointer_set_with_cb()
errno = EINVAL;
return -1;
}
if (*add)
rc = json_object_array_insert_idx(parent, idx, value);
else
rc = json_object_array_put_idx(parent, idx, value);
if (rc < 0)
errno = EINVAL;
return rc;
}
static int json_patch_apply_add_replace(struct json_object **res,
struct json_object *patch_elem,
const char *path, int add, struct json_patch_error *patch_error)
{
struct json_object *value;
int rc;
if (!json_object_object_get_ex(patch_elem, "value", &value)) {
_set_err(EINVAL, "Patch object does not contain a 'value' field");
return -1;
}
/* if this is a replace op, then we need to make sure it exists before replacing */
if (!add && json_pointer_get(*res, path, NULL)) {
_set_err_from_ptrget(errno, "path");
return -1;
}
rc = json_pointer_set_with_cb(res, path, json_object_get(value),
json_object_array_insert_idx_cb, 0, &add);
if (rc)
{
_set_err(errno, "Failed to set value at path referenced by 'path' field");
json_object_put(value);
}
return rc;
}
// callback for json_pointer_set_with_cb()
// key is ignored because this callback is only for arrays
static int json_object_array_move_cb(struct json_object *parent, const char *key, size_t idx,
struct json_object *value, void *priv)
{
int rc;
struct json_pointer_get_result *from = priv;
size_t len = json_object_array_length(parent);
/**
* If it's the same array parent, it means that we removed
* and element from it, so the length is temporarily reduced
* by 1, which means that if we try to move an element to
* the last position, we need to check the current length + 1
*/
if (parent == from->parent)
len++;
if (idx > len)
{
// Note: will propagate back out through json_pointer_set_with_cb()
errno = EINVAL;
return -1;
}
rc = json_object_array_insert_idx(parent, idx, value);
if (rc < 0)
errno = EINVAL;
return rc;
}
static int json_patch_apply_move_copy(struct json_object **res,
struct json_object *patch_elem,
const char *path, int move, struct json_patch_error *patch_error)
{
json_pointer_set_cb array_set_cb;
struct json_pointer_get_result from;
struct json_object *jfrom;
const char *from_s;
size_t from_s_len;
int rc;
if (!json_object_object_get_ex(patch_elem, "from", &jfrom)) {
_set_err(EINVAL, "Patch does not contain a 'from' field");
return -1;
}
from_s = json_object_get_string(jfrom);
from_s_len = strlen(from_s);
if (strncmp(from_s, path, from_s_len) == 0) {
/**
* If lengths match, it's a noop, if they don't,
* then we're trying to move a parent under a child
* which is not allowed as per RFC 6902 section 4.4
* The "from" location MUST NOT be a proper prefix of the "path"
* location; i.e., a location cannot be moved into one of its children.
*/
if (from_s_len == strlen(path))
return 0;
_set_err(EINVAL, "Invalid attempt to move parent under a child");
return -1;
}
rc = json_pointer_get_internal(*res, from_s, &from);
if (rc)
{
_set_err_from_ptrget(errno, "from");
return rc;
}
// Note: it's impossible for json_pointer to find the root obj, due
// to the path check above, so from.parent is guaranteed non-NULL
json_object_get(from.obj);
if (!move) {
array_set_cb = json_object_array_insert_idx_cb;
} else {
rc = __json_patch_apply_remove(&from);
if (rc < 0) {
json_object_put(from.obj);
return rc;
}
array_set_cb = json_object_array_move_cb;
}
rc = json_pointer_set_with_cb(res, path, from.obj, array_set_cb, 0, &from);
if (rc)
{
_set_err(errno, "Failed to set value at path referenced by 'path' field");
json_object_put(from.obj);
}
return rc;
}
int json_patch_apply(struct json_object *copy_from, struct json_object *patch,
struct json_object **base, struct json_patch_error *patch_error)
{
size_t ii;
int rc = 0;
struct json_patch_error placeholder;
if (!patch_error)
patch_error = &placeholder;
patch_error->patch_failure_idx = SIZE_T_MAX;
patch_error->errno_code = 0;
if (base == NULL||
(*base == NULL && copy_from == NULL) ||
(*base != NULL && copy_from != NULL))
{
_set_err(EFAULT, "Exactly one of *base or copy_from must be non-NULL");
return -1;
}
if (!json_object_is_type(patch, json_type_array)) {
_set_err(EFAULT, "Patch object is not of type json_type_array");
return -1;
}
if (copy_from != NULL)
{
if (json_object_deep_copy(copy_from, base, NULL) < 0)
{
_set_err(ENOMEM, "Unable to copy copy_from using json_object_deep_copy()");
return -1;
}
}
/* Go through all operations ; apply them on res */
for (ii = 0; ii < json_object_array_length(patch); ii++) {
struct json_object *jop, *jpath;
struct json_object *patch_elem = json_object_array_get_idx(patch, ii);
const char *op, *path;
patch_error->patch_failure_idx = ii;
if (!json_object_object_get_ex(patch_elem, "op", &jop)) {
_set_err(EINVAL, "Patch object does not contain 'op' field");
return -1;
}
op = json_object_get_string(jop);
if (!json_object_object_get_ex(patch_elem, "path", &jpath)) {
_set_err(EINVAL, "Patch object does not contain 'path' field");
return -1;
}
path = json_object_get_string(jpath); // Note: empty string is ok!
if (!strcmp(op, "test"))
rc = json_patch_apply_test(base, patch_elem, path, patch_error);
else if (!strcmp(op, "remove"))
rc = json_patch_apply_remove(base, path, patch_error);
else if (!strcmp(op, "add"))
rc = json_patch_apply_add_replace(base, patch_elem, path, 1, patch_error);
else if (!strcmp(op, "replace"))
rc = json_patch_apply_add_replace(base, patch_elem, path, 0, patch_error);
else if (!strcmp(op, "move"))
rc = json_patch_apply_move_copy(base, patch_elem, path, 1, patch_error);
else if (!strcmp(op, "copy"))
rc = json_patch_apply_move_copy(base, patch_elem, path, 0, patch_error);
else {
_set_err(EINVAL, "Patch object has invalid 'op' field");
return -1;
}
if (rc < 0)
break;
}
return rc;
}

View File

@@ -1,80 +0,0 @@
/*
* Copyright (c) 2021 Alexadru Ardelean.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/
/**
* @file
* @brief JSON Patch (RFC 6902) implementation for manipulating JSON objects
*/
#ifndef _json_patch_h_
#define _json_patch_h_
#include "json_pointer.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Details of an error that occurred during json_patch_apply()
*/
struct json_patch_error {
/**
* An errno value indicating what kind of error occurred.
* Possible values include:
* - ENOENT - A path referenced in the operation does not exist.
* - EINVAL - An invalid operation or with invalid path was attempted
* - ENOMEM - Unable to allocate memory
* - EFAULT - Invalid arguments were passed to json_patch_apply()
* (i.e. a C API error, vs. a data error like EINVAL)
*/
int errno_code;
/**
* The index into the patch array of the operation that failed,
* or SIZE_T_MAX for overall errors.
*/
size_t patch_failure_idx;
/**
* A human readable error message.
* Allocated from static storage, does not need to be freed.
*/
const char *errmsg;
};
/**
* Apply the JSON patch to the base object.
* The patch object must be formatted as per RFC 6902, i.e.
* a json_type_array containing patch operations.
* If the patch is not correctly formatted, an error will
* be returned.
*
* The json_object at *base will be modified in place.
* Exactly one of *base or copy_from must be non-NULL.
* If *base is NULL, a new copy of copy_from will allocated and populated
* using json_object_deep_copy(). In this case json_object_put() _must_ be
* used to free *base even if the overall patching operation fails.
*
* If anything fails during patching a negative value will be returned,
* and patch_error (if non-NULL) will be populated with error details.
*
* @param base a pointer to the JSON object which to patch
* @param patch the JSON object that describes the patch to be applied
* @param copy_from a JSON object to copy to *base
* @param patch_error optional, details about errors
*
* @return negative if an error (or not found), or 0 if patch completely applied
*/
JSON_EXPORT int json_patch_apply(struct json_object *copy_from, struct json_object *patch,
struct json_object **base, struct json_patch_error *patch_error);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -15,9 +15,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "json_object_private.h"
#include "json_pointer.h" #include "json_pointer.h"
#include "json_pointer_private.h"
#include "strdup_compat.h" #include "strdup_compat.h"
#include "vasprintf_compat.h" #include "vasprintf_compat.h"
@@ -43,9 +41,10 @@ static void string_replace_all_occurrences_with_char(char *s, const char *occur,
} }
} }
static int is_valid_index(const char *path, size_t *idx) static int is_valid_index(struct json_object *jo, const char *path, size_t *idx)
{ {
size_t i, len = strlen(path); size_t i, len = strlen(path);
long int idx_val = -1;
/* this code-path optimizes a bit, for when we reference the 0-9 index range /* this code-path optimizes a bit, for when we reference the 0-9 index range
* in a JSON array and because leading zeros not allowed * in a JSON array and because leading zeros not allowed
*/ */
@@ -54,7 +53,7 @@ static int is_valid_index(const char *path, size_t *idx)
if (is_plain_digit(path[0])) if (is_plain_digit(path[0]))
{ {
*idx = (path[0] - '0'); *idx = (path[0] - '0');
return 1; goto check_oob;
} }
errno = EINVAL; errno = EINVAL;
return 0; return 0;
@@ -75,27 +74,34 @@ static int is_valid_index(const char *path, size_t *idx)
} }
} }
// We know it's all digits, so the only error case here is overflow, idx_val = strtol(path, NULL, 10);
// but ULLONG_MAX will be longer than any array length so that's ok. if (idx_val < 0)
*idx = strtoull(path, NULL, 10); {
errno = EINVAL;
return 0;
}
*idx = idx_val;
check_oob:
len = json_object_array_length(jo);
if (*idx >= len)
{
errno = ENOENT;
return 0;
}
return 1; return 1;
} }
static int json_pointer_get_single_path(struct json_object *obj, char *path, static int json_pointer_get_single_path(struct json_object *obj, char *path,
struct json_object **value, size_t *idx) struct json_object **value)
{ {
if (json_object_is_type(obj, json_type_array)) if (json_object_is_type(obj, json_type_array))
{ {
if (!is_valid_index(path, idx)) size_t idx;
if (!is_valid_index(obj, path, &idx))
return -1; return -1;
if (*idx >= json_object_array_length(obj)) obj = json_object_array_get_idx(obj, idx);
{
errno = ENOENT;
return -1;
}
obj = json_object_array_get_idx(obj, *idx);
if (obj) if (obj)
{ {
if (value) if (value)
@@ -121,8 +127,7 @@ static int json_pointer_get_single_path(struct json_object *obj, char *path,
} }
static int json_pointer_set_single_path(struct json_object *parent, const char *path, static int json_pointer_set_single_path(struct json_object *parent, const char *path,
struct json_object *value, struct json_object *value)
json_pointer_set_cb set_cb, int cb_handles_obj, void *priv)
{ {
if (json_object_is_type(parent, json_type_array)) if (json_object_is_type(parent, json_type_array))
{ {
@@ -130,25 +135,16 @@ static int json_pointer_set_single_path(struct json_object *parent, const char *
/* RFC (Chapter 4) states that '-' may be used to add new elements to an array */ /* RFC (Chapter 4) states that '-' may be used to add new elements to an array */
if (path[0] == '-' && path[1] == '\0') if (path[0] == '-' && path[1] == '\0')
return json_object_array_add(parent, value); return json_object_array_add(parent, value);
if (!is_valid_index(path, &idx)) if (!is_valid_index(parent, path, &idx))
return -1; return -1;
return set_cb(parent, NULL, idx, value, priv); return json_object_array_put_idx(parent, idx, value);
} }
/* path replacements should have been done in json_pointer_get_single_path(), /* path replacements should have been done in json_pointer_get_single_path(),
* and we should still be good here * and we should still be good here
*/ */
if (json_object_is_type(parent, json_type_object)) if (json_object_is_type(parent, json_type_object))
{
if (cb_handles_obj)
{
return set_cb(parent, path, (size_t)-1, value, priv);
}
else
{
return json_object_object_add(parent, path, value); return json_object_object_add(parent, path, value);
}
}
/* Getting here means that we tried to "dereference" a primitive JSON type /* Getting here means that we tried to "dereference" a primitive JSON type
* (like string, int, bool).i.e. add a sub-object to it * (like string, int, bool).i.e. add a sub-object to it
@@ -157,11 +153,9 @@ static int json_pointer_set_single_path(struct json_object *parent, const char *
return -1; return -1;
} }
static int json_pointer_result_get_recursive(struct json_object *obj, char *path, static int json_pointer_get_recursive(struct json_object *obj, char *path,
struct json_pointer_get_result *res) struct json_object **value)
{ {
struct json_object *parent_obj = obj;
size_t idx = 0;
char *endp; char *endp;
int rc; int rc;
@@ -178,47 +172,24 @@ static int json_pointer_result_get_recursive(struct json_object *obj, char *path
*endp = '\0'; *endp = '\0';
/* If we err-ed here, return here */ /* If we err-ed here, return here */
if ((rc = json_pointer_get_single_path(obj, path, &obj, &idx))) if ((rc = json_pointer_get_single_path(obj, path, &obj)))
return rc; return rc;
if (endp) if (endp)
{ {
/* Put the slash back, so that the sanity check passes on next recursion level */ /* Put the slash back, so that the sanity check passes on next recursion level */
*endp = '/'; *endp = '/';
return json_pointer_result_get_recursive(obj, endp, res); return json_pointer_get_recursive(obj, endp, value);
} }
/* We should be at the end of the recursion here */ /* We should be at the end of the recursion here */
if (res) {
res->parent = parent_obj;
res->obj = obj;
if (json_object_is_type(res->parent, json_type_array))
res->index_in_parent = idx;
else
res->key_in_parent = path;
}
return 0;
}
static int json_pointer_object_get_recursive(struct json_object *obj, char *path,
struct json_object **value)
{
struct json_pointer_get_result res;
int rc;
rc = json_pointer_result_get_recursive(obj, path, &res);
if (rc)
return rc;
if (value) if (value)
*value = res.obj; *value = obj;
return 0; return 0;
} }
int json_pointer_get_internal(struct json_object *obj, const char *path, int json_pointer_get(struct json_object *obj, const char *path, struct json_object **res)
struct json_pointer_get_result *res)
{ {
char *path_copy = NULL; char *path_copy = NULL;
int rc; int rc;
@@ -231,10 +202,8 @@ int json_pointer_get_internal(struct json_object *obj, const char *path,
if (path[0] == '\0') if (path[0] == '\0')
{ {
res->parent = NULL; if (res)
res->obj = obj; *res = obj;
res->key_in_parent = NULL;
res->index_in_parent = UINT32_MAX;
return 0; return 0;
} }
@@ -244,30 +213,12 @@ int json_pointer_get_internal(struct json_object *obj, const char *path,
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
} }
rc = json_pointer_result_get_recursive(obj, path_copy, res); rc = json_pointer_get_recursive(obj, path_copy, res);
/* re-map the path string to the const-path string */
if (rc == 0 && json_object_is_type(res->parent, json_type_object) && res->key_in_parent)
res->key_in_parent = path + (res->key_in_parent - path_copy);
free(path_copy); free(path_copy);
return rc; return rc;
} }
int json_pointer_get(struct json_object *obj, const char *path, struct json_object **res)
{
struct json_pointer_get_result jpres;
int rc;
rc = json_pointer_get_internal(obj, path, &jpres);
if (rc)
return rc;
if (res)
*res = jpres.obj;
return 0;
}
int json_pointer_getf(struct json_object *obj, struct json_object **res, const char *path_fmt, ...) int json_pointer_getf(struct json_object *obj, struct json_object **res, const char *path_fmt, ...)
{ {
char *path_copy = NULL; char *path_copy = NULL;
@@ -294,16 +245,14 @@ int json_pointer_getf(struct json_object *obj, struct json_object **res, const c
goto out; goto out;
} }
rc = json_pointer_object_get_recursive(obj, path_copy, res); rc = json_pointer_get_recursive(obj, path_copy, res);
out: out:
free(path_copy); free(path_copy);
return rc; return rc;
} }
int json_pointer_set_with_cb(struct json_object **obj, const char *path, int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value)
struct json_object *value,
json_pointer_set_cb set_cb, int cb_handles_obj, void *priv)
{ {
const char *endp; const char *endp;
char *path_copy = NULL; char *path_copy = NULL;
@@ -333,7 +282,7 @@ int json_pointer_set_with_cb(struct json_object **obj, const char *path,
if ((endp = strrchr(path, '/')) == path) if ((endp = strrchr(path, '/')) == path)
{ {
path++; path++;
return json_pointer_set_single_path(*obj, path, value, set_cb, cb_handles_obj, priv); return json_pointer_set_single_path(*obj, path, value);
} }
/* pass a working copy to the recursive call */ /* pass a working copy to the recursive call */
@@ -343,28 +292,14 @@ int json_pointer_set_with_cb(struct json_object **obj, const char *path,
return -1; return -1;
} }
path_copy[endp - path] = '\0'; path_copy[endp - path] = '\0';
rc = json_pointer_object_get_recursive(*obj, path_copy, &set); rc = json_pointer_get_recursive(*obj, path_copy, &set);
free(path_copy); free(path_copy);
if (rc) if (rc)
return rc; return rc;
endp++; endp++;
return json_pointer_set_single_path(set, endp, value, set_cb, cb_handles_obj, priv); return json_pointer_set_single_path(set, endp, value);
}
static int default_put_cb(struct json_object *parent, const char *key, size_t idx,
struct json_object *value, void *priv)
{
if (key == NULL)
return json_object_array_put_idx(parent, idx, value);
else
return json_object_object_add(parent, key, value);
}
int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value)
{
return json_pointer_set_with_cb(obj, path, value, default_put_cb, 1, NULL);
} }
int json_pointer_setf(struct json_object **obj, struct json_object *value, const char *path_fmt, int json_pointer_setf(struct json_object **obj, struct json_object *value, const char *path_fmt,
@@ -412,64 +347,15 @@ int json_pointer_setf(struct json_object **obj, struct json_object *value, const
} }
*endp = '\0'; *endp = '\0';
rc = json_pointer_object_get_recursive(*obj, path_copy, &set); rc = json_pointer_get_recursive(*obj, path_copy, &set);
if (rc) if (rc)
goto out; goto out;
set_single_path: set_single_path:
endp++; endp++;
rc = json_pointer_set_single_path(set, endp, value, default_put_cb, 1, NULL); rc = json_pointer_set_single_path(set, endp, value);
out: out:
free(path_copy); free(path_copy);
return rc; return rc;
} }
int json_pointer_set_with_limit_index(struct json_object **obj, const char *path,
struct json_object *value, size_t limit_index)
{
// -1 means no limits
if (limit_index == (size_t)-1)
{
return json_pointer_set_with_cb(obj, path, value, default_put_cb, 1, NULL);
}
return json_pointer_set_with_cb(obj, path, value,
json_object_array_put_with_idx_limit_cb, 0, &limit_index);
}
/* safe callback for array index limit */
int json_object_array_put_with_idx_limit_cb(struct json_object *jso, const char *key, size_t idx,
struct json_object *jso_new, void *priv)
{
size_t max_idx;
if (key == NULL)
{
// array operation
// use priv as a size_t pointer to pass in the maximum allowed index.
// The priv is required context for this callback and must not be NULL.
if (!priv)
{
errno = EFAULT;
return -1;
}
max_idx = *(size_t*)priv;
// Check against a maximum to prevent excessive memory allocations.
// An extremely large index, even if it doesn't overflow size_t,
// will cause a huge memory allocation request via realloc,
// leading to an OOM.
if (idx > max_idx)
{
errno = EINVAL;
return -1;
}
return json_object_array_put_idx(jso, idx, jso_new);
}
else
{
// object operation
return json_object_object_add(jso, key, jso_new);
}
}

View File

@@ -32,6 +32,11 @@ extern "C" {
* Internally, this is equivalent to doing a series of 'json_object_object_get()' * Internally, this is equivalent to doing a series of 'json_object_object_get()'
* and 'json_object_array_get_idx()' along the given 'path'. * and 'json_object_array_get_idx()' along the given 'path'.
* *
* Note that the 'path' string supports 'printf()' type arguments, so, whatever
* is added after the 'res' param will be treated as an argument for 'path'
* Example: json_pointer_get(obj, "/foo/%d/%s", &res, 0, bar)
* This means, that you need to escape '%' with '%%' (just like in printf())
*
* @param obj the json_object instance/tree from where to retrieve sub-objects * @param obj the json_object instance/tree from where to retrieve sub-objects
* @param path a (RFC6901) string notation for the sub-object to retrieve * @param path a (RFC6901) string notation for the sub-object to retrieve
* @param res a pointer that stores a reference to the json_object * @param res a pointer that stores a reference to the json_object
@@ -45,9 +50,7 @@ JSON_EXPORT int json_pointer_get(struct json_object *obj, const char *path,
/** /**
* This is a variant of 'json_pointer_get()' that supports printf() style arguments. * This is a variant of 'json_pointer_get()' that supports printf() style arguments.
* *
* Variable arguments go after the 'path_fmt' parameter. * Example: json_pointer_getf(obj, res, "/foo/%d/%s", 0, bak)
*
* Example: json_pointer_getf(obj, res, "/foo/%d/%s", 0, "bar")
* This also means that you need to escape '%' with '%%' (just like in printf()) * This also means that you need to escape '%' with '%%' (just like in printf())
* *
* Please take into consideration all recommended 'printf()' format security * Please take into consideration all recommended 'printf()' format security
@@ -81,9 +84,10 @@ JSON_EXPORT int json_pointer_getf(struct json_object *obj, struct json_object **
* That also implies that 'json_pointer_set()' does not do any refcount incrementing. * That also implies that 'json_pointer_set()' does not do any refcount incrementing.
* (Just that single decrement that was mentioned above). * (Just that single decrement that was mentioned above).
* *
* @warning This function is vulnerable to an OOM. * Note that the 'path' string supports 'printf()' type arguments, so, whatever
* To prevent this, use the safer variant 'json_pointer_set_with_limit_index()' * is added after the 'value' param will be treated as an argument for 'path'
* or the flexible 'json_pointer_set_with_array_cb()' with a custom callback. * Example: json_pointer_set(obj, "/foo/%d/%s", value, 0, bak)
* This means, that you need to escape '%' with '%%' (just like in printf())
* *
* @param obj the json_object instance/tree to which to add a sub-object * @param obj the json_object instance/tree to which to add a sub-object
* @param path a (RFC6901) string notation for the sub-object to set in the tree * @param path a (RFC6901) string notation for the sub-object to set in the tree
@@ -97,9 +101,7 @@ JSON_EXPORT int json_pointer_set(struct json_object **obj, const char *path,
/** /**
* This is a variant of 'json_pointer_set()' that supports printf() style arguments. * This is a variant of 'json_pointer_set()' that supports printf() style arguments.
* *
* Variable arguments go after the 'path_fmt' parameter. * Example: json_pointer_setf(obj, value, "/foo/%d/%s", 0, bak)
*
* Example: json_pointer_setf(obj, value, "/foo/%d/%s", 0, "bar")
* This also means that you need to escape '%' with '%%' (just like in printf()) * This also means that you need to escape '%' with '%%' (just like in printf())
* *
* Please take into consideration all recommended 'printf()' format security * Please take into consideration all recommended 'printf()' format security
@@ -114,73 +116,6 @@ JSON_EXPORT int json_pointer_set(struct json_object **obj, const char *path,
JSON_EXPORT int json_pointer_setf(struct json_object **obj, struct json_object *value, JSON_EXPORT int json_pointer_setf(struct json_object **obj, struct json_object *value,
const char *path_fmt, ...); const char *path_fmt, ...);
/**
* A convenient and safe variant of 'json_pointer_set()' that prevents excessive memory allocations
* by enforcing a limit on array indices.
*
* @param obj the json_object instance/tree to which to add a sub-object
* @param path a (RFC6901) string notation for the sub-object to set in the tree
* @param value object to set at path
* @param limit_index The maximum allowed value for an array index. If a path
* contains an index larger than this, the function will fail
* with errno set to EINVAL. A value of -1 can be used to specify
* no limit, reverting to the original behavior
*
* @return negative if an error (or not found), or 0 if succeeded
*/
JSON_EXPORT int json_pointer_set_with_limit_index(struct json_object **obj, const char *path,
struct json_object *value, size_t limit_index);
/**
* Callback function type.
*
* When setting an array element, 'key' will be NULL and 'idx' will be the
* target index.
* When setting an object field, 'key' will be the target key and 'idx' will
* be -1.
*/
typedef int(*json_pointer_set_cb)(json_object *parent, const char *key, size_t idx,
json_object *value, void *priv);
/**
* Variant of 'json_pointer_set()' that allows specifying a custom callback
*
* @param obj the json_object instance/tree to which to add a sub-object
* @param path a (RFC6901) string notation for the sub-object to set in the tree
* @param value object to set at path
* @param set_cb A custom callback function to handle setting the element
* @param cb_handles_obj If 0, the callback is only invoked for array modifications.
* If 1, the callback is invoked for both array and object
* modifications.
* @param priv A private pointer passed through to the set_cb callback,
* for user-defined context
*
* @return negative if an error (or not found), or 0 if succeeded
*/
JSON_EXPORT int json_pointer_set_with_cb(struct json_object **obj, const char *path,
struct json_object *value,
json_pointer_set_cb set_cb, int cb_handles_obj, void *priv);
/**
* A safer callback for 'json_pointer_set_with_cb()' that enforces a
* maximum array index.
*
* This function can be used as the 'set_cb' argument to prevent OOM.
* It expects the 'priv' argument to be a valid pointer to a 'size_t' variable
* that holds the maximum allowed index.
*
* @param jso the parent json_object array.
* @param key the object field where the element is to be placed, should be NULL here.
* @param idx the index where the element is to be placed.
* @param jso_new the new json_object to place at the index.
* @param priv A pointer to a 'size_t' variable specifying the maximum index.
* This pointer must not be NULL.
*
* @return 0 on success, or a negative value if idx exceeds the limit or 'priv' is NULL.
*/
JSON_EXPORT int json_object_array_put_with_idx_limit_cb(struct json_object *jso, const char *key, size_t idx,
struct json_object *jso_new, void *priv);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -1,50 +0,0 @@
/*
* Copyright (c) 2023 Eric Hawicz
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*/
/**
* @file
* @brief Do not use, json-c internal, may be changed or removed at any time.
*/
#ifndef _json_pointer_private_h_
#define _json_pointer_private_h_
#ifdef __cplusplus
extern "C" {
#endif
struct json_pointer_get_result {
struct json_object *parent;
struct json_object *obj;
// The key of the found object; only valid when parent is json_type_object
// Caution: re-uses tail end of the `path` argument to json_pointer_get_internal
const char *key_in_parent;
// the index of the found object; only valid when parent is json_type_array
uint32_t index_in_parent;
};
int json_pointer_get_internal(struct json_object *obj, const char *path,
struct json_pointer_get_result *res);
// replaced by json_pointer_set_cb
// typedef int(*json_pointer_array_set_cb)(json_object *parent, size_t idx,
// json_object *value, void *priv);
typedef int(*json_pointer_set_cb)(json_object *parent, const char *key, size_t idx,
json_object *value, void *priv);
// replaced by json_pointer_set_with_cb
// int json_pointer_set_with_array_cb(struct json_object **obj, const char *path,
// struct json_object *value,
// json_pointer_array_set_cb array_set_cb, void *priv);
int json_pointer_set_with_cb(struct json_object **obj, const char *path,
struct json_object *value,
json_pointer_set_cb set_cb, int cb_handles_obj, void *priv);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -46,7 +46,7 @@
#define jt_hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x)&7) + 9) #define jt_hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x)&7) + 9)
#if !HAVE_STRNCASECMP && defined(_WIN32) #if !HAVE_STRNCASECMP && defined(_MSC_VER)
/* MSC has the version as _strnicmp */ /* MSC has the version as _strnicmp */
#define strncasecmp _strnicmp #define strncasecmp _strnicmp
#elif !HAVE_STRNCASECMP #elif !HAVE_STRNCASECMP
@@ -104,6 +104,7 @@ static const char *json_tokener_errors[] = {
"success", "success",
"continue", "continue",
"nesting too deep", "nesting too deep",
"out of memory",
"unexpected end of data", "unexpected end of data",
"unexpected character", "unexpected character",
"null expected", "null expected",
@@ -116,8 +117,7 @@ static const char *json_tokener_errors[] = {
"invalid string sequence", "invalid string sequence",
"expected comment", "expected comment",
"invalid utf-8 string", "invalid utf-8 string",
"buffer size overflow", "buffer size overflow"
"out of memory"
}; };
/* clang-format on */ /* clang-format on */
@@ -145,8 +145,8 @@ enum json_tokener_error json_tokener_get_error(struct json_tokener *tok)
} }
/* Stuff for decoding unicode sequences */ /* Stuff for decoding unicode sequences */
#define IS_HIGH_SURROGATE(uc) (((uc)&0xFFFFFC00) == 0xD800) #define IS_HIGH_SURROGATE(uc) (((uc)&0xFC00) == 0xD800)
#define IS_LOW_SURROGATE(uc) (((uc)&0xFFFFFC00) == 0xDC00) #define IS_LOW_SURROGATE(uc) (((uc)&0xFC00) == 0xDC00)
#define DECODE_SURROGATE_PAIR(hi, lo) ((((hi)&0x3FF) << 10) + ((lo)&0x3FF) + 0x10000) #define DECODE_SURROGATE_PAIR(hi, lo) ((((hi)&0x3FF) << 10) + ((lo)&0x3FF) + 0x10000)
static unsigned char utf8_replacement_char[3] = {0xEF, 0xBF, 0xBD}; static unsigned char utf8_replacement_char[3] = {0xEF, 0xBF, 0xBD};
@@ -154,9 +154,6 @@ struct json_tokener *json_tokener_new_ex(int depth)
{ {
struct json_tokener *tok; struct json_tokener *tok;
if (depth < 1)
return NULL;
tok = (struct json_tokener *)calloc(1, sizeof(struct json_tokener)); tok = (struct json_tokener *)calloc(1, sizeof(struct json_tokener));
if (!tok) if (!tok)
return NULL; return NULL;
@@ -185,8 +182,6 @@ struct json_tokener *json_tokener_new(void)
void json_tokener_free(struct json_tokener *tok) void json_tokener_free(struct json_tokener *tok)
{ {
if (!tok)
return;
json_tokener_reset(tok); json_tokener_reset(tok);
if (tok->pb) if (tok->pb)
printbuf_free(tok->pb); printbuf_free(tok->pb);
@@ -231,10 +226,7 @@ struct json_object *json_tokener_parse_verbose(const char *str, enum json_tokene
tok = json_tokener_new(); tok = json_tokener_new();
if (!tok) if (!tok)
{
*error = json_tokener_error_memory;
return NULL; return NULL;
}
obj = json_tokener_parse_ex(tok, str, -1); obj = json_tokener_parse_ex(tok, str, -1);
*error = tok->err; *error = tok->err;
if (tok->err != json_tokener_success if (tok->err != json_tokener_success
@@ -345,32 +337,13 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
#ifdef HAVE_USELOCALE #ifdef HAVE_USELOCALE
{ {
#ifdef HAVE_DUPLOCALE
locale_t duploc = duplocale(oldlocale); locale_t duploc = duplocale(oldlocale);
if (duploc == NULL && errno == ENOMEM)
{
tok->err = json_tokener_error_memory;
return NULL;
}
newloc = newlocale(LC_NUMERIC_MASK, "C", duploc); newloc = newlocale(LC_NUMERIC_MASK, "C", duploc);
#else
newloc = newlocale(LC_NUMERIC_MASK, "C", oldlocale);
#endif
if (newloc == NULL) if (newloc == NULL)
{ {
tok->err = json_tokener_error_memory;
#ifdef HAVE_DUPLOCALE
freelocale(duploc); freelocale(duploc);
#endif
return NULL; return NULL;
} }
#ifdef NEWLOCALE_NEEDS_FREELOCALE
#ifdef HAVE_DUPLOCALE
// Older versions of FreeBSD (<12.4) don't free the locale
// passed to newlocale(), so do it here
freelocale(duploc);
#endif
#endif
uselocale(newloc); uselocale(newloc);
} }
#elif defined(HAVE_SETLOCALE) #elif defined(HAVE_SETLOCALE)
@@ -381,11 +354,8 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
{ {
oldlocale = strdup(tmplocale); oldlocale = strdup(tmplocale);
if (oldlocale == NULL) if (oldlocale == NULL)
{
tok->err = json_tokener_error_memory;
return NULL; return NULL;
} }
}
setlocale(LC_NUMERIC, "C"); setlocale(LC_NUMERIC, "C");
} }
#endif #endif
@@ -691,12 +661,6 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
state = json_tokener_state_string_escape; state = json_tokener_state_string_escape;
break; break;
} }
else if ((tok->flags & JSON_TOKENER_STRICT) && (unsigned char)c <= 0x1f)
{
// Disallow control characters in strict mode
tok->err = json_tokener_error_parse_string;
goto out;
}
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok))
{ {
printbuf_memappend_checked(tok->pb, case_start, printbuf_memappend_checked(tok->pb, case_start,
@@ -1250,12 +1214,6 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
state = json_tokener_state_string_escape; state = json_tokener_state_string_escape;
break; break;
} }
else if ((tok->flags & JSON_TOKENER_STRICT) && (unsigned char)c <= 0x1f)
{
// Disallow control characters in strict mode
tok->err = json_tokener_error_parse_string;
goto out;
}
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok))
{ {
printbuf_memappend_checked(tok->pb, case_start, printbuf_memappend_checked(tok->pb, case_start,
@@ -1291,11 +1249,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
goto redo_char; goto redo_char;
case json_tokener_state_object_value_add: case json_tokener_state_object_value_add:
if (json_object_object_add(current, obj_field_name, obj) != 0) json_object_object_add(current, obj_field_name, obj);
{
tok->err = json_tokener_error_memory;
goto out;
}
free(obj_field_name); free(obj_field_name);
obj_field_name = NULL; obj_field_name = NULL;
saved_state = json_tokener_state_object_sep; saved_state = json_tokener_state_object_sep;

View File

@@ -28,6 +28,7 @@ enum json_tokener_error
json_tokener_success, json_tokener_success,
json_tokener_continue, json_tokener_continue,
json_tokener_error_depth, json_tokener_error_depth,
json_tokener_error_memory,
json_tokener_error_parse_eof, json_tokener_error_parse_eof,
json_tokener_error_parse_unexpected, json_tokener_error_parse_unexpected,
json_tokener_error_parse_null, json_tokener_error_parse_null,
@@ -40,8 +41,7 @@ enum json_tokener_error
json_tokener_error_parse_string, json_tokener_error_parse_string,
json_tokener_error_parse_comment, json_tokener_error_parse_comment,
json_tokener_error_parse_utf8_string, json_tokener_error_parse_utf8_string,
json_tokener_error_size, /* A string longer than INT32_MAX was passed as input */ json_tokener_error_size
json_tokener_error_memory /* Failed to allocate memory */
}; };
/** /**
@@ -206,7 +206,6 @@ JSON_EXPORT struct json_tokener *json_tokener_new(void);
/** /**
* Allocate a new json_tokener with a custom max nesting depth. * Allocate a new json_tokener with a custom max nesting depth.
* The depth must be at least 1.
* @see JSON_TOKENER_DEFAULT_DEPTH * @see JSON_TOKENER_DEFAULT_DEPTH
*/ */
JSON_EXPORT struct json_tokener *json_tokener_new_ex(int depth); JSON_EXPORT struct json_tokener *json_tokener_new_ex(int depth);
@@ -231,7 +230,7 @@ JSON_EXPORT void json_tokener_reset(struct json_tokener *tok);
JSON_EXPORT struct json_object *json_tokener_parse(const char *str); JSON_EXPORT struct json_object *json_tokener_parse(const char *str);
/** /**
* Parse a json_object out of the string `str`, but if it fails * Parser a json_object out of the string `str`, but if it fails
* return the error in `*error`. * return the error in `*error`.
* @see json_tokener_parse() * @see json_tokener_parse()
* @see json_tokener_parse_ex() * @see json_tokener_parse_ex()

View File

@@ -37,15 +37,13 @@
#include <unistd.h> #include <unistd.h>
#endif /* HAVE_UNISTD_H */ #endif /* HAVE_UNISTD_H */
#ifdef _WIN32 #ifdef WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif
#include <io.h> #include <io.h>
#include <windows.h> #include <windows.h>
#endif /* defined(_WIN32) */ #endif /* defined(WIN32) */
#if !defined(HAVE_OPEN) && defined(_WIN32) #if !defined(HAVE_OPEN) && defined(WIN32)
#define open _open #define open _open
#endif #endif

View File

@@ -1,37 +0,0 @@
#include <winver.h>
#include "json_c_version.h"
VS_VERSION_INFO VERSIONINFO
FILEVERSION JSON_C_MAJOR_VERSION,JSON_C_MINOR_VERSION,JSON_C_MICRO_VERSION,0
PRODUCTVERSION JSON_C_MAJOR_VERSION,JSON_C_MINOR_VERSION,JSON_C_MICRO_VERSION,0
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_DOS_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "04090000" /* Lang = US English, Charset = ASCII */
BEGIN
VALUE "Comments", "A JSON implementation in C\0"
VALUE "CompanyName", "Eric Haszlakiewicz\0"
VALUE "FileDescription", "JSON-C\0"
VALUE "FileVersion", JSON_C_VERSION "\0"
VALUE "InternalName", "libjson-c.dll\0"
VALUE "LegalCopyright", "MIT License, 2009-2012\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "libjson-c.dll\0"
VALUE "ProductName", "JSON-C\0"
VALUE "ProductVersion", JSON_C_VERSION "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 0 /* US English, ASCII */
END
END

View File

@@ -25,9 +25,7 @@
#endif #endif
#if defined(_MSC_VER) || defined(__MINGW32__) #if defined(_MSC_VER) || defined(__MINGW32__)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h> /* Get InterlockedCompareExchange */ #include <windows.h> /* Get InterlockedCompareExchange */
#endif #endif

View File

@@ -334,9 +334,8 @@ int lh_table_resize(struct lh_table *t, int new_size);
/** /**
* @deprecated Don't use this outside of linkhash.h: * @deprecated Don't use this outside of linkhash.h:
*/ */
#if !defined (__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) #if (defined(AIX_CC) || (defined(_MSC_VER) && (_MSC_VER <= 1800)) )
/* C89 compilers like VS2010 can't handle inline funcs, so skip it there, /* VS2010 can't handle inline funcs, so skip it there */
note: this also applies to -std=c89 in GCC! */
#define _LH_INLINE #define _LH_INLINE
#else #else
#define _LH_INLINE inline #define _LH_INLINE inline

View File

@@ -1,284 +0,0 @@
project('json-c', 'c', version: '0.18.99',
meson_version: '>=0.54.0',
license: 'MIT',
default_options: ['buildtype=release', 'warning_level=2'])
cc = meson.get_compiler('c')
# Configuration header generation
conf_data = configuration_data()
jconf_data = configuration_data()
conf_data.set('VERSION', meson.project_version())
has_std_lib = cc.has_header('stdlib.h')
has_std_arg = cc.has_header('stdarg.h')
has_string = cc.has_header('string.h')
has_float = cc.has_header('float.h')
if has_std_lib and has_std_arg and has_string and has_float
conf_data.set('STDC_HEADERS', 1, description : 'Define to 1 if you have the ANSI C header files.')
endif
bsd_dep = dependency('libbsd', required: false)
headers = {
'bsd/stdlib.h': bsd_dep,
'dlfcn.h': [],
'endian.h': [],
'fcntl.h': [],
'inttypes.h': [],
'limits.h': [],
'locale.h': [],
'memory.h': [],
'stdarg.h': [],
'stdint.h': [],
'stdlib.h': [],
'string.h': [],
'strings.h': [],
'syslog.h': [],
'sys/cdefs.h': [],
'sys/param.h': [],
'sys/random.h': [],
'sys/resource.h': [],
'sys/stat.h': [],
'sys/types.h': [],
'unistd.h': [],
'xlocale.h': [],
}
foreach h, d : headers
if cc.has_header(h, dependencies: d)
conf_data.set('HAVE_@0@'.format(h.underscorify().to_upper()), 1, description : 'Define to 1 if you have the <@0@> header file'.format(h))
endif
endforeach
if cc.has_header('inttypes.h')
conf_data.set('JSON_C_HAVE_INTTYPES_H', 1, description : 'Define to 1 if you have the <inttypes.h> header file.')
jconf_data.set('JSON_C_HAVE_INTTYPES_H', 1, description : 'Define to 1 if you have the <inttypes.h> header file.')
endif
if cc.has_header('stdint.h')
conf_data.set('JSON_C_HAVE_STDINT_H', 1, description : 'Define to 1 if you have the <stdint.h> header file.')
jconf_data.set('JSON_C_HAVE_STDINT_H', 1, description : 'Define to 1 if you have the <stdint.h> header file.')
endif
funcs = [
'open',
'realloc',
'setlocale',
'strdup',
'strerror',
'uselocale',
'duplocale',
'vsyslog',
'getrandom',
'getrusage',
'strtoll',
'strtoull',
'arc4random',
'vasprintf',
]
if conf_data.has('HAVE_STRINGS_H')
funcs += ['strcasecmp', 'strncasecmp']
endif
foreach f : funcs
if cc.has_function(f)
conf_data.set('HAVE_@0@'.format(f.to_upper()), 1, description : 'Define to 1 if you have the `@0@` function.'.format(f))
endif
endforeach
foreach f : ['snprintf', 'vsnprintf', 'vprintf']
if cc.has_header_symbol('stdio.h', f)
conf_data.set('HAVE_@0@'.format(f.to_upper()), 1, description : 'Define to 1 if you have the `@0@` function.'.format(f))
endif
endforeach
if not conf_data.has('HAVE_VPRINTF') and cc.has_function('_doprnt')
conf_data.set('HAVE_DOPRNT', 1, description : 'Define to 1 if you have _doprnt but not vprintf.')
endif
if conf_data.has('HAVE_STRTOLL')
conf_data.set('json_c_strtoll', 'strtoll')
elif cc.has_function('_strtoi64', prefix : '#include <stdlib.h>')
conf_data.set('json_c_strtoll', '_strtoi64')
endif
if conf_data.has('HAVE_STRTOULL')
conf_data.set('json_c_strtoull', 'strtoull')
elif cc.has_function('_strtoui64', prefix : '#include <stdlib.h>')
conf_data.set('json_c_strtoull', '_strtoui64')
endif
decls = {
'INFINITY': 'math.h',
'isinf': 'math.h',
'isnan': 'math.h',
'NAN': 'math.h',
'_finite': 'float.h',
'_isnan': 'float.h',
}
foreach d, h : decls
if cc.has_header_symbol(h, d)
conf_data.set('HAVE_DECL_@0@'.format(d.to_upper()), 1, description : 'Define to 1 if you have the declaration of `@0@`'.format(d))
endif
endforeach
check_thread = cc.compiles('__thread int x;', name: 'Check for __thread support')
if check_thread
conf_data.set('HAVE___THREAD', 1)
conf_data.set('SPEC___THREAD', '__thread')
elif cc.get_argument_syntax() == 'msvc'
conf_data.set('SPEC___THREAD', '__declspec(thread)')
endif
gnu_warning_section_support = cc.compiles('''
extern void json_object_get();
__asm__(".section .gnu.json_object_get\n\t.ascii \"Please link against libjson-c instead of libjson\"\n\t.text");
int main(int c, char *v) { return 0; }
''', name: 'Check for GNU warning section support')
if gnu_warning_section_support
conf_data.set('HAS_GNU_WARNING_LONG', 1, description : 'Define to 1 if the compiler supports .gnu.warning sections.')
endif
atomic_builtin_support = cc.compiles('''
int main() {
int x = 0;
int i = __sync_add_and_fetch(&x, 1);
return x;
}
''',
name: 'Check for atomic builtins')
if atomic_builtin_support
conf_data.set('HAVE_ATOMIC_BUILTINS', 1, description : 'Define to 1 if the compiler supports atomic builtins.')
endif
if get_option('enable_rdrand')
conf_data.set('ENABLE_RDRAND', 1)
endif
if get_option('override_get_random_seed')
conf_data.set('OVERRIDE_GET_RANDOM_SEED', get_option('override_get_random_seed'))
endif
if get_option('enable_threading')
conf_data.set('ENABLE_THREADING', 1)
endif
if get_option('newlocale_needs_freelocale')
conf_data.set('NEWLOCALE_NEEDS_FREELOCALE', 1)
endif
conf_data.set('SIZEOF_INT', cc.sizeof('int'))
conf_data.set('SIZEOF_INT64_T', cc.sizeof('int64_t', prefix : '#include <stdint.h>'))
conf_data.set('SIZEOF_LONG', cc.sizeof('long'))
conf_data.set('SIZEOF_LONG_LONG', cc.sizeof('long long'))
conf_data.set('SIZEOF_SIZE_T', cc.sizeof('size_t', prefix : '#include <stddef.h>'))
if cc.get_argument_syntax() == 'msvc'
conf_data.set('SIZEOF_SSIZE_T', cc.sizeof('SSIZE_T', prefix : '#include <BaseTsd.h>\n#include <stddef.h>'))
else
conf_data.set('SIZEOF_SSIZE_T', cc.sizeof('ssize_t', prefix : '#include <sys/types.h>'))
endif
conf_data.set('PACKAGE_VERSION', meson.project_version())
conf_data.set('PROJECT_NAME', meson.project_name())
configure_header = configure_file(
output: 'config.h',
configuration: conf_data
)
json_configure_header = configure_file(
output: 'json_config.h',
configuration: jconf_data
)
jhconf_data = configuration_data()
jhconf_data.set('JSON_H_JSON_PATCH',
get_option('disable_json_patch') ? '' : '#include "json_patch.h"'
)
jhconf_data.set('JSON_H_JSON_POINTER',
get_option('disable_json_pointer') ? '' : '#include "json_pointer.h"'
)
json_header = configure_file(
input: 'json.h.cmakein',
output: 'json.h',
configuration: jhconf_data
)
# Platform-specific flags
add_project_arguments('-D_GNU_SOURCE', language: 'c')
if host_machine.system() == 'windows'
add_project_arguments('-DWIN32', language: 'c')
endif
# Compiler flags
message('target is ' + host_machine.system())
if host_machine.system() == 'windows'
# Cover any compiler on Windows attempting to use MSVC's standard library
add_project_arguments('-D_CRT_NONSTDC_NO_DEPRECATE', '-D_CRT_SECURE_NO_WARNINGS', language: 'c')
endif
add_project_arguments(cc.get_supported_arguments('-Wno-unused-parameter'), language : 'c')
sym = cc.get_supported_link_arguments(
'-Wl,--version-script,@0@/json-c.sym'.format(
meson.current_source_dir(),
),
)
# Source files
sources = files(
'arraylist.c', 'debug.c', 'json_c_version.c', 'json_object.c',
'json_object_iterator.c', 'json_tokener.c', 'json_util.c',
'json_visit.c', 'linkhash.c', 'printbuf.c', 'random_seed.c',
'strerror_override.c'
)
if not get_option('disable_json_pointer')
sources += files('json_pointer.c')
if not get_option('disable_json_patch')
sources += files('json_patch.c')
endif
endif
# Include directories
inc = include_directories('.')
# Build library
libjson = library('json-c',
sources,
include_directories: inc,
dependencies: bsd_dep,
install: true,
link_args: sym,
version: '5.4.0',
soversion: '5',
)
jsonc_dep = declare_dependency(link_with: libjson, include_directories: inc)
meson.override_dependency('json-c', jsonc_dep)
# Install headers
install_headers(
'arraylist.h', 'debug.h', 'json_c_version.h', 'json_inttypes.h',
'json_object.h', 'json_object_iterator.h', 'json_tokener.h',
'json_types.h', 'json_util.h', 'json_visit.h', 'linkhash.h',
'printbuf.h', json_configure_header, json_header
)
# Optional apps
if get_option('build_apps') and host_machine.system() != 'windows'
subdir('apps')
endif
# Optional tests
if get_option('buildtype') == 'debug'
subdir('tests')
endif

View File

@@ -1,11 +0,0 @@
option('disable_bsymbolic', type: 'boolean', value: false, description: 'Avoid linking with -Bsymbolic-function')
option('disable_thread_local_storage', type: 'boolean', value: false, description: 'Disable Thread-Local Storage')
option('enable_rdrand', type: 'boolean', value: false, description: 'Enable RDRAND Hardware RNG')
option('enable_threading', type: 'boolean', value: false, description: 'Enable partial threading support')
option('override_get_random_seed', type: 'boolean', value: false, description: 'Override json_c_get_random_seed()')
option('disable_extra_libs', type: 'boolean', value: false, description: 'Avoid linking extra libraries like libbsd')
option('disable_json_pointer', type: 'boolean', value: false, description: 'Disable JSON pointer support')
option('disable_json_patch', type: 'boolean', value: false, description: 'Disable JSON patch support')
option('newlocale_needs_freelocale', type: 'boolean', value: false, description: 'FreeBSD workaround for newlocale')
option('build_apps', type: 'boolean', value: true, description: 'Build command-line apps')

View File

@@ -46,7 +46,7 @@ static void do_cpuid(int regs[], int h)
/* clang-format on */ /* clang-format on */
} }
#elif defined _MSC_VER && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)) #elif defined _MSC_VER
#define HAS_X86_CPUID 1 #define HAS_X86_CPUID 1
#define do_cpuid __cpuid #define do_cpuid __cpuid
@@ -129,7 +129,7 @@ static int get_rdrand_seed(void)
#endif #endif
#if defined _MSC_VER && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)) #if defined _MSC_VER
#if _MSC_VER >= 1700 #if _MSC_VER >= 1700
#define HAVE_RDRAND 1 #define HAVE_RDRAND 1
@@ -229,7 +229,6 @@ static int get_dev_random_seed(int *seed)
if ((buf.st_mode & S_IFCHR) == 0) if ((buf.st_mode & S_IFCHR) == 0)
return -1; return -1;
/* coverity[toctou] */
int fd = open(dev_random_file, O_RDONLY); int fd = open(dev_random_file, O_RDONLY);
if (fd < 0) if (fd < 0)
{ {
@@ -254,7 +253,7 @@ static int get_dev_random_seed(int *seed)
/* get_cryptgenrandom_seed */ /* get_cryptgenrandom_seed */
#ifdef _WIN32 #ifdef WIN32
#define HAVE_CRYPTGENRANDOM 1 #define HAVE_CRYPTGENRANDOM 1

View File

@@ -36,6 +36,6 @@ static int json_c_snprintf(char *str, size_t size, const char *format, ...)
#elif !defined(HAVE_SNPRINTF) /* !HAVE_SNPRINTF */ #elif !defined(HAVE_SNPRINTF) /* !HAVE_SNPRINTF */
#error snprintf is required but was not found #error snprintf is required but was not found
#endif /* !HAVE_SNPRINTF */ #endif /* !HAVE_SNPRINTF && defined(WIN32) */
#endif /* __snprintf_compat_h */ #endif /* __snprintf_compat_h */

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.9...3.12) # see ../CMakeLists.txt for why cmake_minimum_required(VERSION 3.1)
add_executable(test1Formatted test1.c parse_flags.c parse_flags.h) add_executable(test1Formatted test1.c parse_flags.c parse_flags.h)
target_compile_definitions(test1Formatted PRIVATE TEST_FORMATTED=1) target_compile_definitions(test1Formatted PRIVATE TEST_FORMATTED=1)
target_link_libraries(test1Formatted PRIVATE ${PROJECT_NAME}) target_link_libraries(test1Formatted PRIVATE ${PROJECT_NAME})
@@ -39,10 +39,6 @@ set(ALL_TEST_NAMES
if (NOT DISABLE_JSON_POINTER) if (NOT DISABLE_JSON_POINTER)
set(ALL_TEST_NAMES ${ALL_TEST_NAMES} test_json_pointer) set(ALL_TEST_NAMES ${ALL_TEST_NAMES} test_json_pointer)
set(ALL_TEST_NAMES ${ALL_TEST_NAMES} test_safe_json_pointer_set)
if (NOT DISABLE_JSON_PATCH)
set(ALL_TEST_NAMES ${ALL_TEST_NAMES} test_json_patch)
endif()
endif() endif()
foreach(TESTNAME ${ALL_TEST_NAMES}) foreach(TESTNAME ${ALL_TEST_NAMES})

View File

@@ -1,233 +0,0 @@
[
{
"comment": "4.1. add with missing object",
"doc": { "q": { "bar": 2 } },
"patch": [ {"op": "add", "path": "/a/b", "value": 1} ],
"error":
"path /a does not exist -- missing objects are not created recursively"
},
{
"comment": "A.1. Adding an Object Member",
"doc": {
"foo": "bar"
},
"patch": [
{ "op": "add", "path": "/baz", "value": "qux" }
],
"expected": {
"baz": "qux",
"foo": "bar"
}
},
{
"comment": "A.2. Adding an Array Element",
"doc": {
"foo": [ "bar", "baz" ]
},
"patch": [
{ "op": "add", "path": "/foo/1", "value": "qux" }
],
"expected": {
"foo": [ "bar", "qux", "baz" ]
}
},
{
"comment": "A.3. Removing an Object Member",
"doc": {
"baz": "qux",
"foo": "bar"
},
"patch": [
{ "op": "remove", "path": "/baz" }
],
"expected": {
"foo": "bar"
}
},
{
"comment": "A.4. Removing an Array Element",
"doc": {
"foo": [ "bar", "qux", "baz" ]
},
"patch": [
{ "op": "remove", "path": "/foo/1" }
],
"expected": {
"foo": [ "bar", "baz" ]
}
},
{
"comment": "A.5. Replacing a Value",
"doc": {
"baz": "qux",
"foo": "bar"
},
"patch": [
{ "op": "replace", "path": "/baz", "value": "boo" }
],
"expected": {
"baz": "boo",
"foo": "bar"
}
},
{
"comment": "A.6. Moving a Value",
"doc": {
"foo": {
"bar": "baz",
"waldo": "fred"
},
"qux": {
"corge": "grault"
}
},
"patch": [
{ "op": "move", "from": "/foo/waldo", "path": "/qux/thud" }
],
"expected": {
"foo": {
"bar": "baz"
},
"qux": {
"corge": "grault",
"thud": "fred"
}
}
},
{
"comment": "A.7. Moving an Array Element",
"doc": {
"foo": [ "all", "grass", "cows", "eat" ]
},
"patch": [
{ "op": "move", "from": "/foo/1", "path": "/foo/3" }
],
"expected": {
"foo": [ "all", "cows", "eat", "grass" ]
}
},
{
"comment": "A.8. Testing a Value: Success",
"doc": {
"baz": "qux",
"foo": [ "a", 2, "c" ]
},
"patch": [
{ "op": "test", "path": "/baz", "value": "qux" },
{ "op": "test", "path": "/foo/1", "value": 2 }
],
"expected": {
"baz": "qux",
"foo": [ "a", 2, "c" ]
}
},
{
"comment": "A.9. Testing a Value: Error",
"doc": {
"baz": "qux"
},
"patch": [
{ "op": "test", "path": "/baz", "value": "bar" }
],
"error": "string not equivalent"
},
{
"comment": "A.10. Adding a nested Member Object",
"doc": {
"foo": "bar"
},
"patch": [
{ "op": "add", "path": "/child", "value": { "grandchild": { } } }
],
"expected": {
"foo": "bar",
"child": {
"grandchild": {
}
}
}
},
{
"comment": "A.11. Ignoring Unrecognized Elements",
"doc": {
"foo":"bar"
},
"patch": [
{ "op": "add", "path": "/baz", "value": "qux", "xyz": 123 }
],
"expected": {
"foo":"bar",
"baz":"qux"
}
},
{
"comment": "A.12. Adding to a Non-existent Target",
"doc": {
"foo": "bar"
},
"patch": [
{ "op": "add", "path": "/baz/bat", "value": "qux" }
],
"error": "add to a non-existent target"
},
{
"comment": "A.13 Invalid JSON Patch Document",
"doc": {
"foo": "bar"
},
"patch": [
{ "op": "add", "path": "/baz", "value": "qux", "op": "remove" }
],
"error_wont_happen_in_jsonc": "operation has two 'op' members",
"error": "Did not find element referenced by path field"
},
{
"comment": "A.14. ~ Escape Ordering",
"doc": {
"/": 9,
"~1": 10
},
"patch": [{"op": "test", "path": "/~01", "value": 10}],
"expected": {
"/": 9,
"~1": 10
}
},
{
"comment": "A.15. Comparing Strings and Numbers",
"doc": {
"/": 9,
"~1": 10
},
"patch": [{"op": "test", "path": "/~01", "value": "10"}],
"error": "number is not equal to string"
},
{
"comment": "A.16. Adding an Array Value",
"doc": {
"foo": ["bar"]
},
"patch": [{ "op": "add", "path": "/foo/-", "value": ["abc", "def"] }],
"expected": {
"foo": ["bar", ["abc", "def"]]
}
}
]

View File

@@ -1,540 +0,0 @@
[
{ "comment": "empty list, empty docs",
"doc": {},
"patch": [],
"expected": {} },
{ "comment": "empty patch list",
"doc": {"foo": 1},
"patch": [],
"expected": {"foo": 1} },
{ "comment": "rearrangements OK?",
"doc": {"foo": 1, "bar": 2},
"patch": [],
"expected": {"bar":2, "foo": 1} },
{ "comment": "rearrangements OK? How about one level down ... array",
"doc": [{"foo": 1, "bar": 2}],
"patch": [],
"expected": [{"bar":2, "foo": 1}] },
{ "comment": "rearrangements OK? How about one level down...",
"doc": {"foo":{"foo": 1, "bar": 2}},
"patch": [],
"expected": {"foo":{"bar":2, "foo": 1}} },
{ "comment": "add replaces any existing field",
"doc": {"foo": null},
"patch": [{"op": "add", "path": "/foo", "value":1}],
"expected": {"foo": 1} },
{ "comment": "toplevel array",
"doc": [],
"patch": [{"op": "add", "path": "/0", "value": "foo"}],
"expected": ["foo"] },
{ "comment": "toplevel array, no change",
"doc": ["foo"],
"patch": [],
"expected": ["foo"] },
{ "comment": "toplevel object, numeric string",
"doc": {},
"patch": [{"op": "add", "path": "/foo", "value": "1"}],
"expected": {"foo":"1"} },
{ "comment": "toplevel object, integer",
"doc": {},
"patch": [{"op": "add", "path": "/foo", "value": 1}],
"expected": {"foo":1} },
{ "comment": "Toplevel scalar values OK?",
"doc": "foo",
"patch": [{"op": "replace", "path": "", "value": "bar"}],
"expected": "bar"
},
{ "comment": "replace object document with array document?",
"doc": {},
"patch": [{"op": "add", "path": "", "value": []}],
"expected": [] },
{ "comment": "replace array document with object document?",
"doc": [],
"patch": [{"op": "add", "path": "", "value": {}}],
"expected": {} },
{ "comment": "append to root array document?",
"doc": [],
"patch": [{"op": "add", "path": "/-", "value": "hi"}],
"expected": ["hi"] },
{ "comment": "Add, / target",
"doc": {},
"patch": [ {"op": "add", "path": "/", "value":1 } ],
"expected": {"":1} },
{ "comment": "Add, /foo/ deep target (trailing slash)",
"doc": {"foo": {}},
"patch": [ {"op": "add", "path": "/foo/", "value":1 } ],
"expected": {"foo":{"": 1}} },
{ "comment": "Add composite value at top level",
"doc": {"foo": 1},
"patch": [{"op": "add", "path": "/bar", "value": [1, 2]}],
"expected": {"foo": 1, "bar": [1, 2]} },
{ "comment": "Add into composite value",
"doc": {"foo": 1, "baz": [{"qux": "hello"}]},
"patch": [{"op": "add", "path": "/baz/0/foo", "value": "world"}],
"expected": {"foo": 1, "baz": [{"qux": "hello", "foo": "world"}]} },
{ "doc": {"bar": [1, 2]},
"patch": [{"op": "add", "path": "/bar/8", "value": "5"}],
"error": "Out of bounds (upper)" },
{ "doc": {"bar": [1, 2]},
"patch": [{"op": "add", "path": "/bar/-1", "value": "5"}],
"error": "Out of bounds (lower)" },
{ "doc": {"foo": 1},
"patch": [{"op": "add", "path": "/bar", "value": true}],
"expected": {"foo": 1, "bar": true} },
{ "doc": {"foo": 1},
"patch": [{"op": "add", "path": "/bar", "value": false}],
"expected": {"foo": 1, "bar": false} },
{ "doc": {"foo": 1},
"patch": [{"op": "add", "path": "/bar", "value": null}],
"expected": {"foo": 1, "bar": null} },
{ "comment": "0 can be an array index or object element name",
"doc": {"foo": 1},
"patch": [{"op": "add", "path": "/0", "value": "bar"}],
"expected": {"foo": 1, "0": "bar" } },
{ "doc": ["foo"],
"patch": [{"op": "add", "path": "/1", "value": "bar"}],
"expected": ["foo", "bar"] },
{ "doc": ["foo", "sil"],
"patch": [{"op": "add", "path": "/1", "value": "bar"}],
"expected": ["foo", "bar", "sil"] },
{ "doc": ["foo", "sil"],
"patch": [{"op": "add", "path": "/0", "value": "bar"}],
"expected": ["bar", "foo", "sil"] },
{ "comment": "push item to array via last index + 1",
"doc": ["foo", "sil"],
"patch": [{"op":"add", "path": "/2", "value": "bar"}],
"expected": ["foo", "sil", "bar"] },
{ "comment": "add item to array at index > length should fail",
"doc": ["foo", "sil"],
"patch": [{"op":"add", "path": "/3", "value": "bar"}],
"error": "index is greater than number of items in array" },
{ "comment": "test against implementation-specific numeric parsing",
"doc": {"1e0": "foo"},
"patch": [{"op": "test", "path": "/1e0", "value": "foo"}],
"expected": {"1e0": "foo"} },
{ "comment": "test with bad number should fail",
"doc": ["foo", "bar"],
"patch": [{"op": "test", "path": "/1e0", "value": "bar"}],
"error": "test op shouldn't get array element 1" },
{ "doc": ["foo", "sil"],
"patch": [{"op": "add", "path": "/bar", "value": 42}],
"error": "Object operation on array target" },
{ "doc": ["foo", "sil"],
"patch": [{"op": "add", "path": "/1", "value": ["bar", "baz"]}],
"expected": ["foo", ["bar", "baz"], "sil"],
"comment": "value in array add not flattened" },
{ "doc": {"foo": 1, "bar": [1, 2, 3, 4]},
"patch": [{"op": "remove", "path": "/bar"}],
"expected": {"foo": 1} },
{ "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
"patch": [{"op": "remove", "path": "/baz/0/qux"}],
"expected": {"foo": 1, "baz": [{}]} },
{ "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
"patch": [{"op": "replace", "path": "/foo", "value": [1, 2, 3, 4]}],
"expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]} },
{ "doc": {"foo": [1, 2, 3, 4], "baz": [{"qux": "hello"}]},
"patch": [{"op": "replace", "path": "/baz/0/qux", "value": "world"}],
"expected": {"foo": [1, 2, 3, 4], "baz": [{"qux": "world"}]} },
{ "doc": ["foo"],
"patch": [{"op": "replace", "path": "/0", "value": "bar"}],
"expected": ["bar"] },
{ "doc": [""],
"patch": [{"op": "replace", "path": "/0", "value": 0}],
"expected": [0] },
{ "doc": [""],
"patch": [{"op": "replace", "path": "/0", "value": true}],
"expected": [true] },
{ "doc": [""],
"patch": [{"op": "replace", "path": "/0", "value": false}],
"expected": [false] },
{ "doc": [""],
"patch": [{"op": "replace", "path": "/0", "value": null}],
"expected": [null] },
{ "doc": ["foo", "sil"],
"patch": [{"op": "replace", "path": "/1", "value": ["bar", "baz"]}],
"expected": ["foo", ["bar", "baz"]],
"comment": "value in array replace not flattened" },
{ "comment": "replace whole document",
"doc": {"foo": "bar"},
"patch": [{"op": "replace", "path": "", "value": {"baz": "qux"}}],
"expected": {"baz": "qux"} },
{ "comment": "add whole document, null",
"doc": {},
"Note1": "We can't pass null in to json_patch_apply, so start with _something_ and remove it",
"patch": [
{"op": "remove", "path": ""},
{"op": "add", "path": "", "value": {"baz": "qux"}}
],
"expected": {"baz": "qux"} },
{ "comment": "replace whole document, null",
"doc": {},
"Note1": "We can't pass null in to json_patch_apply, so start with _something_ and remove it",
"patch": [
{"op": "remove", "path": ""},
{"op": "replace", "path": "", "value": {"baz": "qux"}}
],
"error": "The spec says the target location must exist, so replacing a null document fails"
},
{ "comment": "remove whole document",
"doc": {"foo": "bar"},
"patch": [{"op": "remove", "path": ""}],
"expected": null },
{ "comment": "remove whole document",
"doc": {"foo": "bar"},
"patch": [{"op": "remove", "path": ""}],
"expected": null },
{ "comment": "remove whole document, array",
"doc": ["foo", "bar"],
"patch": [{"op": "remove", "path": ""}],
"expected": null },
{ "comment": "remove whole document, string",
"doc": "foo",
"patch": [{"op": "remove", "path": ""}],
"expected": null },
{ "comment": "remove whole document, null",
"doc": {},
"Note1": "We can't pass null in to json_patch_apply, so start with _something_ and remove it",
"patch": [
{"op": "remove", "path": ""},
{"op": "remove", "path": ""},
],
"error": "The spec says the target location must exist, so removing a null document fails"
},
{ "comment": "test replace with missing parent key should fail",
"doc": {"bar": "baz"},
"patch": [{"op": "replace", "path": "/foo/bar", "value": false}],
"error": "replace op should fail with missing parent key" },
{ "comment": "spurious patch properties",
"doc": {"foo": 1},
"patch": [{"op": "test", "path": "/foo", "value": 1, "spurious": 1}],
"expected": {"foo": 1} },
{ "doc": {"foo": null},
"patch": [{"op": "test", "path": "/foo", "value": null}],
"expected": {"foo": null},
"comment": "null value should be valid obj property" },
{ "doc": {"foo": null},
"patch": [{"op": "replace", "path": "/foo", "value": "truthy"}],
"expected": {"foo": "truthy"},
"comment": "null value should be valid obj property to be replaced with something truthy" },
{ "doc": {"foo": null},
"patch": [{"op": "move", "from": "/foo", "path": "/bar"}],
"expected": {"bar": null},
"comment": "null value should be valid obj property to be moved" },
{ "doc": {"foo": null},
"patch": [{"op": "copy", "from": "/foo", "path": "/bar"}],
"expected": {"foo": null, "bar": null},
"comment": "null value should be valid obj property to be copied" },
{ "doc": {"foo": null},
"patch": [{"op": "remove", "path": "/foo"}],
"expected": {},
"comment": "null value should be valid obj property to be removed" },
{ "doc": {"foo": "bar"},
"patch": [{"op": "replace", "path": "/foo", "value": null}],
"expected": {"foo": null},
"comment": "null value should still be valid obj property replace other value" },
{ "doc": {"foo": {"foo": 1, "bar": 2}},
"patch": [{"op": "test", "path": "/foo", "value": {"bar": 2, "foo": 1}}],
"expected": {"foo": {"foo": 1, "bar": 2}},
"comment": "test should pass despite rearrangement" },
{ "doc": {"foo": [{"foo": 1, "bar": 2}]},
"patch": [{"op": "test", "path": "/foo", "value": [{"bar": 2, "foo": 1}]}],
"expected": {"foo": [{"foo": 1, "bar": 2}]},
"comment": "test should pass despite (nested) rearrangement" },
{ "doc": {"foo": {"bar": [1, 2, 5, 4]}},
"patch": [{"op": "test", "path": "/foo", "value": {"bar": [1, 2, 5, 4]}}],
"expected": {"foo": {"bar": [1, 2, 5, 4]}},
"comment": "test should pass - no error" },
{ "doc": {"foo": {"bar": [1, 2, 5, 4]}},
"patch": [{"op": "test", "path": "/foo", "value": [1, 2]}],
"error": "test op should fail" },
{ "comment": "Test the whole document",
"doc": { "foo": 1 },
"patch": [{"op": "test", "path": "", "value": {"foo": 1}}],
"expected": { "foo": 1 } },
{ "comment": "Test the whole document, no match",
"doc": { "foo": 1 },
"patch": [{"op": "test", "path": "", "value": {"foo": 2}}],
"expected": { "foo": 1 },
"error": "Tested value does not match original doc" },
{ "comment": "Empty-string element",
"doc": { "": 1 },
"patch": [{"op": "test", "path": "/", "value": 1}],
"expected": { "": 1 } },
{ "doc": {
"foo": ["bar", "baz"],
"": 0,
"a/b": 1,
"c%d": 2,
"e^f": 3,
"g|h": 4,
"i\\j": 5,
"k\"l": 6,
" ": 7,
"m~n": 8
},
"patch": [{"op": "test", "path": "/foo", "value": ["bar", "baz"]},
{"op": "test", "path": "/foo/0", "value": "bar"},
{"op": "test", "path": "/", "value": 0},
{"op": "test", "path": "/a~1b", "value": 1},
{"op": "test", "path": "/c%d", "value": 2},
{"op": "test", "path": "/e^f", "value": 3},
{"op": "test", "path": "/g|h", "value": 4},
{"op": "test", "path": "/i\\j", "value": 5},
{"op": "test", "path": "/k\"l", "value": 6},
{"op": "test", "path": "/ ", "value": 7},
{"op": "test", "path": "/m~0n", "value": 8}],
"expected": {
"": 0,
" ": 7,
"a/b": 1,
"c%d": 2,
"e^f": 3,
"foo": [
"bar",
"baz"
],
"g|h": 4,
"i\\j": 5,
"k\"l": 6,
"m~n": 8
}
},
{ "comment": "Move to same location has no effect",
"doc": {"foo": 1},
"patch": [{"op": "move", "from": "/foo", "path": "/foo"}],
"expected": {"foo": 1} },
{ "doc": {"foo": 1, "baz": [{"qux": "hello"}]},
"patch": [{"op": "move", "from": "/foo", "path": "/bar"}],
"expected": {"baz": [{"qux": "hello"}], "bar": 1} },
{ "doc": {"baz": [{"qux": "hello"}], "bar": 1},
"patch": [{"op": "move", "from": "/baz/0/qux", "path": "/baz/1"}],
"expected": {"baz": [{}, "hello"], "bar": 1} },
{ "doc": {"baz": [{"qux": "hello"}], "bar": 1},
"patch": [{"op": "copy", "from": "/baz/0", "path": "/boo"}],
"expected": {"baz":[{"qux":"hello"}],"bar":1,"boo":{"qux":"hello"}} },
{ "comment": "replacing the root of the document is possible with add",
"doc": {"foo": "bar"},
"patch": [{"op": "add", "path": "", "value": {"baz": "qux"}}],
"expected": {"baz":"qux"}},
{ "comment": "Adding to \"/-\" adds to the end of the array",
"doc": [ 1, 2 ],
"patch": [ { "op": "add", "path": "/-", "value": { "foo": [ "bar", "baz" ] } } ],
"expected": [ 1, 2, { "foo": [ "bar", "baz" ] } ]},
{ "comment": "Adding to \"/-\" adds to the end of the array, even n levels down",
"doc": [ 1, 2, [ 3, [ 4, 5 ] ] ],
"patch": [ { "op": "add", "path": "/2/1/-", "value": { "foo": [ "bar", "baz" ] } } ],
"expected": [ 1, 2, [ 3, [ 4, 5, { "foo": [ "bar", "baz" ] } ] ] ]},
{ "comment": "test remove with bad number should fail",
"doc": {"foo": 1, "baz": [{"qux": "hello"}]},
"patch": [{"op": "remove", "path": "/baz/1e0/qux"}],
"error": "remove op shouldn't remove from array with bad number" },
{ "comment": "test remove on array",
"doc": [1, 2, 3, 4],
"patch": [{"op": "remove", "path": "/0"}],
"expected": [2, 3, 4] },
{ "comment": "test repeated removes",
"doc": [1, 2, 3, 4],
"patch": [{ "op": "remove", "path": "/1" },
{ "op": "remove", "path": "/2" }],
"expected": [1, 3] },
{ "comment": "test remove with bad index should fail",
"doc": [1, 2, 3, 4],
"patch": [{"op": "remove", "path": "/1e0"}],
"error": "remove op shouldn't remove from array with bad number" },
{ "comment": "test replace with bad number should fail",
"doc": [""],
"patch": [{"op": "replace", "path": "/1e0", "value": false}],
"error": "replace op shouldn't replace in array with bad number" },
{ "comment": "test copy with bad number should fail",
"doc": {"baz": [1,2,3], "bar": 1},
"patch": [{"op": "copy", "from": "/baz/1e0", "path": "/boo"}],
"error": "copy op shouldn't work with bad number" },
{ "comment": "test move with bad number should fail",
"doc": {"foo": 1, "baz": [1,2,3,4]},
"patch": [{"op": "move", "from": "/baz/1e0", "path": "/foo"}],
"error": "move op shouldn't work with bad number" },
{ "comment": "test add with bad number should fail",
"doc": ["foo", "sil"],
"patch": [{"op": "add", "path": "/1e0", "value": "bar"}],
"error": "add op shouldn't add to array with bad number" },
{ "comment": "missing 'path' parameter",
"doc": {},
"patch": [ { "op": "add", "value": "bar" } ],
"error": "missing 'path' parameter" },
{ "comment": "'path' parameter with null value",
"doc": {},
"patch": [ { "op": "add", "path": null, "value": "bar" } ],
"error": "null is not valid value for 'path'" },
{ "comment": "invalid JSON Pointer token",
"doc": {},
"patch": [ { "op": "add", "path": "foo", "value": "bar" } ],
"error": "JSON Pointer should start with a slash" },
{ "comment": "missing 'value' parameter to add",
"doc": [ 1 ],
"patch": [ { "op": "add", "path": "/-" } ],
"error": "missing 'value' parameter" },
{ "comment": "missing 'value' parameter to replace",
"doc": [ 1 ],
"patch": [ { "op": "replace", "path": "/0" } ],
"error": "missing 'value' parameter" },
{ "comment": "missing 'value' parameter to test",
"doc": [ null ],
"patch": [ { "op": "test", "path": "/0" } ],
"error": "missing 'value' parameter" },
{ "comment": "missing value parameter to test - where undef is falsy",
"doc": [ false ],
"patch": [ { "op": "test", "path": "/0" } ],
"error": "missing 'value' parameter" },
{ "comment": "missing from parameter to copy",
"doc": [ 1 ],
"patch": [ { "op": "copy", "path": "/-" } ],
"error": "missing 'from' parameter" },
{ "comment": "missing from location to copy",
"doc": { "foo": 1 },
"patch": [ { "op": "copy", "from": "/bar", "path": "/foo" } ],
"error": "missing 'from' location" },
{ "comment": "missing from parameter to move",
"doc": { "foo": 1 },
"patch": [ { "op": "move", "path": "" } ],
"error": "missing 'from' parameter" },
{ "comment": "missing from location to move",
"doc": { "foo": 1 },
"patch": [ { "op": "move", "from": "/bar", "path": "/foo" } ],
"error": "missing 'from' location" },
{ "comment": "duplicate ops, json-c parses this as op:move",
"doc": { "foo": "bar" },
"patch": [ { "op": "add", "path": "/baz", "value": "qux",
"op": "move", "from":"/foo" } ],
"error_wont_happen_in_jsonc": "patch has two 'op' members",
"expected": { "baz": "bar" }
},
{ "comment": "unrecognized op should fail",
"doc": {"foo": 1},
"patch": [{"op": "spam", "path": "/foo", "value": 1}],
"error": "Unrecognized op 'spam'" },
{ "comment": "test with bad array number that has leading zeros",
"doc": ["foo", "bar"],
"patch": [{"op": "test", "path": "/00", "value": "foo"}],
"error": "test op should reject the array value, it has leading zeros" },
{ "comment": "test with bad array number that has leading zeros",
"doc": ["foo", "bar"],
"patch": [{"op": "test", "path": "/01", "value": "bar"}],
"error": "test op should reject the array value, it has leading zeros" },
{ "comment": "Removing nonexistent field",
"doc": {"foo" : "bar"},
"patch": [{"op": "remove", "path": "/baz"}],
"error": "removing a nonexistent field should fail" },
{ "comment": "Removing deep nonexistent path",
"doc": {"foo" : "bar"},
"patch": [{"op": "remove", "path": "/missing1/missing2"}],
"error": "removing a nonexistent field should fail" },
{ "comment": "Removing nonexistent index",
"doc": ["foo", "bar"],
"patch": [{"op": "remove", "path": "/2"}],
"error": "removing a nonexistent index should fail" },
{ "comment": "Patch with different capitalisation than doc",
"doc": {"foo":"bar"},
"patch": [{"op": "add", "path": "/FOO", "value": "BAR"}],
"expected": {"foo": "bar", "FOO": "BAR"}
}
]

View File

@@ -1,76 +0,0 @@
#This hack is needed for Windows tests
test_lib = static_library(
'jsonctest',
objects: libjson.extract_all_objects(
recursive: false,
),
install: false,
)
test_deps = declare_dependency(
include_directories: '..',
link_with: test_lib,
)
# List of test sources and expected output files
test_cases = [
['test1', 'test1.expected'],
['test2', 'test2.expected'],
['test4', 'test4.expected'],
['testReplaceExisting', 'testReplaceExisting.expected'],
['test_cast', 'test_cast.expected'],
['test_charcase', 'test_charcase.expected'],
['test_compare', 'test_compare.expected'],
['test_deep_copy', 'test_deep_copy.expected'],
['test_double_serializer', 'test_double_serializer.expected'],
['test_float', 'test_float.expected'],
['test_int_add', 'test_int_add.expected'],
['test_int_get', 'test_int_get.expected'],
['test_locale', 'test_locale.expected'],
['test_null', 'test_null.expected'],
['test_parse', 'test_parse.expected'],
['test_parse_int64', 'test_parse_int64.expected'],
['test_printbuf', 'test_printbuf.expected'],
['test_set_serializer', 'test_set_serializer.expected'],
['test_set_value', 'test_set_value.expected'],
['test_strerror', 'test_strerror.expected'],
['test_util_file', 'test_util_file.expected'],
['test_visit', 'test_visit.expected'],
['test_object_iterator', 'test_object_iterator.expected'],
['test_json_pointer', 'test_json_pointer.expected'],
['test_safe_json_pointer_set', 'test_safe_json_pointer_set.expected'],
['test_json_patch', 'test_json_patch.expected'],
]
# Copy expected files and test data
expected_files = []
foreach t : test_cases
expected_files += t[1]
endforeach
foreach f : expected_files + ['valid.json', 'valid_nested.json', 'json_patch_spec_tests.json', 'json_patch_tests.json']
configure_file(input: f, output: f, copy: true)
endforeach
# Build and register tests
special_args = {
'test_json_patch': ['.'],
'test_util_file': ['.'],
}
testdir = meson.current_build_dir()
message('Test data directory: ' + testdir)
foreach t : test_cases
name = t[0]
expected = t[1]
exe = executable(name, name + '.c',
dependencies: test_deps
)
test(name, exe,
args: special_args.get(name, []),
env: ['EXPECTED_FILE=' + meson.current_build_dir() / expected],
workdir: testdir
)
endforeach

View File

@@ -189,42 +189,6 @@ void test_array_list_expand_internal(void)
json_object_put(my_array); json_object_put(my_array);
} }
void test_array_insert_idx(void);
void test_array_insert_idx(void)
{
json_object *my_array;
struct json_object *jo1;
my_array = json_object_new_array();
json_object_array_add(my_array, json_object_new_int(1));
json_object_array_add(my_array, json_object_new_int(2));
json_object_array_add(my_array, json_object_new_int(5));
json_object_array_insert_idx(my_array, 2, json_object_new_int(4));
jo1 = json_tokener_parse("[1, 2, 4, 5]");
assert(1 == json_object_equal(my_array, jo1));
json_object_put(jo1);
json_object_array_insert_idx(my_array, 2, json_object_new_int(3));
jo1 = json_tokener_parse("[1, 2, 3, 4, 5]");
assert(1 == json_object_equal(my_array, jo1));
json_object_put(jo1);
json_object_array_insert_idx(my_array, 5, json_object_new_int(6));
jo1 = json_tokener_parse("[1, 2, 3, 4, 5, 6]");
assert(1 == json_object_equal(my_array, jo1));
json_object_put(jo1);
json_object_array_insert_idx(my_array, 7, json_object_new_int(8));
jo1 = json_tokener_parse("[1, 2, 3, 4, 5, 6, null, 8]");
assert(1 == json_object_equal(my_array, jo1));
json_object_put(jo1);
json_object_put(my_array);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
json_object *my_string, *my_int, *my_null, *my_object, *my_array; json_object *my_string, *my_int, *my_null, *my_object, *my_array;
@@ -289,8 +253,6 @@ int main(int argc, char **argv)
json_object_put(my_array); json_object_put(my_array);
test_array_insert_idx();
test_array_del_idx(); test_array_del_idx();
test_array_list_expand_internal(); test_array_list_expand_internal();

View File

@@ -36,7 +36,6 @@ int main(int argc, char **argv)
\"array_with_zero\": [ 0 ],\n\ \"array_with_zero\": [ 0 ],\n\
\"empty_object\": {},\n\ \"empty_object\": {},\n\
\"nonempty_object\": { \"a\": 123 },\n\ \"nonempty_object\": { \"a\": 123 },\n\
\"nan\": NaN,\n\
}"; }";
/* Note: 2147483649 = INT_MAX + 2 */ /* Note: 2147483649 = INT_MAX + 2 */
/* Note: 9223372036854775809 = INT64_MAX + 2 */ /* Note: 9223372036854775809 = INT64_MAX + 2 */
@@ -63,7 +62,6 @@ int main(int argc, char **argv)
getit(new_obj, "array_with_zero"); getit(new_obj, "array_with_zero");
getit(new_obj, "empty_object"); getit(new_obj, "empty_object");
getit(new_obj, "nonempty_object"); getit(new_obj, "nonempty_object");
getit(new_obj, "nan");
// Now check the behaviour of the json_object_is_type() function. // Now check the behaviour of the json_object_is_type() function.
printf("\n================================\n"); printf("\n================================\n");
@@ -77,7 +75,6 @@ int main(int argc, char **argv)
checktype(new_obj, "int64_number"); checktype(new_obj, "int64_number");
checktype(new_obj, "negative_number"); checktype(new_obj, "negative_number");
checktype(new_obj, "a_null"); checktype(new_obj, "a_null");
checktype(new_obj, "nan");
json_object_put(new_obj); json_object_put(new_obj);

View File

@@ -12,7 +12,6 @@ Parsed input: {
"array_with_zero": [ 0 ], "array_with_zero": [ 0 ],
"empty_object": {}, "empty_object": {},
"nonempty_object": { "a": 123 }, "nonempty_object": { "a": 123 },
"nan": NaN,
} }
Result is not NULL Result is not NULL
new_obj.string_of_digits json_object_get_type()=string new_obj.string_of_digits json_object_get_type()=string
@@ -93,12 +92,6 @@ new_obj.nonempty_object json_object_get_int64()=0
new_obj.nonempty_object json_object_get_uint64()=0 new_obj.nonempty_object json_object_get_uint64()=0
new_obj.nonempty_object json_object_get_boolean()=0 new_obj.nonempty_object json_object_get_boolean()=0
new_obj.nonempty_object json_object_get_double()=0.000000 new_obj.nonempty_object json_object_get_double()=0.000000
new_obj.nan json_object_get_type()=double
new_obj.nan json_object_get_int()=-2147483648
new_obj.nan json_object_get_int64()=-9223372036854775808
new_obj.nan json_object_get_uint64()=0
new_obj.nan json_object_get_boolean()=1
new_obj.nan json_object_get_double()=nan
================================ ================================
json_object_is_type: null,boolean,double,int,object,array,string json_object_is_type: null,boolean,double,int,object,array,string
@@ -111,4 +104,3 @@ new_obj.boolean_false : 0,1,0,0,0,0,0
new_obj.int64_number : 0,0,0,1,0,0,0 new_obj.int64_number : 0,0,0,1,0,0,0
new_obj.negative_number : 0,0,0,1,0,0,0 new_obj.negative_number : 0,0,0,1,0,0,0
new_obj.a_null : 1,0,0,0,0,0,0 new_obj.a_null : 1,0,0,0,0,0,0
new_obj.nan : 0,0,1,0,0,0,0

View File

@@ -4,12 +4,9 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#include <math.h>
#include "json.h" #include "json.h"
#define I32_MAX_S "2147483647"
#define I32_MIN_S "-2147483648"
#define I64_MAX_S "9223372036854775807" #define I64_MAX_S "9223372036854775807"
#define I64_OVER "9223372036854775808" #define I64_OVER "9223372036854775808"
#define I64_MIN_S "-9223372036854775808" #define I64_MIN_S "-9223372036854775808"
@@ -28,7 +25,6 @@
#define N_I64 json_object_new_int64 #define N_I64 json_object_new_int64
#define N_U64 json_object_new_uint64 #define N_U64 json_object_new_uint64
#define N_STR json_object_new_string #define N_STR json_object_new_string
#define N_DBL json_object_new_double
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@@ -45,15 +41,10 @@ int main(int argc, char **argv)
CHECK_GET_INT(N_I64(INT32_MAX), INT32_MAX && errno == 0); CHECK_GET_INT(N_I64(INT32_MAX), INT32_MAX && errno == 0);
CHECK_GET_INT(N_I64(INT32_MIN), INT32_MIN && errno == 0); CHECK_GET_INT(N_I64(INT32_MIN), INT32_MIN && errno == 0);
CHECK_GET_INT(N_I64(INT64_MAX), INT32_MAX && errno == ERANGE); CHECK_GET_INT(N_I64(INT64_MAX), INT32_MAX && errno == 0);
CHECK_GET_INT(N_I64(INT64_MIN), INT32_MIN && errno == ERANGE); CHECK_GET_INT(N_I64(INT64_MIN), INT32_MIN && errno == 0);
CHECK_GET_INT(N_STR(I32_MAX_S), INT32_MAX && errno == 0); CHECK_GET_INT(N_STR(I64_MAX_S), INT32_MAX && errno == 0);
CHECK_GET_INT(N_STR(I32_MIN_S), INT32_MIN && errno == 0); CHECK_GET_INT(N_STR(I64_MIN_S), INT32_MIN && errno == 0);
CHECK_GET_INT(N_STR(I64_MAX_S), INT32_MAX && errno == ERANGE);
CHECK_GET_INT(N_STR(I64_MIN_S), INT32_MIN && errno == ERANGE);
CHECK_GET_INT(N_DBL(INFINITY), INT32_MAX && errno == ERANGE);
CHECK_GET_INT(N_DBL(-INFINITY), INT32_MIN && errno == ERANGE);
CHECK_GET_INT(N_DBL(NAN), INT32_MIN && errno == EINVAL);
printf("INT GET PASSED\n"); printf("INT GET PASSED\n");
CHECK_GET_INT64(N_I64(INT64_MAX), INT64_MAX && errno == 0); CHECK_GET_INT64(N_I64(INT64_MAX), INT64_MAX && errno == 0);
@@ -62,17 +53,11 @@ int main(int argc, char **argv)
CHECK_GET_INT64(N_STR(I64_MIN_S), INT64_MIN && errno == 0); CHECK_GET_INT64(N_STR(I64_MIN_S), INT64_MIN && errno == 0);
CHECK_GET_INT64(N_STR(I64_OVER), INT64_MAX && errno == ERANGE); CHECK_GET_INT64(N_STR(I64_OVER), INT64_MAX && errno == ERANGE);
CHECK_GET_INT64(N_STR(I64_UNDER), INT64_MIN && errno == ERANGE); CHECK_GET_INT64(N_STR(I64_UNDER), INT64_MIN && errno == ERANGE);
CHECK_GET_INT64(N_DBL(INFINITY), INT64_MAX && errno == ERANGE);
CHECK_GET_INT64(N_DBL(-INFINITY), INT64_MIN && errno == ERANGE);
CHECK_GET_INT64(N_DBL(NAN), INT64_MIN && errno == EINVAL);
printf("INT64 GET PASSED\n"); printf("INT64 GET PASSED\n");
CHECK_GET_UINT64(N_U64(UINT64_MAX), UINT64_MAX && errno == 0); CHECK_GET_UINT64(N_U64(UINT64_MAX), UINT64_MAX && errno == 0);
CHECK_GET_UINT64(N_U64(-1), UINT64_MAX && errno == 0); CHECK_GET_UINT64(N_U64(-1), UINT64_MAX && errno == 0);
CHECK_GET_UINT64(N_STR(U64_OUT_S), UINT64_MAX && errno == ERANGE); CHECK_GET_UINT64(N_STR(U64_OUT_S), UINT64_MAX && errno == ERANGE);
CHECK_GET_UINT64(N_DBL(INFINITY), UINT64_MAX && errno == ERANGE);
CHECK_GET_UINT64(N_DBL(-INFINITY), 0 && errno == ERANGE);
CHECK_GET_UINT64(N_DBL(NAN), 0 && errno == EINVAL);
printf("UINT64 GET PASSED\n"); printf("UINT64 GET PASSED\n");
printf("PASSED\n"); printf("PASSED\n");

View File

@@ -1,127 +0,0 @@
#ifdef NDEBUG
#undef NDEBUG
#endif
#include "strerror_override.h"
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "config.h"
#include "json.h"
#include "snprintf_compat.h"
#ifndef PATH_MAX
#define PATH_MAX 256
#endif
void test_json_patch_op(struct json_object *jo)
{
const char *comment = json_object_get_string(json_object_object_get(jo, "comment"));
struct json_object *doc = json_object_object_get(jo, "doc");
struct json_object *patch = json_object_object_get(jo, "patch");
struct json_object *expected = NULL;
json_bool have_expected = json_object_object_get_ex(jo, "expected", &expected);
struct json_object *error = json_object_object_get(jo, "error");
const char *error_s = json_object_get_string(error);
struct json_object *res = NULL;
int ret;
printf("Testing '%s', doc '%s' patch '%s' : ",
comment ? comment : error_s,
json_object_get_string(doc),
json_object_get_string(patch));
if (!error && !have_expected) {
printf("BAD TEST - no expected or error conditions in test: %s\n", json_object_to_json_string(jo));
assert(0);
}
fflush(stdout);
struct json_patch_error jperr;
if (error) {
assert(-1 == json_patch_apply(doc, patch, &res, &jperr));
assert(jperr.errno_code != 0);
printf("OK\n");
printf(" => json_patch_apply failed as expected: %s at patch idx %zu: %s\n",
strerror(jperr.errno_code), jperr.patch_failure_idx, jperr.errmsg);
json_object_put(res);
} else {
ret = json_patch_apply(doc, patch, &res, &jperr);
if (ret) {
fprintf(stderr, "json_patch_apply() returned '%d'\n", ret);
fprintf(stderr, "Expected: %s\n", json_object_get_string(expected));
fprintf(stderr, "Got: %s\n", res ? json_object_get_string(res) : "(null)");
fprintf(stderr, "json_patch_apply failed: %s at patch idx %zu: %s\n",
strerror(jperr.errno_code), jperr.patch_failure_idx, jperr.errmsg);
fflush(stderr);
assert(0);
}
// Note: res might be NULL if the whole document was removed
assert(jperr.errno_code == 0);
ret = json_object_equal(expected, res);
if (ret == 0) {
fprintf(stderr, "json_object_equal() returned '%d'\n", ret);
fprintf(stderr, "Expected: %s\n", json_object_get_string(expected));
fprintf(stderr, "Got: %s\n", json_object_get_string(res));
fflush(stderr);
assert(0);
}
json_object_put(res);
res = NULL;
printf("OK\n");
}
}
void test_json_patch_using_file(const char *testdir, const char *filename)
{
char full_filename[PATH_MAX];
(void)snprintf(full_filename, sizeof(full_filename), "%s/%s", testdir, filename);
size_t ii;
printf("Testing using file %s\n", filename);
json_object *jo = json_object_from_file(full_filename);
if (!jo) {
fprintf(stderr, "FAIL: unable to open %s: %s\n", full_filename, strerror(errno));
exit(EXIT_FAILURE);
}
for (ii = 0; ii < json_object_array_length(jo); ii++) {
struct json_object *jo1 = json_object_array_get_idx(jo, ii);
test_json_patch_op(jo1);
}
json_object_put(jo);
}
int main(int argc, char **argv)
{
const char *testdir;
if (argc < 2)
{
fprintf(stderr,
"Usage: %s <testdir>\n"
" <testdir> is the location of input files\n",
argv[0]);
return EXIT_FAILURE;
}
testdir = argv[1];
// Test json_c_version.c
if (strncmp(json_c_version(), JSON_C_VERSION, sizeof(JSON_C_VERSION)))
{
printf("FAIL: Output from json_c_version(): %s does not match %s",
json_c_version(), JSON_C_VERSION);
return EXIT_FAILURE;
}
if (json_c_version_num() != JSON_C_VERSION_NUM)
{
printf("FAIL: Output from json_c_version_num(): %d does not match %d",
json_c_version_num(), JSON_C_VERSION_NUM);
return EXIT_FAILURE;
}
test_json_patch_using_file(testdir, "json_patch_spec_tests.json");
test_json_patch_using_file(testdir, "json_patch_tests.json");
return 0;
}

View File

@@ -1,158 +0,0 @@
Testing using file json_patch_spec_tests.json
Testing '4.1. add with missing object', doc '{ "q": { "bar": 2 } }' patch '[ { "op": "add", "path": "\/a\/b", "value": 1 } ]' : OK
=> json_patch_apply failed as expected: ERRNO=ENOENT at patch idx 0: Failed to set value at path referenced by 'path' field
Testing 'A.1. Adding an Object Member', doc '{ "foo": "bar" }' patch '[ { "op": "add", "path": "\/baz", "value": "qux" } ]' : OK
Testing 'A.2. Adding an Array Element', doc '{ "foo": [ "bar", "baz" ] }' patch '[ { "op": "add", "path": "\/foo\/1", "value": "qux" } ]' : OK
Testing 'A.3. Removing an Object Member', doc '{ "baz": "qux", "foo": "bar" }' patch '[ { "op": "remove", "path": "\/baz" } ]' : OK
Testing 'A.4. Removing an Array Element', doc '{ "foo": [ "bar", "qux", "baz" ] }' patch '[ { "op": "remove", "path": "\/foo\/1" } ]' : OK
Testing 'A.5. Replacing a Value', doc '{ "baz": "qux", "foo": "bar" }' patch '[ { "op": "replace", "path": "\/baz", "value": "boo" } ]' : OK
Testing 'A.6. Moving a Value', doc '{ "foo": { "bar": "baz", "waldo": "fred" }, "qux": { "corge": "grault" } }' patch '[ { "op": "move", "from": "\/foo\/waldo", "path": "\/qux\/thud" } ]' : OK
Testing 'A.7. Moving an Array Element', doc '{ "foo": [ "all", "grass", "cows", "eat" ] }' patch '[ { "op": "move", "from": "\/foo\/1", "path": "\/foo\/3" } ]' : OK
Testing 'A.8. Testing a Value: Success', doc '{ "baz": "qux", "foo": [ "a", 2, "c" ] }' patch '[ { "op": "test", "path": "\/baz", "value": "qux" }, { "op": "test", "path": "\/foo\/1", "value": 2 } ]' : OK
Testing 'A.9. Testing a Value: Error', doc '{ "baz": "qux" }' patch '[ { "op": "test", "path": "\/baz", "value": "bar" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=ENOENT at patch idx 0: Value of element referenced by 'path' field did not match 'value' field
Testing 'A.10. Adding a nested Member Object', doc '{ "foo": "bar" }' patch '[ { "op": "add", "path": "\/child", "value": { "grandchild": { } } } ]' : OK
Testing 'A.11. Ignoring Unrecognized Elements', doc '{ "foo": "bar" }' patch '[ { "op": "add", "path": "\/baz", "value": "qux", "xyz": 123 } ]' : OK
Testing 'A.12. Adding to a Non-existent Target', doc '{ "foo": "bar" }' patch '[ { "op": "add", "path": "\/baz\/bat", "value": "qux" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=ENOENT at patch idx 0: Failed to set value at path referenced by 'path' field
Testing 'A.13 Invalid JSON Patch Document', doc '{ "foo": "bar" }' patch '[ { "op": "remove", "path": "\/baz", "value": "qux" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=ENOENT at patch idx 0: Did not find element referenced by path field
Testing 'A.14. ~ Escape Ordering', doc '{ "\/": 9, "~1": 10 }' patch '[ { "op": "test", "path": "\/~01", "value": 10 } ]' : OK
Testing 'A.15. Comparing Strings and Numbers', doc '{ "\/": 9, "~1": 10 }' patch '[ { "op": "test", "path": "\/~01", "value": "10" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=ENOENT at patch idx 0: Value of element referenced by 'path' field did not match 'value' field
Testing 'A.16. Adding an Array Value', doc '{ "foo": [ "bar" ] }' patch '[ { "op": "add", "path": "\/foo\/-", "value": [ "abc", "def" ] } ]' : OK
Testing using file json_patch_tests.json
Testing 'empty list, empty docs', doc '{ }' patch '[ ]' : OK
Testing 'empty patch list', doc '{ "foo": 1 }' patch '[ ]' : OK
Testing 'rearrangements OK?', doc '{ "foo": 1, "bar": 2 }' patch '[ ]' : OK
Testing 'rearrangements OK? How about one level down ... array', doc '[ { "foo": 1, "bar": 2 } ]' patch '[ ]' : OK
Testing 'rearrangements OK? How about one level down...', doc '{ "foo": { "foo": 1, "bar": 2 } }' patch '[ ]' : OK
Testing 'add replaces any existing field', doc '{ "foo": null }' patch '[ { "op": "add", "path": "\/foo", "value": 1 } ]' : OK
Testing 'toplevel array', doc '[ ]' patch '[ { "op": "add", "path": "\/0", "value": "foo" } ]' : OK
Testing 'toplevel array, no change', doc '[ "foo" ]' patch '[ ]' : OK
Testing 'toplevel object, numeric string', doc '{ }' patch '[ { "op": "add", "path": "\/foo", "value": "1" } ]' : OK
Testing 'toplevel object, integer', doc '{ }' patch '[ { "op": "add", "path": "\/foo", "value": 1 } ]' : OK
Testing 'Toplevel scalar values OK?', doc 'foo' patch '[ { "op": "replace", "path": "", "value": "bar" } ]' : OK
Testing 'replace object document with array document?', doc '{ }' patch '[ { "op": "add", "path": "", "value": [ ] } ]' : OK
Testing 'replace array document with object document?', doc '[ ]' patch '[ { "op": "add", "path": "", "value": { } } ]' : OK
Testing 'append to root array document?', doc '[ ]' patch '[ { "op": "add", "path": "\/-", "value": "hi" } ]' : OK
Testing 'Add, / target', doc '{ }' patch '[ { "op": "add", "path": "\/", "value": 1 } ]' : OK
Testing 'Add, /foo/ deep target (trailing slash)', doc '{ "foo": { } }' patch '[ { "op": "add", "path": "\/foo\/", "value": 1 } ]' : OK
Testing 'Add composite value at top level', doc '{ "foo": 1 }' patch '[ { "op": "add", "path": "\/bar", "value": [ 1, 2 ] } ]' : OK
Testing 'Add into composite value', doc '{ "foo": 1, "baz": [ { "qux": "hello" } ] }' patch '[ { "op": "add", "path": "\/baz\/0\/foo", "value": "world" } ]' : OK
Testing 'Out of bounds (upper)', doc '{ "bar": [ 1, 2 ] }' patch '[ { "op": "add", "path": "\/bar\/8", "value": "5" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Failed to set value at path referenced by 'path' field
Testing 'Out of bounds (lower)', doc '{ "bar": [ 1, 2 ] }' patch '[ { "op": "add", "path": "\/bar\/-1", "value": "5" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Failed to set value at path referenced by 'path' field
Testing '(null)', doc '{ "foo": 1 }' patch '[ { "op": "add", "path": "\/bar", "value": true } ]' : OK
Testing '(null)', doc '{ "foo": 1 }' patch '[ { "op": "add", "path": "\/bar", "value": false } ]' : OK
Testing '(null)', doc '{ "foo": 1 }' patch '[ { "op": "add", "path": "\/bar", "value": null } ]' : OK
Testing '0 can be an array index or object element name', doc '{ "foo": 1 }' patch '[ { "op": "add", "path": "\/0", "value": "bar" } ]' : OK
Testing '(null)', doc '[ "foo" ]' patch '[ { "op": "add", "path": "\/1", "value": "bar" } ]' : OK
Testing '(null)', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/1", "value": "bar" } ]' : OK
Testing '(null)', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/0", "value": "bar" } ]' : OK
Testing 'push item to array via last index + 1', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/2", "value": "bar" } ]' : OK
Testing 'add item to array at index > length should fail', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/3", "value": "bar" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Failed to set value at path referenced by 'path' field
Testing 'test against implementation-specific numeric parsing', doc '{ "1e0": "foo" }' patch '[ { "op": "test", "path": "\/1e0", "value": "foo" } ]' : OK
Testing 'test with bad number should fail', doc '[ "foo", "bar" ]' patch '[ { "op": "test", "path": "\/1e0", "value": "bar" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Invalid path field
Testing 'Object operation on array target', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/bar", "value": 42 } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Failed to set value at path referenced by 'path' field
Testing 'value in array add not flattened', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/1", "value": [ "bar", "baz" ] } ]' : OK
Testing '(null)', doc '{ "foo": 1, "bar": [ 1, 2, 3, 4 ] }' patch '[ { "op": "remove", "path": "\/bar" } ]' : OK
Testing '(null)', doc '{ "foo": 1, "baz": [ { "qux": "hello" } ] }' patch '[ { "op": "remove", "path": "\/baz\/0\/qux" } ]' : OK
Testing '(null)', doc '{ "foo": 1, "baz": [ { "qux": "hello" } ] }' patch '[ { "op": "replace", "path": "\/foo", "value": [ 1, 2, 3, 4 ] } ]' : OK
Testing '(null)', doc '{ "foo": [ 1, 2, 3, 4 ], "baz": [ { "qux": "hello" } ] }' patch '[ { "op": "replace", "path": "\/baz\/0\/qux", "value": "world" } ]' : OK
Testing '(null)', doc '[ "foo" ]' patch '[ { "op": "replace", "path": "\/0", "value": "bar" } ]' : OK
Testing '(null)', doc '[ "" ]' patch '[ { "op": "replace", "path": "\/0", "value": 0 } ]' : OK
Testing '(null)', doc '[ "" ]' patch '[ { "op": "replace", "path": "\/0", "value": true } ]' : OK
Testing '(null)', doc '[ "" ]' patch '[ { "op": "replace", "path": "\/0", "value": false } ]' : OK
Testing '(null)', doc '[ "" ]' patch '[ { "op": "replace", "path": "\/0", "value": null } ]' : OK
Testing 'value in array replace not flattened', doc '[ "foo", "sil" ]' patch '[ { "op": "replace", "path": "\/1", "value": [ "bar", "baz" ] } ]' : OK
Testing 'replace whole document', doc '{ "foo": "bar" }' patch '[ { "op": "replace", "path": "", "value": { "baz": "qux" } } ]' : OK
Testing 'add whole document, null', doc '{ }' patch '[ { "op": "remove", "path": "" }, { "op": "add", "path": "", "value": { "baz": "qux" } } ]' : OK
Testing 'replace whole document, null', doc '{ }' patch '[ { "op": "remove", "path": "" }, { "op": "replace", "path": "", "value": { "baz": "qux" } } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 1: Invalid path field
Testing 'remove whole document', doc '{ "foo": "bar" }' patch '[ { "op": "remove", "path": "" } ]' : OK
Testing 'remove whole document', doc '{ "foo": "bar" }' patch '[ { "op": "remove", "path": "" } ]' : OK
Testing 'remove whole document, array', doc '[ "foo", "bar" ]' patch '[ { "op": "remove", "path": "" } ]' : OK
Testing 'remove whole document, string', doc 'foo' patch '[ { "op": "remove", "path": "" } ]' : OK
Testing 'remove whole document, null', doc '{ }' patch '[ { "op": "remove", "path": "" }, { "op": "remove", "path": "" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 1: Invalid path field
Testing 'test replace with missing parent key should fail', doc '{ "bar": "baz" }' patch '[ { "op": "replace", "path": "\/foo\/bar", "value": false } ]' : OK
=> json_patch_apply failed as expected: ERRNO=ENOENT at patch idx 0: Did not find element referenced by path field
Testing 'spurious patch properties', doc '{ "foo": 1 }' patch '[ { "op": "test", "path": "\/foo", "value": 1, "spurious": 1 } ]' : OK
Testing 'null value should be valid obj property', doc '{ "foo": null }' patch '[ { "op": "test", "path": "\/foo", "value": null } ]' : OK
Testing 'null value should be valid obj property to be replaced with something truthy', doc '{ "foo": null }' patch '[ { "op": "replace", "path": "\/foo", "value": "truthy" } ]' : OK
Testing 'null value should be valid obj property to be moved', doc '{ "foo": null }' patch '[ { "op": "move", "from": "\/foo", "path": "\/bar" } ]' : OK
Testing 'null value should be valid obj property to be copied', doc '{ "foo": null }' patch '[ { "op": "copy", "from": "\/foo", "path": "\/bar" } ]' : OK
Testing 'null value should be valid obj property to be removed', doc '{ "foo": null }' patch '[ { "op": "remove", "path": "\/foo" } ]' : OK
Testing 'null value should still be valid obj property replace other value', doc '{ "foo": "bar" }' patch '[ { "op": "replace", "path": "\/foo", "value": null } ]' : OK
Testing 'test should pass despite rearrangement', doc '{ "foo": { "foo": 1, "bar": 2 } }' patch '[ { "op": "test", "path": "\/foo", "value": { "bar": 2, "foo": 1 } } ]' : OK
Testing 'test should pass despite (nested) rearrangement', doc '{ "foo": [ { "foo": 1, "bar": 2 } ] }' patch '[ { "op": "test", "path": "\/foo", "value": [ { "bar": 2, "foo": 1 } ] } ]' : OK
Testing 'test should pass - no error', doc '{ "foo": { "bar": [ 1, 2, 5, 4 ] } }' patch '[ { "op": "test", "path": "\/foo", "value": { "bar": [ 1, 2, 5, 4 ] } } ]' : OK
Testing 'test op should fail', doc '{ "foo": { "bar": [ 1, 2, 5, 4 ] } }' patch '[ { "op": "test", "path": "\/foo", "value": [ 1, 2 ] } ]' : OK
=> json_patch_apply failed as expected: ERRNO=ENOENT at patch idx 0: Value of element referenced by 'path' field did not match 'value' field
Testing 'Test the whole document', doc '{ "foo": 1 }' patch '[ { "op": "test", "path": "", "value": { "foo": 1 } } ]' : OK
Testing 'Test the whole document, no match', doc '{ "foo": 1 }' patch '[ { "op": "test", "path": "", "value": { "foo": 2 } } ]' : OK
=> json_patch_apply failed as expected: ERRNO=ENOENT at patch idx 0: Value of element referenced by 'path' field did not match 'value' field
Testing 'Empty-string element', doc '{ "": 1 }' patch '[ { "op": "test", "path": "\/", "value": 1 } ]' : OK
Testing '(null)', doc '{ "foo": [ "bar", "baz" ], "": 0, "a\/b": 1, "c%d": 2, "e^f": 3, "g|h": 4, "i\\j": 5, "k\"l": 6, " ": 7, "m~n": 8 }' patch '[ { "op": "test", "path": "\/foo", "value": [ "bar", "baz" ] }, { "op": "test", "path": "\/foo\/0", "value": "bar" }, { "op": "test", "path": "\/", "value": 0 }, { "op": "test", "path": "\/a~1b", "value": 1 }, { "op": "test", "path": "\/c%d", "value": 2 }, { "op": "test", "path": "\/e^f", "value": 3 }, { "op": "test", "path": "\/g|h", "value": 4 }, { "op": "test", "path": "\/i\\j", "value": 5 }, { "op": "test", "path": "\/k\"l", "value": 6 }, { "op": "test", "path": "\/ ", "value": 7 }, { "op": "test", "path": "\/m~0n", "value": 8 } ]' : OK
Testing 'Move to same location has no effect', doc '{ "foo": 1 }' patch '[ { "op": "move", "from": "\/foo", "path": "\/foo" } ]' : OK
Testing '(null)', doc '{ "foo": 1, "baz": [ { "qux": "hello" } ] }' patch '[ { "op": "move", "from": "\/foo", "path": "\/bar" } ]' : OK
Testing '(null)', doc '{ "baz": [ { "qux": "hello" } ], "bar": 1 }' patch '[ { "op": "move", "from": "\/baz\/0\/qux", "path": "\/baz\/1" } ]' : OK
Testing '(null)', doc '{ "baz": [ { "qux": "hello" } ], "bar": 1 }' patch '[ { "op": "copy", "from": "\/baz\/0", "path": "\/boo" } ]' : OK
Testing 'replacing the root of the document is possible with add', doc '{ "foo": "bar" }' patch '[ { "op": "add", "path": "", "value": { "baz": "qux" } } ]' : OK
Testing 'Adding to "/-" adds to the end of the array', doc '[ 1, 2 ]' patch '[ { "op": "add", "path": "\/-", "value": { "foo": [ "bar", "baz" ] } } ]' : OK
Testing 'Adding to "/-" adds to the end of the array, even n levels down', doc '[ 1, 2, [ 3, [ 4, 5 ] ] ]' patch '[ { "op": "add", "path": "\/2\/1\/-", "value": { "foo": [ "bar", "baz" ] } } ]' : OK
Testing 'test remove with bad number should fail', doc '{ "foo": 1, "baz": [ { "qux": "hello" } ] }' patch '[ { "op": "remove", "path": "\/baz\/1e0\/qux" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Invalid path field
Testing 'test remove on array', doc '[ 1, 2, 3, 4 ]' patch '[ { "op": "remove", "path": "\/0" } ]' : OK
Testing 'test repeated removes', doc '[ 1, 2, 3, 4 ]' patch '[ { "op": "remove", "path": "\/1" }, { "op": "remove", "path": "\/2" } ]' : OK
Testing 'test remove with bad index should fail', doc '[ 1, 2, 3, 4 ]' patch '[ { "op": "remove", "path": "\/1e0" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Invalid path field
Testing 'test replace with bad number should fail', doc '[ "" ]' patch '[ { "op": "replace", "path": "\/1e0", "value": false } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Invalid path field
Testing 'test copy with bad number should fail', doc '{ "baz": [ 1, 2, 3 ], "bar": 1 }' patch '[ { "op": "copy", "from": "\/baz\/1e0", "path": "\/boo" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Invalid from field
Testing 'test move with bad number should fail', doc '{ "foo": 1, "baz": [ 1, 2, 3, 4 ] }' patch '[ { "op": "move", "from": "\/baz\/1e0", "path": "\/foo" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Invalid from field
Testing 'test add with bad number should fail', doc '[ "foo", "sil" ]' patch '[ { "op": "add", "path": "\/1e0", "value": "bar" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Failed to set value at path referenced by 'path' field
Testing 'missing 'path' parameter', doc '{ }' patch '[ { "op": "add", "value": "bar" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Patch object does not contain 'path' field
Testing ''path' parameter with null value', doc '{ }' patch '[ { "op": "add", "path": null, "value": "bar" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Failed to set value at path referenced by 'path' field
Testing 'invalid JSON Pointer token', doc '{ }' patch '[ { "op": "add", "path": "foo", "value": "bar" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Failed to set value at path referenced by 'path' field
Testing 'missing 'value' parameter to add', doc '[ 1 ]' patch '[ { "op": "add", "path": "\/-" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Patch object does not contain a 'value' field
Testing 'missing 'value' parameter to replace', doc '[ 1 ]' patch '[ { "op": "replace", "path": "\/0" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Patch object does not contain a 'value' field
Testing 'missing 'value' parameter to test', doc '[ null ]' patch '[ { "op": "test", "path": "\/0" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Patch object does not contain a 'value' field
Testing 'missing value parameter to test - where undef is falsy', doc '[ false ]' patch '[ { "op": "test", "path": "\/0" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Patch object does not contain a 'value' field
Testing 'missing from parameter to copy', doc '[ 1 ]' patch '[ { "op": "copy", "path": "\/-" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Patch does not contain a 'from' field
Testing 'missing from location to copy', doc '{ "foo": 1 }' patch '[ { "op": "copy", "from": "\/bar", "path": "\/foo" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=ENOENT at patch idx 0: Did not find element referenced by from field
Testing 'missing from parameter to move', doc '{ "foo": 1 }' patch '[ { "op": "move", "path": "" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Patch does not contain a 'from' field
Testing 'missing from location to move', doc '{ "foo": 1 }' patch '[ { "op": "move", "from": "\/bar", "path": "\/foo" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=ENOENT at patch idx 0: Did not find element referenced by from field
Testing 'duplicate ops, json-c parses this as op:move', doc '{ "foo": "bar" }' patch '[ { "op": "move", "path": "\/baz", "value": "qux", "from": "\/foo" } ]' : OK
Testing 'unrecognized op should fail', doc '{ "foo": 1 }' patch '[ { "op": "spam", "path": "\/foo", "value": 1 } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Patch object has invalid 'op' field
Testing 'test with bad array number that has leading zeros', doc '[ "foo", "bar" ]' patch '[ { "op": "test", "path": "\/00", "value": "foo" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Invalid path field
Testing 'test with bad array number that has leading zeros', doc '[ "foo", "bar" ]' patch '[ { "op": "test", "path": "\/01", "value": "bar" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=EINVAL at patch idx 0: Invalid path field
Testing 'Removing nonexistent field', doc '{ "foo": "bar" }' patch '[ { "op": "remove", "path": "\/baz" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=ENOENT at patch idx 0: Did not find element referenced by path field
Testing 'Removing deep nonexistent path', doc '{ "foo": "bar" }' patch '[ { "op": "remove", "path": "\/missing1\/missing2" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=ENOENT at patch idx 0: Did not find element referenced by path field
Testing 'Removing nonexistent index', doc '[ "foo", "bar" ]' patch '[ { "op": "remove", "path": "\/2" } ]' : OK
=> json_patch_apply failed as expected: ERRNO=ENOENT at patch idx 0: Did not find element referenced by path field
Testing 'Patch with different capitalisation than doc', doc '{ "foo": "bar" }' patch '[ { "op": "add", "path": "\/FOO", "value": "BAR" } ]' : OK

View File

@@ -1,17 +0,0 @@
#!/bin/sh
export _JSON_C_STRERROR_ENABLE=1
# Common definitions
if test -z "$srcdir"; then
srcdir="${0%/*}"
test "$srcdir" = "$0" && srcdir=.
test -z "$srcdir" && srcdir=.
fi
. "$srcdir/test-defs.sh"
filename=$(basename "$0")
filename="${filename%.*}"
run_output_test $filename "$srcdir"
exit $?

View File

@@ -269,22 +269,6 @@ static void test_example_set(void)
printf("%s\n", json_object_get_string(jo1)); printf("%s\n", json_object_get_string(jo1));
json_object_put(jo1); json_object_put(jo1);
jo1 = json_tokener_parse("[0, 1, 2, 3]");
jo2 = json_tokener_parse("[0, 1, 2, 3, null, null, null, 7]");
assert(0 == json_pointer_set(&jo1, "/7", json_object_new_int(7)));
assert(1 == json_object_equal(jo1, jo2));
json_object_put(jo1);
jo1 = json_tokener_parse("[0, 1, 2, 3]");
assert(0 == json_pointer_setf(&jo1, json_object_new_int(7), "/%u", 7));
assert(1 == json_object_equal(jo1, jo2));
json_object_put(jo1);
json_object_put(jo2);
} }
static void test_wrong_inputs_set(void) static void test_wrong_inputs_set(void)

View File

@@ -113,9 +113,6 @@ static void test_basic_parse(void)
single_basic_parse("\"\\udd27\"", 0); single_basic_parse("\"\\udd27\"", 0);
// Test with a "short" high surrogate // Test with a "short" high surrogate
single_basic_parse("[9,'\\uDAD", 0); single_basic_parse("[9,'\\uDAD", 0);
single_basic_parse("\"[9,'\\uDAD\"", 0);
// Test with a supplemental character that looks like a high surrogate
single_basic_parse("\"\\uD836\\uDE87\"", 0);
single_basic_parse("null", 0); single_basic_parse("null", 0);
single_basic_parse("NaN", 0); single_basic_parse("NaN", 0);
single_basic_parse("-NaN", 0); /* non-sensical, returns null */ single_basic_parse("-NaN", 0); /* non-sensical, returns null */
@@ -300,7 +297,6 @@ struct incremental_step
{"d", -1, -1, json_tokener_continue, 0, 0}, {"d", -1, -1, json_tokener_continue, 0, 0},
{"1", -1, -1, json_tokener_continue, 0, 0}, {"1", -1, -1, json_tokener_continue, 0, 0},
{"e\"", -1, -1, json_tokener_success, 1, 0}, {"e\"", -1, -1, json_tokener_success, 1, 0},
/* parse two char at every time */ /* parse two char at every time */
{"\"\\u", -1, -1, json_tokener_continue, 0, 0}, {"\"\\u", -1, -1, json_tokener_continue, 0, 0},
{"d8", -1, -1, json_tokener_continue, 0, 0}, {"d8", -1, -1, json_tokener_continue, 0, 0},
@@ -326,20 +322,10 @@ struct incremental_step
{"\"fff \\ud83d\\ude", -1, -1, json_tokener_continue, 0, 0}, {"\"fff \\ud83d\\ude", -1, -1, json_tokener_continue, 0, 0},
{"00 bar\"", -1, -1, json_tokener_success, 1, 0}, {"00 bar\"", -1, -1, json_tokener_success, 1, 0},
/* Check a utf-8 char (a+umlaut) that has bytes that look negative when
char are signed (see also control char check below) */
{"\"\xc3\xa4\"", -1, -1, json_tokener_success, 1, 0},
{"\"\xc3\xa4\"", -1, -1, json_tokener_success, 1, JSON_TOKENER_STRICT},
/* Check that json_tokener_reset actually resets */ /* Check that json_tokener_reset actually resets */
{"{ \"foo", -1, -1, json_tokener_continue, 1, 0}, {"{ \"foo", -1, -1, json_tokener_continue, 1, 0},
{": \"bar\"}", -1, 0, json_tokener_error_parse_unexpected, 1, 0}, {": \"bar\"}", -1, 0, json_tokener_error_parse_unexpected, 1, 0},
/* Check a supplemental code point that looks like a high surrogate */
{"\"\\uD836", -1, -1, json_tokener_continue, 0, 0},
{"\\uDE87", -1, -1, json_tokener_continue, 0, 0},
{"\"", -1, -1, json_tokener_success, 1, 0},
/* Check incremental parsing with trailing characters */ /* Check incremental parsing with trailing characters */
{"{ \"foo", -1, -1, json_tokener_continue, 0, 0}, {"{ \"foo", -1, -1, json_tokener_continue, 0, 0},
{"\": {\"bar", -1, -1, json_tokener_continue, 0, 0}, {"\": {\"bar", -1, -1, json_tokener_continue, 0, 0},
@@ -408,8 +394,8 @@ struct incremental_step
{"Infinity", 9, 8, json_tokener_success, 1, 0}, {"Infinity", 9, 8, json_tokener_success, 1, 0},
{"infinity", 9, 8, json_tokener_success, 1, 0}, {"infinity", 9, 8, json_tokener_success, 1, 0},
{"infinity", 9, 0, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT},
{"-infinity", 10, 9, json_tokener_success, 1, 0}, {"-infinity", 10, 9, json_tokener_success, 1, 0},
{"infinity", 9, 0, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT},
{"-infinity", 10, 1, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT}, {"-infinity", 10, 1, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT},
{"inf", 3, 3, json_tokener_continue, 0, 0}, {"inf", 3, 3, json_tokener_continue, 0, 0},
@@ -476,15 +462,12 @@ struct incremental_step
{"[18446744073709551616]", 23, 21, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, {"[18446744073709551616]", 23, 21, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT},
/* XXX this seems like a bug, should fail with _error_parse_number instead */ /* XXX this seems like a bug, should fail with _error_parse_number instead */
{"18446744073709551616", 21, 20, json_tokener_success, 1, 0},
{"18446744073709551616", 21, 20, json_tokener_error_parse_eof, 1, JSON_TOKENER_STRICT}, {"18446744073709551616", 21, 20, json_tokener_error_parse_eof, 1, JSON_TOKENER_STRICT},
/* Exceeding integer limits as double parse OK */ /* Exceeding integer limits as double parse OK */
{"[9223372036854775808.0]", 24, 23, json_tokener_success, 1, 0}, {"[9223372036854775808.0]", 24, 23, json_tokener_success, 1, 0},
{"[-9223372036854775809.0]", 25, 24, json_tokener_success, 1, 0},
{"[-9223372036854775809.0]", 25, 24, json_tokener_success, 1, JSON_TOKENER_STRICT}, {"[-9223372036854775809.0]", 25, 24, json_tokener_success, 1, JSON_TOKENER_STRICT},
{"[18446744073709551615.0]", 25, 24, json_tokener_success, 1, 0}, {"[18446744073709551615.0]", 25, 24, json_tokener_success, 1, 0},
{"[18446744073709551616.0]", 25, 24, json_tokener_success, 1, 0},
{"[18446744073709551616.0]", 25, 24, json_tokener_success, 1, JSON_TOKENER_STRICT}, {"[18446744073709551616.0]", 25, 24, json_tokener_success, 1, JSON_TOKENER_STRICT},
/* offset=1 because "n" is the start of "null". hmm... */ /* offset=1 because "n" is the start of "null". hmm... */
@@ -541,7 +524,6 @@ struct incremental_step
{"\"\\a\"", -1, 2, json_tokener_error_parse_string, 1, 0}, {"\"\\a\"", -1, 2, json_tokener_error_parse_string, 1, 0},
/* Check '\'' in strict model */ /* Check '\'' in strict model */
{"\'foo\'", -1, 5, json_tokener_success, 1, 0},
{"\'foo\'", -1, 0, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT}, {"\'foo\'", -1, 0, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT},
/* Parse array/object */ /* Parse array/object */
@@ -553,7 +535,7 @@ struct incremental_step
{"{\"a\":}", -1, 5, json_tokener_error_parse_unexpected, 1, 0}, {"{\"a\":}", -1, 5, json_tokener_error_parse_unexpected, 1, 0},
{"{\"a\":1,\"a\":2}", -1, -1, json_tokener_success, 1, 0}, {"{\"a\":1,\"a\":2}", -1, -1, json_tokener_success, 1, 0},
{"\"a\":1}", -1, 3, json_tokener_success, 1, 0}, {"\"a\":1}", -1, 3, json_tokener_success, 1, 0},
{"{\"a\":1", -1, -1, json_tokener_continue, 1, 0}, //} {"{\"a\":1", -1, -1, json_tokener_continue, 1, 0},
{"[,]", -1, 1, json_tokener_error_parse_unexpected, 1, 0}, {"[,]", -1, 1, json_tokener_error_parse_unexpected, 1, 0},
{"[,1]", -1, 1, json_tokener_error_parse_unexpected, 1, 0}, {"[,1]", -1, 1, json_tokener_error_parse_unexpected, 1, 0},
@@ -562,10 +544,9 @@ struct incremental_step
* in what we accept (up to a point). * in what we accept (up to a point).
*/ */
{"[1,2,3,]", -1, -1, json_tokener_success, 0, 0}, {"[1,2,3,]", -1, -1, json_tokener_success, 0, 0},
{"[1,2,3,]", -1, 7, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT},
{"[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0, 0}, {"[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0, 0},
{"[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0, JSON_TOKENER_STRICT},
{"[1,2,3,]", -1, 7, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT},
{"{\"a\":1,}", -1, 7, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT}, {"{\"a\":1,}", -1, 7, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT},
// utf-8 test // utf-8 test
@@ -614,80 +595,6 @@ struct incremental_step
{"\x7b\x22\x31\x81\x22\x3a\x31\x7d", -1, 3, json_tokener_error_parse_utf8_string, 1, {"\x7b\x22\x31\x81\x22\x3a\x31\x7d", -1, 3, json_tokener_error_parse_utf8_string, 1,
JSON_TOKENER_VALIDATE_UTF8}, JSON_TOKENER_VALIDATE_UTF8},
// Note, current asciiz APIs can't parse \x00, skip it
{ "\"0\x01\x02\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
"\x10\x11\x12\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\"",
-1, -1, json_tokener_success, 1, 0 },
{ "{\"0\x01\x02\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
"\x10\x11\x12\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\":1}",
-1, -1, json_tokener_success, 1, 0 },
// Test control chars again, this time in strict mode, which should fail
{ "\"\x01\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x02\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x03\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x04\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x05\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x06\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x07\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x08\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x09\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x0a\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x0b\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x0c\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x0d\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x0e\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x0f\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x10\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x11\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x12\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x13\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x14\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x15\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x16\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x17\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x18\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x19\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x1a\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x1b\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x1c\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x1d\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x1e\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "\"\x1f\"", -1, 1, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x01\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x02\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x03\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x04\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x05\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x06\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x07\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x08\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x09\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x0a\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x0b\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x0c\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x0d\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x0e\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x0f\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x10\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x11\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x12\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x13\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x14\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x15\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x16\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x17\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x18\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x19\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x1a\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x1b\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x1c\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x1d\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x1e\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{ "{\"\x1f\":1}", -1, 2, json_tokener_error_parse_string, 1, JSON_TOKENER_STRICT },
{NULL, -1, -1, json_tokener_success, 0, 0}, {NULL, -1, -1, json_tokener_success, 0, 0},
}; };
@@ -711,7 +618,7 @@ static void test_incremental_parse(void)
printf("json_tokener_parse(%s) ... ", string_to_parse); printf("json_tokener_parse(%s) ... ", string_to_parse);
new_obj = json_tokener_parse(string_to_parse); new_obj = json_tokener_parse(string_to_parse);
if (new_obj == NULL) if (new_obj == NULL)
printf("%s", "got error as expected\n"); puts("got error as expected");
/* test incremental parsing in various forms */ /* test incremental parsing in various forms */
tok = json_tokener_new(); tok = json_tokener_new();

View File

@@ -13,8 +13,6 @@ new_obj.to_string("\ud840\u4e16")="<22>世"
new_obj.to_string("\ud840")="<22>" new_obj.to_string("\ud840")="<22>"
new_obj.to_string("\udd27")="<22>" new_obj.to_string("\udd27")="<22>"
new_obj.to_string([9,'\uDAD)=null new_obj.to_string([9,'\uDAD)=null
new_obj.to_string("[9,'\uDAD")=null
new_obj.to_string("\uD836\uDE87")="𝪇"
new_obj.to_string(null)=null new_obj.to_string(null)=null
new_obj.to_string(NaN)=NaN new_obj.to_string(NaN)=NaN
new_obj.to_string(-NaN)=null new_obj.to_string(-NaN)=null
@@ -136,13 +134,8 @@ json_tokener_parse_ex(tok, "fff \ud834\udd, 15) ... OK: got correct error: cont
json_tokener_parse_ex(tok, 1e bar" , 7) ... OK: got object of type [string]: "fff 𝄞 bar" json_tokener_parse_ex(tok, 1e bar" , 7) ... OK: got object of type [string]: "fff 𝄞 bar"
json_tokener_parse_ex(tok, "fff \ud83d\ude, 15) ... OK: got correct error: continue json_tokener_parse_ex(tok, "fff \ud83d\ude, 15) ... OK: got correct error: continue
json_tokener_parse_ex(tok, 00 bar" , 7) ... OK: got object of type [string]: "fff 😀 bar" json_tokener_parse_ex(tok, 00 bar" , 7) ... OK: got object of type [string]: "fff 😀 bar"
json_tokener_parse_ex(tok, "ä" , 4) ... OK: got object of type [string]: "ä"
json_tokener_parse_ex(tok, "ä" , 4) ... OK: got object of type [string]: "ä"
json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue
json_tokener_parse_ex(tok, : "bar"} , 8) ... OK: got correct error: unexpected character json_tokener_parse_ex(tok, : "bar"} , 8) ... OK: got correct error: unexpected character
json_tokener_parse_ex(tok, "\uD836 , 7) ... OK: got correct error: continue
json_tokener_parse_ex(tok, \uDE87 , 6) ... OK: got correct error: continue
json_tokener_parse_ex(tok, " , 1) ... OK: got object of type [string]: "𝪇"
json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue
json_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue json_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue
json_tokener_parse_ex(tok, ":13}}XXXX , 10) ... OK: got object of type [object]: { "foo": { "bar": 13 } } json_tokener_parse_ex(tok, ":13}}XXXX , 10) ... OK: got object of type [object]: { "foo": { "bar": 13 } }
@@ -184,8 +177,8 @@ json_tokener_parse_ex(tok, null , 4) ... OK: got correct error: continu
json_tokener_parse_ex(tok, null , 5) ... OK: got object of type [null]: null json_tokener_parse_ex(tok, null , 5) ... OK: got object of type [null]: null
json_tokener_parse_ex(tok, Infinity , 9) ... OK: got object of type [double]: Infinity json_tokener_parse_ex(tok, Infinity , 9) ... OK: got object of type [double]: Infinity
json_tokener_parse_ex(tok, infinity , 9) ... OK: got object of type [double]: Infinity json_tokener_parse_ex(tok, infinity , 9) ... OK: got object of type [double]: Infinity
json_tokener_parse_ex(tok, infinity , 9) ... OK: got correct error: unexpected character
json_tokener_parse_ex(tok, -infinity , 10) ... OK: got object of type [double]: -Infinity json_tokener_parse_ex(tok, -infinity , 10) ... OK: got object of type [double]: -Infinity
json_tokener_parse_ex(tok, infinity , 9) ... OK: got correct error: unexpected character
json_tokener_parse_ex(tok, -infinity , 10) ... OK: got correct error: unexpected character json_tokener_parse_ex(tok, -infinity , 10) ... OK: got correct error: unexpected character
json_tokener_parse_ex(tok, inf , 3) ... OK: got correct error: continue json_tokener_parse_ex(tok, inf , 3) ... OK: got correct error: continue
json_tokener_parse_ex(tok, inity , 6) ... OK: got object of type [double]: Infinity json_tokener_parse_ex(tok, inity , 6) ... OK: got object of type [double]: Infinity
@@ -225,14 +218,11 @@ json_tokener_parse_ex(tok, [-9223372036854775809], 23) ... OK: got correct erro
json_tokener_parse_ex(tok, [18446744073709551615], 23) ... OK: got object of type [array]: [ 18446744073709551615 ] json_tokener_parse_ex(tok, [18446744073709551615], 23) ... OK: got object of type [array]: [ 18446744073709551615 ]
json_tokener_parse_ex(tok, [18446744073709551616], 23) ... OK: got object of type [array]: [ 18446744073709551615 ] json_tokener_parse_ex(tok, [18446744073709551616], 23) ... OK: got object of type [array]: [ 18446744073709551615 ]
json_tokener_parse_ex(tok, [18446744073709551616], 23) ... OK: got correct error: number expected json_tokener_parse_ex(tok, [18446744073709551616], 23) ... OK: got correct error: number expected
json_tokener_parse_ex(tok, 18446744073709551616, 21) ... OK: got object of type [int]: 18446744073709551615
json_tokener_parse_ex(tok, 18446744073709551616, 21) ... OK: got correct error: unexpected end of data json_tokener_parse_ex(tok, 18446744073709551616, 21) ... OK: got correct error: unexpected end of data
json_tokener_parse_ex(tok, [9223372036854775808.0], 24) ... OK: got object of type [array]: [ 9223372036854775808.0 ] json_tokener_parse_ex(tok, [9223372036854775808.0], 24) ... OK: got object of type [array]: [ 9223372036854775808.0 ]
json_tokener_parse_ex(tok, [-9223372036854775809.0], 25) ... OK: got object of type [array]: [ -9223372036854775809.0 ] json_tokener_parse_ex(tok, [-9223372036854775809.0], 25) ... OK: got object of type [array]: [ -9223372036854775809.0 ]
json_tokener_parse_ex(tok, [-9223372036854775809.0], 25) ... OK: got object of type [array]: [ -9223372036854775809.0 ]
json_tokener_parse_ex(tok, [18446744073709551615.0], 25) ... OK: got object of type [array]: [ 18446744073709551615.0 ] json_tokener_parse_ex(tok, [18446744073709551615.0], 25) ... OK: got object of type [array]: [ 18446744073709551615.0 ]
json_tokener_parse_ex(tok, [18446744073709551616.0], 25) ... OK: got object of type [array]: [ 18446744073709551616.0 ] json_tokener_parse_ex(tok, [18446744073709551616.0], 25) ... OK: got object of type [array]: [ 18446744073709551616.0 ]
json_tokener_parse_ex(tok, [18446744073709551616.0], 25) ... OK: got object of type [array]: [ 18446744073709551616.0 ]
json_tokener_parse_ex(tok, noodle , 7) ... OK: got correct error: null expected json_tokener_parse_ex(tok, noodle , 7) ... OK: got correct error: null expected
json_tokener_parse_ex(tok, naodle , 7) ... OK: got correct error: null expected json_tokener_parse_ex(tok, naodle , 7) ... OK: got correct error: null expected
json_tokener_parse_ex(tok, track , 6) ... OK: got correct error: boolean expected json_tokener_parse_ex(tok, track , 6) ... OK: got correct error: boolean expected
@@ -260,7 +250,6 @@ json_tokener_parse_ex(tok, "\t" , 4) ... OK: got object of type [string
json_tokener_parse_ex(tok, "\/" , 4) ... OK: got object of type [string]: "\/" json_tokener_parse_ex(tok, "\/" , 4) ... OK: got object of type [string]: "\/"
json_tokener_parse_ex(tok, "/" , 3) ... OK: got object of type [string]: "\/" json_tokener_parse_ex(tok, "/" , 3) ... OK: got object of type [string]: "\/"
json_tokener_parse_ex(tok, "\a" , 4) ... OK: got correct error: invalid string sequence json_tokener_parse_ex(tok, "\a" , 4) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, 'foo' , 5) ... OK: got object of type [string]: "foo"
json_tokener_parse_ex(tok, 'foo' , 5) ... OK: got correct error: unexpected character json_tokener_parse_ex(tok, 'foo' , 5) ... OK: got correct error: unexpected character
json_tokener_parse_ex(tok, [1,2,3] , 7) ... OK: got object of type [array]: [ 1, 2, 3 ] json_tokener_parse_ex(tok, [1,2,3] , 7) ... OK: got object of type [array]: [ 1, 2, 3 ]
json_tokener_parse_ex(tok, [1,2,3} , 7) ... OK: got correct error: array value separator ',' expected json_tokener_parse_ex(tok, [1,2,3} , 7) ... OK: got correct error: array value separator ',' expected
@@ -274,9 +263,8 @@ json_tokener_parse_ex(tok, {"a":1 , 6) ... OK: got correct error: continu
json_tokener_parse_ex(tok, [,] , 3) ... OK: got correct error: unexpected character json_tokener_parse_ex(tok, [,] , 3) ... OK: got correct error: unexpected character
json_tokener_parse_ex(tok, [,1] , 4) ... OK: got correct error: unexpected character json_tokener_parse_ex(tok, [,1] , 4) ... OK: got correct error: unexpected character
json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got object of type [array]: [ 1, 2, 3 ] json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got object of type [array]: [ 1, 2, 3 ]
json_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character
json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got correct error: unexpected character json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got correct error: unexpected character
json_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character
json_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character
json_tokener_parse_ex(tok, {"a":1,} , 8) ... OK: got correct error: unexpected character json_tokener_parse_ex(tok, {"a":1,} , 8) ... OK: got correct error: unexpected character
json_tokener_parse_ex(tok, "123asc$%&" , 11) ... OK: got object of type [string]: "123asc$%&" json_tokener_parse_ex(tok, "123asc$%&" , 11) ... OK: got object of type [string]: "123asc$%&"
json_tokener_parse_ex(tok, "123asc$%&" , 11) ... OK: got object of type [string]: "123asc$%&" json_tokener_parse_ex(tok, "123asc$%&" , 11) ... OK: got object of type [string]: "123asc$%&"
@@ -300,73 +288,5 @@ json_tokener_parse_ex(tok, "\ud855
json_tokener_parse_ex(tok, "\ud0031<33>" , 10) ... OK: got correct error: invalid utf-8 string json_tokener_parse_ex(tok, "\ud0031<33>" , 10) ... OK: got correct error: invalid utf-8 string
json_tokener_parse_ex(tok, 11<31>11 , 5) ... OK: got correct error: invalid utf-8 string json_tokener_parse_ex(tok, 11<31>11 , 5) ... OK: got correct error: invalid utf-8 string
json_tokener_parse_ex(tok, {"1<>":1} , 8) ... OK: got correct error: invalid utf-8 string json_tokener_parse_ex(tok, {"1<>":1} , 8) ... OK: got correct error: invalid utf-8 string
json_tokener_parse_ex(tok, "0 End Incremental Tests OK=198 ERROR=0
", 36) ... OK: got object of type [string]: "0\u0001\u0002\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f"
json_tokener_parse_ex(tok, {"0
":1}, 40) ... OK: got object of type [object]: { "0\u0001\u0002\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f": 1 }
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, " " , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "
" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, " " , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, " " , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "
" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, "" , 3) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {" ":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"
":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {" ":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {" ":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"
":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
json_tokener_parse_ex(tok, {"":1} , 7) ... OK: got correct error: invalid string sequence
================================== ==================================

View File

@@ -1,249 +0,0 @@
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "json.h"
static const char *input_json_str = "{ "
"'foo': ['bar', 'baz'], "
"'': 0, "
"'a/b': 1, "
"'c%d': 2, "
"'e^f': 3, "
"'g|h': 4, "
"'i\\\\j': 5, "
"'k\\\"l': 6, "
"' ': 7, "
"'m~n': 8 "
"}";
static void test_example_set_with_limit_index(void)
{
struct json_object *jo2, *jo1 = json_tokener_parse(input_json_str);
size_t limit_index = 10;
// testing if json_pointer_set_with_limit_index() works as json_pointer_set()
assert(jo1 != NULL);
printf("PASSED - SET_WITH_LIMIT - LOADED TEST JSON\n");
printf("%s\n", json_object_get_string(jo1));
assert(0 == json_pointer_set_with_limit_index(&jo1, "/foo/1", json_object_new_string("cod"), limit_index));
assert(0 == strcmp("cod", json_object_get_string(json_object_array_get_idx(
json_object_object_get(jo1, "foo"), 1))));
printf("PASSED - SET_WITH_LIMIT - 'cod' in /foo/1\n");
assert(0 != json_pointer_set_with_limit_index(&jo1, "/fud/gaw", (jo2 = json_tokener_parse("[1,2,3]")), limit_index));
assert(errno == ENOENT);
printf("PASSED - SET_WITH_LIMIT - non-existing /fud/gaw\n");
assert(0 == json_pointer_set_with_limit_index(&jo1, "/fud", json_object_new_object(), limit_index));
printf("PASSED - SET_WITH_LIMIT - /fud == {}\n");
assert(0 == json_pointer_set_with_limit_index(&jo1, "/fud/gaw", jo2, limit_index)); /* re-using jo2 from above */
printf("PASSED - SET_WITH_LIMIT - /fug/gaw == [1,2,3]\n");
assert(0 == json_pointer_set_with_limit_index(&jo1, "/fud/gaw/0", json_object_new_int(0), limit_index));
assert(0 == json_pointer_setf(&jo1, json_object_new_int(0), "%s%s/%d", "/fud", "/gaw", 0));
printf("PASSED - SET_WITH_LIMIT - /fug/gaw == [0,2,3]\n");
assert(0 == json_pointer_set_with_limit_index(&jo1, "/fud/gaw/-", json_object_new_int(4), limit_index));
printf("PASSED - SET_WITH_LIMIT - /fug/gaw == [0,2,3,4]\n");
assert(0 == json_pointer_set_with_limit_index(&jo1, "/", json_object_new_int(9), limit_index));
printf("PASSED - SET_WITH_LIMIT - / == 9\n");
jo2 = json_tokener_parse(
"{ 'foo': [ 'bar', 'cod' ], '': 9, 'a/b': 1, 'c%d': 2, 'e^f': 3, 'g|h': 4, 'i\\\\j': "
"5, 'k\\\"l': 6, ' ': 7, 'm~n': 8, 'fud': { 'gaw': [ 0, 2, 3, 4 ] } }");
assert(json_object_equal(jo2, jo1));
printf("PASSED - SET_WITH_LIMIT - Final JSON is: %s\n", json_object_get_string(jo1));
json_object_put(jo2);
assert(0 == json_pointer_set_with_limit_index(&jo1, "", json_object_new_int(10), limit_index));
assert(10 == json_object_get_int(jo1));
printf("%s\n", json_object_get_string(jo1));
json_object_put(jo1);
jo1 = json_tokener_parse("[0, 1, 2, 3]");
jo2 = json_tokener_parse("[0, 1, 2, 3, null, null, null, 7]");
assert(0 == json_pointer_set_with_limit_index(&jo1, "/7", json_object_new_int(7), limit_index));
assert(1 == json_object_equal(jo1, jo2));
json_object_put(jo1);
jo1 = json_tokener_parse("[0, 1, 2, 3]");
assert(0 == json_pointer_setf(&jo1, json_object_new_int(7), "/%u", 7));
assert(1 == json_object_equal(jo1, jo2));
json_object_put(jo1);
json_object_put(jo2);
// testing with limit_index
jo1 = json_tokener_parse("{'foo': ['bar', 'baz']}");
jo2 = json_tokener_parse("{'foo': ['bar', 'cod']}");
assert(0 == json_pointer_set_with_limit_index(&jo1, "/foo/1", json_object_new_string("cod"), limit_index));
assert(json_object_equal(jo1, jo2));
printf("PASSED - SET_LIMIT - Set value within limit (/foo/1 with limit 10)\n");
assert(0 == json_pointer_set_with_limit_index(&jo1, "/bar", json_object_new_string("new_field"), limit_index));
printf("PASSED - SET_LIMIT - Set value on an object (limit is ignored)\n");
assert(0 == json_pointer_set_with_limit_index(&jo1, "/foo/20", json_object_new_string("big_index"), (size_t)-1));
printf("PASSED - SET_LIMIT - Set value with limit_index = -1 (no limit)\n");
json_object_put(jo1);
json_object_put(jo2);
}
static void test_wrong_inputs_set_with_limit_index(void)
{
struct json_object *jo2, *jo1 = json_tokener_parse(input_json_str);
size_t limit_index = 10;
// testing if json_pointer_set_with_limit_index() works as json_pointer_set()
assert(jo1 != NULL);
printf("PASSED - SET_WITH_LIMIT - LOADED TEST JSON\n");
printf("%s\n", json_object_get_string(jo1));
assert(0 != json_pointer_set_with_limit_index(NULL, NULL, NULL, limit_index));
assert(0 != json_pointer_set_with_limit_index(&jo1, NULL, NULL, limit_index));
printf("PASSED - SET_WITH_LIMIT - failed with NULL params for input json & path\n");
assert(0 != json_pointer_set_with_limit_index(&jo1, "foo/bar", (jo2 = json_object_new_string("cod")), limit_index));
printf("PASSED - SET_WITH_LIMIT - failed 'cod' with path 'foo/bar'\n");
json_object_put(jo2);
// assert(0 !=
// json_pointer_setf(&jo1, (jo2 = json_object_new_string("cod")), "%s", "foo/bar"));
// printf("PASSED - SET_WITH_LIMIT - failed 'cod' with path 'foo/bar'\n");
// json_object_put(jo2);
assert(0 != json_pointer_set_with_limit_index(&jo1, "0", (jo2 = json_object_new_string("cod")), limit_index));
printf("PASSED - SET_WITH_LIMIT - failed with invalid array index'\n");
json_object_put(jo2);
jo2 = json_object_new_string("whatever");
assert(0 != json_pointer_set_with_limit_index(&jo1, "/fud/gaw", jo2, limit_index));
assert(0 == json_pointer_set_with_limit_index(&jo1, "/fud", json_object_new_object(), limit_index));
assert(0 == json_pointer_set_with_limit_index(&jo1, "/fud/gaw", jo2, limit_index)); /* re-using jo2 from above */
// ownership of jo2 transferred into jo1
jo2 = json_object_new_int(0);
assert(0 != json_pointer_set_with_limit_index(&jo1, "/fud/gaw/0", jo2, limit_index));
json_object_put(jo2);
jo2 = json_object_new_int(0);
assert(0 != json_pointer_set_with_limit_index(&jo1, "/fud/gaw/", jo2, limit_index));
json_object_put(jo2);
printf("PASSED - SET_WITH_LIMIT - failed to set index to non-array\n");
// assert(0 == json_pointer_setf(&jo1, json_object_new_string("cod"), "%s", "\0"));
json_object_put(jo1);
// testing with limit_index
jo1 = json_tokener_parse("{'foo': ['bar', 'baz']}");
errno = 0;
jo2 = json_object_new_string("out_of_bounds");
assert(0 != json_pointer_set_with_limit_index(&jo1, "/foo/20", jo2, limit_index));
assert(errno == EINVAL);
printf("PASSED - SET_LIMIT - Failed to set index 20 with limit 10\n");
// The value object was not consumed, so we must put it.
json_object_put(jo2);
// corner case: setting an index that equals the limit (should be ok, as it's idx > max_idx)
errno = 0;
assert(0 == json_pointer_set_with_limit_index(&jo1, "/foo/10", json_object_new_string("at_the_limit"), limit_index));
printf("PASSED - SET_LIMIT - Succeeded to set index 10 with limit 10\n");
json_object_put(jo1);
}
// callback for testing json_pointer_set_with_cb()
static int test_cb_print_msg(json_object *parent, const char *key, size_t idx,
json_object *value, void *priv)
{
printf("PASSED - SET_WITH_CB - This callback is called\n");
json_object_put(value);
return 0;
}
// callback for testing json_pointer_set_with_cb() with rejection logic
static int test_cb_reject_logic(json_object *parent, const char *key, size_t idx,
json_object *value, void *priv)
{
// Reject any operation if the key is "reject"
if (key && strcmp(key, "reject") == 0)
{
printf("PASSED - SET_WITH_CB - Callback correctly identified key 'reject' to reject\n");
// Note: caller of json_pointer_set must free value
return -1;
}
json_object_put(value);
return 0;
}
static void test_set_with_cb(void)
{
struct json_object *jo2, *jo1 = json_tokener_parse(input_json_str);
size_t limit_index = 5;
assert(jo1 != NULL);
printf("PASSED - SET_WITH_CB - LOADED TEST JSON\n");
printf("%s\n", json_object_get_string(jo1));
assert(0 == json_pointer_set_with_cb(&jo1, "/foo/1", json_object_new_string("cod"), test_cb_print_msg, 1, NULL));
printf("PASSED - SET_WITH_CB - callback test_cb_print_msg for /foo/1\n");
assert(0 == json_pointer_set_with_cb(&jo1, "/foo/4", json_object_new_string("in"), json_object_array_put_with_idx_limit_cb, 0, &limit_index));
printf("PASSED - SET_WITH_CB - callback json_object_array_put_with_idx_limit_cb for /foo/4 with limit_index 5\n");
assert(0 == json_pointer_set_with_cb(&jo1, "/foo/5", json_object_new_string("border"), json_object_array_put_with_idx_limit_cb, 0, &limit_index));
printf("PASSED - SET_WITH_CB - failed with callback json_object_array_put_with_idx_limit_cb for /foo/5 with limit_index 5\n");
assert(0 != json_pointer_set_with_cb(&jo1, "/foo/10", (jo2 = json_object_new_string("out")), json_object_array_put_with_idx_limit_cb, 0, &limit_index));
json_object_put(jo2);
assert(errno == EINVAL);
printf("PASSED - SET_WITH_CB - failed with callback json_object_array_put_with_idx_limit_cb for /foo/10 with limit_index 5\n");
assert(0 != json_pointer_set_with_cb(&jo1, "/foo/2", (jo2 = json_object_new_string("null_priv")), json_object_array_put_with_idx_limit_cb, 0, NULL));
json_object_put(jo2);
assert(errno == EFAULT);
printf("PASSED - SET_WITH_CB - failed with callback json_object_array_put_with_idx_limit_cb with NULL priv\n");
json_object_put(jo1);
jo1 = json_tokener_parse("{'foo': 'bar'}");
assert(jo1 != NULL);
assert(0 == json_pointer_set_with_cb(&jo1, "/foo", json_object_new_string("cod"), test_cb_print_msg, 1, NULL));
printf("PASSED - SET_WITH_CB - cb_handles_obj=1: callback was triggered for object operation\n");
assert(0 == json_pointer_set_with_cb(&jo1, "/new_key", json_object_new_string("new_value"), test_cb_print_msg, 0, NULL));
printf("PASSED - SET_WITH_CB - cb_handles_obj=0: callback was NOT triggered for object operation, default logic was used\n");
json_object_put(jo1);
// testing rejection logic callback
jo1 = json_tokener_parse("{'data': {} }");
assert(jo1 != NULL);
assert(0 == json_pointer_set_with_cb(&jo1, "/data/accept", json_object_new_string("accepted_value"), test_cb_reject_logic, 1, NULL));
printf("PASSED - SET_WITH_CB - Rejection callback approved an allowed key\n");
assert(0 != json_pointer_set_with_cb(&jo1, "/data/reject", (jo2 = json_object_new_string("rejected_value")), test_cb_reject_logic, 1, NULL));
json_object_put(jo2);
printf("PASSED - SET_WITH_CB - Rejection callback rejected a forbidden key\n");
json_object_put(jo1);
}
int main(int argc, char **argv)
{
test_example_set_with_limit_index();
test_wrong_inputs_set_with_limit_index();
test_set_with_cb();
return 0;
}

View File

@@ -1,36 +0,0 @@
PASSED - SET_WITH_LIMIT - LOADED TEST JSON
{ "foo": [ "bar", "baz" ], "": 0, "a\/b": 1, "c%d": 2, "e^f": 3, "g|h": 4, "i\\j": 5, "k\"l": 6, " ": 7, "m~n": 8 }
PASSED - SET_WITH_LIMIT - 'cod' in /foo/1
PASSED - SET_WITH_LIMIT - non-existing /fud/gaw
PASSED - SET_WITH_LIMIT - /fud == {}
PASSED - SET_WITH_LIMIT - /fug/gaw == [1,2,3]
PASSED - SET_WITH_LIMIT - /fug/gaw == [0,2,3]
PASSED - SET_WITH_LIMIT - /fug/gaw == [0,2,3,4]
PASSED - SET_WITH_LIMIT - / == 9
PASSED - SET_WITH_LIMIT - Final JSON is: { "foo": [ "bar", "cod" ], "": 9, "a\/b": 1, "c%d": 2, "e^f": 3, "g|h": 4, "i\\j": 5, "k\"l": 6, " ": 7, "m~n": 8, "fud": { "gaw": [ 0, 2, 3, 4 ] } }
10
PASSED - SET_LIMIT - Set value within limit (/foo/1 with limit 10)
PASSED - SET_LIMIT - Set value on an object (limit is ignored)
PASSED - SET_LIMIT - Set value with limit_index = -1 (no limit)
PASSED - SET_WITH_LIMIT - LOADED TEST JSON
{ "foo": [ "bar", "baz" ], "": 0, "a\/b": 1, "c%d": 2, "e^f": 3, "g|h": 4, "i\\j": 5, "k\"l": 6, " ": 7, "m~n": 8 }
PASSED - SET_WITH_LIMIT - failed with NULL params for input json & path
PASSED - SET_WITH_LIMIT - failed 'cod' with path 'foo/bar'
PASSED - SET_WITH_LIMIT - failed with invalid array index'
PASSED - SET_WITH_LIMIT - failed to set index to non-array
PASSED - SET_LIMIT - Failed to set index 20 with limit 10
PASSED - SET_LIMIT - Succeeded to set index 10 with limit 10
PASSED - SET_WITH_CB - LOADED TEST JSON
{ "foo": [ "bar", "baz" ], "": 0, "a\/b": 1, "c%d": 2, "e^f": 3, "g|h": 4, "i\\j": 5, "k\"l": 6, " ": 7, "m~n": 8 }
PASSED - SET_WITH_CB - This callback is called
PASSED - SET_WITH_CB - callback test_cb_print_msg for /foo/1
PASSED - SET_WITH_CB - callback json_object_array_put_with_idx_limit_cb for /foo/4 with limit_index 5
PASSED - SET_WITH_CB - failed with callback json_object_array_put_with_idx_limit_cb for /foo/5 with limit_index 5
PASSED - SET_WITH_CB - failed with callback json_object_array_put_with_idx_limit_cb for /foo/10 with limit_index 5
PASSED - SET_WITH_CB - failed with callback json_object_array_put_with_idx_limit_cb with NULL priv
PASSED - SET_WITH_CB - This callback is called
PASSED - SET_WITH_CB - cb_handles_obj=1: callback was triggered for object operation
PASSED - SET_WITH_CB - cb_handles_obj=0: callback was NOT triggered for object operation, default logic was used
PASSED - SET_WITH_CB - Rejection callback approved an allowed key
PASSED - SET_WITH_CB - Callback correctly identified key 'reject' to reject
PASSED - SET_WITH_CB - Rejection callback rejected a forbidden key

View File

@@ -1 +0,0 @@
test_basic.test

View File

@@ -2,11 +2,11 @@
#undef NDEBUG #undef NDEBUG
#endif #endif
#include "strerror_override.h" #include "strerror_override.h"
#ifdef _WIN32 #ifdef WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <io.h> #include <io.h>
#include <windows.h> #include <windows.h>
#endif /* defined(_WIN32) */ #endif /* defined(WIN32) */
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <stddef.h> #include <stddef.h>
@@ -27,9 +27,7 @@
static void test_read_valid_with_fd(const char *testdir); static void test_read_valid_with_fd(const char *testdir);
static void test_read_valid_nested_with_fd(const char *testdir); static void test_read_valid_nested_with_fd(const char *testdir);
static void test_read_nonexistant(void); static void test_read_nonexistant(void);
#ifndef _WIN32
static void test_read_closed(void); static void test_read_closed(void);
#endif
static void test_write_to_file(void); static void test_write_to_file(void);
static void stat_and_cat(const char *file); static void stat_and_cat(const char *file);
@@ -94,12 +92,7 @@ static void test_write_to_file(void)
static void stat_and_cat(const char *file) static void stat_and_cat(const char *file)
{ {
struct stat sb; struct stat sb;
int flags = O_RDONLY; int d = open(file, O_RDONLY);
#ifdef O_BINARY
// This fixes Windows which otherwise opens this in text mode and returns different counts
flags |= O_BINARY;
#endif
int d = open(file, flags);
if (d < 0) if (d < 0)
{ {
printf("FAIL: unable to open %s: %s\n", file, strerror(errno)); printf("FAIL: unable to open %s: %s\n", file, strerror(errno));
@@ -166,10 +159,7 @@ int main(int argc, char **argv)
test_read_valid_with_fd(testdir); test_read_valid_with_fd(testdir);
test_read_valid_nested_with_fd(testdir); test_read_valid_nested_with_fd(testdir);
test_read_nonexistant(); test_read_nonexistant();
#ifndef _WIN32
// Disabled because the Windows CRT causes a crash during this test that cannot be disabled/stopped/worked around
test_read_closed(); test_read_closed();
#endif
test_write_to_file(); test_write_to_file();
test_read_fd_equal(testdir); test_read_fd_equal(testdir);
return EXIT_SUCCESS; return EXIT_SUCCESS;
@@ -179,12 +169,8 @@ static void test_read_valid_with_fd(const char *testdir)
{ {
char filename[PATH_MAX]; char filename[PATH_MAX];
(void)snprintf(filename, sizeof(filename), "%s/valid.json", testdir); (void)snprintf(filename, sizeof(filename), "%s/valid.json", testdir);
int flags = O_RDONLY;
#ifdef O_BINARY int d = open(filename, O_RDONLY);
// This fixes Windows which otherwise opens this in text mode and returns different counts
flags |= O_BINARY;
#endif
int d = open(filename, flags);
if (d < 0) if (d < 0)
{ {
fprintf(stderr, "FAIL: unable to open %s: %s\n", filename, strerror(errno)); fprintf(stderr, "FAIL: unable to open %s: %s\n", filename, strerror(errno));
@@ -208,12 +194,8 @@ static void test_read_valid_nested_with_fd(const char *testdir)
{ {
char filename[PATH_MAX]; char filename[PATH_MAX];
(void)snprintf(filename, sizeof(filename), "%s/valid_nested.json", testdir); (void)snprintf(filename, sizeof(filename), "%s/valid_nested.json", testdir);
int flags = O_RDONLY;
#ifdef O_BINARY int d = open(filename, O_RDONLY);
// This fixes Windows which otherwise opens this in text mode and returns different counts
flags |= O_BINARY;
#endif
int d = open(filename, flags);
if (d < 0) if (d < 0)
{ {
fprintf(stderr, "FAIL: unable to open %s: %s\n", filename, strerror(errno)); fprintf(stderr, "FAIL: unable to open %s: %s\n", filename, strerror(errno));
@@ -268,7 +250,7 @@ static void test_read_nonexistant(void)
json_util_get_last_err()); json_util_get_last_err());
} }
} }
#ifndef _WIN32
static void test_read_closed(void) static void test_read_closed(void)
{ {
// Test reading from a closed fd // Test reading from a closed fd
@@ -276,7 +258,6 @@ static void test_read_closed(void)
if (d < 0) if (d < 0)
{ {
puts("FAIL: unable to open"); puts("FAIL: unable to open");
return;
} }
// Copy over to a fixed fd number so test output is consistent. // Copy over to a fixed fd number so test output is consistent.
int fixed_d = 10; int fixed_d = 10;
@@ -300,7 +281,6 @@ static void test_read_closed(void)
"expecting NULL, EBADF, got:NULL, %s\n", "expecting NULL, EBADF, got:NULL, %s\n",
json_util_get_last_err()); json_util_get_last_err());
} }
#endif
static void test_read_fd_equal(const char *testdir) static void test_read_fd_equal(const char *testdir)
{ {
@@ -308,12 +288,8 @@ static void test_read_fd_equal(const char *testdir)
(void)snprintf(filename, sizeof(filename), "%s/valid_nested.json", testdir); (void)snprintf(filename, sizeof(filename), "%s/valid_nested.json", testdir);
json_object *jso = json_object_from_file(filename); json_object *jso = json_object_from_file(filename);
int flags = O_RDONLY;
#ifdef O_BINARY int d = open(filename, O_RDONLY);
// This fixes Windows which otherwise opens this in text mode and returns different counts
flags |= O_BINARY;
#endif
int d = open(filename, flags);
if (d < 0) if (d < 0)
{ {
fprintf(stderr, "FAIL: unable to open %s: %s\n", filename, strerror(errno)); fprintf(stderr, "FAIL: unable to open %s: %s\n", filename, strerror(errno));

View File

@@ -8,9 +8,9 @@
#include "snprintf_compat.h" #include "snprintf_compat.h"
#ifndef _WIN32 #ifndef WIN32
#include <stdarg.h> #include <stdarg.h>
#endif /* !defined(_WIN32) */ #endif /* !defined(WIN32) */
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@@ -18,10 +18,10 @@
/* CAW: compliant version of vasprintf */ /* CAW: compliant version of vasprintf */
static int vasprintf(char **buf, const char *fmt, va_list ap) static int vasprintf(char **buf, const char *fmt, va_list ap)
{ {
#ifndef _WIN32 #ifndef WIN32
static char _T_emptybuffer = '\0'; static char _T_emptybuffer = '\0';
va_list ap2; va_list ap2;
#endif /* !defined(_WIN32) */ #endif /* !defined(WIN32) */
int chars; int chars;
char *b; char *b;
@@ -30,16 +30,16 @@ static int vasprintf(char **buf, const char *fmt, va_list ap)
return -1; return -1;
} }
#ifdef _WIN32 #ifdef WIN32
chars = _vscprintf(fmt, ap); chars = _vscprintf(fmt, ap);
#else /* !defined(_WIN32) */ #else /* !defined(WIN32) */
/* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite
* our buffer like on some 64bit sun systems... but hey, it's time to move on * our buffer like on some 64bit sun systems... but hey, it's time to move on
*/ */
va_copy(ap2, ap); va_copy(ap2, ap);
chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap2); chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap2);
va_end(ap2); va_end(ap2);
#endif /* defined(_WIN32) */ #endif /* defined(WIN32) */
if (chars < 0 || (size_t)chars + 1 > SIZE_MAX / sizeof(char)) if (chars < 0 || (size_t)chars + 1 > SIZE_MAX / sizeof(char))
{ {
return -1; return -1;