From bc5c17d2ffbbbafa4acc7390f3a0a960b3efb29c Mon Sep 17 00:00:00 2001 From: TizenOpenSource Date: Thu, 7 Dec 2023 17:57:36 +0900 Subject: [PATCH] Imported Upstream version 0.17 --- .clang-format | 2 + .editorconfig | 2 +- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .gitignore | 2 + .travis.yml | 56 +- AUTHORS | 41 + CMakeLists.txt | 191 +- ChangeLog | 101 +- README.html | 4 +- README.md | 119 +- RELEASE_CHECKLIST.txt | 49 +- abi-check.sh | 42 + apps/json_parse.c | 63 +- appveyor.yml | 122 +- arraylist.c | 25 + arraylist.h | 6 +- bench/README.bench.md | 2 +- cmake-configure | 10 + cmake/config.h.in | 15 + cmake/json_config.h.in | 3 + debug.h | 6 +- doc/Doxyfile | 2363 -------------------- doc/Doxyfile.in | 73 +- doc/html/README_8md.html | 8 +- doc/html/annotated.html | 16 +- doc/html/arraylist_8h.html | 44 +- doc/html/classes.html | 18 +- doc/html/deprecated.html | 32 +- doc/html/dir_71f13e590eb9d766c31051438785ada5.html | 98 - doc/html/dir_b62156a74b5a818be0c2ef9f85294b95.html | 62 + doc/html/files.html | 34 +- doc/html/functions.html | 25 +- doc/html/functions_vars.html | 25 +- doc/html/globals.html | 9 +- doc/html/globals_0x69.html | 85 + doc/html/globals_0x6a.html | 35 +- doc/html/globals_0x6c.html | 32 +- doc/html/globals_0x70.html | 6 +- doc/html/globals_0x73.html | 6 +- doc/html/globals_0x75.html | 85 + doc/html/globals_defs.html | 20 +- doc/html/globals_enum.html | 4 +- doc/html/globals_eval.html | 7 +- doc/html/globals_func.html | 47 +- doc/html/globals_type.html | 19 +- doc/html/globals_vars.html | 4 +- doc/html/index.html | 81 +- doc/html/issues__closed__for__0_813_8md.html | 8 +- doc/html/issues__closed__for__0_814_8md.html | 8 +- doc/html/issues__closed__for__0_815_8md.html | 57 + doc/html/issues__closed__for__0_816_8md.html | 57 + doc/html/issues__closed__for__0_817_8md.html | 57 + doc/html/json_8h.html | 8 +- doc/html/json__c__version_8h.html | 18 +- doc/html/json__inttypes_8h.html | 73 +- doc/html/json__object_8h.html | 168 +- doc/html/json__object__iterator_8h.html | 10 +- doc/html/json__patch_8h.html | 128 ++ doc/html/json__pointer_8h.html | 18 +- doc/html/json__pointer__private_8h.html | 174 ++ doc/html/json__tokener_8h.html | 16 +- doc/html/json__types_8h.html | 10 +- doc/html/json__util_8h.html | 20 +- doc/html/json__visit_8h.html | 10 +- doc/html/linkhash_8h.html | 337 ++- doc/html/md_README.html | 4 +- doc/html/md_issues_closed_for_0.html | 277 ++- doc/html/pages.html | 4 +- doc/html/printbuf_8h.html | 14 +- doc/html/structarray__list.html | 6 +- doc/html/structjson__object__iter.html | 6 +- doc/html/structjson__object__iterator.html | 6 +- doc/html/structjson__patch__error.html | 120 + doc/html/structjson__pointer__get__result.html | 123 + doc/html/structjson__tokener.html | 6 +- doc/html/structjson__tokener__srec.html | 6 +- doc/html/structlh__entry.html | 29 +- doc/html/structlh__table.html | 23 +- doc/html/structprintbuf.html | 6 +- fuzz/build.sh | 2 +- fuzz/tokener_parse_ex_fuzzer.cc | 8 +- issues_closed_for_0.15.md | 85 + issues_closed_for_0.16.md | 107 + issues_closed_for_0.17.md | 88 + json-c.sym | 13 + json.h => json.h.cmakein | 3 +- json_c_version.h | 8 +- json_inttypes.h | 13 + json_object.c | 271 ++- json_object.h | 69 +- json_object_iterator.c | 4 +- json_patch.c | 332 +++ json_patch.h | 80 + json_pointer.c | 149 +- json_pointer.h | 18 +- json_pointer_private.h | 43 + json_tokener.c | 221 +- json_tokener.h | 1 + json_types.h | 2 +- json_util.c | 66 +- json_util.h | 11 +- linkhash.c | 26 +- linkhash.h | 110 +- printbuf.c | 35 +- printbuf.h | 10 +- random_seed.c | 132 +- snprintf_compat.h | 2 +- strerror_override.c | 3 +- strerror_override_private.h | 14 - tests/CMakeLists.txt | 62 +- tests/json_patch_spec_tests.json | 233 ++ tests/json_patch_tests.json | 540 +++++ tests/parse_flags.c | 3 + tests/test1.c | 76 +- tests/test1.expected | 2 +- tests/test1Formatted_plain.expected | 2 +- tests/test1Formatted_pretty.expected | 4 +- tests/test1Formatted_spaced.expected | 2 +- tests/test1Formatted_spaced_pretty.expected | 4 +- ...est1Formatted_spaced_pretty_pretty_tab.expected | 4 +- tests/test2.c | 3 + tests/test4.c | 5 +- tests/testReplaceExisting.c | 3 + tests/test_cast.c | 15 +- tests/test_cast.expected | 35 + tests/test_charcase.c | 5 +- tests/test_compare.c | 5 +- tests/test_deep_copy.c | 6 +- tests/test_deep_copy.expected | 6 +- tests/test_double_serializer.c | 5 +- tests/test_float.c | 3 + tests/test_int_add.c | 3 + tests/test_int_get.c | 65 + tests/test_int_get.expected | 5 + tests/test_int_get.test | 1 + tests/test_json_patch.c | 127 ++ tests/test_json_patch.expected | 158 ++ tests/test_json_patch.test | 17 + tests/test_json_pointer.c | 18 +- tests/test_locale.c | 5 +- tests/test_null.c | 3 + tests/test_object_iterator.c | 3 + tests/test_parse.c | 360 +-- tests/test_parse.expected | 15 +- tests/test_parse_int64.c | 5 +- tests/test_printbuf.c | 7 +- tests/test_set_serializer.c | 6 +- tests/test_set_serializer.expected | 2 +- tests/test_set_value.c | 11 + tests/test_strerror.c | 13 + tests/test_strerror.expected | 2 + tests/test_strerror.test | 1 + tests/test_util_file.c | 20 +- tests/test_util_file.expected | 2 +- tests/test_visit.c | 3 + vasprintf_compat.h | 23 +- 156 files changed, 6114 insertions(+), 3618 deletions(-) create mode 100644 abi-check.sh delete mode 100644 doc/Doxyfile delete mode 100644 doc/html/dir_71f13e590eb9d766c31051438785ada5.html create mode 100644 doc/html/dir_b62156a74b5a818be0c2ef9f85294b95.html create mode 100644 doc/html/globals_0x69.html create mode 100644 doc/html/globals_0x75.html create mode 100644 doc/html/issues__closed__for__0_815_8md.html create mode 100644 doc/html/issues__closed__for__0_816_8md.html create mode 100644 doc/html/issues__closed__for__0_817_8md.html create mode 100644 doc/html/json__patch_8h.html create mode 100644 doc/html/json__pointer__private_8h.html create mode 100644 doc/html/structjson__patch__error.html create mode 100644 doc/html/structjson__pointer__get__result.html create mode 100644 issues_closed_for_0.15.md create mode 100644 issues_closed_for_0.16.md create mode 100644 issues_closed_for_0.17.md rename json.h => json.h.cmakein (94%) create mode 100644 json_patch.c create mode 100644 json_patch.h create mode 100644 json_pointer_private.h delete mode 100644 strerror_override_private.h create mode 100644 tests/json_patch_spec_tests.json create mode 100644 tests/json_patch_tests.json create mode 100644 tests/test_int_get.c create mode 100644 tests/test_int_get.expected create mode 120000 tests/test_int_get.test create mode 100644 tests/test_json_patch.c create mode 100644 tests/test_json_patch.expected create mode 100755 tests/test_json_patch.test create mode 100644 tests/test_strerror.c create mode 100644 tests/test_strerror.expected create mode 120000 tests/test_strerror.test diff --git a/.clang-format b/.clang-format index d6972be..365efb2 100644 --- a/.clang-format +++ b/.clang-format @@ -23,6 +23,8 @@ AllowShortFunctionsOnASingleLine: Empty BreakBeforeBraces: Custom # Control of individual brace wrapping cases. BraceWrapping: + # Wrap brackets inside of a case + AfterCaseLabel: true # Wrap class definition. AfterClass: true # Wrap control statements diff --git a/.editorconfig b/.editorconfig index 7a625d1..e7fd7e4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,5 +1,5 @@ # EditorConfig -# http://EditorConfig.org +# https://EditorConfig.org # top-most EditorConfig file root = true diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 693a294..54bed91 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,7 +8,7 @@ assignees: '' --- Note: for general questions and comments, please use the forums at: -https://groups.google.com/forum/#!forum/json-c +https://groups.google.com/g/json-c **Describe the bug** A clear and concise description of what the bug is, and any information about where you're running into the bug that you feel might be relevant. diff --git a/.gitignore b/.gitignore index 1cdaf9b..4b7da9f 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ /tests/test_double_serializer /tests/test_float /tests/test_int_add +/tests/test_int_get /tests/test_json_pointer /tests/test_locale /tests/test_null @@ -70,6 +71,7 @@ # It's not good practice to build directly in the source tree # but ignore cmake auto-generated files anyway: /json_config.h +/json.h /config.h /json-c.pc /Makefile diff --git a/.travis.yml b/.travis.yml index 08772c1..769bf4f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: cpp matrix: include: -# gcc -# xenial + +# ubuntu xenial 16.04 # gcc 5 is the default on xenial - os: linux dist: xenial @@ -15,35 +15,37 @@ matrix: - doxygen - cmake env: CHECK="true" -# bionic - - os: linux - dist: bionic - compiler: gcc - env: MATRIX_EVAL="CC=gcc-6 && CXX=g++-6" - # gcc 7 is the default on bionic +# 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" - - os: linux - dist: bionic - compiler: gcc - env: MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" -# clang -# xenial +# ubuntu focal fossa 20.04 +# gcc 9 is the default on bionic - os: linux - dist: xenial - compiler: clang + dist: focal + compiler: gcc addons: apt: - sources: - - llvm-toolchain-xenial-5.0 packages: - - clang-5.0 + - valgrind + - cppcheck + - doxygen - cmake - env: MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0" + env: CHECK="true" + +# clang +# xenial - os: linux dist: xenial compiler: clang @@ -56,9 +58,9 @@ matrix: - cmake env: MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0" - # clang-7 is the default on xenial and bionic + # clang-7 is the default on focal, xenial and bionic - os: linux - dist: xenial + dist: focal compiler: clang addons: apt: @@ -69,17 +71,9 @@ matrix: - cmake env: CHECK="true" -# bionic - - os: linux - dist: bionic - compiler: clang - env: CHECK="true" # osx - os: osx - osx_image: xcode9.4 - env: XCODE="true" - - os: osx - osx_image: xcode10.1 + osx_image: xcode13.4 env: XCODE="true" CHECK="true" # run coveralls diff --git a/AUTHORS b/AUTHORS index fce4dd8..f0fcf97 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,30 +1,71 @@ +Alan Coopersmith Alexander Dahl +Alexandru Ardelean +An7ar35 andy5995 +Aram Poghosyan Björn Esser +BonsaY changyong guo chenguoping +Chris Lamb Christopher Head Chris Wolfe C. Watford (christopher.watford@gmail.com) +Daniel Danzberger Darjan Krijan +David McCann +DeX77 +Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> +dota17 +Eric Haszlakiewicz Eric Hawicz +Even Rouault +Federico Francescon +Gianluigi Tiesi grdowns +Hex052 +hofnarr +ihsinme <61293369+ihsinme@users.noreply.github.com> Ivan Romanov Jaap Keuter +Jakov Smolic janczer +JC (Jonathan Chen) Jehan Jehiah Czebotar Jonathan Wiens Jose Bollo +José Bollo +Juuso Alasuutari Keith Holman +Khem Raj +Kizuna-Meraki +Leon Gross Liang, Gao +Luca Mannella +Marc <34656315+MarcT512@users.noreply.github.com> +Matthias Gatto max +Micah Snyder Michael Clark myd7349 +Pascal Cuoq +Pawday +Philosoph228 Pierce Lopez Po-Chuan Hsieh Ramiro Polla Rikard Falkeborn +Robert Bielik Robert +Rosen Penev Rubasri Kalidas +Sergey Sharshunov +Simon McVittie +ssrlive <30760636+ssrlive@users.noreply.github.com> +Tobias Nießen +Tobias Stoeckmann +Tudor Brindus Unmanned Player <36690541+unmanned-player@users.noreply.github.com> +Yurii Rashkovskii diff --git a/CMakeLists.txt b/CMakeLists.txt index 99ab904..0aa1b64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,31 +1,26 @@ -# Many projects still are stuck using CMake 2.8 is several places so it's good to provide backward support too. This is -# specially true in old embedded systems (OpenWRT and friends) where CMake isn't necessarily upgraded. -cmake_minimum_required(VERSION 2.8) +# CMake 3.9 was released in 2017/07 +# As of 2023, many versions of Linux, NetBSD and FreeBSD provide, +# and many OpenWRT packages require, much newer CMake packages. +# We're stopping before 3.10 because that version starts requiring +# c++11, which isn't available on e.g HPUX. +cmake_minimum_required(VERSION 3.9) -if(POLICY CMP0048) - cmake_policy(SET CMP0048 NEW) -endif() +# The project() command manages VERSION variables. +cmake_policy(SET CMP0048 NEW) # JSON-C library is C only project. -if (CMAKE_VERSION VERSION_LESS 3.0) - project(json-c) - set(PROJECT_VERSION_MAJOR "0") - set(PROJECT_VERSION_MINOR "15") - set(PROJECT_VERSION_PATCH "0") - set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") -else() - project(json-c LANGUAGES C VERSION 0.15) -endif() +# PROJECT_VERSION{,_MAJOR,_MINOR,_PATCH} set by project(): +project(json-c LANGUAGES C VERSION 0.17) -# If we've got 3.0 then it's good, let's provide support. Otherwise, leave it be. -if(POLICY CMP0038) - # Policy CMP0038 introduced was in CMake 3.0 - cmake_policy(SET CMP0038 NEW) -endif() +# Targets may not link directly to themselves. +cmake_policy(SET CMP0038 NEW) -if(POLICY CMP0054) - cmake_policy(SET CMP0054 NEW) -endif() +# 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 if(NOT CMAKE_BUILD_TYPE) @@ -36,22 +31,13 @@ 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) -if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING AND - (NOT MSVC OR NOT (MSVC_VERSION LESS 1800)) # Tests need at least VS2013 - ) -add_subdirectory(tests) -endif() - -if (NOT MSVC) # cmd line apps don't built on Windows currently. -add_subdirectory(apps) -endif() - # Set some packaging variables. set(CPACK_PACKAGE_NAME "${PROJECT_NAME}") set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") @@ -79,6 +65,10 @@ include(CMakePackageConfigHelpers) option(BUILD_SHARED_LIBS "Default to building shared 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. ADD_CUSTOM_TARGET(distcheck COMMAND make package_source @@ -97,6 +87,11 @@ option(DISABLE_WERROR "Avoid treating compiler warnings as fatal option(ENABLE_RDRAND "Enable RDRAND Hardware RNG Hash Seed." 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(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_PATCH "Disable JSON patch (RFC6902) support." OFF) +option(NEWLOCALE_NEEDS_FREELOCALE "Work around newlocale bugs in old FreeBSD by calling freelocale" OFF) +option(BUILD_APPS "Default to building apps" ON) if (UNIX OR MINGW OR CYGWIN) @@ -144,11 +139,18 @@ check_include_file(stdint.h HAVE_STDINT_H) check_include_file(stdlib.h HAVE_STDLIB_H) check_include_file(sys/cdefs.h HAVE_SYS_CDEFS_H) check_include_file(sys/param.h HAVE_SYS_PARAM_H) +check_include_file(sys/random.h HAVE_SYS_RANDOM_H) check_include_file(sys/stat.h HAVE_SYS_STAT_H) check_include_file(xlocale.h HAVE_XLOCALE_H) -if (HAVE_INTTYPES_H AND NOT MSVC) - set(JSON_C_HAVE_INTTYPES_H 1) +# Set json-c specific vars to stamp into json_config.h +# in a way that hopefully won't conflict with other +# projects that use json-c. +if (HAVE_INTTYPES_H) + set(JSON_C_HAVE_INTTYPES_H 1) +endif() +if (HAVE_STDINT_H) + set(JSON_C_HAVE_STDINT_H 1) endif() check_symbol_exists(_isnan "float.h" HAVE_DECL__ISNAN) @@ -169,6 +171,19 @@ check_symbol_exists(vasprintf "stdio.h" HAVE_VASPRINTF) check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF) check_symbol_exists(vprintf "stdio.h" HAVE_VPRINTF) +check_symbol_exists(arc4random "stdlib.h" HAVE_ARC4RANDOM) +if (NOT HAVE_ARC4RANDOM AND DISABLE_EXTRA_LIBS STREQUAL "OFF") + check_include_file(bsd/stdlib.h HAVE_BSD_STDLIB_H) + if (HAVE_BSD_STDLIB_H) + list(APPEND CMAKE_REQUIRED_LIBRARIES "bsd") + unset(HAVE_ARC4RANDOM CACHE) + check_symbol_exists(arc4random "bsd/stdlib.h" HAVE_ARC4RANDOM) + if (NOT HAVE_ARC4RANDOM) + list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "bsd") + endif() + endif() +endif() + if (HAVE_FCNTL_H) check_symbol_exists(open "fcntl.h" HAVE_OPEN) endif() @@ -179,6 +194,18 @@ if (HAVE_LOCALE_H) check_symbol_exists(setlocale "locale.h" HAVE_SETLOCALE) check_symbol_exists(uselocale "locale.h" HAVE_USELOCALE) endif() + +# uClibc *intentionally* crashes in duplocale(), at least as of: +# 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 +# locale handling entirely. +exec_program(${CMAKE_C_COMPILER} ARGS -dumpmachine OUTPUT_VARIABLE CMAKE_GNU_C_MACHINE) +if (CMAKE_GNU_C_MACHINE MATCHES "uclibc") + message(STATUS "Detected uClibc compiler, disabling locale handling") + set(HAVE_SETLOCALE 0) + set(HAVE_USELOCALE 0) +endif() + if (HAVE_STRINGS_H) check_symbol_exists(strcasecmp "strings.h" HAVE_STRCASECMP) check_symbol_exists(strncasecmp "strings.h" HAVE_STRNCASECMP) @@ -190,6 +217,9 @@ endif() if (HAVE_SYSLOG_H) check_symbol_exists(vsyslog "syslog.h" HAVE_VSYSLOG) endif() +if (HAVE_SYS_RANDOM_H) + check_symbol_exists(getrandom "sys/random.h" HAVE_GETRANDOM) +endif() if (HAVE_SYS_RESOURCE_H) check_symbol_exists(getrusage "sys/resource.h" HAVE_GETRUSAGE) endif() @@ -265,7 +295,7 @@ message(STATUS "Wrote ${PROJECT_BINARY_DIR}/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") -if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") +if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections") if ("${DISABLE_WERROR}" STREQUAL "OFF") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") @@ -281,6 +311,11 @@ if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") endif() add_definitions(-D_GNU_SOURCE) + + if ("${CMAKE_C_COMPILER_ID}" 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_ID}" STREQUAL "MSVC") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /DEBUG") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4100") @@ -354,14 +389,13 @@ set(JSON_C_PUBLIC_HEADERS # Note: config.h is _not_ included here ${PROJECT_BINARY_DIR}/json_config.h - ${PROJECT_SOURCE_DIR}/json.h + ${PROJECT_BINARY_DIR}/json.h ${PROJECT_SOURCE_DIR}/arraylist.h ${PROJECT_SOURCE_DIR}/debug.h ${PROJECT_SOURCE_DIR}/json_c_version.h ${PROJECT_SOURCE_DIR}/json_inttypes.h ${PROJECT_SOURCE_DIR}/json_object.h ${PROJECT_SOURCE_DIR}/json_object_iterator.h - ${PROJECT_SOURCE_DIR}/json_pointer.h ${PROJECT_SOURCE_DIR}/json_tokener.h ${PROJECT_SOURCE_DIR}/json_types.h ${PROJECT_SOURCE_DIR}/json_util.h @@ -373,9 +407,9 @@ set(JSON_C_PUBLIC_HEADERS set(JSON_C_HEADERS ${JSON_C_PUBLIC_HEADERS} ${PROJECT_SOURCE_DIR}/json_object_private.h + ${PROJECT_SOURCE_DIR}/json_pointer_private.h ${PROJECT_SOURCE_DIR}/random_seed.h ${PROJECT_SOURCE_DIR}/strerror_override.h - ${PROJECT_SOURCE_DIR}/strerror_override_private.h ${PROJECT_SOURCE_DIR}/math_compat.h ${PROJECT_SOURCE_DIR}/snprintf_compat.h ${PROJECT_SOURCE_DIR}/strdup_compat.h @@ -388,7 +422,6 @@ set(JSON_C_SOURCES ${PROJECT_SOURCE_DIR}/json_c_version.c ${PROJECT_SOURCE_DIR}/json_object.c ${PROJECT_SOURCE_DIR}/json_object_iterator.c - ${PROJECT_SOURCE_DIR}/json_pointer.c ${PROJECT_SOURCE_DIR}/json_tokener.c ${PROJECT_SOURCE_DIR}/json_util.c ${PROJECT_SOURCE_DIR}/json_visit.c @@ -398,16 +431,38 @@ set(JSON_C_SOURCES ${PROJECT_SOURCE_DIR}/strerror_override.c ) +if (NOT DISABLE_JSON_POINTER) + 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_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() + set(JSON_H_JSON_POINTER "") + set(JSON_H_JSON_PATCH "") +endif() + +configure_file(json.h.cmakein ${PROJECT_BINARY_DIR}/json.h @ONLY) + include_directories(${PROJECT_SOURCE_DIR}) include_directories(${PROJECT_BINARY_DIR}) add_subdirectory(doc) -# uninstall -add_custom_target(uninstall - COMMAND cat ${PROJECT_BINARY_DIR}/install_manifest.txt | xargs rm - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) +# "uninstall" custom target for make generators in unix like operating systems +# and if that target is not present +if (CMAKE_GENERATOR STREQUAL "Unix Makefiles") + if(NOT TARGET uninstall) + add_custom_target(uninstall + COMMAND cat ${PROJECT_BINARY_DIR}/install_manifest.txt | xargs rm + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + endif() +endif() # XXX for a normal full distribution we'll need to figure out # XXX how to build both shared and static libraries. @@ -417,7 +472,7 @@ add_library(${PROJECT_NAME} ${JSON_C_HEADERS} ) set_target_properties(${PROJECT_NAME} PROPERTIES - VERSION 5.1.0 + VERSION 5.3.0 SOVERSION 5) list(APPEND CMAKE_TARGETS ${PROJECT_NAME}) # If json-c is used as subroject it set to target correct interface -I flags and allow @@ -428,6 +483,8 @@ target_include_directories(${PROJECT_NAME} $ ) +target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_REQUIRED_LIBRARIES}) + # Allow to build static and shared libraries at the same time if (BUILD_STATIC_LIBS AND BUILD_SHARED_LIBS) set(STATIC_LIB ${PROJECT_NAME}-static) @@ -435,6 +492,13 @@ if (BUILD_STATIC_LIBS AND BUILD_SHARED_LIBS) ${JSON_C_SOURCES} ${JSON_C_HEADERS} ) + target_include_directories(${PROJECT_NAME}-static + PUBLIC + $ + $ + ) + + target_link_libraries(${PROJECT_NAME}-static PUBLIC ${CMAKE_REQUIRED_LIBRARIES}) # rename the static library if (NOT MSVC) @@ -461,7 +525,7 @@ install(TARGETS ${CMAKE_TARGETS} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ${CMAKE_INSTALL_INCLUDEDIR}/json-c ) install(EXPORT ${PROJECT_NAME}-targets @@ -489,9 +553,40 @@ if (UNIX OR MINGW OR CYGWIN) SET(libdir ${CMAKE_INSTALL_FULL_LIBDIR}) SET(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR}) SET(VERSION ${PROJECT_VERSION}) + + # Linking against the static json-c requires + # dependent packages to include additional libs: + SET(LIBS_LIST ${CMAKE_REQUIRED_LIBRARIES}) + + # Note: We would need cmake >= 3.12 in order to use list(TRANSFORM ...) + function(list_transform_prepend var prefix) + set(temp "") + foreach(f ${${var}}) + list(APPEND temp "${prefix}${f}") + endforeach() + set(${var} "${temp}" PARENT_SCOPE) + endfunction() + list_transform_prepend(LIBS_LIST "-l") + + string(REPLACE ";" " " LIBS "${LIBS_LIST}") + 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") install(FILES ${PROJECT_BINARY_DIR}/json-c.pc DESTINATION "${INSTALL_PKGCONFIG_DIR}") endif () -install(FILES ${JSON_C_PUBLIC_HEADERS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/json-c) +install(FILES ${JSON_C_PUBLIC_HEADERS} DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/json-c) + +if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING AND + (NOT MSVC OR NOT (MSVC_VERSION LESS 1800)) # Tests need at least VS2013 + ) +add_subdirectory(tests) +endif() + +if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_APPS) +# skip apps when we're included in someone else's build +if (NOT MSVC) # cmd line apps don't built on Windows currently. +add_subdirectory(apps) +endif() +endif() + diff --git a/ChangeLog b/ChangeLog index 8e1ac53..d1e3f4e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,95 @@ -Next Release 0.15 -===================== +0.17 (up to commit 077661f, 2023-08-08) +======================================== + +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 +--------------------------------- +* When serializing with JSON_C_TO_STRING_PRETTY set, keep the opening and + closing curly or square braces on same line for empty objects or arrays. +* Disable locale handling when targeting a uClibc system due to problems + with its duplocale() function. +* When parsing with JSON_TOKENER_STRICT set, integer overflow/underflow + now result in a json_tokener_error_parse_number. Without that flag + 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) +======================================== + +Deprecated and removed features: +-------------------------------- +* JSON_C_OBJECT_KEY_IS_CONSTANT is deprecated in favor of + JSON_C_OBJECT_ADD_CONSTANT_KEY +* Direct access to lh_table and lh_entry structure members is deprecated. + Use access functions instead, lh_table_head(), lh_entry_next(), etc... +* Drop REFCOUNT_DEBUG code. + +New features +------------ +* The 0.16 release introduces no new features + +Build changes +------------- +* Add a DISABLE_EXTRA_LIBS option to skip using libbsd +* Add a DISABLE_JSON_POINTER option to skip compiling in json_pointer support. + +Significant changes and bug fixes +--------------------------------- +* Cap string length at INT_MAX to avoid various issues with very long strings. +* json_object_deep_copy: fix deep copy of strings containing '\0' +* Fix read past end of buffer in the "json_parse" command +* Avoid out of memory accesses in the locally provided vasprintf() function + (for those platforms that use it) +* Handle allocation failure in json_tokener_new_ex +* Fix use-after-free in json_tokener_new_ex() in the event of printbuf_new() returning NULL +* printbuf_memset(): set gaps to zero - areas within the print buffer which + have not been initialized by using printbuf_memset +* printbuf: return -1 on invalid arguments (len < 0 or total buffer > INT_MAX) +* sprintbuf(): propagate printbuf_memappend errors back to the caller + +Optimizations +-------------- +* Speed up parsing by replacing ctype functions with simplified, faster + non-locale-sensitive ones in json_tokener and json_object_to_json_string. +* Neither vertical tab nor formfeed are considered whitespace per the JSON spec +* json_object: speed up creation of objects, calloc() -> malloc() + set fields +* Avoid needless extra strlen() call in json_c_shallow_copy_default() and + json_object_equal() when the object is known to be a json_type_string. + +Other changes +------------- +* Validate size arguments in arraylist functions. +* Use getrandom() if available; with GRND_NONBLOCK to allow use of json-c + very early during boot, such as part of cryptsetup. +* Use arc4random() if it's available. +* random_seed: on error, continue to next method instead of exiting the process +* Close file when unable to read from /dev/urandom in get_dev_random_seed() + +*** + +0.15 (up to commit 870965e, 2020/07/26) +======================================== Deprecated and removed features: -------------------------------- @@ -59,7 +148,7 @@ Other changes * #589 - Detect broken RDRAND during initialization; also, fix segfault in the CPUID check. * #592 - Fix integer overflows to prevert out of bounds write on large input. -* Protect against division by zero in linkhash, when creaed with zero size. +* Protect against division by zero in linkhash, when created with zero size. * #602 - Fix json_parse_uint64() internal error checking, leaving the retval untouched in more failure cases. * #614 - Prevent truncation when custom double formatters insert extra \0's @@ -185,7 +274,7 @@ Behavior changes: * Use size_t for array length and size. Platforms where sizeof(size_t) != sizeof(int) may not be backwards compatible See commits 45c56b, 92e9a5 and others. -* Check for failue when allocating memory, returning NULL and errno=ENOMEM. +* Check for failure when allocating memory, returning NULL and errno=ENOMEM. See commit 2149a04. * Change json_object_object_add() return type from void to int, and will return -1 on failures, instead of exiting. (Note: this is not an ABI change) @@ -376,7 +465,7 @@ List of new functions added: * Add an alternative iterator implementation, see json_object_iterator.h * Make json_object_iter public to enable external use of the json_object_object_foreachC macro. - * Add a printbuf_memset() function to provide an effecient way to set and + * Add a printbuf_memset() function to provide an efficient way to set and append things like whitespace indentation. * Adjust json_object_is_type and json_object_get_type so they return json_type_null for NULL objects and handle NULL passed to @@ -462,7 +551,7 @@ List of new functions added: 0.7 === * Add escaping of backslash to json output - * Add escaping of foward slash on tokenizing and output + * Add escaping of forward slash on tokenizing and output * Changes to internal tokenizer from using recursion to using a depth state structure to allow incremental parsing diff --git a/README.html b/README.html index e91da73..483e407 100644 --- a/README.html +++ b/README.html @@ -26,12 +26,12 @@

Documentation

-

Doxygen generated documentation exists here.

+

Doxygen generated documentation exists here.

GIT Reposository

git clone https://github.com/json-c/json-c.git

-

Mailing List

+

Mailing List

Send email to json-c <at> googlegroups <dot> com

License

diff --git a/README.md b/README.md index cd66d49..04ac67f 100644 --- a/README.md +++ b/README.md @@ -4,40 +4,67 @@ ======== 1. [Overview and Build Status](#overview) -2. [Building on Unix](#buildunix) +2. [Getting Help](#gettinghelp) +3. [Building on Unix](#buildunix) * [Prerequisites](#installprereq) * [Build commands](#buildcmds) -3. [CMake options](#CMake) -4. [Testing](#testing) -5. [Building with `vcpkg`](#buildvcpkg) -6. [Linking to libjson-c](#linking) -7. [Using json-c](#using) +4. [CMake options](#CMake) +5. [Testing](#testing) +6. [Building with `vcpkg`](#buildvcpkg) +7. [Building for Android](#android) +7. [Linking to libjson-c](#linking) +8. [Using json-c](#using) JSON-C - A JSON implementation in C ----------------------------------- -Build Status -* [AppVeyor Build](https://ci.appveyor.com/project/hawicz/json-c) ![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/json-c/json-c?branch=master&svg=true) -* [Travis Build](https://travis-ci.org/json-c/json-c) ![Travis Build Status](https://travis-ci.org/json-c/json-c.svg?branch=master) - -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) - JSON-C implements a reference counting object model that allows you to easily construct JSON objects in C, output them as JSON formatted strings and parse JSON formatted strings back into the C representation of JSON objects. -It aims to conform to [RFC 7159](https://tools.ietf.org/html/rfc7159). +It aims to conform to [RFC 8259](https://www.rfc-editor.org/rfc/rfc8259). + +Skip down to [Using json-c](#using) +or check out the [API docs](https://json-c.github.io/json-c/), +if you already have json-c installed and ready to use. + +Home page for json-c: https://github.com/json-c/json-c/wiki + +Getting Help +------------ + +If you have questions about using json-c, please start a thread on +our forums at: https://groups.google.com/forum/#!forum/json-c + +If you believe you've discovered a bug, report it at +(https://github.com/json-c/json-c/issues). Please be sure to include +the version of json-c you're using, the OS you're running on, and any +other relevant details. Fully reproducible test cases and/or patches +to fix problems are greatly appreciated. + +Fixes for bugs, or small new features can be directly submitted as a +[pull request](https://github.com/json-c/json-c/pulls). For major new +features or large changes of any kind, please first start a discussion +on the [forums](https://groups.google.com/forum/#!forum/json-c). + Building on Unix with `git`, `gcc` and `cmake` -------------------------------------------------- -Home page for json-c: https://github.com/json-c/json-c/wiki +If you already have json-c installed, see [Linking to `libjson-c`](#linking) +for how to build and link your program against it. + +Build Status +* [AppVeyor Build](https://ci.appveyor.com/project/hawicz/json-c) ![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/json-c/json-c?branch=master&svg=true) +* [Travis Build](https://app.travis-ci.com/github/json-c/json-c) ![Travis Build Status](https://api.travis-ci.com/json-c/json-c.svg?branch=master) + +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) ### Prerequisites: - `gcc`, `clang`, or another C compiler - - cmake>=2.8, >=3.16 recommended + - `cmake>=2.8`, `>=3.16` recommended, `cmake=>3.1` for tests To generate docs you'll also need: - `doxygen>=1.8.13` @@ -74,13 +101,13 @@ Then: $ make $ make test $ make USE_VALGRIND=0 test # optionally skip using valgrind -$ make install +$ sudo make install # it could be necessary to execute make install ``` ### Generating documentation with Doxygen: -The libray documentation can be generated directly from the source codes using Doxygen tool: +The library documentation can be generated directly from the source code using Doxygen tool: ```sh # in build directory @@ -105,6 +132,8 @@ DISABLE_STATIC_FPIC | Bool | The default builds position independent DISABLE_BSYMBOLIC | Bool | Disable use of -Bsymbolic-functions. DISABLE_THREAD_LOCAL_STORAGE | Bool | Disable use of Thread-Local Storage (HAVE___THREAD). DISABLE_WERROR | Bool | Disable use of -Werror. +DISABLE_EXTRA_LIBS | Bool | Disable use of extra libraries, libbsd +DISABLE_JSON_POINTER | Bool | Omit json_pointer support from the build. ENABLE_RDRAND | Bool | Enable RDRAND Hardware RNG Hash Seed. ENABLE_THREADING | Bool | Enable partial threading support. OVERRIDE_GET_RANDOM_SEED | String | A block of code to use instead of the default implementation of json_c_get_random_seed(), e.g. on embedded platforms where not even the fallback to time() works. Must be a single line. @@ -186,7 +215,7 @@ If a test fails, check `Testing/Temporary/LastTest.log`, `tests/testSubDir/${testname}/${testname}.vg.out`, and other similar files. If there is insufficient output try: ```sh -VERBOSE=1 make test +VERBOSE=1 CTEST_OUTPUT_ON_FAILURE=1 make test ``` or ```sh @@ -208,6 +237,29 @@ 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. +Building for Android +---------------------- + +Building on Android is now particularly well supported, but there +have been some reports of success using +https://developer.android.com/ndk/guides/cmake + +``` +mkdir json-c-build +cd json-c-build/ +export NDK_HOME=~/Library/Android/sdk/ndk/22.1.7171670/ +cmake \ + --toolchain=$NDK_HOME/build/cmake/android.toolchain.cmake \ + -DANDROID_STL=none \ + -DANDROID_ABI=arm64-v8a \ + -DANDROID_PLATFORM=android-29 \ + -DANDROID_LD=lld \ + -DCMAKE_BUILD_TYPE=MinSizeRel \ + -DCMAKE_INSTALL_PREFIX= \ + -DENABLE_THREADING=true \ + .. +make install +``` Linking to `libjson-c` ---------------------- @@ -220,19 +272,36 @@ CFLAGS += $(shell pkg-config --cflags json-c) LDFLAGS += $(shell pkg-config --libs json-c) ``` -Without `pkgconfig`, you would do something like this: +Without `pkgconfig`, you might do something like this: ```make JSON_C_DIR=/path/to/json_c/install CFLAGS += -I$(JSON_C_DIR)/include/json-c +# Or to use lines like: #include +#CFLAGS += -I$(JSON_C_DIR)/include LDFLAGS+= -L$(JSON_C_DIR)/lib -ljson-c ``` +If your project uses cmake: + +* Add to your CMakeLists.txt file: + +```cmake +find_package(json-c CONFIG) +target_link_libraries(${PROJECT_NAME} PRIVATE json-c::json-c) +``` + +* Then you might run in your project: + +```sh +cd build +cmake -DCMAKE_PREFIX_PATH=/path/to/json_c/install/lib64/cmake .. +``` Using json-c ------------ -To use json-c you can either include json.h, or preferrably, one of the +To use json-c you can either include json.h, or preferably, one of the following more specific header files: * json_object.h - Core types and methods. @@ -241,9 +310,9 @@ following more specific header files: objects from a json-c object tree. * json_object_iterator.h - Methods for iterating over single json_object instances. (See also `json_object_object_foreach()` in json_object.h) * json_visit.h - Methods for walking a tree of json-c objects. -* json_util.h - Miscelleanous utility functions. +* json_util.h - Miscellaneous utility functions. -For a full list of headers see [files.html](http://json-c.github.io/json-c/json-c-current-release/doc/html/files.html) +For a full list of headers see [files.html](https://json-c.github.io/json-c/json-c-current-release/doc/html/files.html) The primary type in json-c is json_object. It describes a reference counted tree of json objects which are created by either parsing text with a @@ -251,7 +320,7 @@ json_tokener (i.e. `json_tokener_parse_ex()`), or by creating (with `json_object_new_object()`, `json_object_new_int()`, etc...) and adding (with `json_object_object_add()`, `json_object_array_add()`, etc...) them individually. -Typically, every object in the tree will have one reference, from it's parent. +Typically, every object in the tree will have one reference, from its parent. When you are done with the tree of objects, you call json_object_put() on just the root object to free it, which recurses down through any child objects calling json_object_put() on each one of those in turn. @@ -266,7 +335,7 @@ the parent being freed or it being removed from its parent When parsing text, the json_tokener object is independent from the json_object that it returns. It can be allocated (`json_tokener_new()`) -used ones or multiple times (`json_tokener_parse_ex()`, and +used one or multiple times (`json_tokener_parse_ex()`, and freed (`json_tokener_free()`) while the json_object objects live on. A json_object tree can be serialized back into a string with diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index 20c08fd..8720c3e 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -16,11 +16,19 @@ changes (added/removed/updated funcs, etc...), and detect backwards compat issues. * 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. * Mention removed features in ChangeLog * Consider re-adding backwards compatible support, through symbol aliases and appropriate entries in json-c.sym + * Be sure any new symbols are listed in json-c.sym as part of + the _new_ release version. * Update the AUTHORS file + + PREV=$(git tag | tail -1) + ( git log -r ${PREV}..HEAD | grep Author: | sed -e's/Author: //' ; cat AUTHORS ) | sort -u > A1 + mv A1 AUTHORS + * Exclude mentioning changes that have already been included in a point release of the previous release branch. @@ -33,29 +41,33 @@ ## Release creation Start creating the new release: - release=0.15 + + 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} + rm -rf distcheck mkdir distcheck cd distcheck # Note, the build directory *must* be entirely separate from # the source tree for distcheck to work properly. - cmake ../json-c-${release} + cmake -DCMAKE_BUILD_TYPE=Release ../json-c-${release} make distcheck cd .. Make any fixes/changes *before* branching. cd json-c-${release} - git branch json-c-${release} - git checkout json-c-${release} + git checkout -b json-c-${release} ------------ Using ${release}: Update the version in json_c_version.h Update the version in CMakeLists.txt (VERSION in the project(...) line) - Update the version in config.h.win32 (several places) Update the set_target_properties() line in CmakeLists.txt to set the shared library version. Generally, unless we're doing a major release, change: @@ -74,9 +86,11 @@ If we're doing a major release (SONAME bump), also bump the version Generate the doxygen documentation: - doxygen + (cd ../distcheck && make doc) + cp -r -p ../distcheck/doc/{html,Doxyfile} doc/. + rm doc/Doxyfile # Remove generated file w/ hardcoded paths git add -f doc - git commit doc + git commit doc -m "Generate docs for the ${release} release" ------------ @@ -86,7 +100,11 @@ Create the release tarballs: echo .git > excludes tar -czf json-c-${release}.tar.gz -X excludes json-c-${release} - echo doc >> excludes + echo 'doc/*.cmake' >> excludes + echo 'doc/CMakeFiles' >> excludes + echo 'doc/Makefile' >> excludes + echo 'doc/Doxyfile' >> excludes + echo 'doc/html' >> excludes tar -czf json-c-${release}-nodoc.tar.gz -X excludes json-c-${release} ------------ @@ -104,8 +122,9 @@ Tag the branch: Go to Amazon S3 service at: https://console.aws.amazon.com/s3/ -Upload the two tarballs in the json-c_releases folder. - When uploading, use "Standard" storage class, and make the uploaded files publicly accessible. +Upload the two tarballs in the json-c_releases/releases folder. +* Expand "Permissions", pick "Grant public-read access" +* Expand "Properties", ensure "Standard" storage class is picked. Logout of Amazon S3, and verify that the files are visible. https://s3.amazonaws.com/json-c_releases/releases/index.html @@ -121,13 +140,14 @@ Add new section to ChangeLog for ${release}+1 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 CMakeLists.txt - Update the version in config.h.win32 Update RELEASE_CHECKLIST.txt, set release=${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 0.${release}.99" + git commit -a -m "Update the master branch to version ${release}.99" git push ------------ @@ -143,6 +163,8 @@ Update the gh-pages branch with new docs: mkdir json-c-${release} cp -R ../json-c-${release}/doc json-c-${release}/. git add json-c-${release} + rm json-c-current-release + ln -s json-c-${release} json-c-current-release git commit -a -m "Add the ${release} docs." vi index.html @@ -161,7 +183,8 @@ Update checksums on wiki page. openssl md5 json-c*gz 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 ------------ diff --git a/abi-check.sh b/abi-check.sh new file mode 100644 index 0000000..6dab54a --- /dev/null +++ b/abi-check.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +prev=0.16 +release=0.17 + +# ... clone json-c, abi-compliance-checker, abi-dumper + +mkdir build +cd build +CFLAGS=-Og cmake -DCMAKE_INSTALL_PREFIX=~/json-c-installs/json-c-${release} .. +make && make test && make install + +# Assume the old version has already been built + +cd ~/abi-compliance-checker +mkxml() +{ + ver="$1" +cat < json-c-${ver}.xml + + + ${ver} + + + +../json-c-installs/json-c-${ver}/include/json-c + + + +../json-c-installs/json-c-${ver}/lib64/libjson-c.so + + +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/..." diff --git a/apps/json_parse.c b/apps/json_parse.c index bba4622..31221d0 100644 --- a/apps/json_parse.c +++ b/apps/json_parse.c @@ -22,16 +22,30 @@ #include #endif -static int formatted_output = 0; +#ifndef JSON_NORETURN +#if defined(_MSC_VER) +#define JSON_NORETURN __declspec(noreturn) +#elif defined(__OS400__) +#define JSON_NORETURN +#else +/* 'cold' attribute is for optimization, telling the computer this code + * path is unlikely. + */ +#define JSON_NORETURN __attribute__((noreturn, cold)) +#endif +#endif + +static int formatted_output = JSON_C_TO_STRING_SPACED; static int show_output = 1; static int strict_mode = 0; +static int color = 0; static const char *fname = NULL; #ifndef HAVE_JSON_TOKENER_GET_PARSE_END #define json_tokener_get_parse_end(tok) ((tok)->char_offset) #endif -static void usage(const char *argv0, int exitval, const char *errmsg); +JSON_NORETURN static void usage(const char *argv0, int exitval, const char *errmsg); static void showmem(void); static int parseit(int fd, int (*callback)(struct json_object *)); static int showobj(struct json_object *new_obj); @@ -42,7 +56,7 @@ static void showmem(void) struct rusage rusage; memset(&rusage, 0, sizeof(rusage)); getrusage(RUSAGE_SELF, &rusage); - printf("maxrss: %ld KB\n", rusage.ru_maxrss); + fprintf(stderr, "maxrss: %ld KB\n", rusage.ru_maxrss); #endif } @@ -50,7 +64,7 @@ static int parseit(int fd, int (*callback)(struct json_object *)) { struct json_object *obj; char buf[32768]; - int ret; + ssize_t ret; int depth = JSON_TOKENER_DEFAULT_DEPTH; json_tokener *tok; @@ -73,19 +87,21 @@ static int parseit(int fd, int (*callback)(struct json_object *)) size_t total_read = 0; while ((ret = read(fd, buf, sizeof(buf))) > 0) { - total_read += ret; - int start_pos = 0; - while (start_pos != ret) + size_t retu = (size_t)ret; // We know it's positive + total_read += retu; + size_t start_pos = 0; + while (start_pos != retu) { - obj = json_tokener_parse_ex(tok, &buf[start_pos], ret - start_pos); + obj = json_tokener_parse_ex(tok, &buf[start_pos], retu - start_pos); enum json_tokener_error jerr = json_tokener_get_error(tok); - int parse_end = json_tokener_get_parse_end(tok); + size_t parse_end = json_tokener_get_parse_end(tok); if (obj == NULL && jerr != json_tokener_continue) { - char *aterr = &buf[start_pos + parse_end]; + const char *aterr = (start_pos + parse_end < (int)sizeof(buf)) ? + &buf[start_pos + parse_end] : ""; fflush(stdout); - int fail_offset = total_read - ret + start_pos + parse_end; - fprintf(stderr, "Failed at offset %d: %s %c\n", fail_offset, + size_t fail_offset = total_read - retu + start_pos + parse_end; + fprintf(stderr, "Failed at offset %lu: %s %c\n", (unsigned long)fail_offset, json_tokener_error_desc(jerr), aterr[0]); json_tokener_free(tok); return 1; @@ -101,7 +117,7 @@ static int parseit(int fd, int (*callback)(struct json_object *)) } } start_pos += json_tokener_get_parse_end(tok); - assert(start_pos <= ret); + assert(start_pos <= retu); } } if (ret < 0) @@ -121,15 +137,12 @@ static int showobj(struct json_object *new_obj) return 1; } - printf("Successfully parsed object from %s\n", fname); + fprintf(stderr, "Successfully parsed object from %s\n", fname); if (show_output) { const char *output; - if (formatted_output) - output = json_object_to_json_string(new_obj); - else - output = json_object_to_json_string_ext(new_obj, JSON_C_TO_STRING_PRETTY); + output = json_object_to_json_string_ext(new_obj, formatted_output | color); printf("%s\n", output); } @@ -144,11 +157,14 @@ static void usage(const char *argv0, int exitval, const char *errmsg) fp = stderr; if (errmsg != NULL) fprintf(fp, "ERROR: %s\n\n", errmsg); - fprintf(fp, "Usage: %s [-f] [-n] [-s]\n", argv0); - fprintf(fp, " -f - Format the output with JSON_C_TO_STRING_PRETTY\n"); + fprintf(fp, "Usage: %s [-f|-F ] [-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 , e.g. 0 for JSON_C_TO_STRING_PLAIN\n"); fprintf(fp, " -n - No output\n"); + fprintf(fp, " -c - color\n"); fprintf(fp, " -s - Parse in strict mode, flags:\n"); fprintf(fp, " JSON_TOKENER_STRICT|JSON_TOKENER_ALLOW_TRAILING_CHARS\n"); + fprintf(fp, " Diagnostic information will be emitted to stderr\n"); fprintf(fp, "\nWARNING WARNING WARNING\n"); fprintf(fp, "This is a prototype, it may change or be removed at any time!\n"); @@ -157,16 +173,17 @@ static void usage(const char *argv0, int exitval, const char *errmsg) int main(int argc, char **argv) { - json_object *new_obj; int opt; - while ((opt = getopt(argc, argv, "fhns")) != -1) + while ((opt = getopt(argc, argv, "fF:hnsc")) != -1) { switch (opt) { - case 'f': formatted_output = 1; break; + case 'f': formatted_output = JSON_C_TO_STRING_PRETTY; break; + case 'F': formatted_output = atoi(optarg); break; case 'n': show_output = 0; break; case 's': strict_mode = 1; break; + case 'c': color = JSON_C_TO_STRING_COLOR; break; case 'h': usage(argv[0], 0, NULL); default: /* '?' */ usage(argv[0], EXIT_FAILURE, "Unknown arguments"); } diff --git a/appveyor.yml b/appveyor.yml index 581366d..e0349f6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,37 +1,125 @@ version: '{branch}.{build}' -os: Windows Server 2012 R2 + +image: +# b_toolset: v143 + - Visual Studio 2022 + + # VS2015 also used for earlier VS builds + # aka os: Windows Server 2012 R2 + - Visual Studio 2015 + + # aka os: Windows Server 2016 +# b_toolset: v141 + - Visual Studio 2017 + + # aka os: Windows Server 2019 +# b_toolset: v142 + - Visual Studio 2019 platform: x64 -# There should be a better way to set-up a build matrix. environment: matrix: - b_toolset: Windows7.1SDK - b_config: Debug - - - b_toolset: Windows7.1SDK - b_config: Release - - - b_toolset: v120 - b_config: Debug - b_toolset: v120 - b_config: Release - b_toolset: v140 - b_config: Debug - - b_toolset: v140 - b_config: Release + - b_toolset: v141 + + - b_toolset: v142 + + - b_toolset: v143 + +configuration: + - Debug + - Release build_script: -- cmake -T %b_toolset% -DCMAKE_BUILD_TYPE=%b_config% -DCMAKE_INSTALL_PREFIX=t_install . +- cmake -T %b_toolset% -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_INSTALL_PREFIX=t_install . - cmake --build . --target install +matrix: + exclude: + # Skip release builds for all except the newest image + - image: Visual Studio 2015 + configuration: Release + + # In the "old" image, new toolsets aren't available: + - image: Visual Studio 2015 + b_toolset: v141 + + - image: Visual Studio 2015 + b_toolset: v142 + + - image: Visual Studio 2015 + b_toolset: v143 + + # ---- + + - image: Visual Studio 2017 + configuration: Release + + # In the "new" images, exclude all toolsets except the relevant + # one for that image: + + - image: Visual Studio 2017 + b_toolset: Windows7.1SDK + + - image: Visual Studio 2017 + b_toolset: v120 + + - image: Visual Studio 2017 + b_toolset: v140 + + - image: Visual Studio 2017 + b_toolset: v142 + + - image: Visual Studio 2017 + b_toolset: v143 + + # ---- + + - image: Visual Studio 2019 + configuration: Release + + - image: Visual Studio 2019 + b_toolset: Windows7.1SDK + + - image: Visual Studio 2019 + b_toolset: v120 + + - image: Visual Studio 2019 + b_toolset: v140 + + - image: Visual Studio 2019 + b_toolset: v141 + + - image: Visual Studio 2019 + b_toolset: v143 + + # ---- + + - image: Visual Studio 2022 + b_toolset: Windows7.1SDK + + - image: Visual Studio 2022 + b_toolset: v120 + + - image: Visual Studio 2022 + b_toolset: v140 + + - image: Visual Studio 2022 + b_toolset: v141 + + - image: Visual Studio 2022 + b_toolset: v142 + after_build: - cd t_install -- 7z a ../json-c.win32.%b_toolset%.%b_config%.zip * +- 7z a ../json-c.win32.%b_toolset%.%CONFIGURATION%.zip * artifacts: -- path: json-c.win32.%b_toolset%.%b_config%.zip - name: json-c.win32.%b_toolset%.%b_config%.zip +- path: json-c.win32.%b_toolset%.%CONFIGURATION%.zip + name: json-c.win32.%b_toolset%.%CONFIGURATION%.zip diff --git a/arraylist.c b/arraylist.c index c21b8e1..bfc1425 100644 --- a/arraylist.c +++ b/arraylist.c @@ -45,6 +45,8 @@ struct array_list *array_list_new2(array_list_free_fn *free_fn, int initial_size { struct array_list *arr; + if (initial_size < 0 || (size_t)initial_size >= SIZE_T_MAX / sizeof(void *)) + return NULL; arr = (struct array_list *)malloc(sizeof(struct array_list)); if (!arr) return NULL; @@ -106,6 +108,8 @@ int array_list_shrink(struct array_list *arr, size_t empty_slots) void *t; size_t new_size; + if (empty_slots >= SIZE_T_MAX / sizeof(void *) - arr->length) + return -1; new_size = arr->length + empty_slots; if (new_size == arr->size) return 0; @@ -121,6 +125,27 @@ int array_list_shrink(struct array_list *arr, size_t empty_slots) 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) int array_list_put_idx(struct array_list *arr, size_t idx, void *data) { diff --git a/arraylist.h b/arraylist.h index 1b18756..a12f27f 100644 --- a/arraylist.h +++ b/arraylist.h @@ -15,8 +15,8 @@ * Although this is exposed by the json_object_get_array() method, * it is not recommended for direct use. */ -#ifndef _arraylist_h_ -#define _arraylist_h_ +#ifndef _json_c_arraylist_h_ +#define _json_c_arraylist_h_ #ifdef __cplusplus extern "C" { @@ -62,6 +62,8 @@ extern void array_list_free(struct array_list *al); 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_add(struct array_list *al, void *data); diff --git a/bench/README.bench.md b/bench/README.bench.md index 62c6908..c37cb1a 100644 --- a/bench/README.bench.md +++ b/bench/README.bench.md @@ -70,7 +70,7 @@ Issues Using heaptrack, and analyzing the histogram, only shows ~2.6MB ``` heaptrack ./json_parse -n canada.json - heaptrack --analyze heaptrack*gz -H histgram.out + heaptrack --analyze heaptrack*gz -H histogram.out awk ' { s=$1; count=$2; ru=(int((s+ 15) / 16)) * 16; wasted = ((ru-s)*count); print s, count, ru-s, wasted; total=total+wasted} END { print "Total: ", total }' histogram.out ``` diff --git a/cmake-configure b/cmake-configure index c8e44ae..7110bd0 100755 --- a/cmake-configure +++ b/cmake-configure @@ -30,6 +30,7 @@ $0 [] [-- []] --enable-static build static libraries [default=yes] --disable-Bsymbolic Avoid linking with -Bsymbolic-function --disable-werror Avoid treating compiler warnings as fatal errors + --disable-extra-libs Avoid linking against extra libraries, such as libbsd EOF exit @@ -64,15 +65,24 @@ while [ $# -gt 0 ] ; do --enable-shared) FLAGS+=(-DBUILD_SHARED_LIBS=ON) ;; + --disable-shared) + FLAGS+=(-DBUILD_SHARED_LIBS=OFF) + ;; --enable-static) FLAGS+=(-DBUILD_STATIC_LIBS=ON) ;; + --disable-static) + FLAGS+=(-DBUILD_STATIC_LIBS=OFF) + ;; --disable-Bsymbolic) FLAGS+=(-DDISABLE_BSYMBOLIC=ON) ;; --disable-werror) FLAGS+=(-DDISABLE_WERROR=ON) ;; + --disable-extra-libs) + FLAGS+=(-DDISABLE_EXTRA_LIBS=ON) + ;; --) shift break diff --git a/cmake/config.h.in b/cmake/config.h.in index 547a585..1e6359d 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -56,6 +56,9 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_PARAM_H @HAVE_SYS_PARAM_H@ +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_RANDOM_H + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_RESOURCE_H @@ -71,6 +74,12 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_XLOCALE_H +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_BSD_STDLIB_H + +/* Define to 1 if you have `arc4random' */ +#cmakedefine HAVE_ARC4RANDOM + /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #cmakedefine HAVE_DOPRNT @@ -128,6 +137,9 @@ /* Define to 1 if you have the `uselocale' function. */ #cmakedefine HAVE_USELOCALE +/* 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. */ #cmakedefine HAVE_VASPRINTF @@ -140,6 +152,9 @@ /* Define to 1 if you have the `vsyslog' function. */ #cmakedefine HAVE_VSYSLOG @HAVE_VSYSLOG@ +/* Define if you have the `getrandom' function. */ +#cmakedefine HAVE_GETRANDOM + /* Define if you have the `getrusage' function. */ #cmakedefine HAVE_GETRUSAGE diff --git a/cmake/json_config.h.in b/cmake/json_config.h.in index f30d8a6..790fd7e 100644 --- a/cmake/json_config.h.in +++ b/cmake/json_config.h.in @@ -1,2 +1,5 @@ /* Define to 1 if you have the header file. */ #cmakedefine JSON_C_HAVE_INTTYPES_H @JSON_C_HAVE_INTTYPES_H@ + +/* Define to 1 if you have the header file. */ +#cmakedefine JSON_C_HAVE_STDINT_H @JSON_C_HAVE_STDINT_H@ diff --git a/debug.h b/debug.h index a24136b..4af0ba9 100644 --- a/debug.h +++ b/debug.h @@ -14,8 +14,8 @@ * @file * @brief Do not use, json-c internal, may be changed or removed at any time. */ -#ifndef _DEBUG_H_ -#define _DEBUG_H_ +#ifndef _JSON_C_DEBUG_H_ +#define _JSON_C_DEBUG_H_ #include @@ -24,7 +24,7 @@ extern "C" { #endif #ifndef JSON_EXPORT -#if defined(_MSC_VER) +#if defined(_MSC_VER) && defined(JSON_C_DLL) #define JSON_EXPORT __declspec(dllexport) #else #define JSON_EXPORT extern diff --git a/doc/Doxyfile b/doc/Doxyfile deleted file mode 100644 index 48833f1..0000000 --- a/doc/Doxyfile +++ /dev/null @@ -1,2363 +0,0 @@ -# Doxyfile 1.8.8 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. -# -# All text after a double hash (##) is considered a comment and is placed in -# front of the TAG it is preceding. -# -# All text after a single hash (#) is considered a comment and will be ignored. -# The format is: -# TAG = value [value, ...] -# For lists, items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (\" \"). - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. -# The default value is: UTF-8. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by -# double-quotes, unless you are using Doxywizard) that should identify the -# project for which the documentation is generated. This name is used in the -# title of most generated pages and in a few other places. -# The default value is: My Project. - -PROJECT_NAME = json-c - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. This -# could be handy for archiving the generated documentation or if some version -# control system is used. - -PROJECT_NUMBER = 0.15 - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer a -# quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify an logo or icon that is included in -# the documentation. The maximum height of the logo should not exceed 55 pixels -# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo -# to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path -# into which the generated documentation will be written. If a relative path is -# entered, it will be relative to the location where doxygen was started. If -# left blank the current directory will be used. - -OUTPUT_DIRECTORY = /home/erh/distcheck/doc - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this -# option can be useful when feeding doxygen a huge amount of source files, where -# putting all generated files in the same directory would otherwise causes -# performance problems for the file system. -# The default value is: NO. - -CREATE_SUBDIRS = NO - -# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII -# characters to appear in the names of generated files. If set to NO, non-ASCII -# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode -# U+3044. -# The default value is: NO. - -ALLOW_UNICODE_NAMES = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. -# The default value is: English. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member -# descriptions after the members that are listed in the file and class -# documentation (similar to Javadoc). Set to NO to disable this. -# The default value is: YES. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief -# description of a member or function before the detailed description -# -# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. -# The default value is: YES. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator that is -# used to form the text in various listings. Each string in this list, if found -# as the leading text of the brief description, will be stripped from the text -# and the result, after processing the whole list, is used as the annotated -# text. Otherwise, the brief description is used as-is. If left blank, the -# following values are used ($name is automatically replaced with the name of -# the entity):The $name class, The $name widget, The $name file, is, provides, -# specifies, contains, represents, a, an and the. - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# doxygen will generate a detailed section even if there is only a brief -# description. -# The default value is: NO. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. -# The default value is: NO. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path -# before files name in the file list and in the header files. If set to NO the -# shortest path that makes the file name unique will be used -# The default value is: YES. - -FULL_PATH_NAMES = YES - -# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. -# Stripping is only done if one of the specified strings matches the left-hand -# part of the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the path to -# strip. -# -# Note that you can specify absolute paths here, but also relative paths, which -# will be relative from the directory where doxygen is started. -# This tag requires that the tag FULL_PATH_NAMES is set to YES. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the -# path mentioned in the documentation of a class, which tells the reader which -# header file to include in order to use a class. If left blank only the name of -# the header file containing the class definition is used. Otherwise one should -# specify the list of include paths that are normally passed to the compiler -# using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but -# less readable) file names. This can be useful is your file systems doesn't -# support long names like on DOS, Mac, or CD-ROM. -# The default value is: NO. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the -# first line (until the first dot) of a Javadoc-style comment as the brief -# description. If set to NO, the Javadoc-style will behave just like regular Qt- -# style comments (thus requiring an explicit @brief command for a brief -# description.) -# The default value is: NO. - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first -# line (until the first dot) of a Qt-style comment as the brief description. If -# set to NO, the Qt-style will behave just like regular Qt-style comments (thus -# requiring an explicit \brief command for a brief description.) -# The default value is: NO. - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a -# multi-line C++ special comment block (i.e. a block of //! or /// comments) as -# a brief description. This used to be the default behavior. The new default is -# to treat a multi-line C++ comment block as a detailed description. Set this -# tag to YES if you prefer the old behavior instead. -# -# Note that setting this tag to YES also means that rational rose comments are -# not recognized any more. -# The default value is: NO. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the -# documentation from any documented member that it re-implements. -# The default value is: YES. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a -# new page for each member. If set to NO, the documentation of a member will be -# part of the file/class/namespace that contains it. -# The default value is: NO. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen -# uses this value to replace tabs by spaces in code fragments. -# Minimum value: 1, maximum value: 16, default value: 4. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that act as commands in -# the documentation. An alias has the form: -# name=value -# For example adding -# "sideeffect=@par Side Effects:\n" -# will allow you to put the command \sideeffect (or @sideeffect) in the -# documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. For -# instance, some of the names that are used will be different. The list of all -# members will be omitted, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or -# Python sources only. Doxygen will then generate output that is more tailored -# for that language. For instance, namespaces will be presented as packages, -# qualified scopes will look different, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources. Doxygen will then generate output that is tailored for Fortran. -# The default value is: NO. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for VHDL. -# The default value is: NO. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it -# using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: -# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: -# Fortran. In the later case the parser tries to guess whether the code is fixed -# or free formatted code, this is the default for Fortran type files), VHDL. For -# instance to make doxygen treat .inc files as Fortran files (default is PHP), -# and .f files as C (default is Fortran), use: inc=Fortran f=C. -# -# Note For files without extension you can use no_extension as a placeholder. -# -# Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. - -EXTENSION_MAPPING = - -# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments -# according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you can -# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in -# case of backward compatibilities issues. -# The default value is: YES. - -MARKDOWN_SUPPORT = YES - -# When enabled doxygen tries to link words that correspond to documented -# classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. -# The default value is: YES. - -AUTOLINK_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should set this -# tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. -# The default value is: NO. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. -# The default value is: NO. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. -# The default value is: NO. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate -# getter and setter methods for a property. Setting this option to YES will make -# doxygen to replace the get and set methods by a property in the documentation. -# This will only work if the methods are indeed getting or setting a simple -# type. If this is not the case, or you want to show the methods anyway, you -# should set this option to NO. -# The default value is: YES. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. -# The default value is: NO. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES to allow class member groups of the same type -# (for instance a group of public functions) to be put as a subgroup of that -# type (e.g. under the Public Functions section). Set it to NO to prevent -# subgrouping. Alternatively, this can be done per class using the -# \nosubgrouping command. -# The default value is: YES. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions -# are shown inside the group in which they are included (e.g. using \ingroup) -# instead of on a separate page (for HTML and Man pages) or section (for LaTeX -# and RTF). -# -# Note that this feature does not work in combination with -# SEPARATE_MEMBER_PAGES. -# The default value is: NO. - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions -# with only public data fields or simple typedef fields will be shown inline in -# the documentation of the scope in which they are defined (i.e. file, -# namespace, or group documentation), provided this scope is documented. If set -# to NO, structs, classes, and unions are shown on a separate page (for HTML and -# Man pages) or section (for LaTeX and RTF). -# The default value is: NO. - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or -# enum is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically be -# useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. -# The default value is: NO. - -TYPEDEF_HIDES_STRUCT = NO - -# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This -# cache is used to resolve symbols given their name and scope. Since this can be -# an expensive process and often the same symbol appears multiple times in the -# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small -# doxygen will become slower. If the cache is too large, memory is wasted. The -# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range -# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 -# symbols. At the end of a run doxygen will report the cache usage and suggest -# the optimal cache size from a speed point of view. -# Minimum value: 0, maximum value: 9, default value: 0. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. Private -# class members and static file members will be hidden unless the -# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. -# Note: This will also disable the warnings about undocumented members that are -# normally produced when WARNINGS is set to YES. -# The default value is: NO. - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will -# be included in the documentation. -# The default value is: NO. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal -# scope will be included in the documentation. -# The default value is: NO. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file will be -# included in the documentation. -# The default value is: NO. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO -# only classes defined in header files are included. Does not have any effect -# for Java sources. -# The default value is: YES. - -EXTRACT_LOCAL_CLASSES = NO - -# This flag is only useful for Objective-C code. When set to YES local methods, -# which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO only methods in the interface are -# included. -# The default value is: NO. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base name of -# the file that contains the anonymous namespace. By default anonymous namespace -# are hidden. -# The default value is: NO. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all -# undocumented members inside documented classes or files. If set to NO these -# members will be included in the various overviews, but no documentation -# section is generated. This option has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. If set -# to NO these classes will be included in the various overviews. This option has -# no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO these declarations will be -# included in the documentation. -# The default value is: NO. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO these -# blocks will be appended to the function's detailed documentation block. -# The default value is: NO. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation that is typed after a -# \internal command is included. If the tag is set to NO then the documentation -# will be excluded. Set it to YES to include the internal documentation. -# The default value is: NO. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. -# The default value is: system dependent. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES the -# scope will be hidden. -# The default value is: NO. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of -# the files that are included by a file in the documentation of that file. -# The default value is: YES. - -SHOW_INCLUDE_FILES = NO - -# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each -# grouped member an include statement to the documentation, telling the reader -# which file to include in order to use the member. -# The default value is: NO. - -SHOW_GROUPED_MEMB_INC = NO - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include -# files with double quotes in the documentation rather than with sharp brackets. -# The default value is: NO. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the -# documentation for inline members. -# The default value is: YES. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the -# (detailed) documentation of file and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. -# The default value is: YES. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief -# descriptions of file, namespace and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. Note that -# this will also influence the order of the classes in the class list. -# The default value is: NO. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the -# (brief and detailed) documentation of class members so that constructors and -# destructors are listed first. If set to NO the constructors will appear in the -# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. -# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief -# member documentation. -# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting -# detailed member documentation. -# The default value is: NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy -# of group names into alphabetical order. If set to NO the group names will -# appear in their defined order. -# The default value is: NO. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by -# fully-qualified names, including namespaces. If set to NO, the class list will -# be sorted only by class name, not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the alphabetical -# list. -# The default value is: NO. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper -# type resolution of all parameters of a function it will reject a match between -# the prototype and the implementation of a member function even if there is -# only one candidate or it is obvious which candidate to choose by doing a -# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still -# accept a match between prototype and implementation in such cases. -# The default value is: NO. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the -# todo list. This list is created by putting \todo commands in the -# documentation. -# The default value is: YES. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the -# test list. This list is created by putting \test commands in the -# documentation. -# The default value is: YES. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug -# list. This list is created by putting \bug commands in the documentation. -# The default value is: YES. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) -# the deprecated list. This list is created by putting \deprecated commands in -# the documentation. -# The default value is: YES. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional documentation -# sections, marked by \if ... \endif and \cond -# ... \endcond blocks. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the -# initial value of a variable or macro / define can have for it to appear in the -# documentation. If the initializer consists of more lines than specified here -# it will be hidden. Use a value of 0 to hide initializers completely. The -# appearance of the value of individual variables and macros / defines can be -# controlled using \showinitializer or \hideinitializer command in the -# documentation regardless of this setting. -# Minimum value: 0, maximum value: 10000, default value: 30. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES the list -# will mention the files that were used to generate the documentation. -# The default value is: YES. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This -# will remove the Files entry from the Quick Index and from the Folder Tree View -# (if specified). -# The default value is: YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces -# page. This will remove the Namespaces entry from the Quick Index and from the -# Folder Tree View (if specified). -# The default value is: YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command command input-file, where command is the value of the -# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided -# by doxygen. Whatever the program writes to standard output is used as the file -# version. For an example see the documentation. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. You can -# optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. -# -# Note that if you run doxygen from a directory containing a file called -# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE -# tag is left empty. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files containing -# the reference definitions. This must be a list of .bib files. The .bib -# extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. -# For LaTeX the style of the bibliography can be controlled using -# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. See also \cite for info how to create references. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# Configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated to -# standard output by doxygen. If QUIET is set to YES this implies that the -# messages are off. -# The default value is: NO. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES -# this implies that the warnings are on. -# -# Tip: Turn warnings on while writing the documentation. -# The default value is: YES. - -WARNINGS = YES - -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate -# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag -# will automatically be disabled. -# The default value is: YES. - -WARN_IF_UNDOCUMENTED = YES - -# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. -# The default value is: YES. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that -# are documented, but have no documentation for their parameters or return -# value. If set to NO doxygen will only warn about wrong or incomplete parameter -# documentation, but not about the absence of documentation. -# The default value is: NO. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that doxygen -# can produce. The string should contain the $file, $line, and $text tags, which -# will be replaced by the file and line number from which the warning originated -# and the warning text. Optionally the format may contain $version, which will -# be replaced by the version of the file (if it could be obtained via -# FILE_VERSION_FILTER) -# The default value is: $file:$line: $text. - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning and error -# messages should be written. If left blank the output is written to standard -# error (stderr). - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# Configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag is used to specify the files and/or directories that contain -# documented source files. You may enter file names like myfile.cpp or -# directories like /usr/src/myproject. Separate the files or directories with -# spaces. -# Note: If this tag is empty the current directory is searched. - -INPUT = /home/erh/json-c-0.15 /home/erh/distcheck - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses -# libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of -# possible encodings. -# The default value is: UTF-8. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. - -FILE_PATTERNS = *.h \ - *.md - -# The RECURSIVE tag can be used to specify whether or not subdirectories should -# be searched for input files as well. -# The default value is: NO. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. -# The default value is: NO. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories for example use the pattern */test/* - -EXCLUDE_PATTERNS = \ - */json_object_private.h \ - */debug.h \ - */*config.h \ - */random_seed.h \ - */strerror_*h \ - */*compat.h - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* - -EXCLUDE_SYMBOLS = \ - _json_c_* \ - _LH_* \ - _printbuf_* \ - __STRING - -# The EXAMPLE_PATH tag can be used to specify one or more files or directories -# that contain example code fragments that are included (see the \include -# command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank all -# files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude commands -# irrespective of the value of the RECURSIVE tag. -# The default value is: NO. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or directories -# that contain images that are to be included in the documentation (see the -# \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command: -# -# -# -# where is the value of the INPUT_FILTER tag, and is the -# name of an input file. Doxygen will then use the output that the filter -# program writes to standard output. If FILTER_PATTERNS is specified, this tag -# will be ignored. -# -# Note that the filter must not add or remove lines; it is applied before the -# code is scanned, but not when the output code is generated. If lines are added -# or removed, the anchors will not be placed correctly. - -INPUT_FILTER = /home/erh/json-c-0.15/doc/fixup_markdown.sh - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: pattern=filter -# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how -# filters are used. If the FILTER_PATTERNS tag is empty or if none of the -# patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER ) will also be used to filter the input files that are used for -# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). -# The default value is: NO. - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and -# it is also possible to disable source filtering for a specific pattern using -# *.ext= (so without naming a filter). -# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. - -FILTER_SOURCE_PATTERNS = - -# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that -# is part of the input, its contents will be placed on the main page -# (index.html). This can be useful if you have a project on for instance GitHub -# and want to reuse the introduction page also for the doxygen output. - -USE_MDFILE_AS_MAINPAGE = README.md - -#--------------------------------------------------------------------------- -# Configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will be -# generated. Documented entities will be cross-referenced with these sources. -# -# Note: To get rid of all source code in the generated output, make sure that -# also VERBATIM_HEADERS is set to NO. -# The default value is: NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. -# The default value is: NO. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any -# special comment blocks from generated source code fragments. Normal C, C++ and -# Fortran comments will always remain visible. -# The default value is: YES. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. -# The default value is: NO. - -REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES then for each documented function -# all documented entities called/used by that function will be listed. -# The default value is: NO. - -REFERENCES_RELATION = YES - -# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES, then the hyperlinks from functions in REFERENCES_RELATION and -# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will -# link to the documentation. -# The default value is: YES. - -REFERENCES_LINK_SOURCE = YES - -# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the -# source code will show a tooltip with additional information such as prototype, -# brief description and links to the definition and documentation. Since this -# will make the HTML file larger and loading of large files a bit slower, you -# can opt to disable this feature. -# The default value is: YES. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -SOURCE_TOOLTIPS = YES - -# If the USE_HTAGS tag is set to YES then the references to source code will -# point to the HTML generated by the htags(1) tool instead of doxygen built-in -# source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version -# 4.8.6 or higher. -# -# To use it do the following: -# - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file -# - Make sure the INPUT points to the root of the source tree -# - Run doxygen as normal -# -# Doxygen will invoke htags (and that will in turn invoke gtags), so these -# tools must be available from the command line (i.e. in the search path). -# -# The result: instead of the source browser generated by doxygen, the links to -# source code will now point to the output of htags. -# The default value is: NO. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a -# verbatim copy of the header file for each class for which an include is -# specified. Set to NO to disable this. -# See also: Section \class. -# The default value is: YES. - -VERBATIM_HEADERS = NO - -# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the -# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the -# cost of reduced performance. This can be particularly helpful with template -# rich C++ code for which doxygen's built-in parser lacks the necessary type -# information. -# Note: The availability of this option depends on whether or not doxygen was -# compiled with the --with-libclang option. -# The default value is: NO. - -#CLANG_ASSISTED_PARSING = NO - -# If clang assisted parsing is enabled you can provide the compiler with command -# line options that you would normally use when invoking the compiler. Note that -# the include paths will already be set by doxygen for the files and directories -# specified with INPUT and INCLUDE_PATH. -# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. - -#CLANG_OPTIONS = - -#--------------------------------------------------------------------------- -# Configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all -# compounds will be generated. Enable this if the project contains a lot of -# classes, structs, unions or interfaces. -# The default value is: YES. - -ALPHABETICAL_INDEX = NO - -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output -# The default value is: YES. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a -# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of -# it. -# The default directory is: html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each -# generated HTML page (for example: .htm, .php, .asp). -# The default value is: .html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a user-defined HTML header file for -# each generated HTML page. If the tag is left blank doxygen will generate a -# standard header. -# -# To get valid HTML the header file that includes any scripts and style sheets -# that doxygen needs, which is dependent on the configuration options used (e.g. -# the setting GENERATE_TREEVIEW). It is highly recommended to start with a -# default header using -# doxygen -w html new_header.html new_footer.html new_stylesheet.css -# YourConfigFile -# and then modify the file new_header.html. See also section "Doxygen usage" -# for information on how to generate the default header that doxygen normally -# uses. -# Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. For a description -# of the possible markers and block names see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each -# generated HTML page. If the tag is left blank doxygen will generate a standard -# footer. See HTML_HEADER for more information on how to generate a default -# footer and what special commands can be used inside the footer. See also -# section "Doxygen usage" for information on how to generate the default footer -# that doxygen normally uses. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style -# sheet that is used by each HTML page. It can be used to fine-tune the look of -# the HTML output. If left blank doxygen will generate a default style sheet. -# See also section "Doxygen usage" for information on how to generate the style -# sheet that doxygen normally uses. -# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as -# it is more robust and this tag (HTML_STYLESHEET) will in the future become -# obsolete. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_STYLESHEET = - -# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined -# cascading style sheets that are included after the standard style sheets -# created by doxygen. Using this option one can overrule certain style aspects. -# This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. -# Doxygen will copy the style sheet files to the output directory. -# Note: The order of the extra stylesheet files is of importance (e.g. the last -# stylesheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that the -# files will be copied as-is; there are no commands or markers available. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the stylesheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value -# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 -# purple, and 360 is red again. -# Minimum value: 0, maximum value: 359, default value: 220. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A -# value of 255 will produce the most vivid colors. -# Minimum value: 0, maximum value: 255, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the -# luminance component of the colors in the HTML output. Values below 100 -# gradually make the output lighter, whereas values above 100 make the output -# darker. The value divided by 100 is the actual gamma applied, so 80 represents -# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not -# change the gamma. -# Minimum value: 40, maximum value: 240, default value: 80. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_DYNAMIC_SECTIONS = NO - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries -# shown in the various tree structured indices initially; the user can expand -# and collapse entries dynamically later on. Doxygen will expand the tree to -# such a level that at most the specified number of entries are visible (unless -# a fully collapsed tree already exceeds this amount). So setting the number of -# entries 1 will produce a full collapsed tree by default. 0 is a special value -# representing an infinite number of entries and will result in a full expanded -# tree by default. -# Minimum value: 0, maximum value: 9999, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files will be -# generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_DOCSET = NO - -# This tag determines the name of the docset feed. A documentation feed provides -# an umbrella under which multiple documentation sets from a single provider -# (such as a company or product suite) can be grouped. -# The default value is: Doxygen generated docs. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# This tag specifies a string that should uniquely identify the documentation -# set bundle. This should be a reverse domain-name style string, e.g. -# com.mycompany.MyDocSet. Doxygen will append .docset to the name. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. -# The default value is: org.doxygen.Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. -# The default value is: Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three -# additional HTML index files: index.hhp, index.hhc, and index.hhk. The -# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. -# -# The HTML Help Workshop contains a compiler that can convert all HTML output -# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML -# files are now used as the Windows 98 help format, and will replace the old -# Windows help format (.hlp) on all Windows platforms in the future. Compressed -# HTML files also contain an index, a table of contents, and you can search for -# words in the documentation. The HTML workshop also contains a viewer for -# compressed HTML files. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_HTMLHELP = NO - -# The CHM_FILE tag can be used to specify the file name of the resulting .chm -# file. You can add a path in front of the file if the result should not be -# written to the html output directory. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_FILE = - -# The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler ( hhc.exe). If non-empty -# doxygen will try to run the HTML help compiler on the generated index.hhp. -# The file has to be specified with full path. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -HHC_LOCATION = - -# The GENERATE_CHI flag controls if a separate .chi index file is generated ( -# YES) or that it should be included in the master .chm file ( NO). -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -GENERATE_CHI = NO - -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) -# and project file content. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_INDEX_ENCODING = - -# The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it -# enables the Previous and Next buttons. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members to -# the table of contents of the HTML help documentation and to the tree view. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that -# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help -# (.qch) of the generated HTML documentation. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify -# the file name of the resulting .qch file. The path specified is relative to -# the HTML output folder. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help -# Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt -# Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). -# The default value is: doc. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_VIRTUAL_FOLDER = doc - -# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom -# filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_SECT_FILTER_ATTRS = - -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be -# generated, together with the HTML files, they form an Eclipse help plugin. To -# install this plugin and make it available under the help contents menu in -# Eclipse, the contents of the directory containing the HTML and XML files needs -# to be copied into the plugins directory of eclipse. The name of the directory -# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. -# After copying Eclipse needs to be restarted before the help appears. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the Eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have this -# name. Each documentation set should have its own identifier. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# If you want full control over the layout of the generated HTML pages it might -# be necessary to disable the index and replace it with your own. The -# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top -# of each HTML page. A value of NO enables the index and the value YES disables -# it. Since the tabs in the index contain the same information as the navigation -# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. If the tag -# value is set to YES, a side panel will be generated containing a tree-like -# index structure (just like the one that is generated for HTML Help). For this -# to work a browser that supports JavaScript, DHTML, CSS and frames is required -# (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_TREEVIEW = NO - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that -# doxygen will group on one line in the generated HTML documentation. -# -# Note that a value of 0 will completely suppress the enum values from appearing -# in the overview section. -# Minimum value: 0, maximum value: 20, default value: 4. -# This tag requires that the tag GENERATE_HTML is set to YES. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used -# to set the initial width (in pixels) of the frame in which the tree is shown. -# Minimum value: 0, maximum value: 1500, default value: 250. -# This tag requires that the tag GENERATE_HTML is set to YES. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to -# external symbols imported via tag files in a separate window. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of LaTeX formulas included as images in -# the HTML documentation. When you change the font size after a successful -# doxygen run you need to manually remove any form_*.png images from the HTML -# output directory to force them to be regenerated. -# Minimum value: 8, maximum value: 50, default value: 10. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using prerendered bitmaps. Use this if you do not have LaTeX -# installed or if you want to formulas look prettier in the HTML output. When -# enabled you may also need to install MathJax separately and configure the path -# to it using the MATHJAX_RELPATH option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -USE_MATHJAX = NO - -# When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. -# Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. -# The default value is: HTML-CSS. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_FORMAT = HTML-CSS - -# When MathJax is enabled you need to specify the location relative to the HTML -# output directory using the MATHJAX_RELPATH option. The destination directory -# should contain the MathJax.js script. For instance, if the mathjax directory -# is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax -# Content Delivery Network so you can quickly see the result without installing -# MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest - -# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax -# extension names that should be enabled during MathJax rendering. For example -# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_EXTENSIONS = - -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces -# of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an -# example see the documentation. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_CODEFILE = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for -# the HTML output. The underlying search engine uses javascript and DHTML and -# should work on any modern browser. Note that when using HTML help -# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) -# there is already a search function so this one should typically be disabled. -# For large projects the javascript based search engine can be slow, then -# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to -# search using the keyboard; to jump to the search box use + S -# (what the is depends on the OS and browser, but it is typically -# , / diff --git a/doc/html/annotated.html b/doc/html/annotated.html index 3df9bda..9e9d15a 100644 --- a/doc/html/annotated.html +++ b/doc/html/annotated.html @@ -17,7 +17,7 @@
json-c -  0.15 +  0.17
@@ -51,17 +51,19 @@ oCarray_list oCjson_object_iter oCjson_object_iterator -oCjson_tokener -oCjson_tokener_srec -oClh_entry -oClh_table -\Cprintbuf +oCjson_patch_error +oCjson_pointer_get_result +oCjson_tokener +oCjson_tokener_srec +oClh_entry +oClh_table +\Cprintbuf diff --git a/doc/html/arraylist_8h.html b/doc/html/arraylist_8h.html index 259687d..5820d13 100644 --- a/doc/html/arraylist_8h.html +++ b/doc/html/arraylist_8h.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/arraylist.h File Reference +json-c: arraylist.h File Reference @@ -17,7 +17,7 @@
json-c -  0.15 +  0.17
@@ -40,10 +40,6 @@
  • Globals
  • -
    @@ -86,6 +82,8 @@ Functions   void * array_list_get_idx (struct array_list *al, size_t i)   +int array_list_insert_idx (struct array_list *al, size_t i, void *data) +  int array_list_put_idx (struct array_list *al, size_t i, void *data)   int array_list_add (struct array_list *al, void *data) @@ -274,6 +272,38 @@ Functions
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    int array_list_insert_idx (struct array_listal,
    size_t i,
    void * data 
    )
    +
    + +
    +
    @@ -445,7 +475,7 @@ Functions
    diff --git a/doc/html/classes.html b/doc/html/classes.html index 5f9f20c..85917c2 100644 --- a/doc/html/classes.html +++ b/doc/html/classes.html @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -49,22 +49,22 @@
    A | J | L | P
    - + - + - - + + +
      A  
    -
    json_object_iterator   lh_table   
    json_tokener   
      P  
    +
    json_object_iterator   json_tokener_srec   lh_table   
    json_patch_error   
      L  
    +
      P  
    array_list   json_tokener_srec   
    array_list   json_pointer_get_result   
      J  
    -
      L  
    -
    printbuf   
    json_object_iter   lh_entry   
    json_tokener   lh_entry   printbuf   
    json_object_iter   
    A | J | L | P
    diff --git a/doc/html/deprecated.html b/doc/html/deprecated.html index 2a5adb9..14557d0 100644 --- a/doc/html/deprecated.html +++ b/doc/html/deprecated.html @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -56,12 +56,38 @@
    Class json_tokener_srec
    Don't use this outside of json_tokener.c, it will be made private in a future release.
    Global json_tokener_state
    -
    Don't use this outside of json_tokener.c, it will be made private in a future release.
    +
    Don't use this outside of json_tokener.c, it will be made private in a future release.
    +
    Global lh_entry::k
    +
    Use lh_entry_k() instead of accessing this directly.
    +
    Global lh_entry::k_is_constant
    +
    use lh_entry_k_is_constant() instead.
    +
    Global lh_entry::next
    +
    Use lh_entry_next() instead of accessing this directly.
    +
    Global lh_entry::prev
    +
    Use lh_entry_prev() instead of accessing this directly.
    +
    Global lh_entry::v
    +
    Use lh_entry_v() instead of accessing this directly.
    +
    Global lh_table::count
    +
    Use lh_table_length() instead.
    +
    Global lh_table::equal_fn
    +
    do not use outside of linkhash.c
    +
    Global lh_table::free_fn
    +
    do not use outside of linkhash.c
    +
    Global lh_table::hash_fn
    +
    do not use outside of linkhash.c
    +
    Global lh_table::head
    +
    Use lh_table_head() instead.
    +
    Global lh_table::size
    +
    do not use outside of linkhash.c
    +
    Global lh_table::table
    +
    do not use outside of linkhash.c
    +
    Global lh_table::tail
    +
    Do not use, may be removed in a future release.
    diff --git a/doc/html/dir_71f13e590eb9d766c31051438785ada5.html b/doc/html/dir_71f13e590eb9d766c31051438785ada5.html deleted file mode 100644 index e089d74..0000000 --- a/doc/html/dir_71f13e590eb9d766c31051438785ada5.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - -json-c: /home/erh/json-c-0.15 Directory Reference - - - - - - -
    -
    - - - - - - -
    -
    json-c -  0.15 -
    -
    -
    - - - - -
    -
    -
    -
    json-c-0.15 Directory Reference
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    -Files

    file  arraylist.h
     Internal methods for working with json_type_array objects. Although this is exposed by the json_object_get_array() method, it is not recommended for direct use.
     
    file  json.h
     A convenience header that may be included instead of other individual ones.
     
    file  json_c_version.h
     Methods for retrieving the json-c version.
     
    file  json_inttypes.h
     Do not use, json-c internal, may be changed or removed at any time.
     
    file  json_object.h
     Core json-c API. Start here, or with json_tokener.h.
     
    file  json_object_iterator.h
     An API for iterating over json_type_object objects, styled to be familiar to C++ programmers. Unlike json_object_object_foreach() and json_object_object_foreachC(), this avoids the need to expose json-c internals like lh_entry.
     
    file  json_pointer.h
     JSON Pointer (RFC 6901) implementation for retrieving objects from a json-c object tree.
     
    file  json_tokener.h
     Methods to parse an input string into a tree of json_object objects.
     
    file  json_types.h
     Basic types used in a few places in json-c, but you should include "json_object.h" instead.
     
    file  json_util.h
     Miscllaneous utility functions and macros.
     
    file  json_visit.h
     Methods for walking a tree of objects.
     
    file  linkhash.h
     Internal methods for working with json_type_object objects. Although this is exposed by the json_object_get_object() function and within the json_object_iter type, it is not recommended for direct use.
     
    file  printbuf.h
     Internal string buffer handing. Unless you're writing a json_object_to_json_string_fn implementation for use with json_object_set_serializer() direct use of this is not recommended.
     
    -
    - - - - diff --git a/doc/html/dir_b62156a74b5a818be0c2ef9f85294b95.html b/doc/html/dir_b62156a74b5a818be0c2ef9f85294b95.html new file mode 100644 index 0000000..b6a5efb --- /dev/null +++ b/doc/html/dir_b62156a74b5a818be0c2ef9f85294b95.html @@ -0,0 +1,62 @@ + + + + + +json-c: /home/erh/distcheck Directory Reference + + + + + + +
    +
    + + + + + + +
    +
    json-c +  0.17 +
    +
    +
    + + + + +
    +
    +
    +
    distcheck Directory Reference
    +
    +
    + + + + + +

    +Files

    file  json.h
     A convenience header that may be included instead of other individual ones.
     
    +
    + + + + diff --git a/doc/html/files.html b/doc/html/files.html index 769fef6..be62fff 100644 --- a/doc/html/files.html +++ b/doc/html/files.html @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -48,26 +48,28 @@
    Here is a list of all files with brief descriptions:
    [detail level 12]
    - - - - - - - - - - - - - - + + + + + + + + + + + + + + + +
    \-json-c-0.15
     o*arraylist.hInternal methods for working with json_type_array objects. Although this is exposed by the json_object_get_array() method, it is not recommended for direct use
     o*json.hA convenience header that may be included instead of other individual ones
     o*json_c_version.hMethods for retrieving the json-c version
     o*json_inttypes.hDo not use, json-c internal, may be changed or removed at any time
     o*json_object.hCore json-c API. Start here, or with json_tokener.h
     o*json_object_iterator.hAn API for iterating over json_type_object objects, styled to be familiar to C++ programmers. Unlike json_object_object_foreach() and json_object_object_foreachC(), this avoids the need to expose json-c internals like lh_entry
     o*json_pointer.hJSON Pointer (RFC 6901) implementation for retrieving objects from a json-c object tree
     o*json_tokener.hMethods to parse an input string into a tree of json_object objects
     o*json_types.hBasic types used in a few places in json-c, but you should include "json_object.h" instead
     o*json_util.hMiscllaneous utility functions and macros
     o*json_visit.hMethods for walking a tree of objects
     o*linkhash.hInternal methods for working with json_type_object objects. Although this is exposed by the json_object_get_object() function and within the json_object_iter type, it is not recommended for direct use
     \*printbuf.hInternal string buffer handing. Unless you're writing a json_object_to_json_string_fn implementation for use with json_object_set_serializer() direct use of this is not recommended
    o-distcheck
    |\*json.hA convenience header that may be included instead of other individual ones
    o*arraylist.hInternal methods for working with json_type_array objects. Although this is exposed by the json_object_get_array() method, it is not recommended for direct use
    o*json_c_version.hMethods for retrieving the json-c version
    o*json_inttypes.hDo not use, json-c internal, may be changed or removed at any time
    o*json_object.hCore json-c API. Start here, or with json_tokener.h
    o*json_object_iterator.hAn API for iterating over json_type_object objects, styled to be familiar to C++ programmers. Unlike json_object_object_foreach() and json_object_object_foreachC(), this avoids the need to expose json-c internals like lh_entry
    o*json_patch.hJSON Patch (RFC 6902) implementation for manipulating JSON objects
    o*json_pointer.hJSON Pointer (RFC 6901) implementation for retrieving objects from a json-c object tree
    o*json_pointer_private.hDo not use, json-c internal, may be changed or removed at any time
    o*json_tokener.hMethods to parse an input string into a tree of json_object objects
    o*json_types.hBasic types used in a few places in json-c, but you should include "json_object.h" instead
    o*json_util.hMiscllaneous utility functions and macros
    o*json_visit.hMethods for walking a tree of objects
    o*linkhash.hInternal methods for working with json_type_object objects. Although this is exposed by the json_object_get_object() function and within the json_object_iter type, it is not recommended for direct use
    \*printbuf.hInternal string buffer handling. Unless you're writing a json_object_to_json_string_fn implementation for use with json_object_set_serializer() direct use of this is not recommended
    diff --git a/doc/html/functions.html b/doc/html/functions.html index 21816fc..2465e53 100644 --- a/doc/html/functions.html +++ b/doc/html/functions.html @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -120,6 +120,12 @@
  • err : json_tokener
  • +
  • errmsg +: json_patch_error +
  • +
  • errno_code +: json_patch_error +
  • @@ -148,6 +154,9 @@

    - i -

    @@ -190,7 +202,8 @@

    - o -

    • obj -: json_tokener_srec +: json_pointer_get_result +, json_tokener_srec
    • obj_field_name : json_tokener_srec @@ -202,6 +215,12 @@

      - p -

      @@ -148,6 +154,9 @@

      - i -

      @@ -190,7 +202,8 @@

      - o -

      • obj -: json_tokener_srec +: json_pointer_get_result +, json_tokener_srec
      • obj_field_name : json_tokener_srec @@ -202,6 +215,12 @@

        - p -

          +
        • parent +: json_pointer_get_result +
        • +
        • patch_failure_idx +: json_patch_error +
        • pb : json_tokener
        • @@ -267,7 +286,7 @@ diff --git a/doc/html/globals.html b/doc/html/globals.html index b887b60..1ca85d0 100644 --- a/doc/html/globals.html +++ b/doc/html/globals.html @@ -17,7 +17,7 @@
          json-c -  0.15 +  0.17
          @@ -54,10 +54,12 @@ @@ -89,6 +91,9 @@
        • array_list_get_idx() : arraylist.h
        • +
        • array_list_insert_idx() +: arraylist.h +
        • array_list_length() : arraylist.h
        • @@ -111,7 +116,7 @@ diff --git a/doc/html/globals_0x69.html b/doc/html/globals_0x69.html new file mode 100644 index 0000000..bc196c1 --- /dev/null +++ b/doc/html/globals_0x69.html @@ -0,0 +1,85 @@ + + + + + +json-c: Globals + + + + + + +
          +
          + + + + + + +
          +
          json-c +  0.17 +
          +
          +
          + + + + + + +
          +
          +
          Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
          + +

          - i -

          +
          + + + + diff --git a/doc/html/globals_0x6a.html b/doc/html/globals_0x6a.html index b29c577..8fce44f 100644 --- a/doc/html/globals_0x6a.html +++ b/doc/html/globals_0x6a.html @@ -17,7 +17,7 @@
          json-c -  0.15 +  0.17
          @@ -54,10 +54,12 @@ @@ -80,12 +82,18 @@
        • JSON_C_MINOR_VERSION : json_c_version.h
        • +
        • JSON_C_OBJECT_ADD_CONSTANT_KEY +: json_object.h +
        • JSON_C_OBJECT_ADD_KEY_IS_NEW : json_object.h
        • JSON_C_OBJECT_KEY_IS_CONSTANT : json_object.h
        • +
        • json_c_object_sizeof() +: json_object.h +
        • JSON_C_OPTION_GLOBAL : json_object.h
        • @@ -107,6 +115,9 @@
        • JSON_C_STR_HASH_PERLLIKE : linkhash.h
        • +
        • JSON_C_TO_STRING_COLOR +: json_object.h +
        • JSON_C_TO_STRING_NOSLASHESCAPE : json_object.h
        • @@ -193,6 +204,9 @@
        • json_object_array_get_idx() : json_object.h
        • +
        • json_object_array_insert_idx() +: json_object.h +
        • json_object_array_length() : json_object.h
        • @@ -421,15 +435,27 @@
        • json_parse_uint64() : json_util.h
        • +
        • json_patch_apply() +: json_patch.h +
        • +
        • json_pointer_array_set_cb +: json_pointer_private.h +
        • json_pointer_get() : json_pointer.h
        • +
        • json_pointer_get_internal() +: json_pointer_private.h +
        • json_pointer_getf() : json_pointer.h
        • json_pointer_set() : json_pointer.h
        • +
        • json_pointer_set_with_array_cb() +: json_pointer_private.h +
        • json_pointer_setf() : json_pointer.h
        • @@ -454,6 +480,9 @@
        • json_tokener_error_desc() : json_tokener.h
        • +
        • json_tokener_error_memory +: json_tokener.h +
        • json_tokener_error_parse_array : json_tokener.h
        • @@ -617,7 +646,7 @@ : json_tokener.h
        • json_type -: json_types.h +: json_types.h
        • json_type_array : json_types.h @@ -650,7 +679,7 @@ diff --git a/doc/html/globals_0x6c.html b/doc/html/globals_0x6c.html index f641b4c..7a46853 100644 --- a/doc/html/globals_0x6c.html +++ b/doc/html/globals_0x6c.html @@ -17,7 +17,7 @@
          json-c -  0.15 +  0.17
          @@ -54,10 +54,12 @@ @@ -71,11 +73,23 @@
        • lh_entry_free_fn : linkhash.h
        • -
        • lh_entry_k -: linkhash.h +
        • lh_entry_k() +: linkhash.h
        • -
        • lh_entry_v -: linkhash.h +
        • lh_entry_k_is_constant() +: linkhash.h +
        • +
        • lh_entry_next() +: linkhash.h +
        • +
        • lh_entry_prev() +: linkhash.h +
        • +
        • lh_entry_set_val() +: linkhash.h +
        • +
        • lh_entry_v() +: linkhash.h
        • lh_equal_fn : linkhash.h @@ -89,6 +103,9 @@
        • LH_FREED : linkhash.h
        • +
        • lh_get_hash() +: linkhash.h +
        • lh_hash_fn : linkhash.h
        • @@ -116,6 +133,9 @@
        • lh_table_free() : linkhash.h
        • +
        • lh_table_head() +: linkhash.h +
        • lh_table_insert() : linkhash.h
        • @@ -144,7 +164,7 @@ diff --git a/doc/html/globals_0x70.html b/doc/html/globals_0x70.html index 03bbf1e..ca64b8d 100644 --- a/doc/html/globals_0x70.html +++ b/doc/html/globals_0x70.html @@ -17,7 +17,7 @@
          json-c -  0.15 +  0.17
          @@ -54,10 +54,12 @@ @@ -102,7 +104,7 @@ diff --git a/doc/html/globals_0x73.html b/doc/html/globals_0x73.html index fef8adc..fcd5783 100644 --- a/doc/html/globals_0x73.html +++ b/doc/html/globals_0x73.html @@ -17,7 +17,7 @@
          json-c -  0.15 +  0.17
          @@ -54,10 +54,12 @@ @@ -75,7 +77,7 @@ diff --git a/doc/html/globals_0x75.html b/doc/html/globals_0x75.html new file mode 100644 index 0000000..bbf6cb3 --- /dev/null +++ b/doc/html/globals_0x75.html @@ -0,0 +1,85 @@ + + + + + +json-c: Globals + + + + + + +
          +
          + + + + + + +
          +
          json-c +  0.17 +
          +
          +
          + + + + + + +
          +
          +
          Here is a list of all functions, variables, defines, enums, and typedefs with links to the files they belong to:
          + +

          - u -

          +
          + + + + diff --git a/doc/html/globals_defs.html b/doc/html/globals_defs.html index b0fb3a1..34258f5 100644 --- a/doc/html/globals_defs.html +++ b/doc/html/globals_defs.html @@ -17,7 +17,7 @@
          json-c -  0.15 +  0.17
          @@ -84,6 +84,9 @@
        • JSON_C_MINOR_VERSION : json_c_version.h
        • +
        • JSON_C_OBJECT_ADD_CONSTANT_KEY +: json_object.h +
        • JSON_C_OBJECT_ADD_KEY_IS_NEW : json_object.h
        • @@ -102,6 +105,9 @@
        • JSON_C_STR_HASH_PERLLIKE : linkhash.h
        • +
        • JSON_C_TO_STRING_COLOR +: json_object.h +
        • JSON_C_TO_STRING_NOSLASHESCAPE : json_object.h
        • @@ -145,8 +151,8 @@ : json_visit.h
        • JSON_EXPORT -: printbuf.h -, json_types.h +: json_types.h +, printbuf.h , json_c_version.h
        • JSON_FILE_BUF_SIZE @@ -186,12 +192,6 @@
        • LH_EMPTY : linkhash.h
        • -
        • lh_entry_k -: linkhash.h -
        • -
        • lh_entry_v -: linkhash.h -
        • lh_foreach : linkhash.h
        • @@ -237,7 +237,7 @@ diff --git a/doc/html/globals_enum.html b/doc/html/globals_enum.html index 641cea6..ecbb519 100644 --- a/doc/html/globals_enum.html +++ b/doc/html/globals_enum.html @@ -17,7 +17,7 @@
          json-c -  0.15 +  0.17
          @@ -67,7 +67,7 @@ diff --git a/doc/html/globals_eval.html b/doc/html/globals_eval.html index 3bfbf39..7748435 100644 --- a/doc/html/globals_eval.html +++ b/doc/html/globals_eval.html @@ -17,7 +17,7 @@
          json-c -  0.15 +  0.17
          @@ -67,6 +67,9 @@
        • json_tokener_error_depth : json_tokener.h
        • +
        • json_tokener_error_memory +: json_tokener.h +
        • json_tokener_error_parse_array : json_tokener.h
        • @@ -215,7 +218,7 @@ diff --git a/doc/html/globals_func.html b/doc/html/globals_func.html index 8ffe495..9bc4120 100644 --- a/doc/html/globals_func.html +++ b/doc/html/globals_func.html @@ -17,7 +17,7 @@
          json-c -  0.15 +  0.17
          @@ -80,6 +80,9 @@
        • array_list_get_idx() : arraylist.h
        • +
        • array_list_insert_idx() +: arraylist.h +
        • array_list_length() : arraylist.h
        • @@ -102,8 +105,8 @@

          - j -

            -
          • JSON_C_CONST_FUNCTION() -: json_object.h +
          • json_c_object_sizeof() +: json_object.h
          • json_c_set_serialization_double_format() : json_object.h @@ -132,6 +135,9 @@
          • json_object_array_get_idx() : json_object.h
          • +
          • json_object_array_insert_idx() +: json_object.h +
          • json_object_array_length() : json_object.h
          • @@ -336,15 +342,24 @@
          • json_parse_uint64() : json_util.h
          • +
          • json_patch_apply() +: json_patch.h +
          • json_pointer_get() : json_pointer.h
          • +
          • json_pointer_get_internal() +: json_pointer_private.h +
          • json_pointer_getf() : json_pointer.h
          • json_pointer_set() : json_pointer.h
          • +
          • json_pointer_set_with_array_cb() +: json_pointer_private.h +
          • json_pointer_setf() : json_pointer.h
          • @@ -391,6 +406,27 @@

            - l -

            diff --git a/doc/html/globals_vars.html b/doc/html/globals_vars.html index 3dde8cd..f009eaf 100644 --- a/doc/html/globals_vars.html +++ b/doc/html/globals_vars.html @@ -17,7 +17,7 @@
            json-c -  0.15 +  0.17
            @@ -67,7 +67,7 @@ diff --git a/doc/html/index.html b/doc/html/index.html index 5388ad5..143a68c 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -17,7 +17,7 @@
            json-c -  0.15 +  0.17
            @@ -43,6 +43,7 @@

            json-c

            1. Overview and Build Status
            2. +
            3. Getting Help
            4. Building on Unix
            +
            1. Linking to libjson-c
            2. Using json-c

            JSON-C - A JSON implementation in C

            +

            JSON-C implements a reference counting object model that allows you to easily construct JSON objects in C, output them as JSON formatted strings and parse JSON formatted strings back into the C representation of JSON objects. It aims to conform to RFC 8259.

            +

            Skip down to Using json-c or check out the API docs, if you already have json-c installed and ready to use.

            +

            Home page for json-c: https://github.com/json-c/json-c/wiki

            +

            Getting Help

            +

            If you have questions about using json-c, please start a thread on our forums at: https://groups.google.com/forum/#!forum/json-c

            +

            If you believe you've discovered a bug, report it at (https://github.com/json-c/json-c/issues). Please be sure to include the version of json-c you're using, the OS you're running on, and any other relevant details. Fully reproducible test cases and/or patches to fix problems are greatly appreciated.

            +

            Fixes for bugs, or small new features can be directly submitted as a pull request. For major new features or large changes of any kind, please first start a discussion on the forums.

            +

            Building on Unix with git, gcc and cmake

            +

            If you already have json-c installed, see Linking to `libjson-c` for how to build and link your program against it.

            Build Status

            @@ -70,15 +83,12 @@ -

            JSON-C implements a reference counting object model that allows you to easily construct JSON objects in C, output them as JSON formatted strings and parse JSON formatted strings back into the C representation of JSON objects. It aims to conform to RFC 7159.

            -

            Building on Unix with git, gcc and cmake

            -

            Home page for json-c: https://github.com/json-c/json-c/wiki

            Prerequisites:

            • gcc, clang, or another C compiler
              -
            • cmake>=2.8, >=3.16 recommended
            • +
            • cmake>=2.8, >=3.16 recommended, cmake=>3.1 for tests

            To generate docs you'll also need:

              @@ -101,9 +111,9 @@ $ cmake ../json-c # See CMake section below for custom arguments
              $ make
               $ make test
               $ make USE_VALGRIND=0 test   # optionally skip using valgrind
              -$ make install
              +$ sudo make install          # it could be necessary to execute make install
               

              Generating documentation with Doxygen:

              -

              The libray documentation can be generated directly from the source codes using Doxygen tool:

              +

              The library documentation can be generated directly from the source code using Doxygen tool:

              # in build directory
               make doc
               google-chrome doc/html/index.html
              @@ -129,6 +139,10 @@ google-chrome doc/html/index.html
               
               DISABLE_WERROR Bool Disable use of -Werror. 
               
              +DISABLE_EXTRA_LIBS Bool Disable use of extra libraries, libbsd 
              +
              +DISABLE_JSON_POINTER Bool Omit json_pointer support from the build. 
              +
               ENABLE_RDRAND Bool Enable RDRAND Hardware RNG Hash Seed. 
               
               ENABLE_THREADING Bool Enable partial threading support. 
              @@ -182,7 +196,7 @@ make test
               # By default, if valgrind is available running tests uses it.
               make USE_VALGRIND=0 test   # optionally skip using valgrind
               

              If a test fails, check Testing/Temporary/LastTest.log, tests/testSubDir/${testname}/${testname}.vg.out, and other similar files. If there is insufficient output try:

              -
              VERBOSE=1 make test
              +
              VERBOSE=1 CTEST_OUTPUT_ON_FAILURE=1 make test
               

              or

              JSONC_TEST_TRACE=1 make test
               

              and check the log files again.

              @@ -194,33 +208,62 @@ cd vcpkg ./vcpkg integrate install vcpkg install json-c

              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 on the vcpkg repository.

              -

              Linking to libjson-c

              +

              Building for Android

              +

              Building on Android is now particularly well supported, but there have been some reports of success using https://developer.android.com/ndk/guides/cmake

              +
              mkdir json-c-build
              +cd json-c-build/
              +export NDK_HOME=~/Library/Android/sdk/ndk/22.1.7171670/
              +cmake \
              +    --toolchain=$NDK_HOME/build/cmake/android.toolchain.cmake \
              +    -DANDROID_STL=none \
              +    -DANDROID_ABI=arm64-v8a \
              +    -DANDROID_PLATFORM=android-29 \
              +    -DANDROID_LD=lld \
              +    -DCMAKE_BUILD_TYPE=MinSizeRel \
              +    -DCMAKE_INSTALL_PREFIX=<install prefix> \
              +    -DENABLE_THREADING=true \
              +    ..
              +make install
              +

              Linking to libjson-c

              If your system has pkgconfig, then you can just add this to your makefile:

              CFLAGS += $(shell pkg-config --cflags json-c)
               LDFLAGS += $(shell pkg-config --libs json-c)
              -

              Without pkgconfig, you would do something like this:

              +

              Without pkgconfig, you might do something like this:

              JSON_C_DIR=/path/to/json_c/install
               CFLAGS += -I$(JSON_C_DIR)/include/json-c
              +# Or to use lines like: #include <json-c/json_object.h>
              +#CFLAGS += -I$(JSON_C_DIR)/include
               LDFLAGS+= -L$(JSON_C_DIR)/lib -ljson-c
              -

              Using json-c

              -

              To use json-c you can either include json.h, or preferrably, one of the following more specific header files:

              +

              If your project uses cmake:

              +
                +
              • Add to your CMakeLists.txt file:

                +

                find_package(json-c CONFIG) target_link_libraries(${PROJECT_NAME} PRIVATE json-c::json-c)

                +
              • +
              +
                +
              • Then you might run in your project:

                +

                cd build cmake -DCMAKE_PREFIX_PATH=/path/to/json_c/install/lib64/cmake ..

                +
              • +
              +

              Using json-c

              +

              To use json-c you can either include json.h, or preferably, one of the following more specific header files:

              -

              For a full list of headers see files.html

              -

              The primary type in json-c is json_object. It describes a reference counted tree of json objects which are created by either parsing text with a json_tokener (i.e. json_tokener_parse_ex()), or by creating (with json_object_new_object(), json_object_new_int(), etc...) and adding (with json_object_object_add(), json_object_array_add(), etc...) them individually. Typically, every object in the tree will have one reference, from it's parent. When you are done with the tree of objects, you call json_object_put() on just the root object to free it, which recurses down through any child objects calling json_object_put() on each one of those in turn.

              +

              For a full list of headers see files.html

              +

              The primary type in json-c is json_object. It describes a reference counted tree of json objects which are created by either parsing text with a json_tokener (i.e. json_tokener_parse_ex()), or by creating (with json_object_new_object(), json_object_new_int(), etc...) and adding (with json_object_object_add(), json_object_array_add(), etc...) them individually. Typically, every object in the tree will have one reference, from its parent. When you are done with the tree of objects, you call json_object_put() on just the root object to free it, which recurses down through any child objects calling json_object_put() on each one of those in turn.

              You can get a reference to a single child (json_object_object_get() or json_object_array_get_idx()) and use that object as long as its parent is valid. If you need a child object to live longer than its parent, you can increment the child's refcount (json_object_get()) to allow it to survive the parent being freed or it being removed from its parent (json_object_object_del() or json_object_array_del_idx())

              -

              When parsing text, the json_tokener object is independent from the json_object that it returns. It can be allocated (json_tokener_new()) used ones or multiple times (json_tokener_parse_ex(), and freed (json_tokener_free()) while the json_object objects live on.

              +

              When parsing text, the json_tokener object is independent from the json_object that it returns. It can be allocated (json_tokener_new()) used one or multiple times (json_tokener_parse_ex(), and freed (json_tokener_free()) while the json_object objects live on.

              A json_object tree can be serialized back into a string with json_object_to_json_string_ext(). The string that is returned is only valid until the next "to_json_string" call on that same object. Also, it is freed when the json_object is freed.

            diff --git a/doc/html/issues__closed__for__0_813_8md.html b/doc/html/issues__closed__for__0_813_8md.html index 7bdcf4d..52dadd0 100644 --- a/doc/html/issues__closed__for__0_813_8md.html +++ b/doc/html/issues__closed__for__0_813_8md.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/issues_closed_for_0.13.md File Reference +json-c: issues_closed_for_0.13.md File Reference @@ -17,7 +17,7 @@
            json-c -  0.15 +  0.17
            @@ -43,13 +43,13 @@
            -
            /home/erh/json-c-0.15/issues_closed_for_0.13.md File Reference
            +
            issues_closed_for_0.13.md File Reference
            diff --git a/doc/html/issues__closed__for__0_814_8md.html b/doc/html/issues__closed__for__0_814_8md.html index 8971694..105b838 100644 --- a/doc/html/issues__closed__for__0_814_8md.html +++ b/doc/html/issues__closed__for__0_814_8md.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/issues_closed_for_0.14.md File Reference +json-c: issues_closed_for_0.14.md File Reference @@ -17,7 +17,7 @@
            json-c -  0.15 +  0.17
            @@ -43,13 +43,13 @@
            -
            /home/erh/json-c-0.15/issues_closed_for_0.14.md File Reference
            +
            issues_closed_for_0.14.md File Reference
            diff --git a/doc/html/issues__closed__for__0_815_8md.html b/doc/html/issues__closed__for__0_815_8md.html new file mode 100644 index 0000000..4930f77 --- /dev/null +++ b/doc/html/issues__closed__for__0_815_8md.html @@ -0,0 +1,57 @@ + + + + + +json-c: issues_closed_for_0.15.md File Reference + + + + + + +
            +
            + + + + + + +
            +
            json-c +  0.17 +
            +
            +
            + + + + +
            +
            +
            +
            issues_closed_for_0.15.md File Reference
            +
            +
            +
            + + + + diff --git a/doc/html/issues__closed__for__0_816_8md.html b/doc/html/issues__closed__for__0_816_8md.html new file mode 100644 index 0000000..a348aa5 --- /dev/null +++ b/doc/html/issues__closed__for__0_816_8md.html @@ -0,0 +1,57 @@ + + + + + +json-c: issues_closed_for_0.16.md File Reference + + + + + + +
            +
            + + + + + + +
            +
            json-c +  0.17 +
            +
            +
            + + + + +
            +
            +
            +
            issues_closed_for_0.16.md File Reference
            +
            +
            +
            + + + + diff --git a/doc/html/issues__closed__for__0_817_8md.html b/doc/html/issues__closed__for__0_817_8md.html new file mode 100644 index 0000000..f64be1a --- /dev/null +++ b/doc/html/issues__closed__for__0_817_8md.html @@ -0,0 +1,57 @@ + + + + + +json-c: issues_closed_for_0.17.md File Reference + + + + + + +
            +
            + + + + + + +
            +
            json-c +  0.17 +
            +
            +
            + + + + +
            +
            +
            +
            issues_closed_for_0.17.md File Reference
            +
            +
            +
            + + + + diff --git a/doc/html/json_8h.html b/doc/html/json_8h.html index bc004ab..65c24c8 100644 --- a/doc/html/json_8h.html +++ b/doc/html/json_8h.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/json.h File Reference +json-c: /home/erh/distcheck/json.h File Reference @@ -17,7 +17,7 @@
            json-c -  0.15 +  0.17
            @@ -42,7 +42,7 @@
          @@ -58,7 +58,7 @@
          diff --git a/doc/html/json__c__version_8h.html b/doc/html/json__c__version_8h.html index fc79b74..9126416 100644 --- a/doc/html/json__c__version_8h.html +++ b/doc/html/json__c__version_8h.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/json_c_version.h File Reference +json-c: json_c_version.h File Reference @@ -17,7 +17,7 @@
          json-c -  0.15 +  0.17
          @@ -40,10 +40,6 @@
        • Globals
        -
        @@ -61,13 +57,13 @@ Macros #define JSON_C_MAJOR_VERSION   0   -#define JSON_C_MINOR_VERSION   15 +#define JSON_C_MINOR_VERSION   17   #define JSON_C_MICRO_VERSION   0   #define JSON_C_VERSION_NUM   ((JSON_C_MAJOR_VERSION << 16) | (JSON_C_MINOR_VERSION << 8) | JSON_C_MICRO_VERSION)   -#define JSON_C_VERSION   "0.15" +#define JSON_C_VERSION   "0.17"   #define JSON_EXPORT   extern   @@ -111,7 +107,7 @@ Functions
        - +
        #define JSON_C_MINOR_VERSION   15#define JSON_C_MINOR_VERSION   17
        @@ -123,7 +119,7 @@ Functions
        - +
        #define JSON_C_VERSION   "0.15"#define JSON_C_VERSION   "0.17"
        @@ -195,7 +191,7 @@ Functions
        diff --git a/doc/html/json__inttypes_8h.html b/doc/html/json__inttypes_8h.html index 13a9ce9..240461b 100644 --- a/doc/html/json__inttypes_8h.html +++ b/doc/html/json__inttypes_8h.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/json_inttypes.h File Reference +json-c: json_inttypes.h File Reference @@ -17,7 +17,7 @@
        json-c -  0.15 +  0.17
        @@ -40,14 +40,11 @@
      • Globals
      -
      json_inttypes.h File Reference
      @@ -64,6 +61,17 @@ Macros   #define PRIu64   "I64u"   + + + + + + + + + +

      +Typedefs

      typedef __int32 int32_t
       
      typedef unsigned __int32 uint32_t
       
      typedef __int64 int64_t
       
      typedef unsigned __int64 uint64_t
       

      Detailed Description

      Do not use, json-c internal, may be changed or removed at any time.

      @@ -104,10 +112,59 @@ Macros
      +

      Typedef Documentation

      + +
      +
      + + + + +
      typedef __int32 int32_t
      +
      + +
      +
      + +
      +
      + + + + +
      typedef __int64 int64_t
      +
      + +
      +
      + +
      +
      + + + + +
      typedef unsigned __int32 uint32_t
      +
      + +
      +
      + +
      +
      + + + + +
      typedef unsigned __int64 uint64_t
      +
      + +
      +
      diff --git a/doc/html/json__object_8h.html b/doc/html/json__object_8h.html index a53a851..d684eef 100644 --- a/doc/html/json__object_8h.html +++ b/doc/html/json__object_8h.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/json_object.h File Reference +json-c: json_object.h File Reference @@ -17,7 +17,7 @@
      json-c -  0.15 +  0.17
      @@ -40,10 +40,6 @@
    • Globals
    -
    @@ -77,9 +73,13 @@ Macros   #define JSON_C_TO_STRING_NOSLASHESCAPE   (1 << 4)   +#define JSON_C_TO_STRING_COLOR   (1 << 5) +  #define JSON_C_OBJECT_ADD_KEY_IS_NEW   (1 << 1)   -#define JSON_C_OBJECT_KEY_IS_CONSTANT   (1 << 2) +#define JSON_C_OBJECT_ADD_CONSTANT_KEY   (1 << 2) +  +#define JSON_C_OBJECT_KEY_IS_CONSTANT   JSON_C_OBJECT_ADD_CONSTANT_KEY   #define JSON_C_OPTION_GLOBAL   (0)   @@ -123,8 +123,8 @@ Functions   JSON_EXPORT int json_object_object_length (const struct json_object *obj)   - JSON_C_CONST_FUNCTION (JSON_EXPORT size_t json_c_object_sizeof(void)) -  +size_t json_c_object_sizeof (void) +  JSON_EXPORT int json_object_object_add (struct json_object *obj, const char *key, struct json_object *val)   JSON_EXPORT int json_object_object_add_ex (struct json_object *obj, const char *const key, struct json_object *const val, const unsigned opts) @@ -151,6 +151,8 @@ Functions   JSON_EXPORT int json_object_array_put_idx (struct json_object *obj, size_t idx, struct json_object *val)   +JSON_EXPORT int json_object_array_insert_idx (struct json_object *obj, size_t idx, struct json_object *val) +  JSON_EXPORT struct json_objectjson_object_array_get_idx (const struct json_object *obj, size_t idx)   JSON_EXPORT int json_object_array_del_idx (struct json_object *obj, size_t idx, size_t count) @@ -163,25 +165,25 @@ Functions   JSON_EXPORT int json_object_set_boolean (struct json_object *obj, json_bool new_value)   -JSON_EXPORT struct json_objectjson_object_new_int (int32_t i) +JSON_EXPORT struct json_objectjson_object_new_int (int32_t i)   -JSON_EXPORT struct json_objectjson_object_new_int64 (int64_t i) +JSON_EXPORT struct json_objectjson_object_new_int64 (int64_t i)   -JSON_EXPORT struct json_objectjson_object_new_uint64 (uint64_t i) +JSON_EXPORT struct json_objectjson_object_new_uint64 (uint64_t i)   -JSON_EXPORT int32_t json_object_get_int (const struct json_object *obj) +JSON_EXPORT int32_t json_object_get_int (const struct json_object *obj)   JSON_EXPORT int json_object_set_int (struct json_object *obj, int new_value)   -JSON_EXPORT int json_object_int_inc (struct json_object *obj, int64_t val) +JSON_EXPORT int json_object_int_inc (struct json_object *obj, int64_t val)   -JSON_EXPORT int64_t json_object_get_int64 (const struct json_object *obj) +JSON_EXPORT int64_t json_object_get_int64 (const struct json_object *obj)   -JSON_EXPORT uint64_t json_object_get_uint64 (const struct json_object *obj) +JSON_EXPORT uint64_t json_object_get_uint64 (const struct json_object *obj)   -JSON_EXPORT int json_object_set_int64 (struct json_object *obj, int64_t new_value) +JSON_EXPORT int json_object_set_int64 (struct json_object *obj, int64_t new_value)   -JSON_EXPORT int json_object_set_uint64 (struct json_object *obj, uint64_t new_value) +JSON_EXPORT int json_object_set_uint64 (struct json_object *obj, uint64_t new_value)   JSON_EXPORT struct json_objectjson_object_new_double (double d)   @@ -235,7 +237,7 @@ Variables #define JSON_C_CONST_FUNCTION (   - func ) + func)    func @@ -243,6 +245,19 @@ Variables
    + +
    +
    + + + + +
    #define JSON_C_OBJECT_ADD_CONSTANT_KEY   (1 << 2)
    +
    +

    A flag for the json_object_object_add_ex function which flags the key as being constant memory. This means that the key will NOT be copied via strdup(), resulting in a potentially huge performance win (malloc, strdup and free are usually performance hogs). It is acceptable to use this flag for keys in non-constant memory blocks if the caller ensure that the memory holding the key lives longer than the corresponding json object. However, this is somewhat dangerous and should only be done if really justified. The general use-case for this flag is cases where the key is given as a real constant value in the function call, e.g. as in json_object_object_add_ex(obj, "ip", json, JSON_C_OBJECT_ADD_CONSTANT_KEY);

    + +
    +
    @@ -261,11 +276,11 @@ Variables
    - +
    #define JSON_C_OBJECT_KEY_IS_CONSTANT   (1 << 2)#define JSON_C_OBJECT_KEY_IS_CONSTANT   JSON_C_OBJECT_ADD_CONSTANT_KEY
    -

    A flag for the json_object_object_add_ex function which flags the key as being constant memory. This means that the key will NOT be copied via strdup(), resulting in a potentially huge performance win (malloc, strdup and free are usually performance hogs). It is acceptable to use this flag for keys in non-constant memory blocks if the caller ensure that the memory holding the key lives longer than the corresponding json object. However, this is somewhat dangerous and should only be done if really justified. The general use-case for this flag is cases where the key is given as a real constant value in the function call, e.g. as in json_object_object_add_ex(obj, "ip", json, JSON_C_OBJECT_KEY_IS_CONSTANT);

    +

    This flag is an alias to JSON_C_OBJECT_ADD_CONSTANT_KEY. Historically, this flag was used first and the new name JSON_C_OBJECT_ADD_CONSTANT_KEY was introduced for version 0.16.00 in order to have regular naming. Use of this flag is now legacy.

    @@ -297,6 +312,20 @@ Variables
    + +
    +
    + + + + +
    #define JSON_C_TO_STRING_COLOR   (1 << 5)
    +
    +

    A flag for the json_object_to_json_string_ext() and json_object_to_file_ext() functions which causes the output to be formatted.

    +

    Use color for printing json.

    + +
    +
    @@ -346,7 +375,7 @@ Variables

    A flag for the json_object_to_json_string_ext() and json_object_to_file_ext() functions which causes the output to be formatted.

    -

    See the "Two Space Tab" option at http://jsonformatter.curiousconcept.com/ for an example of the format.

    +

    See the "Two Space Tab" option at https://jsonformatter.curiousconcept.com/ for an example of the format.

    @@ -422,10 +451,10 @@ Variables
    struct json_object *val = NULL; \
    struct lh_entry *entry##key; \
    struct lh_entry *entry_next##key = NULL; \
    -
    for (entry##key = json_object_get_object(obj)->head; \
    -
    (entry##key ? (key = (char *)lh_entry_k(entry##key), \
    -
    val = (struct json_object *)lh_entry_v(entry##key), \
    -
    entry_next##key = entry##key->next, entry##key) \
    +
    for (entry##key = lh_table_head(json_object_get_object(obj)); \
    +
    (entry##key ? (key = (char *)lh_entry_k(entry##key), \
    +
    val = (struct json_object *)lh_entry_v(entry##key), \
    +
    entry_next##key = lh_entry_next(entry##key), entry##key) \
    : 0); \
    entry##key = entry_next##key)

    Iterate through all keys and values of an object.

    @@ -465,11 +494,11 @@ Variables
    -Value:
    for (iter.entry = json_object_get_object(obj)->head; \
    -
    (iter.entry ? (iter.key = (char *)lh_entry_k(iter.entry), \
    -
    iter.val = (struct json_object *)lh_entry_v(iter.entry), iter.entry) \
    +Value:
    for (iter.entry = lh_table_head(json_object_get_object(obj)); \
    +
    (iter.entry ? (iter.key = (char *)lh_entry_k(iter.entry), \
    +
    iter.val = (struct json_object *)lh_entry_v(iter.entry), iter.entry) \
    : 0); \
    -
    iter.entry = iter.entry->next)
    +
    iter.entry = lh_entry_next(iter.entry))

    Iterate through all keys and values of an object (ANSI C Safe)

    Parameters
    @@ -499,15 +528,15 @@ Variables

    Function Documentation

    - +
    - + - - + +
    JSON_C_CONST_FUNCTION size_t json_c_object_sizeof (JSON_EXPORT size_t  json_c_object_sizeofvoid)void )
    @@ -721,6 +750,49 @@ Variables
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    JSON_EXPORT int json_object_array_insert_idx (struct json_objectobj,
    size_t idx,
    struct json_objectval 
    )
    +
    +

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

    +
    Parameters
    + + + + +
    objthe json_object instance
    idxthe index to insert the element at
    valthe json_object to be added
    +
    +
    + +
    +
    @@ -897,7 +969,7 @@ Variables -
    Returns
    0 if the copy went well, -1 if an error occured during copy or if the destination pointer is non-NULL
    +
    Returns
    0 if the copy went well, -1 if an error occurred during copy or if the destination pointer is non-NULL
    @@ -1022,7 +1094,7 @@ Variables
    Parameters
    @@ -1084,7 +1156,7 @@ Variables

    Get the json_bool value of a json_object

    -

    The type is coerced to a json_bool if the passed object is not a json_bool. integer and double objects will return 0 if there value is zero or 1 otherwise. If the passed object is a string it will return 1 if it has a non zero length. If any other object type is passed 1 will be returned if the object is not NULL.

    +

    The type is coerced to a json_bool if the passed object is not a json_bool. integer and double objects will return 0 if there value is zero or 1 otherwise. If the passed object is a string it will return 1 if it has a non zero length. If any other object type is passed 0 will be returned, even non-empty json_type_array and json_type_object objects.

    Parameters
    @@ -1128,7 +1200,7 @@ Variables
    objthe json_object instance
    - + @@ -1154,7 +1226,7 @@ Variables
    JSON_EXPORT int32_t json_object_get_int JSON_EXPORT int32_t json_object_get_int ( const struct json_object obj)
    - + @@ -1289,7 +1361,7 @@ Variables
    JSON_EXPORT int64_t json_object_get_int64 JSON_EXPORT int64_t json_object_get_int64 ( const struct json_object obj)
    - + @@ -1346,7 +1418,7 @@ Variables - + @@ -1365,7 +1437,7 @@ Variables
    JSON_EXPORT uint64_t json_object_get_uint64 JSON_EXPORT uint64_t json_object_get_uint64 ( const struct json_object obj)
    int64_t int64_t  val 
    -
    Returns
    1 if the increment succeded, 0 otherwise
    +
    Returns
    1 if the increment succeeded, 0 otherwise
    @@ -1590,7 +1662,7 @@ Variables JSON_EXPORT struct json_object* json_object_new_int ( - int32_t  + int32_t  i) @@ -1622,7 +1694,7 @@ Variables JSON_EXPORT struct json_object* json_object_new_int64 ( - int64_t  + int64_t  i) @@ -1784,7 +1856,7 @@ Variables JSON_EXPORT struct json_object* json_object_new_uint64 ( - uint64_t  + uint64_t  i) @@ -2199,7 +2271,7 @@ Variables - int64_t  + int64_t  new_value  @@ -2359,7 +2431,7 @@ Variables - uint64_t  + uint64_t  new_value  @@ -2591,7 +2663,7 @@ Variables diff --git a/doc/html/json__object__iterator_8h.html b/doc/html/json__object__iterator_8h.html index 7ae998d..f747fc9 100644 --- a/doc/html/json__object__iterator_8h.html +++ b/doc/html/json__object__iterator_8h.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/json_object_iterator.h File Reference +json-c: json_object_iterator.h File Reference @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -40,10 +40,6 @@
  • Globals
  • -
    @@ -330,7 +326,7 @@ User and internal code MUST NOT make any assumptions about and dependencies on t
    diff --git a/doc/html/json__patch_8h.html b/doc/html/json__patch_8h.html new file mode 100644 index 0000000..4f47595 --- /dev/null +++ b/doc/html/json__patch_8h.html @@ -0,0 +1,128 @@ + + + + + +json-c: json_patch.h File Reference + + + + + + +
    +
    + + + + + + +
    +
    json-c +  0.17 +
    +
    +
    + + + + +
    +
    + +
    +
    json_patch.h File Reference
    +
    +
    + +

    JSON Patch (RFC 6902) implementation for manipulating JSON objects. +More...

    + + + + +

    +Data Structures

    struct  json_patch_error
     
    + + + +

    +Functions

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

    Detailed Description

    +

    JSON Patch (RFC 6902) implementation for manipulating JSON objects.

    +

    Function Documentation

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    JSON_EXPORT int json_patch_apply (struct json_objectcopy_from,
    struct json_objectpatch,
    struct json_object ** base,
    struct json_patch_errorpatch_error 
    )
    +
    +

    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.

    +
    Parameters
    + + + + + +
    basea pointer to the JSON object which to patch
    patchthe JSON object that describes the patch to be applied
    copy_froma JSON object to copy to *base
    patch_erroroptional, details about errors
    +
    +
    +
    Returns
    negative if an error (or not found), or 0 if patch completely applied
    + +
    +
    +
    + + + + diff --git a/doc/html/json__pointer_8h.html b/doc/html/json__pointer_8h.html index 5a6f4b4..2be7e74 100644 --- a/doc/html/json__pointer_8h.html +++ b/doc/html/json__pointer_8h.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/json_pointer.h File Reference +json-c: json_pointer.h File Reference @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -40,10 +40,6 @@
  • Globals
  • -
    @@ -102,7 +98,6 @@ Functions

    Retrieves a JSON sub-object from inside another JSON object using the JSON pointer notation as defined in RFC 6901 https://tools.ietf.org/html/rfc6901

    The returned JSON sub-object is equivalent to parsing manually the 'obj' JSON tree ; i.e. it's not a new object that is created, but rather a pointer inside the JSON tree.

    Internally, this is equivalent to doing a series of 'json_object_object_get()' 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())

    Parameters
    @@ -151,7 +146,8 @@ Functions
    objthe json_object instance/tree from where to retrieve sub-objects

    This is a variant of 'json_pointer_get()' that supports printf() style arguments.

    -

    Example: json_pointer_getf(obj, res, "/foo/%d/%s", 0, bak) This also means that you need to escape '' with '%' (just like in printf())

    +

    Variable arguments go after the 'path_fmt' parameter.

    +

    Example: json_pointer_getf(obj, res, "/foo/%d/%s", 0, "bar") This also means that you need to escape '' with '%' (just like in printf())

    Please take into consideration all recommended 'printf()' format security aspects when using this function.

    Parameters
    @@ -198,7 +194,6 @@ Functions

    Note that 'obj' is a double pointer, mostly for the "" (empty string) case, where the entire JSON object would be replaced by 'value'. In the case of the "" path, the object at '*obj' will have it's refcount decremented with 'json_object_put()' and the 'value' object will be assigned to it.

    For other cases (JSON sub-objects) ownership of 'value' will be transferred into '*obj' via 'json_object_object_add()' & 'json_object_array_put_idx()', so the only time the refcount should be decremented for 'value' is when the return value of 'json_pointer_set()' is negative (meaning the 'value' object did not get set into '*obj').

    That also implies that 'json_pointer_set()' does not do any refcount incrementing. (Just that single decrement that was mentioned above).

    -

    Note that the 'path' string supports 'printf()' type arguments, so, whatever is added after the 'value' param will be treated as an argument for 'path' Example: json_pointer_set(obj, "/foo/%d/%s", value, 0, bak) This means, that you need to escape '' with '%' (just like in printf())

    Parameters
    @@ -247,7 +242,8 @@ Functions
    objthe json_object instance/tree to which to add a sub-object

    This is a variant of 'json_pointer_set()' that supports printf() style arguments.

    -

    Example: json_pointer_setf(obj, value, "/foo/%d/%s", 0, bak) This also means that you need to escape '' with '%' (just like in printf())

    +

    Variable arguments go after the 'path_fmt' parameter.

    +

    Example: json_pointer_setf(obj, value, "/foo/%d/%s", 0, "bar") This also means that you need to escape '' with '%' (just like in printf())

    Please take into consideration all recommended 'printf()' format security aspects when using this function.

    Parameters
    @@ -264,7 +260,7 @@ Functions diff --git a/doc/html/json__pointer__private_8h.html b/doc/html/json__pointer__private_8h.html new file mode 100644 index 0000000..13ca5e8 --- /dev/null +++ b/doc/html/json__pointer__private_8h.html @@ -0,0 +1,174 @@ + + + + + +json-c: json_pointer_private.h File Reference + + + + + + +
    +
    +
    + + + + + +
    +
    json-c +  0.17 +
    +
    +
    + + + + +
    +
    + +
    +
    json_pointer_private.h File Reference
    +
    +
    + +

    Do not use, json-c internal, may be changed or removed at any time. +More...

    + + + + +

    +Data Structures

    struct  json_pointer_get_result
     
    + + + +

    +Typedefs

    typedef int(* json_pointer_array_set_cb )(json_object *parent, size_t idx, json_object *value, void *priv)
     
    + + + + + +

    +Functions

    int json_pointer_get_internal (struct json_object *obj, const char *path, struct json_pointer_get_result *res)
     
    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)
     
    +

    Detailed Description

    +

    Do not use, json-c internal, may be changed or removed at any time.

    +

    Typedef Documentation

    + +
    +
    + + + + +
    typedef int(* json_pointer_array_set_cb)(json_object *parent, size_t idx, json_object *value, void *priv)
    +
    + +
    +
    +

    Function Documentation

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    int json_pointer_get_internal (struct json_objectobj,
    const char * path,
    struct json_pointer_get_resultres 
    )
    +
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    int json_pointer_set_with_array_cb (struct json_object ** obj,
    const char * path,
    struct json_objectvalue,
    json_pointer_array_set_cb array_set_cb,
    void * priv 
    )
    +
    + +
    +
    +
    + + + + diff --git a/doc/html/json__tokener_8h.html b/doc/html/json__tokener_8h.html index 5857a80..70df18a 100644 --- a/doc/html/json__tokener_8h.html +++ b/doc/html/json__tokener_8h.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/json_tokener.h File Reference +json-c: json_tokener.h File Reference @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -40,10 +40,6 @@
  • Globals
  • -
    @@ -104,7 +100,9 @@ Enumerations   json_tokener_error_parse_string, json_tokener_error_parse_comment, json_tokener_error_parse_utf8_string, -json_tokener_error_size +json_tokener_error_memory, +
    +  json_tokener_error_size
    }   @@ -286,6 +284,8 @@ Functions json_tokener_error_parse_utf8_string  +json_tokener_error_memory  + json_tokener_error_size  @@ -682,7 +682,7 @@ Functions
    diff --git a/doc/html/json__types_8h.html b/doc/html/json__types_8h.html index 9d5f53d..376fb12 100644 --- a/doc/html/json__types_8h.html +++ b/doc/html/json__types_8h.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/json_types.h File Reference +json-c: json_types.h File Reference @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -40,10 +40,6 @@
  • Globals
  • -
    @@ -226,7 +222,7 @@ Enumerations
    diff --git a/doc/html/json__util_8h.html b/doc/html/json__util_8h.html index 06fcf4e..e5fe23c 100644 --- a/doc/html/json__util_8h.html +++ b/doc/html/json__util_8h.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/json_util.h File Reference +json-c: json_util.h File Reference @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -40,10 +40,6 @@
  • Globals
  • -
    @@ -82,9 +78,9 @@ Functions   JSON_EXPORT const char * json_util_get_last_err (void)   -JSON_EXPORT int json_parse_int64 (const char *buf, int64_t *retval) +JSON_EXPORT int json_parse_int64 (const char *buf, int64_t *retval)   -JSON_EXPORT int json_parse_uint64 (const char *buf, uint64_t *retval) +JSON_EXPORT int json_parse_uint64 (const char *buf, uint64_t *retval)   JSON_EXPORT int json_parse_double (const char *buf, double *retval)   @@ -393,7 +389,7 @@ Functions - int64_t *  + int64_tretval  @@ -403,6 +399,7 @@ Functions
    +

    A parsing helper for integer values. Returns 0 on success, with the parsed value assigned to *retval. Overflow/underflow are NOT considered errors, but errno will be set to ERANGE, just like the strtol/strtoll functions do.

    @@ -419,7 +416,7 @@ Functions - uint64_t *  + uint64_tretval  @@ -429,6 +426,7 @@ Functions
    +

    A parsing help for integer values, providing one extra bit of magnitude beyond json_parse_int64().

    @@ -469,7 +467,7 @@ Functions diff --git a/doc/html/json__visit_8h.html b/doc/html/json__visit_8h.html index ad80069..cec8b9b 100644 --- a/doc/html/json__visit_8h.html +++ b/doc/html/json__visit_8h.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/json_visit.h File Reference +json-c: json_visit.h File Reference @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -40,10 +40,6 @@
  • Globals
  • -
    @@ -235,7 +231,7 @@ Functions
    diff --git a/doc/html/linkhash_8h.html b/doc/html/linkhash_8h.html index bf40114..772ea22 100644 --- a/doc/html/linkhash_8h.html +++ b/doc/html/linkhash_8h.html @@ -3,7 +3,7 @@ -json-c: /home/erh/json-c-0.15/linkhash.h File Reference +json-c: linkhash.h File Reference @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -40,10 +40,6 @@
  • Globals
  • -
    @@ -80,14 +76,10 @@ Macros   #define JSON_C_STR_HASH_PERLLIKE   1   -#define lh_foreach(table, entry)   for (entry = table->head; entry; entry = entry->next) +#define lh_foreach(table, entry)   for (entry = lh_table_head(table); entry; entry = lh_entry_next(entry))   -#define lh_foreach_safe(table, entry, tmp)   for (entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) +#define lh_foreach_safe(table, entry, tmp)   for (entry = lh_table_head(table); entry && ((tmp = lh_entry_next(entry)) || 1); entry = tmp)   -#define lh_entry_k(entry)   _LH_UNCONST((entry)->k) -  -#define lh_entry_v(entry)   _LH_UNCONST((entry)->v) -  @@ -130,6 +122,22 @@ Functions + + + + + + + + + + + + + + + +

    Typedefs

     
    int lh_table_resize (struct lh_table *t, int new_size)
     
    static struct lh_entrylh_table_head (const lh_table *t)
     
    static unsigned long lh_get_hash (const struct lh_table *t, const void *k)
     
    static void * lh_entry_k (const struct lh_entry *e)
     
    static int lh_entry_k_is_constant (const struct lh_entry *e)
     
    static void * lh_entry_v (const struct lh_entry *e)
     
    static void lh_entry_set_val (struct lh_entry *e, void *newval)
     
    static struct lh_entrylh_entry_next (const struct lh_entry *e)
     
    static struct lh_entrylh_entry_prev (const struct lh_entry *e)
     

    Detailed Description

    Internal methods for working with json_type_object objects. Although this is exposed by the json_object_get_object() function and within the json_object_iter type, it is not recommended for direct use.

    @@ -173,42 +181,6 @@ Functions
    - -
    -
    - - - - - - - - -
    #define lh_entry_k( entry)   _LH_UNCONST((entry)->k)
    -
    -

    Return a non-const version of lh_entry.k.

    -

    lh_entry.k is const to indicate and help ensure that linkhash itself doesn't modify it, but callers are allowed to do what they want with it. See also lh_entry.k_is_constant

    - -
    -
    - -
    -
    - - - - - - - - -
    #define lh_entry_v( entry)   _LH_UNCONST((entry)->v)
    -
    -

    Return a non-const version of lh_entry.v.

    -

    v is const to indicate and help ensure that linkhash itself doesn't modify it, but callers are allowed to do what they want with it.

    - -
    -
    @@ -228,7 +200,7 @@ Functions ) -    for (entry = table->head; entry; entry = entry->next) +    for (entry = lh_table_head(table); entry; entry = lh_entry_next(entry))
    @@ -261,7 +233,7 @@ Functions ) -    for (entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) +    for (entry = lh_table_head(table); entry && ((tmp = lh_entry_next(entry)) || 1); entry = tmp)
    @@ -387,6 +359,234 @@ Functions
    + +
    +
    + + + + + +
    + + + + + + + + +
    static void* lh_entry_k (const struct lh_entrye)
    +
    +inlinestatic
    +
    +

    Return a non-const version of lh_entry.k.

    +

    lh_entry.k is const to indicate and help ensure that linkhash itself doesn't modify it, but callers are allowed to do what they want with it.

    +
    See Also
    lh_entry_k_is_constant()
    + +

    References lh_entry::k.

    + +
    +
    + +
    +
    + + + + + +
    + + + + + + + + +
    static int lh_entry_k_is_constant (const struct lh_entrye)
    +
    +inlinestatic
    +
    +

    Returns 1 if the key for the given entry is constant, and thus does not need to be freed when the lh_entry is freed.

    +
    See Also
    lh_table_insert_w_hash()
    + +

    References lh_entry::k_is_constant.

    + +
    +
    + +
    +
    + + + + + +
    + + + + + + + + +
    static struct lh_entry* lh_entry_next (const struct lh_entrye)
    +
    +staticread
    +
    +

    Return the next element, or NULL if there is no next element.

    +
    See Also
    lh_table_head()
    +
    +lh_entry_prev()
    + +

    References lh_entry::next.

    + +
    +
    + +
    +
    + + + + + +
    + + + + + + + + +
    static struct lh_entry* lh_entry_prev (const struct lh_entrye)
    +
    +staticread
    +
    +

    Return the previous element, or NULL if there is no previous element.

    +
    See Also
    lh_table_head()
    +
    +lh_entry_next()
    + +

    References lh_entry::prev.

    + +
    +
    + +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + +
    static void lh_entry_set_val (struct lh_entrye,
    void * newval 
    )
    +
    +inlinestatic
    +
    +

    Change the value for an entry. The caller is responsible for freeing the previous value.

    + +

    References lh_entry::v.

    + +
    +
    + +
    +
    + + + + + +
    + + + + + + + + +
    static void* lh_entry_v (const struct lh_entrye)
    +
    +inlinestatic
    +
    +

    Return a non-const version of lh_entry.v.

    +

    v is const to indicate and help ensure that linkhash itself doesn't modify it, but callers are allowed to do what they want with it.

    + +

    References lh_entry::v.

    + +
    +
    + +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + +
    static unsigned long lh_get_hash (const struct lh_tablet,
    const void * k 
    )
    +
    +inlinestatic
    +
    +

    Calculate the hash of a key for a given table.

    +

    This is an extension to support functions that need to calculate the hash several times and allows them to do it just once and then pass in the hash to all utility functions. Depending on use case, this can be a considerable performance improvement.

    +
    Parameters
    + + + +
    tthe table (used to obtain hash function)
    ka pointer to the key to lookup
    +
    +
    +
    Returns
    the key's hash
    + +

    References lh_table::hash_fn.

    + +
    +
    @@ -573,6 +773,34 @@ Functions
    + +
    +
    + + + + + +
    + + + + + + + + +
    static struct lh_entry* lh_table_head (const lh_tablet)
    +
    +staticread
    +
    +

    Return the first entry in the lh_table.

    +
    See Also
    lh_entry_next()
    + +

    References lh_table::head.

    + +
    +
    @@ -657,14 +885,14 @@ Functions

    Insert a record into the table using a precalculated key hash.

    -

    The hash h, which should be calculated with lh_get_hash() on k, is provided by the caller, to allow for optimization when multiple operations with the same key are known to be needed.

    +

    The hash h, which should be calculated with lh_get_hash() on k, is provided by the caller, to allow for optimization when multiple operations with the same key are known to be needed.

    Parameters
    - +
    tthe table to insert into.
    ka pointer to the key to insert.
    va pointer to the value to insert.
    hhash value of the key to insert
    optsif set to JSON_C_OBJECT_KEY_IS_CONSTANT, sets lh_entry.k_is_constant so t's free function knows to avoid freeing the key.
    optsif set to JSON_C_OBJECT_ADD_CONSTANT_KEY, sets lh_entry.k_is_constant so t's free function knows to avoid freeing the key.
    @@ -684,6 +912,7 @@ Functions
    +

    Return the number of entries in the table.

    @@ -768,7 +997,7 @@ Functions

    Lookup a record in the table using a precalculated key hash.

    -

    The hash h, which should be calculated with lh_get_hash() on k, is provided by the caller, to allow for optimization when multiple operations with the same key are known to be needed.

    +

    The hash h, which should be calculated with lh_get_hash() on k, is provided by the caller, to allow for optimization when multiple operations with the same key are known to be needed.

    Parameters
    @@ -918,7 +1147,7 @@ Functions diff --git a/doc/html/md_README.html b/doc/html/md_README.html index fcfae7b..a78b7a9 100644 --- a/doc/html/md_README.html +++ b/doc/html/md_README.html @@ -17,7 +17,7 @@ @@ -43,7 +43,7 @@
    diff --git a/doc/html/md_issues_closed_for_0.html b/doc/html/md_issues_closed_for_0.html index 511a824..4122092 100644 --- a/doc/html/md_issues_closed_for_0.html +++ b/doc/html/md_issues_closed_for_0.html @@ -17,7 +17,7 @@ @@ -326,7 +326,7 @@ sed -e's,^\[ *\(.*\)\](https://api.github.com/.*/\([0-9].*\)),[Issue #\2](https:
  • Issue #387 - doc: Use other doxygen feature to specify mainpage \
  • Issue #388 - json_object: Add size_t json_object_sizeof() \
  • Issue #389 - json_object: Avoid double free (and thus a segfault) when ref_count gets < 0 \
  • -
  • Issue #390 - json_object: Add const size_t json_c_object_sizeof() \
  • +
  • Issue #390 - json_object: Add const size_t json_c_object_sizeof() \
  • Issue #391 - Fix non-GNUC define for JSON_C_CONST_FUNCTION \
  • Issue #392 - json_object: Avoid invalid free (and thus a segfault) when ref_count gets < 0 \
  • Issue #393 - json_object_private: Use unsigned 32-bit integer type for refcount \
  • @@ -499,12 +499,281 @@ sed -e's,^\[ *\(.*\)\](https://api.github.com/.*/\([0-9].*\)),[Issue #\2](https:
  • Issue #578 - CMake: Install pkgconfig file in proper location by default \
  • Issue #579 - Enforce strict prototypes. \
  • Issue #580 - Fix CMake tests for enforced strict prototypes. \
  • -
  • Issue #581 - CMakeLists: do not enforce strict prototypes on Windows. \
  • +
  • Issue #581 - CMakeLists: do not enforce strict prototypes on Windows. \
  • + +

    This list was created with:

    +
    curl "https://api.github.com/search/issues?q=repo%3Ajson-c%2Fjson-c+closed%3A>2020-04-18+created%3A<2020-07-23&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
    +#... manual editing ...
    +

    +

    Issues and Pull Requests closed for the 0.15 release (since commit 31ab57ca, the 0.14 branch point, 2020-04-19)

    +
      +
    • Issue #428 - Added new_null() function
    • +
    • Issue #429 - Conflict of interest between JSON_C_TO_STRING_SPACED and JSON_C_TO_STRING_PRETTY
    • +
    • Issue #451 - Add option to disable HAVE___THREAD
    • +
    • Issue #471 - create folders with mode 0755 when building
    • +
    • Issue #476 - Add new function named json_object_new_string_noalloc
    • +
    • Issue #484 - Add support for uint64
    • +
    • Issue #487 - Any plans to make new release? (0.14)
    • +
    • Issue #493 - Kdopen rename library
    • +
    • Issue #507 - Double value -1.0 converts to integer in json_object_to_json_string()
    • +
    • Issue #508 - Recommend enabling the -fPIC compiler flag by default
    • +
    • Issue #517 - Lja mods
    • +
    • Issue #534 - Both json-c and json-glib have json_object_get_type()
    • +
    • Issue #584 - CMake: SOVERSION and the major library VERSION need to be in lockstep.
    • +
    • Issue #585 - CMake: Do not install config.h, as it is not a public header file.
    • +
    • Issue #586 - 10796 Segmentation fault
    • +
    • Issue #588 - Broken RDRAND causes infinite looping
    • +
    • Issue #589 - Detect broken RDRAND during initialization
    • +
    • Issue #590 - Fix segmentation fault in CPUID check
    • +
    • Issue #591 - Update README.md
    • +
    • Issue #592 - Prevent out of boundary write on malicious input
    • +
    • Issue #593 - Building both static and shared libraries
    • +
    • Issue #594 - Some subsequent call of lh_get_hash not working
    • +
    • Issue #595 - Support to build both static and shared libraries
    • +
    • Issue #596 - QA Notice: Package triggers severe warnings
    • +
    • Issue #597 - json_parse demo: fix and use usage() function
    • +
    • Issue #598 - Turning off shared libs causes target duplication or build error
    • +
    • Issue #599 - cannot add more than 11 objects. Is this a known issue?
    • +
    • Issue #600 - Library name conflicts on Windows are back again
    • +
    • Issue #601 - json_tokener_parse() in master sets errno=1 "Operation not permitted"
    • +
    • Issue #602 - fix json_parse_uint64() internal error checking with errno
    • +
    • Issue #603 - Backport of fixes from master branch.
    • +
    • Issue #604 - commit f2e991a3419ee4078e8915e840b1a0d9003b349e breaks cross-compilation with mingw
    • +
    • Issue #605 - Update to 0.15 release
    • +
    • Issue #606 - Improved support for IBM operating systems
    • +
    • Issue #607 - json-c-0.13.x: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ...
    • +
    • Issue #608 - json-c-0.14: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ...
    • +
    • Issue #609 - use unsigned types for sizes in lh_table and entries
    • +
    • Issue #610 - let's not call lh_table_resize with INT_MAX
    • +
    • Issue #611 - json-c-0.12.x: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ...
    • +
    • Issue #613 - json-c-0.10: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ...
    • +
    • Issue #614 - Prevent truncation on custom double formatters.
    • +
    • Issue #615 - New release with security fix
    • +
    • Issue #616 - Parsing fails if UTF-16 low surrogate pair is not in same chunk is the high pair
    • +
    • Issue #617 - Add an option to disable the use of thread-local storage.
    • +
    • Issue #618 - test_deep_copy: Fix assertion value.
    • +
    • Issue #619 - CMake: Fix out-of-tree build for Doxygen documentation.
    • +
    • Issue #621 - json-c and jansson libraries have symbol conflicts
    • +
    • Issue #622 - doc: Move Doxyfile into doc subdir.
    • +
    • Issue #623 - json_tokener_parse : Segmentation fault
    • +
    • Issue #626 - Fixes for cmake 2.8.12 + link issue on AIX 6.1/cc 11.01
    • +
    • Issue #627 - Compat fixes
    • +
    • Issue #628 - get_cryptgenrandom_seed: compat with old windows + fallback
    • +
    • Issue #629 - [0.12] Remove the Visual Studio project file
    • +
    • Issue #630 - Linking with Windows MINGW not working
    • +
    • Issue #632 - Json object split
    • +
    • Issue #633 - fix issue 616: support the surrogate pair in split file.
    • +
    • Issue #634 - Issue #508: -fPIC to link libjson-c.a with libs
    • +
    • Issue #635 - expression has no effect warning in json_tokener.c
    • +
    • Issue #636 - json_object_get_string free str memory
    • +
    • Issue #637 - json_object_put() has 'double free or corruption (out) '
    • +
    • Issue #638 - json-c/json_object.c:50:2: error: #error Unable to determine size of ssize_t
    • +
    • Issue #639 - build: Add a symbol version to all exported symbols
    • +
    • Issue #640 - Fix build issues with SSIZE_MAX on 64bit Linux
    • +
    • Issue #641 - Formal verification of your test suite
    • +
    • Issue #642 - Please provide more precise informations about when to call json_object_put
    • +
    • Issue #643 - not able to compare with string
    • +
    • Issue #644 - Why src->_userdata not checked before calling strdup?
    • +
    • Issue #645 - Misuse of tolower() in json_tokener.c
    • +
    • Issue #646 - Cast to unsigned char instead of int when calling tolower (Fixes #645)
    • +
    +

    This list was created with:

    +
    PREV=2020-07-23
    +NOW=2022-04-13
    +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.16.md
    +
    +

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

    Internal string buffer handing. Unless you're writing a json_object_to_json_string_fn implementation for use with json_object_set_serializer() direct use of this is not recommended. +

    Internal string buffer handling. Unless you're writing a json_object_to_json_string_fn implementation for use with json_object_set_serializer() direct use of this is not recommended. More...

    tthe table to lookup
    json-c -  0.15 +  0.17
    json-c -  0.15 +  0.17
    json-c -  0.15 +  0.17
    json-c -  0.15 +  0.17

    @@ -96,7 +92,7 @@ Functions

     

    Detailed Description

    -

    Internal string buffer handing. Unless you're writing a json_object_to_json_string_fn implementation for use with json_object_set_serializer() direct use of this is not recommended.

    +

    Internal string buffer handling. Unless you're writing a json_object_to_json_string_fn implementation for use with json_object_set_serializer() direct use of this is not recommended.

    Macro Definition Documentation

    @@ -380,7 +376,7 @@ Functions
    diff --git a/doc/html/structarray__list.html b/doc/html/structarray__list.html index ee7dfa0..2b9db27 100644 --- a/doc/html/structarray__list.html +++ b/doc/html/structarray__list.html @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -110,12 +110,12 @@ Data Fields

    The documentation for this struct was generated from the following file: diff --git a/doc/html/structjson__object__iter.html b/doc/html/structjson__object__iter.html index bcfb2ce..f679cb3 100644 --- a/doc/html/structjson__object__iter.html +++ b/doc/html/structjson__object__iter.html @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -98,12 +98,12 @@ Data Fields
    The documentation for this struct was generated from the following file: diff --git a/doc/html/structjson__object__iterator.html b/doc/html/structjson__object__iterator.html index 2e9c27a..c4bc90d 100644 --- a/doc/html/structjson__object__iterator.html +++ b/doc/html/structjson__object__iterator.html @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -70,12 +70,12 @@ Data Fields
    The documentation for this struct was generated from the following file: diff --git a/doc/html/structjson__patch__error.html b/doc/html/structjson__patch__error.html new file mode 100644 index 0000000..65bd58c --- /dev/null +++ b/doc/html/structjson__patch__error.html @@ -0,0 +1,120 @@ + + + + + +json-c: json_patch_error Struct Reference + + + + + + +
    +
    + + + + + + +
    +
    json-c +  0.17 +
    +
    +
    + + + + +
    +
    + +
    +
    json_patch_error Struct Reference
    +
    +
    + + + + + + + + +

    +Data Fields

    int errno_code
     
    size_t patch_failure_idx
     
    const char * errmsg
     
    +

    Detailed Description

    +

    Details of an error that occurred during json_patch_apply()

    +

    Field Documentation

    + +
    +
    + + + + +
    const char* json_patch_error::errmsg
    +
    +

    A human readable error message. Allocated from static storage, does not need to be freed.

    + +
    +
    + +
    +
    + + + + +
    int json_patch_error::errno_code
    +
    +

    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)
    • +
    + +
    +
    + +
    +
    + + + + +
    size_t json_patch_error::patch_failure_idx
    +
    +

    The index into the patch array of the operation that failed, or SIZE_T_MAX for overall errors.

    + +
    +
    +
    The documentation for this struct was generated from the following file: +
    + + + + diff --git a/doc/html/structjson__pointer__get__result.html b/doc/html/structjson__pointer__get__result.html new file mode 100644 index 0000000..0a51ba0 --- /dev/null +++ b/doc/html/structjson__pointer__get__result.html @@ -0,0 +1,123 @@ + + + + + +json-c: json_pointer_get_result Struct Reference + + + + + + +
    +
    + + + + + + +
    +
    json-c +  0.17 +
    +
    +
    + + + + +
    +
    + +
    +
    json_pointer_get_result Struct Reference
    +
    +
    + + + + + + + + + + +

    +Data Fields

    struct json_objectparent
     
    struct json_objectobj
     
    const char * key_in_parent
     
    uint32_t index_in_parent
     
    +

    Field Documentation

    + +
    +
    + + + + +
    uint32_t json_pointer_get_result::index_in_parent
    +
    + +
    +
    + +
    +
    + + + + +
    const char* json_pointer_get_result::key_in_parent
    +
    + +
    +
    + +
    +
    + + + + +
    struct json_object* json_pointer_get_result::obj
    +
    + +
    +
    + +
    +
    + + + + +
    struct json_object* json_pointer_get_result::parent
    +
    + +
    +
    +
    The documentation for this struct was generated from the following file: +
    + + + + diff --git a/doc/html/structjson__tokener.html b/doc/html/structjson__tokener.html index f8f8f56..b16a036 100644 --- a/doc/html/structjson__tokener.html +++ b/doc/html/structjson__tokener.html @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -241,12 +241,12 @@ Data Fields
    The documentation for this struct was generated from the following file: diff --git a/doc/html/structjson__tokener__srec.html b/doc/html/structjson__tokener__srec.html index 454b814..4dda517 100644 --- a/doc/html/structjson__tokener__srec.html +++ b/doc/html/structjson__tokener__srec.html @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -112,12 +112,12 @@ Data Fields
    The documentation for this struct was generated from the following file: diff --git a/doc/html/structlh__entry.html b/doc/html/structlh__entry.html index 6e4f095..1f37b10 100644 --- a/doc/html/structlh__entry.html +++ b/doc/html/structlh__entry.html @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -63,7 +63,7 @@ Data Fields  

    Detailed Description

    -

    An entry in the hash table

    +

    An entry in the hash table. Outside of linkhash.c, treat this as opaque.

    Field Documentation

    @@ -74,7 +74,10 @@ Data Fields
    -

    The key. Use lh_entry_k() instead of accessing this directly.

    +

    The key.

    +
    Deprecated:
    Use lh_entry_k() instead of accessing this directly.
    + +

    Referenced by lh_entry_k().

    @@ -88,6 +91,9 @@ Data Fields

    A flag for users of linkhash to know whether or not they need to free k.

    +
    Deprecated:
    use lh_entry_k_is_constant() instead.
    + +

    Referenced by lh_entry_k_is_constant().

    @@ -100,7 +106,10 @@ Data Fields
    -

    The next entry

    +

    The next entry.

    +
    Deprecated:
    Use lh_entry_next() instead of accessing this directly.
    + +

    Referenced by lh_entry_next().

    @@ -114,6 +123,9 @@ Data Fields

    The previous entry.

    +
    Deprecated:
    Use lh_entry_prev() instead of accessing this directly.
    + +

    Referenced by lh_entry_prev().

    @@ -126,17 +138,20 @@ Data Fields
    -

    The value. Use lh_entry_v() instead of accessing this directly.

    +

    The value.

    +
    Deprecated:
    Use lh_entry_v() instead of accessing this directly.
    + +

    Referenced by lh_entry_set_val(), and lh_entry_v().


    The documentation for this struct was generated from the following file: diff --git a/doc/html/structlh__table.html b/doc/html/structlh__table.html index 9814677..742b030 100644 --- a/doc/html/structlh__table.html +++ b/doc/html/structlh__table.html @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -69,7 +69,7 @@ Data Fields  

    Detailed Description

    -

    The hash table structure.

    +

    The hash table structure. Outside of linkhash.c, treat this as opaque.

    Field Documentation

    @@ -81,6 +81,7 @@ Data Fields

    Numbers of entries.

    +
    Deprecated:
    Use lh_table_length() instead.
    @@ -93,6 +94,7 @@ Data Fields
    +
    Deprecated:
    do not use outside of linkhash.c
    @@ -105,7 +107,8 @@ Data Fields
    -

    A pointer onto the function responsible for freeing an entry.

    +

    A pointer to the function responsible for freeing an entry.

    +
    Deprecated:
    do not use outside of linkhash.c
    @@ -118,6 +121,9 @@ Data Fields
    +
    Deprecated:
    do not use outside of linkhash.c
    + +

    Referenced by lh_get_hash().

    @@ -131,6 +137,9 @@ Data Fields

    The first entry.

    +
    Deprecated:
    Use lh_table_head() instead.
    + +

    Referenced by lh_table_head().

    @@ -144,6 +153,7 @@ Data Fields

    Size of our hash.

    +
    Deprecated:
    do not use outside of linkhash.c
    @@ -156,6 +166,8 @@ Data Fields
    +

    Internal storage of the actual table of entries.

    +
    Deprecated:
    do not use outside of linkhash.c
    @@ -169,16 +181,17 @@ Data Fields

    The last entry.

    +
    Deprecated:
    Do not use, may be removed in a future release.

    The documentation for this struct was generated from the following file: diff --git a/doc/html/structprintbuf.html b/doc/html/structprintbuf.html index a9a2bac..7625680 100644 --- a/doc/html/structprintbuf.html +++ b/doc/html/structprintbuf.html @@ -17,7 +17,7 @@
    json-c -  0.15 +  0.17
    @@ -96,12 +96,12 @@ Data Fields
    The documentation for this struct was generated from the following file: diff --git a/fuzz/build.sh b/fuzz/build.sh index b6a5cc7..7a42e0b 100755 --- a/fuzz/build.sh +++ b/fuzz/build.sh @@ -5,7 +5,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, diff --git a/fuzz/tokener_parse_ex_fuzzer.cc b/fuzz/tokener_parse_ex_fuzzer.cc index 862149b..f058e0f 100644 --- a/fuzz/tokener_parse_ex_fuzzer.cc +++ b/fuzz/tokener_parse_ex_fuzzer.cc @@ -7,7 +7,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) const char *data1 = reinterpret_cast(data); json_tokener *tok = json_tokener_new(); json_object *obj = json_tokener_parse_ex(tok, data1, size); - + + json_object_object_foreach(jobj, key, val) { + (void)json_object_get_type(val); + (void)json_object_get_string(val); + } + (void)json_object_to_json_string(obj, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED); + json_object_put(obj); json_tokener_free(tok); return 0; diff --git a/issues_closed_for_0.15.md b/issues_closed_for_0.15.md new file mode 100644 index 0000000..8c7f2f6 --- /dev/null +++ b/issues_closed_for_0.15.md @@ -0,0 +1,85 @@ +This list was created with: + +``` +curl "https://api.github.com/search/issues?q=repo%3Ajson-c%2Fjson-c+closed%3A>2020-04-18+created%3A<2020-07-23&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 +#... manual editing ... + +``` + +---- + +Issues and Pull Requests closed for the 0.15 release +(since commit 31ab57ca, the 0.14 branch point, 2020-04-19) + +* [Issue #428](https://github.com/json-c/json-c/issues/428) - Added new_null() function +* [Issue #429](https://github.com/json-c/json-c/issues/429) - Conflict of interest between JSON_C_TO_STRING_SPACED and JSON_C_TO_STRING_PRETTY +* [Issue #451](https://github.com/json-c/json-c/issues/451) - Add option to disable HAVE___THREAD +* [Issue #471](https://github.com/json-c/json-c/issues/471) - create folders with mode 0755 when building +* [Issue #476](https://github.com/json-c/json-c/issues/476) - Add new function named json_object_new_string_noalloc +* [Issue #484](https://github.com/json-c/json-c/issues/484) - Add support for uint64 +* [Issue #487](https://github.com/json-c/json-c/issues/487) - Any plans to make new release? (0.14) +* [Issue #493](https://github.com/json-c/json-c/issues/493) - Kdopen rename library +* [Issue #507](https://github.com/json-c/json-c/issues/507) - Double value -1.0 converts to integer in json_object_to_json_string() +* [Issue #508](https://github.com/json-c/json-c/issues/508) - Recommend enabling the `-fPIC` compiler flag by default +* [Issue #517](https://github.com/json-c/json-c/issues/517) - Lja mods +* [Issue #534](https://github.com/json-c/json-c/issues/534) - Both json-c and json-glib have json_object_get_type() +* [Issue #584](https://github.com/json-c/json-c/issues/584) - CMake: SOVERSION and the major library VERSION need to be in lockstep. +* [Issue #585](https://github.com/json-c/json-c/issues/585) - CMake: Do not install config.h, as it is not a public header file. +* [Issue #586](https://github.com/json-c/json-c/issues/586) - 10796 Segmentation fault +* [Issue #588](https://github.com/json-c/json-c/issues/588) - Broken RDRAND causes infinite looping +* [Issue #589](https://github.com/json-c/json-c/issues/589) - Detect broken RDRAND during initialization +* [Issue #590](https://github.com/json-c/json-c/issues/590) - Fix segmentation fault in CPUID check +* [Issue #591](https://github.com/json-c/json-c/issues/591) - Update README.md +* [Issue #592](https://github.com/json-c/json-c/issues/592) - Prevent out of boundary write on malicious input +* [Issue #593](https://github.com/json-c/json-c/issues/593) - Building both static and shared libraries +* [Issue #594](https://github.com/json-c/json-c/issues/594) - Some subsequent call of lh_get_hash not working +* [Issue #595](https://github.com/json-c/json-c/issues/595) - Support to build both static and shared libraries +* [Issue #596](https://github.com/json-c/json-c/issues/596) - QA Notice: Package triggers severe warnings +* [Issue #597](https://github.com/json-c/json-c/issues/597) - json_parse demo: fix and use usage() function +* [Issue #598](https://github.com/json-c/json-c/issues/598) - Turning off shared libs causes target duplication or build error +* [Issue #599](https://github.com/json-c/json-c/issues/599) - cannot add more than 11 objects. Is this a known issue? +* [Issue #600](https://github.com/json-c/json-c/issues/600) - Library name conflicts on Windows are back again +* [Issue #601](https://github.com/json-c/json-c/issues/601) - json_tokener_parse() in master sets errno=1 "Operation not permitted" +* [Issue #602](https://github.com/json-c/json-c/issues/602) - fix json_parse_uint64() internal error checking with errno +* [Issue #603](https://github.com/json-c/json-c/issues/603) - Backport of fixes from master branch. +* [Issue #604](https://github.com/json-c/json-c/issues/604) - commit f2e991a3419ee4078e8915e840b1a0d9003b349e breaks cross-compilation with mingw +* [Issue #605](https://github.com/json-c/json-c/issues/605) - Update to 0.15 release +* [Issue #606](https://github.com/json-c/json-c/issues/606) - Improved support for IBM operating systems +* [Issue #607](https://github.com/json-c/json-c/issues/607) - json-c-0.13.x: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ... +* [Issue #608](https://github.com/json-c/json-c/issues/608) - json-c-0.14: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ... +* [Issue #609](https://github.com/json-c/json-c/issues/609) - use unsigned types for sizes in lh_table and entries +* [Issue #610](https://github.com/json-c/json-c/issues/610) - let's not call lh_table_resize with INT_MAX +* [Issue #611](https://github.com/json-c/json-c/issues/611) - json-c-0.12.x: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ... +* [Issue #613](https://github.com/json-c/json-c/issues/613) - json-c-0.10: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ... +* [Issue #614](https://github.com/json-c/json-c/issues/614) - Prevent truncation on custom double formatters. +* [Issue #615](https://github.com/json-c/json-c/issues/615) - New release with security fix +* [Issue #616](https://github.com/json-c/json-c/issues/616) - Parsing fails if UTF-16 low surrogate pair is not in same chunk is the high pair +* [Issue #617](https://github.com/json-c/json-c/issues/617) - Add an option to disable the use of thread-local storage. +* [Issue #618](https://github.com/json-c/json-c/issues/618) - test_deep_copy: Fix assertion value. +* [Issue #619](https://github.com/json-c/json-c/issues/619) - CMake: Fix out-of-tree build for Doxygen documentation. +* [Issue #621](https://github.com/json-c/json-c/issues/621) - json-c and jansson libraries have symbol conflicts +* [Issue #622](https://github.com/json-c/json-c/issues/622) - doc: Move Doxyfile into doc subdir. +* [Issue #623](https://github.com/json-c/json-c/issues/623) - json_tokener_parse : Segmentation fault +* [Issue #626](https://github.com/json-c/json-c/issues/626) - Fixes for cmake 2.8.12 + link issue on AIX 6.1/cc 11.01 +* [Issue #627](https://github.com/json-c/json-c/issues/627) - Compat fixes +* [Issue #628](https://github.com/json-c/json-c/issues/628) - get_cryptgenrandom_seed: compat with old windows + fallback +* [Issue #629](https://github.com/json-c/json-c/issues/629) - [0.12] Remove the Visual Studio project file +* [Issue #630](https://github.com/json-c/json-c/issues/630) - Linking with Windows MINGW not working +* [Issue #632](https://github.com/json-c/json-c/issues/632) - Json object split +* [Issue #633](https://github.com/json-c/json-c/issues/633) - fix issue 616: support the surrogate pair in split file. +* [Issue #634](https://github.com/json-c/json-c/issues/634) - Issue #508: `-fPIC` to link libjson-c.a with libs +* [Issue #635](https://github.com/json-c/json-c/issues/635) - expression has no effect warning in json_tokener.c +* [Issue #636](https://github.com/json-c/json-c/issues/636) - json_object_get_string free str memory +* [Issue #637](https://github.com/json-c/json-c/issues/637) - json_object_put() has 'double free or corruption (out) ' +* [Issue #638](https://github.com/json-c/json-c/issues/638) - json-c/json_object.c:50:2: error: #error Unable to determine size of ssize_t +* [Issue #639](https://github.com/json-c/json-c/issues/639) - build: Add a symbol version to all exported symbols +* [Issue #640](https://github.com/json-c/json-c/issues/640) - Fix build issues with SSIZE_MAX on 64bit Linux +* [Issue #641](https://github.com/json-c/json-c/issues/641) - Formal verification of your test suite +* [Issue #642](https://github.com/json-c/json-c/issues/642) - Please provide more precise informations about when to call json_object_put +* [Issue #643](https://github.com/json-c/json-c/issues/643) - not able to compare with string +* [Issue #644](https://github.com/json-c/json-c/issues/644) - Why src->_userdata not checked before calling strdup? +* [Issue #645](https://github.com/json-c/json-c/issues/645) - Misuse of tolower() in json_tokener.c +* [Issue #646](https://github.com/json-c/json-c/issues/646) - Cast to unsigned char instead of int when calling tolower (Fixes #645) + diff --git a/issues_closed_for_0.16.md b/issues_closed_for_0.16.md new file mode 100644 index 0000000..290967d --- /dev/null +++ b/issues_closed_for_0.16.md @@ -0,0 +1,107 @@ +This list was created with: + +``` +PREV=2020-07-23 +NOW=2022-04-13 +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.16.md +``` + +* [Issue #464](https://github.com/json-c/json-c/issues/464) - Speed up parsing and object creation +* [Issue #540](https://github.com/json-c/json-c/issues/540) - request: json_init_library +* [Issue #631](https://github.com/json-c/json-c/issues/631) - New 0.14 release requests +* [Issue #647](https://github.com/json-c/json-c/issues/647) - "cmake -DCMAKE_BUILD_TYPE=Release" fails with error: 'cint64' may be used uninitialized +* [Issue #648](https://github.com/json-c/json-c/issues/648) - Fix "may be used uninitialized" Release build failure +* [Issue #649](https://github.com/json-c/json-c/issues/649) - json-c tag 0.15 tarball contains a file doc/Doxyfile and generated doxygen files in doc/html +* [Issue #650](https://github.com/json-c/json-c/issues/650) - README: fix spelling errors +* [Issue #651](https://github.com/json-c/json-c/issues/651) - Getrandom +* [Issue #652](https://github.com/json-c/json-c/issues/652) - Waste memory +* [Issue #653](https://github.com/json-c/json-c/issues/653) - Make the documentation build reproducibly +* [Issue #654](https://github.com/json-c/json-c/issues/654) - A stack-buffer-overflow in json_parse.c:89:44 +* [Issue #655](https://github.com/json-c/json-c/issues/655) - json_parse: Fix read past end of buffer +* [Issue #656](https://github.com/json-c/json-c/issues/656) - Fixed warnings +* [Issue #657](https://github.com/json-c/json-c/issues/657) - Use GRND_NONBLOCK with getrandom. +* [Issue #658](https://github.com/json-c/json-c/issues/658) - json_object_get_boolean() returns wrong result for objects and arrays +* [Issue #659](https://github.com/json-c/json-c/issues/659) - fix json_object_get_boolean() to behave like documented +* [Issue #660](https://github.com/json-c/json-c/issues/660) - Validate size arguments in arraylist functions. +* [Issue #661](https://github.com/json-c/json-c/issues/661) - Cleanup of some code parts +* [Issue #662](https://github.com/json-c/json-c/issues/662) - Prevent signed overflow in get_time_seed +* [Issue #663](https://github.com/json-c/json-c/issues/663) - Properly format errnos in _json_c_strerror +* [Issue #664](https://github.com/json-c/json-c/issues/664) - Limit strings at INT_MAX length +* [Issue #665](https://github.com/json-c/json-c/issues/665) - Handle more allocation failures in json_tokener* functions +* [Issue #666](https://github.com/json-c/json-c/issues/666) - test1 json_object_new_array_ext test is failing +* [Issue #667](https://github.com/json-c/json-c/issues/667) - Fixed test1 regression. +* [Issue #670](https://github.com/json-c/json-c/issues/670) - Created Stone-Paper-Scissor Game by C language +* [Issue #672](https://github.com/json-c/json-c/issues/672) - Calling exit() after failure to generate random seed +* [Issue #673](https://github.com/json-c/json-c/issues/673) - switchcasemenuproject +* [Issue #674](https://github.com/json-c/json-c/issues/674) - random_seed: on error, continue to next method +* [Issue #682](https://github.com/json-c/json-c/issues/682) - libjson-c-dev vs libjson-c3 +* [Issue #683](https://github.com/json-c/json-c/issues/683) - [Question] Is it possible to clear a ptr of json_object? +* [Issue #684](https://github.com/json-c/json-c/issues/684) - json_tokener_parse_verbose failed with core dump +* [Issue #685](https://github.com/json-c/json-c/issues/685) - json_tokener_parse memory leak? +* [Issue #689](https://github.com/json-c/json-c/issues/689) - fix compilation with clang +* [Issue #690](https://github.com/json-c/json-c/issues/690) - "1," produces an object with int 1; "1" produces a null object +* [Issue #691](https://github.com/json-c/json-c/issues/691) - failed tests +* [Issue #692](https://github.com/json-c/json-c/issues/692) - patch to add arc4random +* [Issue #693](https://github.com/json-c/json-c/issues/693) - Optional parameter for packing as array +* [Issue #694](https://github.com/json-c/json-c/issues/694) - fix invalid unsigned arithmetic. +* [Issue #695](https://github.com/json-c/json-c/issues/695) - /tmp/json-c/random_seed.c:327:6: error +* [Issue #696](https://github.com/json-c/json-c/issues/696) - To avoid target exe file export JSON functions. +* [Issue #697](https://github.com/json-c/json-c/issues/697) - json_object_get_string() return value truncated when assigning it to a pointer type in Win32 App +* [Issue #698](https://github.com/json-c/json-c/issues/698) - Feature request: set allocator +* [Issue #699](https://github.com/json-c/json-c/issues/699) - Linking to libjson-c Issue +* [Issue #700](https://github.com/json-c/json-c/issues/700) - Fix unused variable for Win32 build in random_seed.c +* [Issue #701](https://github.com/json-c/json-c/issues/701) - [RFC] json_pointer: allow the feature to be disabled +* [Issue #703](https://github.com/json-c/json-c/issues/703) - Fix vasprintf fallback +* [Issue #706](https://github.com/json-c/json-c/issues/706) - Check __STDC_VERSION__ is defined before checking its value +* [Issue #707](https://github.com/json-c/json-c/issues/707) - How to build json-c-0.15 for arm arch +* [Issue #708](https://github.com/json-c/json-c/issues/708) - direct access to elements +* [Issue #709](https://github.com/json-c/json-c/issues/709) - Include guards not namespaced / build errors for debug.h with openNDS +* [Issue #710](https://github.com/json-c/json-c/issues/710) - 'file system sandbox blocked mmap()' error on iOS +* [Issue #711](https://github.com/json-c/json-c/issues/711) - creating a json object +* [Issue #712](https://github.com/json-c/json-c/issues/712) - building json-c using cmake for ESP32 +* [Issue #713](https://github.com/json-c/json-c/issues/713) - When value converted to char* can not compare it with another value +* [Issue #714](https://github.com/json-c/json-c/issues/714) - Add AfterCaseLabel to .clang-format +* [Issue #716](https://github.com/json-c/json-c/issues/716) - Fixed cmake command +* [Issue #717](https://github.com/json-c/json-c/issues/717) - Cmake is able delete all files by "clean" target +* [Issue #718](https://github.com/json-c/json-c/issues/718) - CMake create uninstall target if unix generator is used +* [Issue #719](https://github.com/json-c/json-c/issues/719) - Parsing multiple JSON strings +* [Issue #722](https://github.com/json-c/json-c/issues/722) - Fix use-after-free in json_tokener_new_ex() +* [Issue #723](https://github.com/json-c/json-c/issues/723) - if set __stdcall (/Gz) +* [Issue #724](https://github.com/json-c/json-c/issues/724) - #723 +* [Issue #725](https://github.com/json-c/json-c/issues/725) - json_object_from_file() execution segment error +* [Issue #726](https://github.com/json-c/json-c/issues/726) - fix cmake version for tests +* [Issue #727](https://github.com/json-c/json-c/issues/727) - Really use prefix JSON_C_OBJECT_ADD_ +* [Issue #728](https://github.com/json-c/json-c/issues/728) - DRAFT PROPOSAL - Add option JSON_C_OBJECT_ADD_IF_NOT_NULL +* [Issue #729](https://github.com/json-c/json-c/issues/729) - * don't assume includedir +* [Issue #731](https://github.com/json-c/json-c/issues/731) - Json-c Error +* [Issue #732](https://github.com/json-c/json-c/issues/732) - Fix/static include dirs +* [Issue #734](https://github.com/json-c/json-c/issues/734) - Newer appveyor config for VS2022 etc... +* [Issue #735](https://github.com/json-c/json-c/issues/735) - Add policy_max to minimum required cmake version +* [Issue #736](https://github.com/json-c/json-c/issues/736) - json_object.c:308: json_object_put: Assertion `jso->_ref_count > 0' failed +* [Issue #737](https://github.com/json-c/json-c/issues/737) - Fix typo in README +* [Issue #738](https://github.com/json-c/json-c/issues/738) - General question - Is there an SLA for handling newly detected security issues? +* [Issue #739](https://github.com/json-c/json-c/issues/739) - json_escape_str(): avoid harmless unsigned integer overflow +* [Issue #741](https://github.com/json-c/json-c/issues/741) - json_type_to_name(): use correct printf() formatter +* [Issue #742](https://github.com/json-c/json-c/issues/742) - json_object_copy_serializer_data(): add assertion +* [Issue #743](https://github.com/json-c/json-c/issues/743) - Cmd adb root +* [Issue #744](https://github.com/json-c/json-c/issues/744) - Close file on error path. +* [Issue #745](https://github.com/json-c/json-c/issues/745) - vasprintf(): avoid out of memory accesses +* [Issue #746](https://github.com/json-c/json-c/issues/746) - Fix typos in code comments and ChangeLog +* [Issue #747](https://github.com/json-c/json-c/issues/747) - json_object_put: Assertion `jso->_ref_count > 0' failed +* [Issue #748](https://github.com/json-c/json-c/issues/748) - sprintbuf(): test for all vsnprintf error values +* [Issue #749](https://github.com/json-c/json-c/issues/749) - sprintbuf(): handle printbuf_memappend errors +* [Issue #750](https://github.com/json-c/json-c/issues/750) - printbuf_memset(): set gaps to zero +* [Issue #751](https://github.com/json-c/json-c/issues/751) - printbuf: do not allow invalid arguments +* [Issue #752](https://github.com/json-c/json-c/issues/752) - Fix typos +* [Issue #753](https://github.com/json-c/json-c/issues/753) - CTest failed in MSVC build +* [Issue #754](https://github.com/json-c/json-c/issues/754) - Minor improvements to documentation +* [Issue #755](https://github.com/json-c/json-c/issues/755) - Fix error messages +* [Issue #758](https://github.com/json-c/json-c/issues/758) - Preserve context if out of memory +* [Issue #760](https://github.com/json-c/json-c/issues/760) - Code style: removed unneeded double-quotes +* [Issue #761](https://github.com/json-c/json-c/issues/761) - Last commit merged to master breaks compilation +* [Issue #762](https://github.com/json-c/json-c/issues/762) - how to merge two jsons by json-c +* [Issue #763](https://github.com/json-c/json-c/issues/763) - Question: sort_fn arguments +* [Issue #764](https://github.com/json-c/json-c/issues/764) - Make test fail on test case test_util_file diff --git a/issues_closed_for_0.17.md b/issues_closed_for_0.17.md new file mode 100644 index 0000000..080f063 --- /dev/null +++ b/issues_closed_for_0.17.md @@ -0,0 +1,88 @@ +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 diff --git a/json-c.sym b/json-c.sym index a348204..c7501bb 100644 --- a/json-c.sym +++ b/json-c.sym @@ -41,6 +41,8 @@ JSONC_PRIVATE { printbuf_new; printbuf_reset; sprintbuf; + # Used by tests: + _json_c_strerror; }; JSONC_0.14 { @@ -163,3 +165,14 @@ JSONC_0.15 { json_object_array_shrink; json_object_new_array_ext; } JSONC_0.14; + +JSONC_0.16 { +# No new symbols in 0.16 +} JSONC_0.15; + +JSONC_0.17 { + global: + json_object_array_insert_idx; + json_patch_apply; +# array_list_insert_idx is intentionally not exported +} JSONC_0.16; diff --git a/json.h b/json.h.cmakein similarity index 94% rename from json.h rename to json.h.cmakein index 6c3b43b..2271320 100644 --- a/json.h +++ b/json.h.cmakein @@ -26,7 +26,8 @@ extern "C" { #include "json_c_version.h" #include "json_object.h" #include "json_object_iterator.h" -#include "json_pointer.h" +@JSON_H_JSON_PATCH@ +@JSON_H_JSON_POINTER@ #include "json_tokener.h" #include "json_util.h" #include "linkhash.h" diff --git a/json_c_version.h b/json_c_version.h index 1652955..808f6b7 100644 --- a/json_c_version.h +++ b/json_c_version.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012,2017,2019,2020 Eric Hawicz + * Copyright (c) 2012,2017 Eric Haszlakiewicz * * This library is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See COPYING for details. @@ -17,14 +17,14 @@ extern "C" { #endif #define JSON_C_MAJOR_VERSION 0 -#define JSON_C_MINOR_VERSION 15 +#define JSON_C_MINOR_VERSION 17 #define JSON_C_MICRO_VERSION 0 #define JSON_C_VERSION_NUM \ ((JSON_C_MAJOR_VERSION << 16) | (JSON_C_MINOR_VERSION << 8) | JSON_C_MICRO_VERSION) -#define JSON_C_VERSION "0.15" +#define JSON_C_VERSION "0.17" #ifndef JSON_EXPORT -#if defined(_MSC_VER) +#if defined(_MSC_VER) && defined(JSON_C_DLL) #define JSON_EXPORT __declspec(dllexport) #else #define JSON_EXPORT extern diff --git a/json_inttypes.h b/json_inttypes.h index e047d4f..a33a31f 100644 --- a/json_inttypes.h +++ b/json_inttypes.h @@ -13,7 +13,15 @@ #include #else +#ifdef JSON_C_HAVE_STDINT_H #include +#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 SCNd64 "I64d" @@ -21,4 +29,9 @@ #endif +#if defined(_MSC_VER) +#include +typedef SSIZE_T ssize_t; +#endif + #endif diff --git a/json_object.c b/json_object.c index 9198257..cc4c1e2 100644 --- a/json_object.c +++ b/json_object.c @@ -13,7 +13,6 @@ #include "strerror_override.h" #include -#include #ifdef HAVE_LIMITS_H #include #endif @@ -35,8 +34,11 @@ #include "snprintf_compat.h" #include "strdup_compat.h" +/* Avoid ctype.h and locale overhead */ +#define is_plain_digit(c) ((c) >= '0' && (c) <= '9') + #if SIZEOF_LONG_LONG != SIZEOF_INT64_T -#error "The long long type isn't 64-bits" +#error The long long type is not 64-bits #endif #ifndef SSIZE_T_MAX @@ -51,9 +53,7 @@ #endif #endif -// Don't define this. It's not thread-safe. -/* #define REFCOUNT_DEBUG 1 */ - +const char *json_number_chars = "0123456789.+-eE"; /* Unused, but part of public API, drop for 1.0 */ const char *json_hex_chars = "0123456789abcdefABCDEF"; static void json_object_generic_delete(struct json_object *jso); @@ -65,6 +65,12 @@ static void json_object_generic_delete(struct json_object *jso); #define inline #endif +/* define colors */ +#define ANSI_COLOR_RESET "\033[0m" +#define ANSI_COLOR_FG_GREEN "\033[0;32m" +#define ANSI_COLOR_FG_BLUE "\033[0;34m" +#define ANSI_COLOR_FG_MAGENTA "\033[0;35m" + /* * Helper functions to more safely cast to a particular type of json_object */ @@ -159,41 +165,6 @@ static json_object_to_json_string_fn _json_object_userdata_to_json_string; * */ JSON_NORETURN static void json_abort(const char *message); -/* ref count debugging */ - -#ifdef REFCOUNT_DEBUG - -static struct lh_table *json_object_table; - -static void json_object_init(void) __attribute__((constructor)); -static void json_object_init(void) -{ - MC_DEBUG("json_object_init: creating object table\n"); - json_object_table = lh_kptr_table_new(128, NULL); -} - -static void json_object_fini(void) __attribute__((destructor)); -static void json_object_fini(void) -{ - struct lh_entry *ent; - if (MC_GET_DEBUG()) - { - if (json_object_table->count) - { - MC_DEBUG("json_object_fini: %d referenced objects at exit\n", - json_object_table->count); - lh_foreach(json_object_table, ent) - { - struct json_object *obj = (struct json_object *)lh_entry_v(ent); - MC_DEBUG("\t%s:%p\n", json_type_to_name(obj->o_type), obj); - } - } - } - MC_DEBUG("json_object_fini: freeing object table\n"); - lh_table_free(json_object_table); -} -#endif /* REFCOUNT_DEBUG */ - /* helper for accessing the optimized string data component in json_object */ static inline char *get_string_component_mutable(struct json_object *jso) @@ -214,10 +185,11 @@ static inline const char *get_string_component(const struct json_object *jso) static int json_escape_str(struct printbuf *pb, const char *str, size_t len, int flags) { - int pos = 0, start_offset = 0; + size_t pos = 0, start_offset = 0; unsigned char c; - while (len--) + while (len) { + --len; c = str[pos]; switch (c) { @@ -235,7 +207,7 @@ static int json_escape_str(struct printbuf *pb, const char *str, size_t len, int break; } - if (pos - start_offset > 0) + if (pos > start_offset) printbuf_memappend(pb, str + start_offset, pos - start_offset); if (c == '\b') @@ -261,7 +233,7 @@ static int json_escape_str(struct printbuf *pb, const char *str, size_t len, int if (c < ' ') { char sbuf[7]; - if (pos - start_offset > 0) + if (pos > start_offset) printbuf_memappend(pb, str + start_offset, pos - start_offset); snprintf(sbuf, sizeof(sbuf), "\\u00%c%c", json_hex_chars[c >> 4], @@ -273,7 +245,7 @@ static int json_escape_str(struct printbuf *pb, const char *str, size_t len, int pos++; } } - if (pos - start_offset > 0) + if (pos > start_offset) printbuf_memappend(pb, str + start_offset, pos - start_offset); return 0; } @@ -337,10 +309,6 @@ int json_object_put(struct json_object *jso) static void json_object_generic_delete(struct json_object *jso) { -#ifdef REFCOUNT_DEBUG - MC_DEBUG("json_object_delete_%s: %p\n", json_type_to_name(jso->o_type), jso); - lh_table_delete(json_object_table, jso); -#endif /* REFCOUNT_DEBUG */ printbuf_free(jso->_pb); free(jso); } @@ -362,10 +330,6 @@ static inline struct json_object *json_object_new(enum json_type o_type, size_t jso->_userdata = NULL; //jso->... // Type-specific fields must be set by caller -#ifdef REFCOUNT_DEBUG - lh_table_insert(json_object_table, jso, jso); - MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso); -#endif /* REFCOUNT_DEBUG */ return jso; } @@ -503,35 +467,45 @@ static int json_object_object_to_json_string(struct json_object *jso, struct pri struct json_object_iter iter; printbuf_strappend(pb, "{" /*}*/); - if (flags & JSON_C_TO_STRING_PRETTY) - printbuf_strappend(pb, "\n"); json_object_object_foreachC(jso, iter) { if (had_children) { printbuf_strappend(pb, ","); - if (flags & JSON_C_TO_STRING_PRETTY) - printbuf_strappend(pb, "\n"); } + if (flags & JSON_C_TO_STRING_PRETTY) + printbuf_strappend(pb, "\n"); had_children = 1; if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) printbuf_strappend(pb, " "); indent(pb, level + 1, flags); + if (flags & JSON_C_TO_STRING_COLOR) + printbuf_strappend(pb, ANSI_COLOR_FG_BLUE); + printbuf_strappend(pb, "\""); json_escape_str(pb, iter.key, strlen(iter.key), flags); + printbuf_strappend(pb, "\""); + + if (flags & JSON_C_TO_STRING_COLOR) + printbuf_strappend(pb, ANSI_COLOR_RESET); + if (flags & JSON_C_TO_STRING_SPACED) - printbuf_strappend(pb, "\": "); + printbuf_strappend(pb, ": "); else - printbuf_strappend(pb, "\":"); - if (iter.val == NULL) + printbuf_strappend(pb, ":"); + + if (iter.val == NULL) { + if (flags & JSON_C_TO_STRING_COLOR) + printbuf_strappend(pb, ANSI_COLOR_FG_MAGENTA); printbuf_strappend(pb, "null"); - else if (iter.val->_to_json_string(iter.val, pb, level + 1, flags) < 0) + if (flags & JSON_C_TO_STRING_COLOR) + printbuf_strappend(pb, ANSI_COLOR_RESET); + } else if (iter.val->_to_json_string(iter.val, pb, level + 1, flags) < 0) return -1; } - if (flags & JSON_C_TO_STRING_PRETTY) + if ((flags & JSON_C_TO_STRING_PRETTY) && had_children) { - if (had_children) - printbuf_strappend(pb, "\n"); + printbuf_strappend(pb, "\n"); indent(pb, level, flags); } if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) @@ -542,7 +516,7 @@ static int json_object_object_to_json_string(struct json_object *jso, struct pri static void json_object_lh_entry_free(struct lh_entry *ent) { - if (!ent->k_is_constant) + if (!lh_entry_k_is_constant(ent)) free(lh_entry_k(ent)); json_object_put((struct json_object *)lh_entry_v(ent)); } @@ -605,7 +579,7 @@ int json_object_object_add_ex(struct json_object *jso, const char *const key, if (!existing_entry) { const void *const k = - (opts & JSON_C_OBJECT_KEY_IS_CONSTANT) ? (const void *)key : strdup(key); + (opts & JSON_C_OBJECT_ADD_CONSTANT_KEY) ? (const void *)key : strdup(key); if (k == NULL) return -1; return lh_table_insert_w_hash(JC_OBJECT(jso)->c_object, k, val, hash, opts); @@ -613,7 +587,7 @@ int json_object_object_add_ex(struct json_object *jso, const char *const key, existing_value = (json_object *)lh_entry_v(existing_entry); if (existing_value) json_object_put(existing_value); - existing_entry->v = val; + lh_entry_set_val(existing_entry, val); return 0; } @@ -672,9 +646,18 @@ void json_object_object_del(struct json_object *jso, const char *key) static int json_object_boolean_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { + int ret; + + if (flags & JSON_C_TO_STRING_COLOR) + printbuf_strappend(pb, ANSI_COLOR_FG_MAGENTA); + if (JC_BOOL(jso)->c_boolean) - return printbuf_strappend(pb, "true"); - return printbuf_strappend(pb, "false"); + ret = printbuf_strappend(pb, "true"); + else + ret = printbuf_strappend(pb, "false"); + if (ret > -1 && flags & JSON_C_TO_STRING_COLOR) + return printbuf_strappend(pb, ANSI_COLOR_RESET); + return ret; } struct json_object *json_object_new_boolean(json_bool b) @@ -735,7 +718,7 @@ struct json_object *json_object_new_int(int32_t i) int32_t json_object_get_int(const struct json_object *jso) { - int64_t cint64=0; + int64_t cint64 = 0; double cdouble; enum json_type o_type; @@ -976,7 +959,21 @@ int json_c_set_serialization_double_format(const char *double_format, int global #endif if (global_serialization_float_format) free(global_serialization_float_format); - global_serialization_float_format = double_format ? strdup(double_format) : NULL; + if (double_format) + { + char *p = strdup(double_format); + if (p == NULL) + { + _json_c_set_last_err("json_c_set_serialization_double_format: " + "out of memory\n"); + return -1; + } + global_serialization_float_format = p; + } + else + { + global_serialization_float_format = NULL; + } } else if (global_or_thread == JSON_C_OPTION_THREAD) { @@ -986,16 +983,31 @@ int json_c_set_serialization_double_format(const char *double_format, int global free(tls_serialization_float_format); tls_serialization_float_format = NULL; } - tls_serialization_float_format = double_format ? strdup(double_format) : NULL; + if (double_format) + { + char *p = strdup(double_format); + if (p == NULL) + { + _json_c_set_last_err("json_c_set_serialization_double_format: " + "out of memory\n"); + return -1; + } + tls_serialization_float_format = p; + } + else + { + tls_serialization_float_format = NULL; + } #else - _json_c_set_last_err("json_c_set_option: not compiled with __thread support\n"); + _json_c_set_last_err("json_c_set_serialization_double_format: not compiled " + "with __thread support\n"); return -1; #endif } else { - _json_c_set_last_err("json_c_set_option: invalid global_or_thread value: %d\n", - global_or_thread); + _json_c_set_last_err("json_c_set_serialization_double_format: invalid " + "global_or_thread value: %d\n", global_or_thread); return -1; } return 0; @@ -1056,8 +1068,7 @@ static int json_object_double_to_json_string_format(struct json_object *jso, str format_drops_decimals = 1; looks_numeric = /* Looks like *some* kind of number */ - isdigit((unsigned char)buf[0]) || - (size > 1 && buf[0] == '-' && isdigit((unsigned char)buf[1])); + is_plain_digit(buf[0]) || (size > 1 && buf[0] == '-' && is_plain_digit(buf[1])); if (size < (int)sizeof(buf) - 2 && looks_numeric && !p && /* Has no decimal point */ strchr(buf, 'e') == NULL && /* Not scientific notation */ @@ -1235,9 +1246,13 @@ static int json_object_string_to_json_string(struct json_object *jso, struct pri int level, int flags) { ssize_t len = JC_STRING(jso)->len; + if (flags & JSON_C_TO_STRING_COLOR) + printbuf_strappend(pb, ANSI_COLOR_FG_GREEN); printbuf_strappend(pb, "\""); json_escape_str(pb, get_string_component(jso), len < 0 ? -(ssize_t)len : len, flags); printbuf_strappend(pb, "\""); + if (flags & JSON_C_TO_STRING_COLOR) + printbuf_strappend(pb, ANSI_COLOR_RESET); return 0; } @@ -1254,17 +1269,17 @@ static struct json_object *_json_object_new_string(const char *s, const size_t l struct json_object_string *jso; /* - * Structures Actual memory layout - * ------------------- -------------------- + * Structures Actual memory layout + * ------------------- -------------------- * [json_object_string [json_object_string * [json_object] [json_object] - * ...other fields... ...other fields... + * ...other fields... ...other fields... * c_string] len - * bytes + * bytes * of * string * data - * \0] + * \0] */ if (len > (SSIZE_T_MAX - (sizeof(*jso) - sizeof(jso->c_string)) - 1)) return NULL; @@ -1281,7 +1296,8 @@ static struct json_object *_json_object_new_string(const char *s, const size_t l return NULL; jso->len = len; memcpy(jso->c_string.idata, s, len); - jso->c_string.idata[len] = '\0'; + // Cast below needed for Clang UB sanitizer + ((char *)jso->c_string.idata)[len] = '\0'; return &jso->base; } @@ -1305,18 +1321,20 @@ const char *json_object_get_string(struct json_object *jso) default: return json_object_to_json_string(jso); } } -int json_object_get_string_len(const struct json_object *jso) + +static inline ssize_t _json_object_get_string_len(const struct json_object_string *jso) { ssize_t len; + len = jso->len; + return (len < 0) ? -(ssize_t)len : len; +} +int json_object_get_string_len(const struct json_object *jso) +{ if (!jso) return 0; switch (jso->o_type) { - case json_type_string: - { - len = JC_STRING_C(jso)->len; - return (len < 0) ? -(ssize_t)len : len; - } + case json_type_string: return _json_object_get_string_len(JC_STRING_C(jso)); default: return 0; } } @@ -1329,16 +1347,24 @@ static int _json_object_set_string_len(json_object *jso, const char *s, size_t l if (jso == NULL || jso->o_type != json_type_string) return 0; - if (len >= SSIZE_T_MAX - 1) + if (len >= INT_MAX - 1) // jso->len is a signed ssize_t, so it can't hold the - // full size_t range. + // full size_t range. json_object_get_string_len returns + // length as int, cap length at INT_MAX. return 0; - dstbuf = get_string_component_mutable(jso); curlen = JC_STRING(jso)->len; - if (curlen < 0) - curlen = -curlen; + if (curlen < 0) { + if (len == 0) { + free(JC_STRING(jso)->c_string.pdata); + JC_STRING(jso)->len = curlen = 0; + } else { + curlen = -curlen; + } + } + newlen = len; + dstbuf = get_string_component_mutable(jso); if ((ssize_t)len > curlen) { @@ -1385,31 +1411,34 @@ static int json_object_array_to_json_string(struct json_object *jso, struct prin size_t ii; printbuf_strappend(pb, "["); - if (flags & JSON_C_TO_STRING_PRETTY) - printbuf_strappend(pb, "\n"); for (ii = 0; ii < json_object_array_length(jso); ii++) { struct json_object *val; if (had_children) { printbuf_strappend(pb, ","); - if (flags & JSON_C_TO_STRING_PRETTY) - printbuf_strappend(pb, "\n"); } + if (flags & JSON_C_TO_STRING_PRETTY) + printbuf_strappend(pb, "\n"); had_children = 1; if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) printbuf_strappend(pb, " "); indent(pb, level + 1, flags); val = json_object_array_get_idx(jso, ii); - if (val == NULL) + if (val == NULL) { + + if (flags & JSON_C_TO_STRING_COLOR) + printbuf_strappend(pb, ANSI_COLOR_FG_MAGENTA); printbuf_strappend(pb, "null"); - else if (val->_to_json_string(val, pb, level + 1, flags) < 0) + if (flags & JSON_C_TO_STRING_COLOR) + printbuf_strappend(pb, ANSI_COLOR_RESET); + + } else if (val->_to_json_string(val, pb, level + 1, flags) < 0) return -1; } - if (flags & JSON_C_TO_STRING_PRETTY) + if ((flags & JSON_C_TO_STRING_PRETTY) && had_children) { - if (had_children) - printbuf_strappend(pb, "\n"); + printbuf_strappend(pb, "\n"); indent(pb, level, flags); } @@ -1491,6 +1520,12 @@ int json_object_array_add(struct json_object *jso, struct json_object *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) { assert(json_object_get_type(jso) == json_type_array); @@ -1605,9 +1640,10 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) case json_type_string: { - return (json_object_get_string_len(jso1) == json_object_get_string_len(jso2) && + return (_json_object_get_string_len(JC_STRING(jso1)) == + _json_object_get_string_len(JC_STRING(jso2)) && memcmp(get_string_component(jso1), get_string_component(jso2), - json_object_get_string_len(jso1)) == 0); + _json_object_get_string_len(JC_STRING(jso1))) == 0); } case json_type_object: return json_object_all_values_equal(jso1, jso2); @@ -1628,14 +1664,22 @@ static int json_object_copy_serializer_data(struct json_object *src, struct json if (dst->_to_json_string == json_object_userdata_to_json_string || dst->_to_json_string == _json_object_userdata_to_json_string) { - dst->_userdata = strdup(src->_userdata); + char *p; + assert(src->_userdata); + p = strdup(src->_userdata); + if (p == NULL) + { + _json_c_set_last_err("json_object_copy_serializer_data: out of memory\n"); + return -1; + } + dst->_userdata = p; } // else if ... other supported serializers ... else { _json_c_set_last_err( - "json_object_deep_copy: unable to copy unknown serializer data: %p\n", - (void *)dst->_to_json_string); + "json_object_copy_serializer_data: unable to copy unknown serializer data: " + "%p\n", (void *)dst->_to_json_string); return -1; } dst->_user_delete = src->_user_delete; @@ -1672,7 +1716,10 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha } break; - case json_type_string: *dst = json_object_new_string(get_string_component(src)); break; + case json_type_string: + *dst = json_object_new_string_len(get_string_component(src), + _json_object_get_string_len(JC_STRING(src))); + break; case json_type_object: *dst = json_object_new_object(); break; @@ -1724,8 +1771,8 @@ static int json_object_deep_copy_recursive(struct json_object *src, struct json_ /* This handles the `json_type_null` case */ if (!iter.val) jso = NULL; - else if (json_object_deep_copy_recursive(iter.val, src, iter.key, -1, &jso, - shallow_copy) < 0) + else if (json_object_deep_copy_recursive(iter.val, src, iter.key, UINT_MAX, + &jso, shallow_copy) < 0) { json_object_put(jso); return -1; @@ -1789,7 +1836,7 @@ int json_object_deep_copy(struct json_object *src, struct json_object **dst, if (shallow_copy == NULL) shallow_copy = json_c_shallow_copy_default; - rc = json_object_deep_copy_recursive(src, NULL, NULL, -1, dst, shallow_copy); + rc = json_object_deep_copy_recursive(src, NULL, NULL, UINT_MAX, dst, shallow_copy); if (rc < 0) { json_object_put(*dst); diff --git a/json_object.h b/json_object.h index a54541c..97ef84c 100644 --- a/json_object.h +++ b/json_object.h @@ -52,7 +52,7 @@ extern "C" { * json_object_to_file_ext() functions which causes * the output to be formatted. * - * See the "Two Space Tab" option at http://jsonformatter.curiousconcept.com/ + * See the "Two Space Tab" option at https://jsonformatter.curiousconcept.com/ * for an example of the format. */ #define JSON_C_TO_STRING_PRETTY (1 << 1) @@ -75,6 +75,15 @@ extern "C" { #define JSON_C_TO_STRING_NOSLASHESCAPE (1 << 4) /** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes + * the output to be formatted. + * + * Use color for printing json. + */ +#define JSON_C_TO_STRING_COLOR (1 << 5) + +/** * A flag for the json_object_object_add_ex function which * causes the value to be added without a check if it already exists. * Note: it is the responsibility of the caller to ensure that no @@ -100,9 +109,17 @@ extern "C" { * key is given as a real constant value in the function * call, e.g. as in * json_object_object_add_ex(obj, "ip", json, - * JSON_C_OBJECT_KEY_IS_CONSTANT); + * JSON_C_OBJECT_ADD_CONSTANT_KEY); + */ +#define JSON_C_OBJECT_ADD_CONSTANT_KEY (1 << 2) +/** + * This flag is an alias to JSON_C_OBJECT_ADD_CONSTANT_KEY. + * Historically, this flag was used first and the new name + * JSON_C_OBJECT_ADD_CONSTANT_KEY was introduced for version + * 0.16.00 in order to have regular naming. + * Use of this flag is now legacy. */ -#define JSON_C_OBJECT_KEY_IS_CONSTANT (1 << 2) +#define JSON_C_OBJECT_KEY_IS_CONSTANT JSON_C_OBJECT_ADD_CONSTANT_KEY /** * Set the global value of an option, which will apply to all @@ -131,7 +148,7 @@ extern "C" { * beyond the lifetime of the parent object. * - Detaching an object field or array index from its parent object * (using `json_object_object_del()` or `json_object_array_del_idx()`) - * - Sharing a json_object with multiple (not necesarily parallel) threads + * - Sharing a json_object with multiple (not necessarily parallel) threads * of execution that all expect to free it (with `json_object_put()`) when * they're done. * @@ -470,19 +487,19 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key * @param val the local name for the json_object* object variable defined in * the body */ -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) #define json_object_object_foreach(obj, key, val) \ char *key = NULL; \ struct json_object *val __attribute__((__unused__)) = NULL; \ - for (struct lh_entry *entry##key = json_object_get_object(obj)->head, \ + for (struct lh_entry *entry##key = lh_table_head(json_object_get_object(obj)), \ *entry_next##key = NULL; \ ({ \ if (entry##key) \ { \ key = (char *)lh_entry_k(entry##key); \ val = (struct json_object *)lh_entry_v(entry##key); \ - entry_next##key = entry##key->next; \ + entry_next##key = lh_entry_next(entry##key); \ }; \ entry##key; \ }); \ @@ -495,25 +512,25 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key struct json_object *val = NULL; \ struct lh_entry *entry##key; \ struct lh_entry *entry_next##key = NULL; \ - for (entry##key = json_object_get_object(obj)->head; \ + for (entry##key = lh_table_head(json_object_get_object(obj)); \ (entry##key ? (key = (char *)lh_entry_k(entry##key), \ val = (struct json_object *)lh_entry_v(entry##key), \ - entry_next##key = entry##key->next, entry##key) \ + entry_next##key = lh_entry_next(entry##key), entry##key) \ : 0); \ entry##key = entry_next##key) -#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L */ +#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) && (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) */ /** Iterate through all keys and values of an object (ANSI C Safe) * @param obj the json_object instance * @param iter the object iterator, use type json_object_iter */ #define json_object_object_foreachC(obj, iter) \ - for (iter.entry = json_object_get_object(obj)->head; \ + for (iter.entry = lh_table_head(json_object_get_object(obj)); \ (iter.entry ? (iter.key = (char *)lh_entry_k(iter.entry), \ iter.val = (struct json_object *)lh_entry_v(iter.entry), iter.entry) \ : 0); \ - iter.entry = iter.entry->next) + iter.entry = lh_entry_next(iter.entry)) /* Array type methods */ @@ -605,6 +622,25 @@ 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, 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) * * *No* reference counts will be changed, and ownership of the returned @@ -656,8 +692,9 @@ JSON_EXPORT struct json_object *json_object_new_boolean(json_bool b); * The type is coerced to a json_bool if the passed object is not a json_bool. * integer and double objects will return 0 if there value is zero * or 1 otherwise. If the passed object is a string it will return - * 1 if it has a non zero length. If any other object type is passed - * 1 will be returned if the object is not NULL. + * 1 if it has a non zero length. + * If any other object type is passed 0 will be returned, even non-empty + * json_type_array and json_type_object objects. * * @param obj the json_object instance * @returns a json_bool @@ -738,7 +775,7 @@ JSON_EXPORT int json_object_set_int(struct json_object *obj, int new_value); * * @param obj the json_object instance * @param val the value to add - * @returns 1 if the increment succeded, 0 otherwise + * @returns 1 if the increment succeeded, 0 otherwise */ JSON_EXPORT int json_object_int_inc(struct json_object *obj, int64_t val); @@ -1055,7 +1092,7 @@ JSON_EXPORT json_c_shallow_copy_fn json_c_shallow_copy_default; * when custom serializers are in use. See also * json_object set_serializer. * - * @returns 0 if the copy went well, -1 if an error occured during copy + * @returns 0 if the copy went well, -1 if an error occurred during copy * or if the destination pointer is non-NULL */ diff --git a/json_object_iterator.c b/json_object_iterator.c index 1c2b3f2..db8488a 100644 --- a/json_object_iterator.c +++ b/json_object_iterator.c @@ -71,7 +71,7 @@ struct json_object_iterator json_object_iter_begin(struct json_object *obj) /// @note For a pair-less Object, head is NULL, which matches our /// definition of the "end" iterator - iter.opaque_ = pTable->head; + iter.opaque_ = lh_table_head(pTable); return iter; } @@ -98,7 +98,7 @@ void json_object_iter_next(struct json_object_iterator *iter) JASSERT(NULL != iter); JASSERT(kObjectEndIterValue != iter->opaque_); - iter->opaque_ = ((const struct lh_entry *)iter->opaque_)->next; + iter->opaque_ = lh_entry_next(((const struct lh_entry *)iter->opaque_)); } /** diff --git a/json_patch.c b/json_patch.c new file mode 100644 index 0000000..5bbc308 --- /dev/null +++ b/json_patch.c @@ -0,0 +1,332 @@ +/* + * 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 +#include +#include + +#include "json_patch.h" +#include "json_object_private.h" +#include "json_pointer_private.h" + +#include +#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_array_cb() +static int json_object_array_insert_idx_cb(struct json_object *parent, 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_array_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_array_cb(res, path, json_object_get(value), + json_object_array_insert_idx_cb, &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_array_cb() +static int json_object_array_move_cb(struct json_object *parent, 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_array_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_array_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_array_cb(res, path, from.obj, array_set_cb, &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; +} diff --git a/json_patch.h b/json_patch.h new file mode 100644 index 0000000..79de5f9 --- /dev/null +++ b/json_patch.h @@ -0,0 +1,80 @@ +/* + * 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 diff --git a/json_pointer.c b/json_pointer.c index 99cc542..89e9e21 100644 --- a/json_pointer.c +++ b/json_pointer.c @@ -10,16 +10,20 @@ #include "strerror_override.h" -#include #include #include #include #include +#include "json_object_private.h" #include "json_pointer.h" +#include "json_pointer_private.h" #include "strdup_compat.h" #include "vasprintf_compat.h" +/* Avoid ctype.h and locale overhead */ +#define is_plain_digit(c) ((c) >= '0' && (c) <= '9') + /** * JavaScript Object Notation (JSON) Pointer * RFC 6901 - https://tools.ietf.org/html/rfc6901 @@ -27,8 +31,8 @@ static void string_replace_all_occurrences_with_char(char *s, const char *occur, char repl_char) { - int slen = strlen(s); - int skip = strlen(occur) - 1; /* length of the occurrence, minus the char we're replacing */ + size_t slen = strlen(s); + size_t skip = strlen(occur) - 1; /* length of the occurrence, minus the char we're replacing */ char *p = s; while ((p = strstr(p, occur))) { @@ -39,18 +43,18 @@ static void string_replace_all_occurrences_with_char(char *s, const char *occur, } } -static int is_valid_index(struct json_object *jo, const char *path, int32_t *idx) +static int is_valid_index(const char *path, size_t *idx) { - int i, len = strlen(path); + size_t i, len = strlen(path); /* 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 */ if (len == 1) { - if (isdigit((unsigned char)path[0])) + if (is_plain_digit(path[0])) { *idx = (path[0] - '0'); - goto check_oob; + return 1; } errno = EINVAL; return 0; @@ -64,39 +68,34 @@ static int is_valid_index(struct json_object *jo, const char *path, int32_t *idx /* RFC states base-10 decimals */ for (i = 0; i < len; i++) { - if (!isdigit((unsigned char)path[i])) + if (!is_plain_digit(path[i])) { errno = EINVAL; return 0; } } - *idx = strtol(path, NULL, 10); - if (*idx < 0) - { - errno = EINVAL; - return 0; - } -check_oob: - len = json_object_array_length(jo); - if (*idx >= len) - { - errno = ENOENT; - return 0; - } + // We know it's all digits, so the only error case here is overflow, + // but ULLONG_MAX will be longer than any array length so that's ok. + *idx = strtoull(path, NULL, 10); return 1; } static int json_pointer_get_single_path(struct json_object *obj, char *path, - struct json_object **value) + struct json_object **value, size_t *idx) { if (json_object_is_type(obj, json_type_array)) { - int32_t idx; - if (!is_valid_index(obj, path, &idx)) + if (!is_valid_index(path, idx)) return -1; - obj = json_object_array_get_idx(obj, idx); + if (*idx >= json_object_array_length(obj)) + { + errno = ENOENT; + return -1; + } + + obj = json_object_array_get_idx(obj, *idx); if (obj) { if (value) @@ -121,18 +120,25 @@ static int json_pointer_get_single_path(struct json_object *obj, char *path, return 0; } +static int json_object_array_put_idx_cb(struct json_object *parent, size_t idx, + struct json_object *value, void *priv) +{ + return json_object_array_put_idx(parent, idx, value); +} + static int json_pointer_set_single_path(struct json_object *parent, const char *path, - struct json_object *value) + struct json_object *value, + json_pointer_array_set_cb array_set_cb, void *priv) { if (json_object_is_type(parent, json_type_array)) { - int32_t idx; + size_t idx; /* RFC (Chapter 4) states that '-' may be used to add new elements to an array */ if (path[0] == '-' && path[1] == '\0') return json_object_array_add(parent, value); - if (!is_valid_index(parent, path, &idx)) + if (!is_valid_index(path, &idx)) return -1; - return json_object_array_put_idx(parent, idx, value); + return array_set_cb(parent, idx, value, priv); } /* path replacements should have been done in json_pointer_get_single_path(), @@ -148,9 +154,11 @@ static int json_pointer_set_single_path(struct json_object *parent, const char * return -1; } -static int json_pointer_get_recursive(struct json_object *obj, char *path, - struct json_object **value) +static int json_pointer_result_get_recursive(struct json_object *obj, char *path, + struct json_pointer_get_result *res) { + struct json_object *parent_obj = obj; + size_t idx; char *endp; int rc; @@ -167,24 +175,47 @@ static int json_pointer_get_recursive(struct json_object *obj, char *path, *endp = '\0'; /* If we err-ed here, return here */ - if ((rc = json_pointer_get_single_path(obj, path, &obj))) + if ((rc = json_pointer_get_single_path(obj, path, &obj, &idx))) return rc; if (endp) { /* Put the slash back, so that the sanity check passes on next recursion level */ *endp = '/'; - return json_pointer_get_recursive(obj, endp, value); + return json_pointer_result_get_recursive(obj, endp, res); } /* 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) - *value = obj; + *value = res.obj; return 0; } -int json_pointer_get(struct json_object *obj, const char *path, struct json_object **res) +int json_pointer_get_internal(struct json_object *obj, const char *path, + struct json_pointer_get_result *res) { char *path_copy = NULL; int rc; @@ -197,8 +228,10 @@ int json_pointer_get(struct json_object *obj, const char *path, struct json_obje if (path[0] == '\0') { - if (res) - *res = obj; + res->parent = NULL; + res->obj = obj; + res->key_in_parent = NULL; + res->index_in_parent = -1; return 0; } @@ -208,12 +241,30 @@ int json_pointer_get(struct json_object *obj, const char *path, struct json_obje errno = ENOMEM; return -1; } - rc = json_pointer_get_recursive(obj, path_copy, res); + rc = json_pointer_result_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); 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, ...) { char *path_copy = NULL; @@ -240,14 +291,16 @@ int json_pointer_getf(struct json_object *obj, struct json_object **res, const c goto out; } - rc = json_pointer_get_recursive(obj, path_copy, res); + rc = json_pointer_object_get_recursive(obj, path_copy, res); out: free(path_copy); return rc; } -int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value) +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) { const char *endp; char *path_copy = NULL; @@ -277,7 +330,7 @@ int json_pointer_set(struct json_object **obj, const char *path, struct json_obj if ((endp = strrchr(path, '/')) == path) { path++; - return json_pointer_set_single_path(*obj, path, value); + return json_pointer_set_single_path(*obj, path, value, array_set_cb, priv); } /* pass a working copy to the recursive call */ @@ -287,14 +340,19 @@ int json_pointer_set(struct json_object **obj, const char *path, struct json_obj return -1; } path_copy[endp - path] = '\0'; - rc = json_pointer_get_recursive(*obj, path_copy, &set); + rc = json_pointer_object_get_recursive(*obj, path_copy, &set); free(path_copy); if (rc) return rc; endp++; - return json_pointer_set_single_path(set, endp, value); + return json_pointer_set_single_path(set, endp, value, array_set_cb, priv); +} + +int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value) +{ + return json_pointer_set_with_array_cb(obj, path, value, json_object_array_put_idx_cb, NULL); } int json_pointer_setf(struct json_object **obj, struct json_object *value, const char *path_fmt, @@ -342,14 +400,15 @@ int json_pointer_setf(struct json_object **obj, struct json_object *value, const } *endp = '\0'; - rc = json_pointer_get_recursive(*obj, path_copy, &set); + rc = json_pointer_object_get_recursive(*obj, path_copy, &set); if (rc) goto out; set_single_path: endp++; - rc = json_pointer_set_single_path(set, endp, value); + rc = json_pointer_set_single_path(set, endp, value, + json_object_array_put_idx_cb, NULL); out: free(path_copy); return rc; diff --git a/json_pointer.h b/json_pointer.h index 06c395b..dfe1185 100644 --- a/json_pointer.h +++ b/json_pointer.h @@ -32,11 +32,6 @@ extern "C" { * Internally, this is equivalent to doing a series of 'json_object_object_get()' * 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 path a (RFC6901) string notation for the sub-object to retrieve * @param res a pointer that stores a reference to the json_object @@ -50,7 +45,9 @@ 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. * - * Example: json_pointer_getf(obj, res, "/foo/%d/%s", 0, bak) + * Variable arguments go after the 'path_fmt' parameter. + * + * Example: json_pointer_getf(obj, res, "/foo/%d/%s", 0, "bar") * This also means that you need to escape '%' with '%%' (just like in printf()) * * Please take into consideration all recommended 'printf()' format security @@ -84,11 +81,6 @@ 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. * (Just that single decrement that was mentioned above). * - * Note that the 'path' string supports 'printf()' type arguments, so, whatever - * is added after the 'value' param will be treated as an argument for 'path' - * 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 path a (RFC6901) string notation for the sub-object to set in the tree * @param value object to set at path @@ -101,7 +93,9 @@ 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. * - * Example: json_pointer_setf(obj, value, "/foo/%d/%s", 0, bak) + * Variable arguments go after the 'path_fmt' parameter. + * + * Example: json_pointer_setf(obj, value, "/foo/%d/%s", 0, "bar") * This also means that you need to escape '%' with '%%' (just like in printf()) * * Please take into consideration all recommended 'printf()' format security diff --git a/json_pointer_private.h b/json_pointer_private.h new file mode 100644 index 0000000..537cabd --- /dev/null +++ b/json_pointer_private.h @@ -0,0 +1,43 @@ +/* + * 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); + +typedef int(*json_pointer_array_set_cb)(json_object *parent, size_t idx, + json_object *value, void *priv); + +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); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/json_tokener.c b/json_tokener.c index 6527270..9926563 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -10,14 +10,14 @@ * * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. * The copyrights to the contents of this file are licensed under the MIT License - * (http://www.opensource.org/licenses/mit-license.php) + * (https://www.opensource.org/licenses/mit-license.php) */ #include "config.h" #include "math_compat.h" #include -#include +#include #include #include #include @@ -53,6 +53,34 @@ #error You do not have strncasecmp on your system. #endif /* HAVE_STRNCASECMP */ +#if defined(_MSC_VER) && (_MSC_VER <= 1800) +/* VS2013 doesn't know about "inline" */ +#define inline __inline +#elif defined(AIX_CC) +#define inline +#endif + +/* The following helper functions are used to speed up parsing. They + * are faster than their ctype counterparts because they assume that + * the input is in ASCII and that the locale is set to "C". The + * compiler will also inline these functions, providing an additional + * speedup by saving on function calls. + */ +static inline int is_ws_char(char c) +{ + return c == ' ' + || c == '\t' + || c == '\n' + || c == '\r'; +} + +static inline int is_hex_char(char c) +{ + return (c >= '0' && c <= '9') + || (c >= 'A' && c <= 'F') + || (c >= 'a' && c <= 'f'); +} + /* Use C99 NAN by default; if not available, nan("") should work too. */ #ifndef NAN #define NAN nan("") @@ -61,7 +89,8 @@ static const char json_null_str[] = "null"; static const int json_null_str_len = sizeof(json_null_str) - 1; static const char json_inf_str[] = "Infinity"; -static const char json_inf_str_lower[] = "infinity"; +/* Swapped case "Infinity" to avoid need to call tolower() on input chars: */ +static const char json_inf_str_invert[] = "iNFINITY"; static const unsigned int json_inf_str_len = sizeof(json_inf_str) - 1; static const char json_nan_str[] = "NaN"; static const int json_nan_str_len = sizeof(json_nan_str) - 1; @@ -87,7 +116,8 @@ static const char *json_tokener_errors[] = { "invalid string sequence", "expected comment", "invalid utf-8 string", - "buffer size overflow" + "buffer size overflow", + "out of memory" }; /* clang-format on */ @@ -134,6 +164,12 @@ struct json_tokener *json_tokener_new_ex(int depth) return NULL; } tok->pb = printbuf_new(); + if (!tok->pb) + { + free(tok->stack); + free(tok); + return NULL; + } tok->max_depth = depth; json_tokener_reset(tok); return tok; @@ -250,11 +286,24 @@ struct json_object *json_tokener_parse_verbose(const char *str, enum json_tokene /* ADVANCE_CHAR() macro: * Increments str & tok->char_offset. - * For convenience of existing conditionals, returns the old value of c (0 on eof) + * For convenience of existing conditionals, returns the old value of c (0 on eof). * Implicit inputs: c var */ #define ADVANCE_CHAR(str, tok) (++(str), ((tok)->char_offset)++, c) +/* printbuf_memappend_checked(p, s, l) macro: + * Add string s of length l to printbuffer p. + * If operation fails abort parse operation with memory error. + */ +#define printbuf_memappend_checked(p, s, l) \ + do { \ + if (printbuf_memappend((p), (s), (l)) < 0) \ + { \ + tok->err = json_tokener_error_memory; \ + goto out; \ + } \ + } while (0) + /* End optimization macro defs */ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *str, int len) @@ -295,6 +344,11 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * freelocale(duploc); return NULL; } +#ifdef NEWLOCALE_NEEDS_FREELOCALE + // Older versions of FreeBSD (<12.4) don't free the locale + // passed to newlocale(), so do it here + freelocale(duploc); +#endif uselocale(newloc); } #elif defined(HAVE_SETLOCALE) @@ -302,7 +356,11 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * char *tmplocale; tmplocale = setlocale(LC_NUMERIC, NULL); if (tmplocale) + { oldlocale = strdup(tmplocale); + if (oldlocale == NULL) + return NULL; + } setlocale(LC_NUMERIC, "C"); } #endif @@ -316,7 +374,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * case json_tokener_state_eatws: /* Advance until we change state */ - while (isspace((unsigned char)c)) + while (is_ws_char(c)) { if ((!ADVANCE_CHAR(str, tok)) || (!PEEK_CHAR(c, tok))) goto out; @@ -324,7 +382,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * if (c == '/' && !(tok->flags & JSON_TOKENER_STRICT)) { printbuf_reset(tok->pb); - printbuf_memappend_fast(tok->pb, &c, 1); + printbuf_memappend_checked(tok->pb, &c, 1); state = json_tokener_state_comment_start; } else @@ -342,14 +400,20 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * saved_state = json_tokener_state_object_field_start; current = json_object_new_object(); if (current == NULL) + { + tok->err = json_tokener_error_memory; goto out; + } break; case '[': state = json_tokener_state_eatws; saved_state = json_tokener_state_array; current = json_object_new_array(); if (current == NULL) + { + tok->err = json_tokener_error_memory; goto out; + } break; case 'I': case 'i': @@ -421,17 +485,15 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * * complicated with likely little performance benefit. */ int is_negative = 0; - const char *_json_inf_str = json_inf_str; - if (!(tok->flags & JSON_TOKENER_STRICT)) - _json_inf_str = json_inf_str_lower; /* Note: tok->st_pos must be 0 when state is set to json_tokener_state_inf */ while (tok->st_pos < (int)json_inf_str_len) { char inf_char = *str; - if (!(tok->flags & JSON_TOKENER_STRICT)) - inf_char = tolower((unsigned char)*str); - if (inf_char != _json_inf_str[tok->st_pos]) + if (inf_char != json_inf_str[tok->st_pos] && + ((tok->flags & JSON_TOKENER_STRICT) || + inf_char != json_inf_str_invert[tok->st_pos]) + ) { tok->err = json_tokener_error_parse_unexpected; goto out; @@ -454,7 +516,10 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * } current = json_object_new_double(is_negative ? -INFINITY : INFINITY); if (current == NULL) + { + tok->err = json_tokener_error_memory; goto out; + } saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; @@ -464,7 +529,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * { int size; int size_nan; - printbuf_memappend_fast(tok->pb, &c, 1); + printbuf_memappend_checked(tok->pb, &c, 1); size = json_min(tok->st_pos + 1, json_null_str_len); size_nan = json_min(tok->st_pos + 1, json_nan_str_len); if ((!(tok->flags & JSON_TOKENER_STRICT) && @@ -487,7 +552,10 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * { current = json_object_new_double(NAN); if (current == NULL) + { + tok->err = json_tokener_error_memory; goto out; + } saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; @@ -516,7 +584,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * tok->err = json_tokener_error_parse_comment; goto out; } - printbuf_memappend_fast(tok->pb, &c, 1); + printbuf_memappend_checked(tok->pb, &c, 1); break; case json_tokener_state_comment: @@ -527,12 +595,12 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * { if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { - printbuf_memappend_fast(tok->pb, case_start, - str - case_start); + printbuf_memappend_checked(tok->pb, case_start, + str - case_start); goto out; } } - printbuf_memappend_fast(tok->pb, case_start, 1 + str - case_start); + printbuf_memappend_checked(tok->pb, case_start, 1 + str - case_start); state = json_tokener_state_comment_end; } break; @@ -545,19 +613,19 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * { if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { - printbuf_memappend_fast(tok->pb, case_start, - str - case_start); + printbuf_memappend_checked(tok->pb, case_start, + str - case_start); goto out; } } - printbuf_memappend_fast(tok->pb, case_start, str - case_start); + printbuf_memappend_checked(tok->pb, case_start, str - case_start); MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf); state = json_tokener_state_eatws; } break; case json_tokener_state_comment_end: - printbuf_memappend_fast(tok->pb, &c, 1); + printbuf_memappend_checked(tok->pb, &c, 1); if (c == '/') { MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf); @@ -577,28 +645,31 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * { if (c == tok->quote_char) { - printbuf_memappend_fast(tok->pb, case_start, - str - case_start); + printbuf_memappend_checked(tok->pb, case_start, + str - case_start); current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos); if (current == NULL) + { + tok->err = json_tokener_error_memory; goto out; + } saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; break; } else if (c == '\\') { - printbuf_memappend_fast(tok->pb, case_start, - str - case_start); + printbuf_memappend_checked(tok->pb, case_start, + str - case_start); saved_state = json_tokener_state_string; state = json_tokener_state_string_escape; break; } if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { - printbuf_memappend_fast(tok->pb, case_start, - str - case_start); + printbuf_memappend_checked(tok->pb, case_start, + str - case_start); goto out; } } @@ -611,7 +682,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * case '"': case '\\': case '/': - printbuf_memappend_fast(tok->pb, &c, 1); + printbuf_memappend_checked(tok->pb, &c, 1); state = saved_state; break; case 'b': @@ -620,15 +691,15 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * case 't': case 'f': if (c == 'b') - printbuf_memappend_fast(tok->pb, "\b", 1); + printbuf_memappend_checked(tok->pb, "\b", 1); else if (c == 'n') - printbuf_memappend_fast(tok->pb, "\n", 1); + printbuf_memappend_checked(tok->pb, "\n", 1); else if (c == 'r') - printbuf_memappend_fast(tok->pb, "\r", 1); + printbuf_memappend_checked(tok->pb, "\r", 1); else if (c == 't') - printbuf_memappend_fast(tok->pb, "\t", 1); + printbuf_memappend_checked(tok->pb, "\t", 1); else if (c == 'f') - printbuf_memappend_fast(tok->pb, "\f", 1); + printbuf_memappend_checked(tok->pb, "\f", 1); state = saved_state; break; case 'u': @@ -647,7 +718,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * /* Handle a 4-byte \uNNNN sequence, or two sequences if a surrogate pair */ while (1) { - if (!c || !strchr(json_hex_chars, c)) + if (!c || !is_hex_char(c)) { tok->err = json_tokener_error_parse_string; goto out; @@ -688,8 +759,8 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * /* High surrogate was not followed by a low surrogate * Replace the high and process the rest normally */ - printbuf_memappend_fast(tok->pb, - (char *)utf8_replacement_char, 3); + printbuf_memappend_checked(tok->pb, + (char *)utf8_replacement_char, 3); } tok->high_surrogate = 0; } @@ -698,14 +769,14 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * { unsigned char unescaped_utf[1]; unescaped_utf[0] = tok->ucs_char; - printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 1); + printbuf_memappend_checked(tok->pb, (char *)unescaped_utf, 1); } else if (tok->ucs_char < 0x800) { unsigned char unescaped_utf[2]; unescaped_utf[0] = 0xc0 | (tok->ucs_char >> 6); unescaped_utf[1] = 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 2); + printbuf_memappend_checked(tok->pb, (char *)unescaped_utf, 2); } else if (IS_HIGH_SURROGATE(tok->ucs_char)) { @@ -714,7 +785,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * * we can't simply peek ahead here, because the * characters we need might not be passed to us * until a subsequent call to json_tokener_parse. - * Instead, transition throug a couple of states. + * Instead, transition through a couple of states. * (now): * _escape_unicode => _unicode_need_escape * (see a '\\' char): @@ -731,7 +802,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * else if (IS_LOW_SURROGATE(tok->ucs_char)) { /* Got a low surrogate not preceded by a high */ - printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3); + printbuf_memappend_checked(tok->pb, (char *)utf8_replacement_char, 3); } else if (tok->ucs_char < 0x10000) { @@ -739,7 +810,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * unescaped_utf[0] = 0xe0 | (tok->ucs_char >> 12); unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); unescaped_utf[2] = 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 3); + printbuf_memappend_checked(tok->pb, (char *)unescaped_utf, 3); } else if (tok->ucs_char < 0x110000) { @@ -748,12 +819,12 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 12) & 0x3f); unescaped_utf[2] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); unescaped_utf[3] = 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 4); + printbuf_memappend_checked(tok->pb, (char *)unescaped_utf, 4); } else { /* Don't know what we got--insert the replacement char */ - printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3); + printbuf_memappend_checked(tok->pb, (char *)utf8_replacement_char, 3); } state = saved_state; // i.e. _state_string or _state_object_field } @@ -768,7 +839,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * * it. Put a replacement char in for the high surrogate * and pop back up to _state_string or _state_object_field. */ - printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3); + printbuf_memappend_checked(tok->pb, (char *)utf8_replacement_char, 3); tok->high_surrogate = 0; tok->ucs_char = 0; tok->st_pos = 0; @@ -787,7 +858,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * * Put a replacement char in for the high surrogate * and handle the escape sequence normally. */ - printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3); + printbuf_memappend_checked(tok->pb, (char *)utf8_replacement_char, 3); tok->high_surrogate = 0; tok->ucs_char = 0; tok->st_pos = 0; @@ -802,7 +873,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * case json_tokener_state_boolean: { int size1, size2; - printbuf_memappend_fast(tok->pb, &c, 1); + printbuf_memappend_checked(tok->pb, &c, 1); size1 = json_min(tok->st_pos + 1, json_true_str_len); size2 = json_min(tok->st_pos + 1, json_false_str_len); if ((!(tok->flags & JSON_TOKENER_STRICT) && @@ -813,7 +884,10 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * { current = json_object_new_boolean(1); if (current == NULL) + { + tok->err = json_tokener_error_memory; goto out; + } saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; @@ -827,7 +901,10 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * { current = json_object_new_boolean(0); if (current == NULL) + { + tok->err = json_tokener_error_memory; goto out; + } saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; @@ -907,7 +984,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { - printbuf_memappend_fast(tok->pb, case_start, case_len); + printbuf_memappend_checked(tok->pb, case_start, case_len); goto out; } } @@ -916,17 +993,17 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * it might have been intended to be, and return a potentially more understandable error right away. However, if we're at the top-level, use the number as-is - because c can be part of a new object to parse on the + because c can be part of a new object to parse on the next call to json_tokener_parse(). */ if (tok->depth > 0 && c != ',' && c != ']' && c != '}' && c != '/' && - c != 'I' && c != 'i' && !isspace((unsigned char)c)) + c != 'I' && c != 'i' && !is_ws_char(c)) { tok->err = json_tokener_error_parse_number; goto out; } if (case_len > 0) - printbuf_memappend_fast(tok->pb, case_start, case_len); + printbuf_memappend_checked(tok->pb, case_start, case_len); // Check for -Infinity if (tok->pb->buf[0] == '-' && case_len <= 1 && (c == 'i' || c == 'I')) @@ -959,13 +1036,26 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * if (!tok->is_double && tok->pb->buf[0] == '-' && json_parse_int64(tok->pb->buf, &num64) == 0) { + if (errno == ERANGE && (tok->flags & JSON_TOKENER_STRICT)) + { + tok->err = json_tokener_error_parse_number; + goto out; + } current = json_object_new_int64(num64); if (current == NULL) + { + tok->err = json_tokener_error_memory; goto out; + } } else if (!tok->is_double && tok->pb->buf[0] != '-' && json_parse_uint64(tok->pb->buf, &numuint64) == 0) { + if (errno == ERANGE && (tok->flags & JSON_TOKENER_STRICT)) + { + tok->err = json_tokener_error_parse_number; + goto out; + } if (numuint64 && tok->pb->buf[0] == '0' && (tok->flags & JSON_TOKENER_STRICT)) { @@ -977,13 +1067,19 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * num64 = (uint64_t)numuint64; current = json_object_new_int64(num64); if (current == NULL) + { + tok->err = json_tokener_error_memory; goto out; + } } else { current = json_object_new_uint64(numuint64); if (current == NULL) + { + tok->err = json_tokener_error_memory; goto out; + } } } else if (tok->is_double && @@ -992,7 +1088,10 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * { current = json_object_new_double_s(numd, tok->pb->buf); if (current == NULL) + { + tok->err = json_tokener_error_memory; goto out; + } } else { @@ -1037,7 +1136,10 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * case json_tokener_state_array_add: if (json_object_array_add(current, obj) != 0) + { + tok->err = json_tokener_error_memory; goto out; + } saved_state = json_tokener_state_array_sep; state = json_tokener_state_eatws; goto redo_char; @@ -1097,25 +1199,30 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * { if (c == tok->quote_char) { - printbuf_memappend_fast(tok->pb, case_start, - str - case_start); + printbuf_memappend_checked(tok->pb, case_start, + str - case_start); obj_field_name = strdup(tok->pb->buf); + if (obj_field_name == NULL) + { + tok->err = json_tokener_error_memory; + goto out; + } saved_state = json_tokener_state_object_field_end; state = json_tokener_state_eatws; break; } else if (c == '\\') { - printbuf_memappend_fast(tok->pb, case_start, - str - case_start); + printbuf_memappend_checked(tok->pb, case_start, + str - case_start); saved_state = json_tokener_state_object_field; state = json_tokener_state_string_escape; break; } if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { - printbuf_memappend_fast(tok->pb, case_start, - str - case_start); + printbuf_memappend_checked(tok->pb, case_start, + str - case_start); goto out; } } diff --git a/json_tokener.h b/json_tokener.h index a07e12c..77abc5c 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -40,6 +40,7 @@ enum json_tokener_error json_tokener_error_parse_string, json_tokener_error_parse_comment, json_tokener_error_parse_utf8_string, + json_tokener_error_memory, json_tokener_error_size }; diff --git a/json_types.h b/json_types.h index 67f4497..b7e55ad 100644 --- a/json_types.h +++ b/json_types.h @@ -18,7 +18,7 @@ extern "C" { #endif #ifndef JSON_EXPORT -#if defined(_MSC_VER) +#if defined(_MSC_VER) && defined(JSON_C_DLL) #define JSON_EXPORT __declspec(dllexport) #else #define JSON_EXPORT extern diff --git a/json_util.c b/json_util.c index a065523..0f570f2 100644 --- a/json_util.c +++ b/json_util.c @@ -14,7 +14,6 @@ #include "strerror_override.h" -#include #include #include #include @@ -61,7 +60,7 @@ static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const static char _last_err[256] = ""; -const char *json_util_get_last_err() +const char *json_util_get_last_err(void) { if (_last_err[0] == '\0') return NULL; @@ -86,13 +85,13 @@ struct json_object *json_object_from_fd_ex(int fd, int in_depth) struct printbuf *pb; struct json_object *obj; char buf[JSON_FILE_BUF_SIZE]; - int ret; + ssize_t ret; int depth = JSON_TOKENER_DEFAULT_DEPTH; json_tokener *tok; if (!(pb = printbuf_new())) { - _json_c_set_last_err("json_object_from_file: printbuf_new failed\n"); + _json_c_set_last_err("json_object_from_fd_ex: printbuf_new failed\n"); return NULL; } @@ -102,19 +101,29 @@ struct json_object *json_object_from_fd_ex(int fd, int in_depth) if (!tok) { _json_c_set_last_err( - "json_object_from_fd: unable to allocate json_tokener(depth=%d): %s\n", depth, - strerror(errno)); + "json_object_from_fd_ex: unable to allocate json_tokener(depth=%d): %s\n", + depth, strerror(errno)); printbuf_free(pb); return NULL; } - while ((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) + while ((ret = read(fd, buf, sizeof(buf))) > 0) { - printbuf_memappend(pb, buf, ret); + if (printbuf_memappend(pb, buf, ret) < 0) + { +#if JSON_FILE_BUF_SIZE > INT_MAX +#error "Can't append more than INT_MAX bytes at a time" +#endif + _json_c_set_last_err( + "json_object_from_fd_ex: failed to printbuf_memappend after reading %d+%d bytes: %s", printbuf_length(pb), (int)ret, strerror(errno)); + json_tokener_free(tok); + printbuf_free(pb); + return NULL; + } } if (ret < 0) { - _json_c_set_last_err("json_object_from_fd: error reading fd %d: %s\n", fd, + _json_c_set_last_err("json_object_from_fd_ex: error reading fd %d: %s\n", fd, strerror(errno)); json_tokener_free(tok); printbuf_free(pb); @@ -138,8 +147,8 @@ struct json_object *json_object_from_file(const char *filename) if ((fd = open(filename, O_RDONLY)) < 0) { - _json_c_set_last_err("json_object_from_file: error opening file %s: %s\n", filename, - strerror(errno)); + _json_c_set_last_err("json_object_from_file: error opening file %s: %s\n", + filename, strerror(errno)); return NULL; } obj = json_object_from_fd(fd); @@ -156,14 +165,14 @@ int json_object_to_file_ext(const char *filename, struct json_object *obj, int f if (!obj) { - _json_c_set_last_err("json_object_to_file: object is null\n"); + _json_c_set_last_err("json_object_to_file_ext: object is null\n"); return -1; } if ((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { - _json_c_set_last_err("json_object_to_file: error opening file %s: %s\n", filename, - strerror(errno)); + _json_c_set_last_err("json_object_to_file_ext: error opening file %s: %s\n", + filename, strerror(errno)); return -1; } ret = _json_object_to_fd(fd, obj, flags, filename); @@ -185,9 +194,9 @@ int json_object_to_fd(int fd, struct json_object *obj, int flags) } static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename) { - int ret; + ssize_t ret; const char *json_str; - unsigned int wpos, wsize; + size_t wpos, wsize; filename = filename ? filename : "(fd)"; @@ -196,20 +205,19 @@ static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const return -1; } - /* CAW: probably unnecessary, but the most 64bit safe */ - wsize = (unsigned int)(strlen(json_str) & UINT_MAX); + wsize = strlen(json_str); wpos = 0; while (wpos < wsize) { if ((ret = write(fd, json_str + wpos, wsize - wpos)) < 0) { - _json_c_set_last_err("json_object_to_file: error writing file %s: %s\n", + _json_c_set_last_err("json_object_to_fd: error writing file %s: %s\n", filename, strerror(errno)); return -1; } /* because of the above check for ret < 0, we can safely cast and add */ - wpos += (unsigned int)ret; + wpos += (size_t)ret; } return 0; @@ -239,7 +247,12 @@ int json_parse_int64(const char *buf, int64_t *retval) val = strtoll(buf, &end, 10); if (end != buf) *retval = val; - return ((val == 0 && errno != 0) || (end == buf)) ? 1 : 0; + if ((val == 0 && errno != 0) || (end == buf)) + { + errno = EINVAL; + return 1; + } + return 0; } int json_parse_uint64(const char *buf, uint64_t *retval) @@ -256,7 +269,12 @@ int json_parse_uint64(const char *buf, uint64_t *retval) val = strtoull(buf, &end, 10); if (end != buf) *retval = val; - return ((val == 0 && errno != 0) || (end == buf)) ? 1 : 0; + if ((val == 0 && errno != 0) || (end == buf)) + { + errno = EINVAL; + return 1; + } + return 0; } #ifndef HAVE_REALLOC @@ -289,8 +307,8 @@ const char *json_type_to_name(enum json_type o_type) int o_type_int = (int)o_type; if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name)) { - _json_c_set_last_err("json_type_to_name: type %d is out of range [0,%d]\n", o_type, - NELEM(json_type_name)); + _json_c_set_last_err("json_type_to_name: type %d is out of range [0,%u]\n", o_type, + (unsigned)NELEM(json_type_name)); return NULL; } return json_type_name[o_type]; diff --git a/json_util.h b/json_util.h index 1f663e8..62ad688 100644 --- a/json_util.h +++ b/json_util.h @@ -100,8 +100,17 @@ JSON_EXPORT int json_object_to_fd(int fd, struct json_object *obj, int flags); */ JSON_EXPORT const char *json_util_get_last_err(void); -/* these parsing helpers return zero on success */ +/** + * A parsing helper for integer values. Returns 0 on success, + * with the parsed value assigned to *retval. Overflow/underflow + * are NOT considered errors, but errno will be set to ERANGE, + * just like the strtol/strtoll functions do. + */ JSON_EXPORT int json_parse_int64(const char *buf, int64_t *retval); +/** + * A parsing help for integer values, providing one extra bit of + * magnitude beyond json_parse_int64(). + */ JSON_EXPORT int json_parse_uint64(const char *buf, uint64_t *retval); /** * @deprecated diff --git a/linkhash.c b/linkhash.c index b021ef1..5e12c51 100644 --- a/linkhash.c +++ b/linkhash.c @@ -65,9 +65,9 @@ int lh_ptr_equal(const void *k1, const void *k2) /* * hashlittle from lookup3.c, by Bob Jenkins, May 2006, Public Domain. - * http://burtleburtle.net/bob/c/lookup3.c + * https://burtleburtle.net/bob/c/lookup3.c * minor modifications to make functions static so no symbols are exported - * minor mofifications to compile with -Werror + * minor modifications to compile with -Werror */ /* @@ -81,7 +81,7 @@ if SELF_TEST is defined. You can use this free for any purpose. It's in the public domain. It has no warranty. You probably want to use hashlittle(). hashlittle() and hashbig() -hash byte arrays. hashlittle() is is faster than hashbig() on +hash byte arrays. hashlittle() is faster than hashbig() on little-endian machines. Intel and AMD are little-endian machines. On second thought, you probably want hashlittle2(), which is identical to hashlittle() except it returns two 32-bit hashes for the price of one. @@ -156,7 +156,7 @@ satisfy this are 14 9 3 7 17 3 Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing for "differ" defined as + with a one-bit base and a two-bit delta. I -used http://burtleburtle.net/bob/hash/avalanche.html to choose +used https://burtleburtle.net/bob/hash/avalanche.html to choose the operations, constants, and arrangements of the variables. This does not achieve avalanche. There are input bits of (a,b,c) @@ -285,9 +285,9 @@ static uint32_t hashlittle(const void *key, size_t length, uint32_t initval) * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash - * noticably faster for short strings (like English words). + * noticeably faster for short strings (like English words). * AddressSanitizer is similarly picky about overrunning - * the buffer. (http://clang.llvm.org/docs/AddressSanitizer.html + * the buffer. (https://clang.llvm.org/docs/AddressSanitizer.html) */ #ifdef VALGRIND #define PRECISE_MEMORY_ACCESS 1 @@ -439,8 +439,8 @@ static uint32_t hashlittle(const void *key, size_t length, uint32_t initval) } /* clang-format on */ -/* a simple hash function similiar to what perl does for strings. - * for good results, the string should not be excessivly large. +/* a simple hash function similar to what perl does for strings. + * for good results, the string should not be excessively large. */ static unsigned long lh_perllike_str_hash(const void *k) { @@ -465,7 +465,7 @@ static unsigned long lh_char_hash(const void *k) if (random_seed == -1) { RANDOM_SEED_TYPE seed; - /* we can't use -1 as it is the unitialized sentinel */ + /* we can't use -1 as it is the uninitialized sentinel */ while ((seed = json_c_get_random_seed()) == -1) {} #if SIZEOF_INT == 8 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 #define USE_SYNC_COMPARE_AND_SWAP 1 @@ -481,12 +481,12 @@ static unsigned long lh_char_hash(const void *k) #elif defined _MSC_VER || defined __MINGW32__ InterlockedCompareExchange(&random_seed, seed, -1); #else - //#warning "racy random seed initializtion if used by multiple threads" + //#warning "racy random seed initialization if used by multiple threads" random_seed = seed; /* potentially racy */ #endif } - return hashlittle((const char *)k, strlen((const char *)k), random_seed); + return hashlittle((const char *)k, strlen((const char *)k), (uint32_t)random_seed); } int lh_char_equal(const void *k1, const void *k2) @@ -546,7 +546,7 @@ int lh_table_resize(struct lh_table *t, int new_size) unsigned long h = lh_get_hash(new_t, ent->k); unsigned int opts = 0; if (ent->k_is_constant) - opts = JSON_C_OBJECT_KEY_IS_CONSTANT; + opts = JSON_C_OBJECT_ADD_CONSTANT_KEY; if (lh_table_insert_w_hash(new_t, ent->k, ent->v, h, opts) != 0) { lh_table_free(new_t); @@ -599,7 +599,7 @@ int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, con } t->table[n].k = k; - t->table[n].k_is_constant = (opts & JSON_C_OBJECT_KEY_IS_CONSTANT); + t->table[n].k_is_constant = (opts & JSON_C_OBJECT_ADD_CONSTANT_KEY); t->table[n].v = v; t->count++; diff --git a/linkhash.h b/linkhash.h index 414599d..5e5e240 100644 --- a/linkhash.h +++ b/linkhash.h @@ -16,8 +16,8 @@ * this is exposed by the json_object_get_object() function and within the * json_object_iter type, it is not recommended for direct use. */ -#ifndef _linkhash_h_ -#define _linkhash_h_ +#ifndef _json_c_linkhash_h_ +#define _json_c_linkhash_h_ #include "json_object.h" @@ -80,64 +80,84 @@ typedef unsigned long(lh_hash_fn)(const void *k); typedef int(lh_equal_fn)(const void *k1, const void *k2); /** - * An entry in the hash table + * An entry in the hash table. Outside of linkhash.c, treat this as opaque. */ struct lh_entry { /** - * The key. Use lh_entry_k() instead of accessing this directly. + * The key. + * @deprecated Use lh_entry_k() instead of accessing this directly. */ const void *k; /** * A flag for users of linkhash to know whether or not they * need to free k. + * @deprecated use lh_entry_k_is_constant() instead. */ int k_is_constant; /** - * The value. Use lh_entry_v() instead of accessing this directly. + * The value. + * @deprecated Use lh_entry_v() instead of accessing this directly. */ const void *v; /** - * The next entry + * The next entry. + * @deprecated Use lh_entry_next() instead of accessing this directly. */ struct lh_entry *next; /** * The previous entry. + * @deprecated Use lh_entry_prev() instead of accessing this directly. */ struct lh_entry *prev; }; /** - * The hash table structure. + * The hash table structure. Outside of linkhash.c, treat this as opaque. */ struct lh_table { /** * Size of our hash. + * @deprecated do not use outside of linkhash.c */ int size; /** * Numbers of entries. + * @deprecated Use lh_table_length() instead. */ int count; /** * The first entry. + * @deprecated Use lh_table_head() instead. */ struct lh_entry *head; /** * The last entry. + * @deprecated Do not use, may be removed in a future release. */ struct lh_entry *tail; + /** + * Internal storage of the actual table of entries. + * @deprecated do not use outside of linkhash.c + */ struct lh_entry *table; /** - * A pointer onto the function responsible for freeing an entry. + * A pointer to the function responsible for freeing an entry. + * @deprecated do not use outside of linkhash.c */ lh_entry_free_fn *free_fn; + /** + * @deprecated do not use outside of linkhash.c + */ lh_hash_fn *hash_fn; + /** + * @deprecated do not use outside of linkhash.c + */ lh_equal_fn *equal_fn; }; typedef struct lh_table lh_table; @@ -145,7 +165,7 @@ typedef struct lh_table lh_table; /** * Convenience list iterator. */ -#define lh_foreach(table, entry) for (entry = table->head; entry; entry = entry->next) +#define lh_foreach(table, entry) for (entry = lh_table_head(table); entry; entry = lh_entry_next(entry)) /** * lh_foreach_safe allows calling of deletion routine while iterating. @@ -155,7 +175,7 @@ typedef struct lh_table lh_table; * @param tmp a struct lh_entry * variable to hold a temporary pointer to the next element */ #define lh_foreach_safe(table, entry, tmp) \ - for (entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) + for (entry = lh_table_head(table); entry && ((tmp = lh_entry_next(entry)) || 1); entry = tmp) /** * Create a new linkhash table. @@ -231,7 +251,7 @@ extern int lh_table_insert(struct lh_table *t, const void *k, const void *v); * @param k a pointer to the key to insert. * @param v a pointer to the value to insert. * @param h hash value of the key to insert - * @param opts if set to JSON_C_OBJECT_KEY_IS_CONSTANT, sets lh_entry.k_is_constant + * @param opts if set to JSON_C_OBJECT_ADD_CONSTANT_KEY, sets lh_entry.k_is_constant * so t's free function knows to avoid freeing the key. */ extern int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, @@ -295,6 +315,9 @@ extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e); */ extern int lh_table_delete(struct lh_table *t, const void *k); +/** + * Return the number of entries in the table. + */ extern int lh_table_length(struct lh_table *t); /** @@ -319,9 +342,18 @@ int lh_table_resize(struct lh_table *t, int new_size); #endif /** + * Return the first entry in the lh_table. + * @see lh_entry_next() + */ +static _LH_INLINE struct lh_entry *lh_table_head(const lh_table *t) +{ + return t->head; +} + +/** * Calculate the hash of a key for a given table. * - * This is an exension to support functions that need to calculate + * This is an extension to support functions that need to calculate * the hash several times and allows them to do it just once and then pass * in the hash to all utility functions. Depending on use case, this can be a * considerable performance improvement. @@ -334,7 +366,6 @@ static _LH_INLINE unsigned long lh_get_hash(const struct lh_table *t, const void return t->hash_fn(k); } -#undef _LH_INLINE /** * @deprecated Don't use this outside of linkhash.h: @@ -350,9 +381,22 @@ static _LH_INLINE unsigned long lh_get_hash(const struct lh_table *t, const void * * lh_entry.k is const to indicate and help ensure that linkhash itself doesn't modify * it, but callers are allowed to do what they want with it. - * See also lh_entry.k_is_constant + * @see lh_entry_k_is_constant() + */ +static _LH_INLINE void *lh_entry_k(const struct lh_entry *e) +{ + return _LH_UNCONST(e->k); +} + +/** + * Returns 1 if the key for the given entry is constant, and thus + * does not need to be freed when the lh_entry is freed. + * @see lh_table_insert_w_hash() */ -#define lh_entry_k(entry) _LH_UNCONST((entry)->k) +static _LH_INLINE int lh_entry_k_is_constant(const struct lh_entry *e) +{ + return e->k_is_constant; +} /** * Return a non-const version of lh_entry.v. @@ -360,7 +404,41 @@ static _LH_INLINE unsigned long lh_get_hash(const struct lh_table *t, const void * v is const to indicate and help ensure that linkhash itself doesn't modify * it, but callers are allowed to do what they want with it. */ -#define lh_entry_v(entry) _LH_UNCONST((entry)->v) +static _LH_INLINE void *lh_entry_v(const struct lh_entry *e) +{ + return _LH_UNCONST(e->v); +} + +/** + * Change the value for an entry. The caller is responsible for freeing + * the previous value. + */ +static _LH_INLINE void lh_entry_set_val(struct lh_entry *e, void *newval) +{ + e->v = newval; +} + +/** + * Return the next element, or NULL if there is no next element. + * @see lh_table_head() + * @see lh_entry_prev() + */ +static _LH_INLINE struct lh_entry *lh_entry_next(const struct lh_entry *e) +{ + return e->next; +} + +/** + * Return the previous element, or NULL if there is no previous element. + * @see lh_table_head() + * @see lh_entry_next() + */ +static _LH_INLINE struct lh_entry *lh_entry_prev(const struct lh_entry *e) +{ + return e->prev; +} + +#undef _LH_INLINE #ifdef __cplusplus } diff --git a/printbuf.c b/printbuf.c index 00822fa..12d3b33 100644 --- a/printbuf.c +++ b/printbuf.c @@ -10,11 +10,12 @@ * * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. * The copyrights to the contents of this file are licensed under the MIT License - * (http://www.opensource.org/licenses/mit-license.php) + * (https://www.opensource.org/licenses/mit-license.php) */ #include "config.h" +#include #include #include #include @@ -56,6 +57,8 @@ struct printbuf *printbuf_new(void) * * If the current size is large enough, nothing is changed. * + * If extension failed, errno is set to indicate the error. + * * Note: this does not check the available space! The caller * is responsible for performing those calculations. */ @@ -68,7 +71,10 @@ static int printbuf_extend(struct printbuf *p, int min_size) return 0; /* Prevent signed integer overflows with large buffers. */ if (min_size > INT_MAX - 8) + { + errno = EFBIG; return -1; + } if (p->size > INT_MAX / 2) new_size = min_size + 8; else { @@ -77,7 +83,7 @@ static int printbuf_extend(struct printbuf *p, int min_size) new_size = min_size + 8; } #ifdef PRINTBUF_DEBUG - MC_DEBUG("printbuf_memappend: realloc " + MC_DEBUG("printbuf_extend: realloc " "bpos=%d min_size=%d old_size=%d new_size=%d\n", p->bpos, min_size, p->size, new_size); #endif /* PRINTBUF_DEBUG */ @@ -91,8 +97,11 @@ static int printbuf_extend(struct printbuf *p, int min_size) int printbuf_memappend(struct printbuf *p, const char *buf, int size) { /* Prevent signed integer overflows with large buffers. */ - if (size > INT_MAX - p->bpos - 1) + if (size < 0 || size > INT_MAX - p->bpos - 1) + { + errno = EFBIG; return -1; + } if (p->size <= p->bpos + size + 1) { if (printbuf_extend(p, p->bpos + size + 1) < 0) @@ -111,8 +120,11 @@ int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) if (offset == -1) offset = pb->bpos; /* Prevent signed integer overflows with large buffers. */ - if (len > INT_MAX - offset) + if (len < 0 || offset < -1 || len > INT_MAX - offset) + { + errno = EFBIG; return -1; + } size_needed = offset + len; if (pb->size < size_needed) { @@ -120,6 +132,8 @@ int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) return -1; } + if (pb->bpos < offset) + memset(pb->buf + pb->bpos, '\0', offset - pb->bpos); memset(pb->buf + offset, charvalue, len); if (pb->bpos < size_needed) pb->bpos = size_needed; @@ -134,16 +148,16 @@ int sprintbuf(struct printbuf *p, const char *msg, ...) int size; char buf[128]; - /* user stack buffer first */ + /* use stack buffer first */ va_start(ap, msg); size = vsnprintf(buf, 128, msg, ap); va_end(ap); /* if string is greater than stack buffer, then use dynamic string - * with vasprintf. Note: some implementation of vsnprintf return -1 + * with vasprintf. Note: some implementations of vsnprintf return -1 * if output is truncated whereas some return the number of bytes that * would have been written - this code handles both cases. */ - if (size == -1 || size > 127) + if (size < 0 || size > 127) { va_start(ap, msg); if ((size = vasprintf(&t, msg, ap)) < 0) @@ -152,15 +166,14 @@ int sprintbuf(struct printbuf *p, const char *msg, ...) return -1; } va_end(ap); - printbuf_memappend(p, t, size); + size = printbuf_memappend(p, t, size); free(t); - return size; } else { - printbuf_memappend(p, buf, size); - return size; + size = printbuf_memappend(p, buf, size); } + return size; } void printbuf_reset(struct printbuf *p) diff --git a/printbuf.h b/printbuf.h index bfcbd2b..8dbf2c6 100644 --- a/printbuf.h +++ b/printbuf.h @@ -10,21 +10,21 @@ * * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. * The copyrights to the contents of this file are licensed under the MIT License - * (http://www.opensource.org/licenses/mit-license.php) + * (https://www.opensource.org/licenses/mit-license.php) */ /** * @file - * @brief Internal string buffer handing. Unless you're writing a + * @brief Internal string buffer handling. Unless you're writing a * json_object_to_json_string_fn implementation for use with * json_object_set_serializer() direct use of this is not * recommended. */ -#ifndef _printbuf_h_ -#define _printbuf_h_ +#ifndef _json_c_printbuf_h_ +#define _json_c_printbuf_h_ #ifndef JSON_EXPORT -#if defined(_MSC_VER) +#if defined(_MSC_VER) && defined(JSON_C_DLL) #define JSON_EXPORT __declspec(dllexport) #else #define JSON_EXPORT extern diff --git a/random_seed.c b/random_seed.c index 1a15350..5b2155d 100644 --- a/random_seed.c +++ b/random_seed.c @@ -13,9 +13,23 @@ #include "config.h" #include "strerror_override.h" #include +#include +#ifdef HAVE_BSD_STDLIB_H +#include +#endif #define DEBUG_SEED(s) +#if defined(__APPLE__) || defined(__unix__) || defined(__linux__) +#define HAVE_DEV_RANDOM 1 +#endif + +#ifdef HAVE_ARC4RANDOM +#undef HAVE_GETRANDOM +#undef HAVE_DEV_RANDOM +#undef HAVE_CRYPTGENRANDOM +#endif + #if defined ENABLE_RDRAND /* cpuid */ @@ -155,9 +169,45 @@ retry: #endif /* defined ENABLE_RDRAND */ -/* has_dev_urandom */ +#ifdef HAVE_GETRANDOM -#if defined(__APPLE__) || defined(__unix__) || defined(__linux__) +#include +#ifdef HAVE_SYS_RANDOM_H +#include +#endif + +static int get_getrandom_seed(int *seed) +{ + DEBUG_SEED("get_getrandom_seed"); + + ssize_t ret; + + do + { + ret = getrandom(seed, sizeof(*seed), GRND_NONBLOCK); + } while ((ret == -1) && (errno == EINTR)); + + if (ret == -1) + { + if (errno == ENOSYS) /* syscall not available in kernel */ + return -1; + if (errno == EAGAIN) /* entropy not yet initialized */ + return -1; + + fprintf(stderr, "error from getrandom(): %s", strerror(errno)); + return -1; + } + + if (ret != sizeof(*seed)) + return -1; + + return 0; +} +#endif /* defined HAVE_GETRANDOM */ + +/* get_dev_random_seed */ + +#ifdef HAVE_DEV_RANDOM #include #include @@ -167,43 +217,36 @@ retry: #include #include -#define HAVE_DEV_RANDOM 1 - static const char *dev_random_file = "/dev/urandom"; -static int has_dev_urandom(void) +static int get_dev_random_seed(int *seed) { + DEBUG_SEED("get_dev_random_seed"); + struct stat buf; if (stat(dev_random_file, &buf)) - { - return 0; - } - return ((buf.st_mode & S_IFCHR) != 0); -} - -/* get_dev_random_seed */ - -static int get_dev_random_seed(void) -{ - DEBUG_SEED("get_dev_random_seed"); + return -1; + if ((buf.st_mode & S_IFCHR) == 0) + return -1; int fd = open(dev_random_file, O_RDONLY); if (fd < 0) { fprintf(stderr, "error opening %s: %s", dev_random_file, strerror(errno)); - exit(1); + return -1; } - int r; - ssize_t nread = read(fd, &r, sizeof(r)); - if (nread != sizeof(r)) + ssize_t nread = read(fd, seed, sizeof(*seed)); + + close(fd); + + if (nread != sizeof(*seed)) { fprintf(stderr, "error short read %s: %s", dev_random_file, strerror(errno)); - exit(1); + return -1; } - close(fd); - return r; + return 0; } #endif @@ -226,13 +269,10 @@ static int get_dev_random_seed(void) #pragma comment(lib, "advapi32.lib") #endif -static int get_time_seed(void); - -static int get_cryptgenrandom_seed(void) +static int get_cryptgenrandom_seed(int *seed) { HCRYPTPROV hProvider = 0; DWORD dwFlags = CRYPT_VERIFYCONTEXT; - int r; DEBUG_SEED("get_cryptgenrandom_seed"); @@ -243,34 +283,37 @@ static int get_cryptgenrandom_seed(void) if (!CryptAcquireContextA(&hProvider, 0, 0, PROV_RSA_FULL, dwFlags)) { fprintf(stderr, "error CryptAcquireContextA 0x%08lx", GetLastError()); - r = get_time_seed(); + return -1; } else { - BOOL ret = CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r); + BOOL ret = CryptGenRandom(hProvider, sizeof(*seed), (BYTE *)seed); CryptReleaseContext(hProvider, 0); if (!ret) { fprintf(stderr, "error CryptGenRandom 0x%08lx", GetLastError()); - r = get_time_seed(); + return -1; } } - return r; + return 0; } #endif /* get_time_seed */ +#ifndef HAVE_ARC4RANDOM #include static int get_time_seed(void) { DEBUG_SEED("get_time_seed"); - return (int)time(NULL) * 433494437; + /* coverity[store_truncates_time_t] */ + return (unsigned)time(NULL) * 433494437; } +#endif /* json_c_get_random_seed */ @@ -283,12 +326,31 @@ int json_c_get_random_seed(void) if (has_rdrand()) return get_rdrand_seed(); #endif +#ifdef HAVE_ARC4RANDOM + /* arc4random never fails, so use it if it's available */ + return arc4random(); +#else +#ifdef HAVE_GETRANDOM + { + int seed = 0; + if (get_getrandom_seed(&seed) == 0) + return seed; + } +#endif #if defined HAVE_DEV_RANDOM && HAVE_DEV_RANDOM - if (has_dev_urandom()) - return get_dev_random_seed(); + { + int seed = 0; + if (get_dev_random_seed(&seed) == 0) + return seed; + } #endif #if defined HAVE_CRYPTGENRANDOM && HAVE_CRYPTGENRANDOM - return get_cryptgenrandom_seed(); + { + int seed = 0; + if (get_cryptgenrandom_seed(&seed) == 0) + return seed; + } #endif return get_time_seed(); +#endif /* !HAVE_ARC4RANDOM */ } diff --git a/snprintf_compat.h b/snprintf_compat.h index 76f7a6c..51fcb24 100644 --- a/snprintf_compat.h +++ b/snprintf_compat.h @@ -35,7 +35,7 @@ static int json_c_snprintf(char *str, size_t size, const char *format, ...) #define snprintf json_c_snprintf #elif !defined(HAVE_SNPRINTF) /* !HAVE_SNPRINTF */ -#error Need vsnprintf! +#error snprintf is required but was not found #endif /* !HAVE_SNPRINTF && defined(WIN32) */ #endif /* __snprintf_compat_h */ diff --git a/strerror_override.c b/strerror_override.c index 7a262f7..a3dd377 100644 --- a/strerror_override.c +++ b/strerror_override.c @@ -94,7 +94,7 @@ char *_json_c_strerror(int errno_in) } // It's not one of the known errno values, return the numeric value. - for (ii = 0; errno_in > 10; errno_in /= 10, ii++) + for (ii = 0; errno_in >= 10; errno_in /= 10, ii++) { digbuf[ii] = "0123456789"[(errno_in % 10)]; } @@ -105,5 +105,6 @@ char *_json_c_strerror(int errno_in) { errno_buf[start_idx] = digbuf[ii]; } + errno_buf[start_idx] = '\0'; return errno_buf; } diff --git a/strerror_override_private.h b/strerror_override_private.h deleted file mode 100644 index 8726e59..0000000 --- a/strerror_override_private.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __json_strerror_override_private_h__ -#define __json_strerror_override_private_h__ - -/** - * @file - * @brief Do not use, json-c internal, may be changed or removed at any time. - */ - -#include "json_types.h" - -/* Used by tests to get consistent output */ -JSON_EXPORT int _json_c_strerror_enable; - -#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 125f615..f54840d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,4 @@ - +cmake_minimum_required(VERSION 3.1) add_executable(test1Formatted test1.c parse_flags.c parse_flags.h) target_compile_definitions(test1Formatted PRIVATE TEST_FORMATTED=1) target_link_libraries(test1Formatted PRIVATE ${PROJECT_NAME}) @@ -12,35 +12,41 @@ target_link_libraries(test2Formatted PRIVATE ${PROJECT_NAME}) include_directories(PUBLIC ${CMAKE_SOURCE_DIR}) -foreach(TESTNAME - test1 - test2 - test4 - testReplaceExisting - test_cast - test_charcase - test_compare - test_deep_copy - test_double_serializer - test_float - test_int_add - test_json_pointer - test_locale - test_null - test_parse - test_parse_int64 - test_printbuf - test_set_serializer - test_set_value - test_util_file - test_visit - test_object_iterator) +set(ALL_TEST_NAMES + test1 + test2 + test4 + testReplaceExisting + test_cast + test_charcase + test_compare + test_deep_copy + test_double_serializer + test_float + test_int_add + test_int_get + test_locale + test_null + test_parse + test_parse_int64 + test_printbuf + test_set_serializer + test_set_value + test_strerror + test_util_file + test_visit + test_object_iterator) -add_executable(${TESTNAME} ${TESTNAME}.c) -if(${TESTNAME} STREQUAL test_util_file) -# For output consistency, we need _json_c_strerror() in some tests: -target_sources(${TESTNAME} PRIVATE ../strerror_override.c) +if (NOT DISABLE_JSON_POINTER) + set(ALL_TEST_NAMES ${ALL_TEST_NAMES} test_json_pointer) + if (NOT DISABLE_JSON_PATCH) + set(ALL_TEST_NAMES ${ALL_TEST_NAMES} test_json_patch) + endif() endif() + +foreach(TESTNAME ${ALL_TEST_NAMES}) + +add_executable(${TESTNAME} ${TESTNAME}.c) add_test(NAME ${TESTNAME} COMMAND ${PROJECT_SOURCE_DIR}/tests/${TESTNAME}.test) # XXX using the non-target_ versions of these doesn't work :( diff --git a/tests/json_patch_spec_tests.json b/tests/json_patch_spec_tests.json new file mode 100644 index 0000000..d7d407d --- /dev/null +++ b/tests/json_patch_spec_tests.json @@ -0,0 +1,233 @@ +[ + { + "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"]] + } + } + +] diff --git a/tests/json_patch_tests.json b/tests/json_patch_tests.json new file mode 100644 index 0000000..8cafb93 --- /dev/null +++ b/tests/json_patch_tests.json @@ -0,0 +1,540 @@ +[ + { "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"} + } + +] diff --git a/tests/parse_flags.c b/tests/parse_flags.c index d0a71bc..6224ca3 100644 --- a/tests/parse_flags.c +++ b/tests/parse_flags.c @@ -1,3 +1,6 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include "config.h" #include diff --git a/tests/test1.c b/tests/test1.c index 6682120..b45f752 100644 --- a/tests/test1.c +++ b/tests/test1.c @@ -1,9 +1,15 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include +#include #include #include #include #include +#include "config.h" + #include "json.h" #include "parse_flags.h" @@ -55,7 +61,7 @@ static const char *to_json_string(json_object *obj, int flags) #endif json_object *make_array(void); -json_object *make_array() +json_object *make_array(void) { json_object *my_array; @@ -71,7 +77,7 @@ json_object *make_array() } void test_array_del_idx(void); -void test_array_del_idx() +void test_array_del_idx(void) { int rc; size_t ii; @@ -137,7 +143,7 @@ void test_array_del_idx() } void test_array_list_expand_internal(void); -void test_array_list_expand_internal() +void test_array_list_expand_internal(void) { int rc; size_t ii; @@ -183,6 +189,42 @@ void test_array_list_expand_internal() 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) { json_object *my_string, *my_int, *my_null, *my_object, *my_array; @@ -247,6 +289,8 @@ int main(int argc, char **argv) json_object_put(my_array); + test_array_insert_idx(); + test_array_del_idx(); test_array_list_expand_internal(); @@ -305,8 +349,34 @@ int main(int argc, char **argv) { printf("\t%s: %s\n", key, json_object_to_json_string(val)); } + + json_object *empty_array = json_object_new_array(); + json_object *empty_obj = json_object_new_object(); + json_object_object_add(my_object, "empty_array", empty_array); + json_object_object_add(my_object, "empty_obj", empty_obj); printf("my_object.to_string()=%s\n", json_object_to_json_string(my_object)); + json_object_put(my_array); + my_array = json_object_new_array_ext(INT_MIN + 1); + if (my_array != NULL) + { + printf("ERROR: able to allocate an array of negative size!\n"); + fflush(stdout); + json_object_put(my_array); + my_array = NULL; + } + +#if SIZEOF_SIZE_T == SIZEOF_INT + my_array = json_object_new_array_ext(INT_MAX / 2 + 2); + if (my_array != NULL) + { + printf("ERROR: able to allocate an array of insufficient size!\n"); + fflush(stdout); + json_object_put(my_array); + my_array = NULL; + } +#endif + json_object_put(my_string); json_object_put(my_int); json_object_put(my_null); diff --git a/tests/test1.expected b/tests/test1.expected index 4b6b252..b473a8b 100644 --- a/tests/test1.expected +++ b/tests/test1.expected @@ -75,4 +75,4 @@ my_object= foo: "bar" bool0: false bool1: true -my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true } +my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "empty_array": [ ], "empty_obj": { } } diff --git a/tests/test1Formatted_plain.expected b/tests/test1Formatted_plain.expected index 128e274..ad12d99 100644 --- a/tests/test1Formatted_plain.expected +++ b/tests/test1Formatted_plain.expected @@ -75,4 +75,4 @@ my_object= foo: "bar" bool0: false bool1: true -my_object.to_string()={"abc":12,"foo":"bar","bool0":false,"bool1":true} +my_object.to_string()={"abc":12,"foo":"bar","bool0":false,"bool1":true,"empty_array":[],"empty_obj":{}} diff --git a/tests/test1Formatted_pretty.expected b/tests/test1Formatted_pretty.expected index b67185f..ab2cc78 100644 --- a/tests/test1Formatted_pretty.expected +++ b/tests/test1Formatted_pretty.expected @@ -97,5 +97,7 @@ my_object.to_string()={ "abc":12, "foo":"bar", "bool0":false, - "bool1":true + "bool1":true, + "empty_array":[], + "empty_obj":{} } diff --git a/tests/test1Formatted_spaced.expected b/tests/test1Formatted_spaced.expected index fe6979d..f57bd05 100644 --- a/tests/test1Formatted_spaced.expected +++ b/tests/test1Formatted_spaced.expected @@ -75,4 +75,4 @@ my_object= foo: "bar" bool0: false bool1: true -my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true } +my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "empty_array": [ ], "empty_obj": { } } diff --git a/tests/test1Formatted_spaced_pretty.expected b/tests/test1Formatted_spaced_pretty.expected index 104a554..c88729f 100644 --- a/tests/test1Formatted_spaced_pretty.expected +++ b/tests/test1Formatted_spaced_pretty.expected @@ -97,5 +97,7 @@ my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, - "bool1": true + "bool1": true, + "empty_array": [], + "empty_obj": {} } diff --git a/tests/test1Formatted_spaced_pretty_pretty_tab.expected b/tests/test1Formatted_spaced_pretty_pretty_tab.expected index f9a8e87..bab239f 100644 --- a/tests/test1Formatted_spaced_pretty_pretty_tab.expected +++ b/tests/test1Formatted_spaced_pretty_pretty_tab.expected @@ -97,5 +97,7 @@ my_object.to_string()={ "abc": 12, "foo": "bar", "bool0": false, - "bool1": true + "bool1": true, + "empty_array": [], + "empty_obj": {} } diff --git a/tests/test2.c b/tests/test2.c index 209fa26..0a5f315 100644 --- a/tests/test2.c +++ b/tests/test2.c @@ -1,3 +1,6 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include #include #include diff --git a/tests/test4.c b/tests/test4.c index 288cec1..1e136e5 100644 --- a/tests/test4.c +++ b/tests/test4.c @@ -2,6 +2,9 @@ * gcc -o utf8 utf8.c -I/home/y/include -L./.libs -ljson */ +#ifdef NDEBUG +#undef NDEBUG +#endif #include "config.h" #include #include @@ -28,7 +31,7 @@ void print_hex(const char *s) } static void test_lot_of_adds(void); -static void test_lot_of_adds() +static void test_lot_of_adds(void) { int ii; char key[50]; diff --git a/tests/testReplaceExisting.c b/tests/testReplaceExisting.c index ee3cae0..60a194a 100644 --- a/tests/testReplaceExisting.c +++ b/tests/testReplaceExisting.c @@ -1,3 +1,6 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include #include #include diff --git a/tests/test_cast.c b/tests/test_cast.c index fb63e0d..02e19ea 100644 --- a/tests/test_cast.c +++ b/tests/test_cast.c @@ -3,6 +3,9 @@ * Also checks the json_object_get_type and json_object_is_type functions. */ +#ifdef NDEBUG +#undef NDEBUG +#endif #include "config.h" #include #include @@ -28,6 +31,11 @@ int main(int argc, char **argv) \"int64_number\": 2147483649,\n\ \"negative_number\": -321321321,\n\ \"a_null\": null,\n\ + \"empty_array\": [],\n\ + \"nonempty_array\": [ 123 ],\n\ + \"array_with_zero\": [ 0 ],\n\ + \"empty_object\": {},\n\ + \"nonempty_object\": { \"a\": 123 },\n\ }"; /* Note: 2147483649 = INT_MAX + 2 */ /* Note: 9223372036854775809 = INT64_MAX + 2 */ @@ -49,6 +57,11 @@ int main(int argc, char **argv) getit(new_obj, "int64_number"); getit(new_obj, "negative_number"); getit(new_obj, "a_null"); + getit(new_obj, "empty_array"); + getit(new_obj, "nonempty_array"); + getit(new_obj, "array_with_zero"); + getit(new_obj, "empty_object"); + getit(new_obj, "nonempty_object"); // Now check the behaviour of the json_object_is_type() function. printf("\n================================\n"); @@ -84,7 +97,7 @@ static void getit(struct json_object *new_obj, const char *field) printf("new_obj.%s json_object_get_double()=%f\n", field, json_object_get_double(o)); } -static void checktype_header() +static void checktype_header(void) { printf("json_object_is_type: %s,%s,%s,%s,%s,%s,%s\n", json_type_to_name(json_type_null), json_type_to_name(json_type_boolean), json_type_to_name(json_type_double), diff --git a/tests/test_cast.expected b/tests/test_cast.expected index 347d540..6a19de9 100644 --- a/tests/test_cast.expected +++ b/tests/test_cast.expected @@ -7,6 +7,11 @@ Parsed input: { "int64_number": 2147483649, "negative_number": -321321321, "a_null": null, + "empty_array": [], + "nonempty_array": [ 123 ], + "array_with_zero": [ 0 ], + "empty_object": {}, + "nonempty_object": { "a": 123 }, } Result is not NULL new_obj.string_of_digits json_object_get_type()=string @@ -57,6 +62,36 @@ new_obj.a_null json_object_get_int64()=0 new_obj.a_null json_object_get_uint64()=0 new_obj.a_null json_object_get_boolean()=0 new_obj.a_null json_object_get_double()=0.000000 +new_obj.empty_array json_object_get_type()=array +new_obj.empty_array json_object_get_int()=0 +new_obj.empty_array json_object_get_int64()=0 +new_obj.empty_array json_object_get_uint64()=0 +new_obj.empty_array json_object_get_boolean()=0 +new_obj.empty_array json_object_get_double()=0.000000 +new_obj.nonempty_array json_object_get_type()=array +new_obj.nonempty_array json_object_get_int()=0 +new_obj.nonempty_array json_object_get_int64()=0 +new_obj.nonempty_array json_object_get_uint64()=0 +new_obj.nonempty_array json_object_get_boolean()=0 +new_obj.nonempty_array json_object_get_double()=0.000000 +new_obj.array_with_zero json_object_get_type()=array +new_obj.array_with_zero json_object_get_int()=0 +new_obj.array_with_zero json_object_get_int64()=0 +new_obj.array_with_zero json_object_get_uint64()=0 +new_obj.array_with_zero json_object_get_boolean()=0 +new_obj.array_with_zero json_object_get_double()=0.000000 +new_obj.empty_object json_object_get_type()=object +new_obj.empty_object json_object_get_int()=0 +new_obj.empty_object json_object_get_int64()=0 +new_obj.empty_object json_object_get_uint64()=0 +new_obj.empty_object json_object_get_boolean()=0 +new_obj.empty_object json_object_get_double()=0.000000 +new_obj.nonempty_object json_object_get_type()=object +new_obj.nonempty_object json_object_get_int()=0 +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_boolean()=0 +new_obj.nonempty_object json_object_get_double()=0.000000 ================================ json_object_is_type: null,boolean,double,int,object,array,string diff --git a/tests/test_charcase.c b/tests/test_charcase.c index 208a782..8ffcb68 100644 --- a/tests/test_charcase.c +++ b/tests/test_charcase.c @@ -1,3 +1,6 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include #include #include @@ -19,7 +22,7 @@ int main(int argc, char **argv) } /* make sure only lowercase forms are parsed in strict mode */ -static void test_case_parse() +static void test_case_parse(void) { struct json_tokener *tok; json_object *new_obj; diff --git a/tests/test_compare.c b/tests/test_compare.c index 25cecdb..ed697cd 100644 --- a/tests/test_compare.c +++ b/tests/test_compare.c @@ -2,6 +2,9 @@ * Tests if json_object_equal behaves correct. */ +#ifdef NDEBUG +#undef NDEBUG +#endif #include "config.h" #include #include @@ -9,7 +12,7 @@ #include "json_inttypes.h" #include "json_object.h" -int main() +int main(int argc, char **argv) { /* integer tests */ struct json_object *int1 = json_object_new_int(0); diff --git a/tests/test_deep_copy.c b/tests/test_deep_copy.c index 34ef1fe..5f03829 100644 --- a/tests/test_deep_copy.c +++ b/tests/test_deep_copy.c @@ -22,7 +22,7 @@ static const char *json_str1 = " \"number\": 16446744073709551615," " \"title\": \"S\"," " \"null_obj\": null, " - " \"exixt\": false," + " \"exist\": false," " \"quantity\":20," " \"univalent\":19.8," " \"GlossList\": {" @@ -136,7 +136,7 @@ int main(int argc, char **argv) assert(0 == json_object_deep_copy(src2, &dst2, NULL)); assert(0 == json_object_deep_copy(src3, &dst3, NULL)); - printf("PASSED - all json_object_deep_copy() returned succesful\n"); + printf("PASSED - all json_object_deep_copy() returned successful\n"); assert(-1 == json_object_deep_copy(src1, &dst1, NULL)); assert(errno == EINVAL); @@ -151,7 +151,7 @@ int main(int argc, char **argv) assert(1 == json_object_equal(src2, dst2)); assert(1 == json_object_equal(src3, dst3)); - printf("PASSED - all json_object_equal() tests returned succesful\n"); + printf("PASSED - all json_object_equal() tests returned successful\n"); assert(0 == strcmp(json_object_to_json_string_ext(src1, JSON_C_TO_STRING_PRETTY), json_object_to_json_string_ext(dst1, JSON_C_TO_STRING_PRETTY))); diff --git a/tests/test_deep_copy.expected b/tests/test_deep_copy.expected index 3580ddc..3bd4462 100644 --- a/tests/test_deep_copy.expected +++ b/tests/test_deep_copy.expected @@ -1,7 +1,7 @@ PASSED - loaded input data -PASSED - all json_object_deep_copy() returned succesful +PASSED - all json_object_deep_copy() returned successful PASSED - all json_object_deep_copy() returned EINVAL for non-null pointer -PASSED - all json_object_equal() tests returned succesful +PASSED - all json_object_equal() tests returned successful PASSED - comparison of string output PASSED - trying to overrwrite an object that has refcount > 1 Printing JSON objects for visual inspection @@ -14,7 +14,7 @@ Printing JSON objects for visual inspection "number":16446744073709551615, "title":"S", "null_obj":null, - "exixt":false, + "exist":false, "quantity":20, "univalent":19.8, "GlossList":{ diff --git a/tests/test_double_serializer.c b/tests/test_double_serializer.c index 8b2487a..59e95c2 100644 --- a/tests/test_double_serializer.c +++ b/tests/test_double_serializer.c @@ -2,6 +2,9 @@ * Tests if the format string for double serialization is handled correctly */ +#ifdef NDEBUG +#undef NDEBUG +#endif #include "config.h" #include @@ -11,7 +14,7 @@ /* Avoid compiler warnings about diving by constant zero */ double zero_dot_zero = 0.0; -int main() +int main(int argc, char **argv) { struct json_object *obj = json_object_new_double(0.5); char udata[] = "test"; diff --git a/tests/test_float.c b/tests/test_float.c index 99b2b1c..68a763d 100644 --- a/tests/test_float.c +++ b/tests/test_float.c @@ -1,5 +1,8 @@ /* Copyright (C) 2016 by Rainer Gerhards * Released under ASL 2.0 */ +#ifdef NDEBUG +#undef NDEBUG +#endif #include "config.h" #include "json_object.h" #include "json_tokener.h" diff --git a/tests/test_int_add.c b/tests/test_int_add.c index 644aed9..142feac 100644 --- a/tests/test_int_add.c +++ b/tests/test_int_add.c @@ -1,3 +1,6 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include #include diff --git a/tests/test_int_get.c b/tests/test_int_get.c new file mode 100644 index 0000000..be30364 --- /dev/null +++ b/tests/test_int_get.c @@ -0,0 +1,65 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif +#include +#include +#include + +#include "json.h" + +#define I64_MAX_S "9223372036854775807" +#define I64_OVER "9223372036854775808" +#define I64_MIN_S "-9223372036854775808" +#define I64_UNDER "-9223372036854775809" +#define U64_MAX_S "18446744073709551615" +#define U64_OUT_S "18446744073709551616" + +#define CHECK_GET(GET_F, J, EXPECTED) { struct json_object *jtmp = J; errno = 0; assert(GET_F(jtmp) == EXPECTED); json_object_put(jtmp); } +#define CHECK_GET_INT(J, EXPECTED) CHECK_GET(json_object_get_int, J, EXPECTED) +#define CHECK_GET_INT64(J, EXPECTED) CHECK_GET(json_object_get_int64, J, EXPECTED) +#define CHECK_GET_UINT64(J, EXPECTED) CHECK_GET(json_object_get_uint64, J, EXPECTED) + +#define CHECK_BASE(J, EXPECTED) CHECK_GET_INT(J, EXPECTED); CHECK_GET_INT64(J, EXPECTED); CHECK_GET_UINT64(J, EXPECTED) + +#define N_INT json_object_new_int +#define N_I64 json_object_new_int64 +#define N_U64 json_object_new_uint64 +#define N_STR json_object_new_string + +int main(int argc, char **argv) +{ + CHECK_BASE(N_INT(5), 5); + CHECK_BASE(N_INT(0), 0); + CHECK_BASE(N_STR("0"), 0); + CHECK_BASE(N_STR("00000"), 0); + CHECK_BASE(N_STR("000004568789"), 4568789); + CHECK_BASE(N_STR("0xFF"), 0 && errno == 0); // Hex-string values being parsed as 0 is the intended behavior + CHECK_BASE(N_STR("333this_seems_a_valid_string"), 333); + CHECK_BASE(N_STR("this_is_not_a_number"), 0 && errno == EINVAL); + CHECK_BASE(N_STR("B0"), 0 && errno == EINVAL); + printf("BASE CHECK PASSED\n"); + + 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(INT64_MAX), INT32_MAX && errno == 0); + CHECK_GET_INT(N_I64(INT64_MIN), INT32_MIN && errno == 0); + CHECK_GET_INT(N_STR(I64_MAX_S), INT32_MAX && errno == 0); + CHECK_GET_INT(N_STR(I64_MIN_S), INT32_MIN && errno == 0); + printf("INT GET PASSED\n"); + + CHECK_GET_INT64(N_I64(INT64_MAX), INT64_MAX && errno == 0); + CHECK_GET_INT64(N_I64(INT64_MIN), INT64_MIN && errno == 0); + CHECK_GET_INT64(N_STR(I64_MAX_S), INT64_MAX && 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_UNDER), INT64_MIN && errno == ERANGE); + printf("INT64 GET PASSED\n"); + + 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_STR(U64_OUT_S), UINT64_MAX && errno == ERANGE); + printf("UINT64 GET PASSED\n"); + + printf("PASSED\n"); + return 0; +} diff --git a/tests/test_int_get.expected b/tests/test_int_get.expected new file mode 100644 index 0000000..a9d78bf --- /dev/null +++ b/tests/test_int_get.expected @@ -0,0 +1,5 @@ +BASE CHECK PASSED +INT GET PASSED +INT64 GET PASSED +UINT64 GET PASSED +PASSED diff --git a/tests/test_int_get.test b/tests/test_int_get.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_int_get.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_json_patch.c b/tests/test_json_patch.c new file mode 100644 index 0000000..eeb791c --- /dev/null +++ b/tests/test_json_patch.c @@ -0,0 +1,127 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif +#include "strerror_override.h" +#include +#include +#include +#include +#include + +#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 \n" + " 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; +} diff --git a/tests/test_json_patch.expected b/tests/test_json_patch.expected new file mode 100644 index 0000000..523d276 --- /dev/null +++ b/tests/test_json_patch.expected @@ -0,0 +1,158 @@ +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 diff --git a/tests/test_json_patch.test b/tests/test_json_patch.test new file mode 100755 index 0000000..0dc5aff --- /dev/null +++ b/tests/test_json_patch.test @@ -0,0 +1,17 @@ +#!/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 $? diff --git a/tests/test_json_pointer.c b/tests/test_json_pointer.c index 3174c87..09c195a 100644 --- a/tests/test_json_pointer.c +++ b/tests/test_json_pointer.c @@ -124,7 +124,7 @@ static void test_example_get(void) json_object_put(jo1); } -/* I'm not too happy with the RFC example to test the recusion of the json_pointer_get() function */ +/* I'm not too happy with the RFC example to test the recursion of the json_pointer_get() function */ static void test_recursion_get(void) { struct json_object *jo2, *jo1 = json_tokener_parse(rec_input_json_str); @@ -269,6 +269,22 @@ static void test_example_set(void) 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(&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) diff --git a/tests/test_locale.c b/tests/test_locale.c index 55c9cc6..79f6c2c 100644 --- a/tests/test_locale.c +++ b/tests/test_locale.c @@ -1,3 +1,6 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include #include #include @@ -21,8 +24,6 @@ int main(int argc, char **argv) json_object *new_obj; #ifdef HAVE_SETLOCALE setlocale(LC_NUMERIC, "de_DE"); -#else - printf("No locale\n"); #endif char buf1[10], buf2[10]; diff --git a/tests/test_null.c b/tests/test_null.c index 0a2275b..d2a0ddc 100644 --- a/tests/test_null.c +++ b/tests/test_null.c @@ -2,6 +2,9 @@ * Tests if binary strings are supported. */ +#ifdef NDEBUG +#undef NDEBUG +#endif #include "config.h" #include #include diff --git a/tests/test_object_iterator.c b/tests/test_object_iterator.c index da5192a..4928088 100644 --- a/tests/test_object_iterator.c +++ b/tests/test_object_iterator.c @@ -1,3 +1,6 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include "config.h" #include #include diff --git a/tests/test_parse.c b/tests/test_parse.c index 5363f32..92d822a 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -1,3 +1,6 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include #include #include @@ -35,13 +38,14 @@ static void do_clear_serializer(json_object *jso); static void single_incremental_parse(const char *test_string, int clear_serializer) { - int ii; + size_t ii; int chunksize = atoi(getenv("TEST_PARSE_CHUNKSIZE")); struct json_tokener *tok; enum json_tokener_error jerr; json_object *all_at_once_obj, *new_obj; const char *all_at_once_str, *new_str; + new_obj = NULL; assert(chunksize > 0); all_at_once_obj = json_tokener_parse(test_string); if (clear_serializer) @@ -49,7 +53,7 @@ static void single_incremental_parse(const char *test_string, int clear_serializ all_at_once_str = json_object_to_json_string(all_at_once_obj); tok = json_tokener_new(); - int test_string_len = strlen(test_string) + 1; // Including '\0' ! + size_t test_string_len = strlen(test_string) + 1; // Including '\0' ! for (ii = 0; ii < test_string_len; ii += chunksize) { int len_to_parse = chunksize; @@ -92,7 +96,7 @@ static void single_basic_parse(const char *test_string, int clear_serializer) if (getenv("TEST_PARSE_CHUNKSIZE") != NULL) single_incremental_parse(test_string, clear_serializer); } -static void test_basic_parse() +static void test_basic_parse(void) { single_basic_parse("\"\003\"", 0); single_basic_parse("/* hello */\"foo\"", 0); @@ -195,13 +199,13 @@ static void test_basic_parse() single_basic_parse("[18446744073709551616]", 1); } -static void test_utf8_parse() +static void test_utf8_parse(void) { // json_tokener_parse doesn't support checking for byte order marks. // It's the responsibility of the caller to detect and skip a BOM. // Both of these checks return null. - char *utf8_bom = "\xEF\xBB\xBF"; - char *utf8_bom_and_chars = "\xEF\xBB\xBF{}"; + const char *utf8_bom = "\xEF\xBB\xBF"; + const char *utf8_bom_and_chars = "\xEF\xBB\xBF{}"; single_basic_parse(utf8_bom, 0); single_basic_parse(utf8_bom_and_chars, 0); } @@ -222,7 +226,7 @@ static int clear_serializer(json_object *jso, int flags, json_object *parent_jso return JSON_C_VISIT_RETURN_CONTINUE; } -static void test_verbose_parse() +static void test_verbose_parse(void) { json_object *new_obj; enum json_tokener_error error = json_tokener_success; @@ -256,24 +260,24 @@ struct incremental_step } incremental_steps[] = { /* Check that full json messages can be parsed, both w/ and w/o a reset */ - {"{ \"foo\": 123 }", -1, -1, json_tokener_success, 0}, - {"{ \"foo\": 456 }", -1, -1, json_tokener_success, 1}, - {"{ \"foo\": 789 }", -1, -1, json_tokener_success, 1}, + {"{ \"foo\": 123 }", -1, -1, json_tokener_success, 0, 0}, + {"{ \"foo\": 456 }", -1, -1, json_tokener_success, 1, 0}, + {"{ \"foo\": 789 }", -1, -1, json_tokener_success, 1, 0}, /* Check the comment parse*/ - {"/* hello */{ \"foo\"", -1, -1, json_tokener_continue, 0}, - {"/* hello */:/* hello */", -1, -1, json_tokener_continue, 0}, - {"\"bar\"/* hello */", -1, -1, json_tokener_continue, 0}, - {"}/* hello */", -1, -1, json_tokener_success, 1}, - {"/ hello ", -1, 1, json_tokener_error_parse_comment, 1}, - {"/* hello\"foo\"", -1, -1, json_tokener_continue, 1}, - {"/* hello*\"foo\"", -1, -1, json_tokener_continue, 1}, - {"// hello\"foo\"", -1, -1, json_tokener_continue, 1}, + {"/* hello */{ \"foo\"", -1, -1, json_tokener_continue, 0, 0}, + {"/* hello */:/* hello */", -1, -1, json_tokener_continue, 0, 0}, + {"\"bar\"/* hello */", -1, -1, json_tokener_continue, 0, 0}, + {"}/* hello */", -1, -1, json_tokener_success, 1, 0}, + {"/ hello ", -1, 1, json_tokener_error_parse_comment, 1, 0}, + {"/* hello\"foo\"", -1, -1, json_tokener_continue, 1, 0}, + {"/* hello*\"foo\"", -1, -1, json_tokener_continue, 1, 0}, + {"// hello\"foo\"", -1, -1, json_tokener_continue, 1, 0}, /* Check a basic incremental parse */ - {"{ \"foo", -1, -1, json_tokener_continue, 0}, - {"\": {\"bar", -1, -1, json_tokener_continue, 0}, - {"\":13}}", -1, -1, json_tokener_success, 1}, + {"{ \"foo", -1, -1, json_tokener_continue, 0, 0}, + {"\": {\"bar", -1, -1, json_tokener_continue, 0, 0}, + {"\":13}}", -1, -1, json_tokener_success, 1, 0}, /* Check the UTF-16 surrogate pair handling in various ways. * Note: \ud843\udd1e is u+1D11E, Musical Symbol G Clef @@ -281,56 +285,56 @@ struct incremental_step * PuTTY doesn't currently show this character. */ /* parse one char at every time */ - {"\"\\", -1, -1, json_tokener_continue, 0}, - {"u", -1, -1, json_tokener_continue, 0}, - {"d", -1, -1, json_tokener_continue, 0}, - {"8", -1, -1, json_tokener_continue, 0}, - {"3", -1, -1, json_tokener_continue, 0}, - {"4", -1, -1, json_tokener_continue, 0}, - {"\\", -1, -1, json_tokener_continue, 0}, - {"u", -1, -1, json_tokener_continue, 0}, - {"d", -1, -1, json_tokener_continue, 0}, - {"d", -1, -1, json_tokener_continue, 0}, - {"1", -1, -1, json_tokener_continue, 0}, - {"e\"", -1, -1, json_tokener_success, 1}, + {"\"\\", -1, -1, json_tokener_continue, 0, 0}, + {"u", -1, -1, json_tokener_continue, 0, 0}, + {"d", -1, -1, json_tokener_continue, 0, 0}, + {"8", -1, -1, json_tokener_continue, 0, 0}, + {"3", -1, -1, json_tokener_continue, 0, 0}, + {"4", -1, -1, json_tokener_continue, 0, 0}, + {"\\", -1, -1, json_tokener_continue, 0, 0}, + {"u", -1, -1, json_tokener_continue, 0, 0}, + {"d", -1, -1, json_tokener_continue, 0, 0}, + {"d", -1, -1, json_tokener_continue, 0, 0}, + {"1", -1, -1, json_tokener_continue, 0, 0}, + {"e\"", -1, -1, json_tokener_success, 1, 0}, /* parse two char at every time */ - {"\"\\u", -1, -1, json_tokener_continue, 0}, - {"d8", -1, -1, json_tokener_continue, 0}, - {"34", -1, -1, json_tokener_continue, 0}, - {"\\u", -1, -1, json_tokener_continue, 0}, - {"dd", -1, -1, json_tokener_continue, 0}, - {"1e\"", -1, -1, json_tokener_success, 1}, + {"\"\\u", -1, -1, json_tokener_continue, 0, 0}, + {"d8", -1, -1, json_tokener_continue, 0, 0}, + {"34", -1, -1, json_tokener_continue, 0, 0}, + {"\\u", -1, -1, json_tokener_continue, 0, 0}, + {"dd", -1, -1, json_tokener_continue, 0, 0}, + {"1e\"", -1, -1, json_tokener_success, 1, 0}, /* check the low surrogate pair */ - {"\"\\ud834", -1, -1, json_tokener_continue, 0}, - {"\\udd1e\"", -1, -1, json_tokener_success, 1}, - {"\"\\ud834\\", -1, -1, json_tokener_continue, 0}, - {"udd1e\"", -1, -1, json_tokener_success, 1}, - {"\"\\ud834\\u", -1, -1, json_tokener_continue, 0}, - {"dd1e\"", -1, -1, json_tokener_success, 1}, - {"\"fff \\ud834\\ud", -1, -1, json_tokener_continue, 0}, - {"d1e bar\"", -1, -1, json_tokener_success, 1}, - {"\"fff \\ud834\\udd", -1, -1, json_tokener_continue, 0}, - {"1e bar\"", -1, -1, json_tokener_success, 1}, + {"\"\\ud834", -1, -1, json_tokener_continue, 0, 0}, + {"\\udd1e\"", -1, -1, json_tokener_success, 1, 0}, + {"\"\\ud834\\", -1, -1, json_tokener_continue, 0, 0}, + {"udd1e\"", -1, -1, json_tokener_success, 1, 0}, + {"\"\\ud834\\u", -1, -1, json_tokener_continue, 0, 0}, + {"dd1e\"", -1, -1, json_tokener_success, 1, 0}, + {"\"fff \\ud834\\ud", -1, -1, json_tokener_continue, 0, 0}, + {"d1e bar\"", -1, -1, json_tokener_success, 1, 0}, + {"\"fff \\ud834\\udd", -1, -1, json_tokener_continue, 0, 0}, + {"1e bar\"", -1, -1, json_tokener_success, 1, 0}, /* \ud83d\ude00 is U+1F600, Grinning Face * Displays fine in PuTTY, though you may need "less -r" */ - {"\"fff \\ud83d\\ude", -1, -1, json_tokener_continue, 0}, - {"00 bar\"", -1, -1, json_tokener_success, 1}, + {"\"fff \\ud83d\\ude", -1, -1, json_tokener_continue, 0, 0}, + {"00 bar\"", -1, -1, json_tokener_success, 1, 0}, /* Check that json_tokener_reset actually resets */ - {"{ \"foo", -1, -1, json_tokener_continue, 1}, - {": \"bar\"}", -1, 0, json_tokener_error_parse_unexpected, 1}, + {"{ \"foo", -1, -1, json_tokener_continue, 1, 0}, + {": \"bar\"}", -1, 0, json_tokener_error_parse_unexpected, 1, 0}, /* Check incremental parsing with trailing characters */ - {"{ \"foo", -1, -1, json_tokener_continue, 0}, - {"\": {\"bar", -1, -1, json_tokener_continue, 0}, - {"\":13}}XXXX", 10, 6, json_tokener_success, 0}, - {"XXXX", 4, 0, json_tokener_error_parse_unexpected, 1}, + {"{ \"foo", -1, -1, json_tokener_continue, 0, 0}, + {"\": {\"bar", -1, -1, json_tokener_continue, 0, 0}, + {"\":13}}XXXX", 10, 6, json_tokener_success, 0, 0}, + {"XXXX", 4, 0, json_tokener_error_parse_unexpected, 1, 0}, /* Check that trailing characters can change w/o a reset */ - {"{\"x\": 123 }\"X\"", -1, 11, json_tokener_success, 0}, - {"\"Y\"", -1, -1, json_tokener_success, 1}, + {"{\"x\": 123 }\"X\"", -1, 11, json_tokener_success, 0, 0}, + {"\"Y\"", -1, -1, json_tokener_success, 1, 0}, /* Trailing characters should cause a failure in strict mode */ {"{\"foo\":9}{\"bar\":8}", -1, 9, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT}, @@ -342,116 +346,148 @@ struct incremental_step JSON_TOKENER_STRICT | JSON_TOKENER_ALLOW_TRAILING_CHARS}, /* To stop parsing a number we need to reach a non-digit, e.g. a \0 */ - {"1", 1, 1, json_tokener_continue, 0}, + {"1", 1, 1, json_tokener_continue, 0, 0}, /* This should parse as the number 12, since it continues the "1" */ - {"2", 2, 1, json_tokener_success, 0}, - {"12{", 3, 2, json_tokener_success, 1}, + {"2", 2, 1, json_tokener_success, 0, 0}, + {"12{", 3, 2, json_tokener_success, 1, 0}, /* Parse number in strict mode */ {"[02]", -1, 3, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, - {"0e+0", 5, 4, json_tokener_success, 1}, - {"[0e+0]", -1, -1, json_tokener_success, 1}, + {"0e+0", 5, 4, json_tokener_success, 1, 0}, + {"[0e+0]", -1, -1, json_tokener_success, 1, 0}, /* The behavior when missing the exponent varies slightly */ - {"0e", 2, 2, json_tokener_continue, 1}, - {"0e", 3, 2, json_tokener_success, 1}, + {"0e", 2, 2, json_tokener_continue, 1, 0}, + {"0e", 3, 2, json_tokener_success, 1, 0}, {"0e", 3, 2, json_tokener_error_parse_eof, 1, JSON_TOKENER_STRICT}, - {"[0e]", -1, -1, json_tokener_success, 1}, + {"[0e]", -1, -1, json_tokener_success, 1, 0}, {"[0e]", -1, 3, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, - {"0e+", 3, 3, json_tokener_continue, 1}, - {"0e+", 4, 3, json_tokener_success, 1}, + {"0e+", 3, 3, json_tokener_continue, 1, 0}, + {"0e+", 4, 3, json_tokener_success, 1, 0}, {"0e+", 4, 3, json_tokener_error_parse_eof, 1, JSON_TOKENER_STRICT}, - {"[0e+]", -1, -1, json_tokener_success, 1}, + {"[0e+]", -1, -1, json_tokener_success, 1, 0}, {"[0e+]", -1, 4, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, - {"0e-", 3, 3, json_tokener_continue, 1}, - {"0e-", 4, 3, json_tokener_success, 1}, + {"0e-", 3, 3, json_tokener_continue, 1, 0}, + {"0e-", 4, 3, json_tokener_success, 1, 0}, {"0e-", 4, 3, json_tokener_error_parse_eof, 1, JSON_TOKENER_STRICT}, - {"[0e-]", -1, -1, json_tokener_success, 1}, + {"[0e-]", -1, -1, json_tokener_success, 1, 0}, {"[0e-]", -1, 4, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, /* You might expect this to fail, but it won't because it's a valid partial parse; note the char_offset: */ - {"0e+-", 5, 3, json_tokener_success, 1}, + {"0e+-", 5, 3, json_tokener_success, 1, 0}, {"0e+-", 5, 3, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, - {"[0e+-]", -1, 4, json_tokener_error_parse_number, 1}, + {"[0e+-]", -1, 4, json_tokener_error_parse_number, 1, 0}, /* Similar tests for other kinds of objects: */ /* These could all return success immediately, since regardless of what follows the false/true/null token we *will* return a json object, but it currently doesn't work that way. hmm... */ - {"false", 5, 5, json_tokener_continue, 1}, - {"false", 6, 5, json_tokener_success, 1}, - {"true", 4, 4, json_tokener_continue, 1}, - {"true", 5, 4, json_tokener_success, 1}, - {"null", 4, 4, json_tokener_continue, 1}, - {"null", 5, 4, json_tokener_success, 1}, - - {"Infinity", 9, 8, json_tokener_success, 1}, - {"infinity", 9, 8, json_tokener_success, 1}, - {"-infinity", 10, 9, json_tokener_success, 1}, + {"false", 5, 5, json_tokener_continue, 1, 0}, + {"false", 6, 5, json_tokener_success, 1, 0}, + {"true", 4, 4, json_tokener_continue, 1, 0}, + {"true", 5, 4, json_tokener_success, 1, 0}, + {"null", 4, 4, json_tokener_continue, 1, 0}, + {"null", 5, 4, json_tokener_success, 1, 0}, + + {"Infinity", 9, 8, json_tokener_success, 1, 0}, + {"infinity", 9, 8, 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}, - {"inf", 3, 3, json_tokener_continue, 0}, - {"inity", 6, 5, json_tokener_success, 1}, - {"-inf", 4, 4, json_tokener_continue, 0}, - {"inity", 6, 5, json_tokener_success, 1}, + {"inf", 3, 3, json_tokener_continue, 0, 0}, + {"inity", 6, 5, json_tokener_success, 1, 0}, + {"-inf", 4, 4, json_tokener_continue, 0, 0}, + {"inity", 6, 5, json_tokener_success, 1, 0}, - {"i", 1, 1, json_tokener_continue, 0}, - {"n", 1, 1, json_tokener_continue, 0}, - {"f", 1, 1, json_tokener_continue, 0}, - {"i", 1, 1, json_tokener_continue, 0}, - {"n", 1, 1, json_tokener_continue, 0}, - {"i", 1, 1, json_tokener_continue, 0}, - {"t", 1, 1, json_tokener_continue, 0}, - {"y", 1, 1, json_tokener_continue, 0}, - {"", 1, 0, json_tokener_success, 1}, + {"i", 1, 1, json_tokener_continue, 0, 0}, + {"n", 1, 1, json_tokener_continue, 0, 0}, + {"f", 1, 1, json_tokener_continue, 0, 0}, + {"i", 1, 1, json_tokener_continue, 0, 0}, + {"n", 1, 1, json_tokener_continue, 0, 0}, + {"i", 1, 1, json_tokener_continue, 0, 0}, + {"t", 1, 1, json_tokener_continue, 0, 0}, + {"y", 1, 1, json_tokener_continue, 0, 0}, + {"", 1, 0, json_tokener_success, 1, 0}, - {"-", 1, 1, json_tokener_continue, 0}, - {"inf", 3, 3, json_tokener_continue, 0}, - {"ini", 3, 3, json_tokener_continue, 0}, - {"ty", 3, 2, json_tokener_success, 1}, + {"-", 1, 1, json_tokener_continue, 0, 0}, + {"inf", 3, 3, json_tokener_continue, 0, 0}, + {"ini", 3, 3, json_tokener_continue, 0, 0}, + {"ty", 3, 2, json_tokener_success, 1, 0}, - {"-", 1, 1, json_tokener_continue, 0}, - {"i", 1, 1, json_tokener_continue, 0}, - {"nfini", 5, 5, json_tokener_continue, 0}, - {"ty", 3, 2, json_tokener_success, 1}, + {"-", 1, 1, json_tokener_continue, 0, 0}, + {"i", 1, 1, json_tokener_continue, 0, 0}, + {"nfini", 5, 5, json_tokener_continue, 0, 0}, + {"ty", 3, 2, json_tokener_success, 1, 0}, - {"-i", 2, 2, json_tokener_continue, 0}, - {"nfinity", 8, 7, json_tokener_success, 1}, + {"-i", 2, 2, json_tokener_continue, 0, 0}, + {"nfinity", 8, 7, json_tokener_success, 1, 0}, - {"InfinityX", 10, 8, json_tokener_success, 0}, - {"X", 1, 0, json_tokener_error_parse_unexpected, 1}, + {"InfinityX", 10, 8, json_tokener_success, 0, 0}, + {"X", 1, 0, json_tokener_error_parse_unexpected, 1, 0}, - {"Infinity1234", 13, 8, json_tokener_success, 0}, - {"1234", 5, 4, json_tokener_success, 1}, + {"Infinity1234", 13, 8, json_tokener_success, 0, 0}, + {"1234", 5, 4, json_tokener_success, 1, 0}, - {"Infinity9999", 8, 8, json_tokener_continue, 0}, + {"Infinity9999", 8, 8, json_tokener_continue, 0, 0}, /* returns the Infinity loaded up by the previous call: */ - {"1234", 5, 0, json_tokener_success, 0}, - {"1234", 5, 4, json_tokener_success, 1}, + {"1234", 5, 0, json_tokener_success, 0, 0}, + {"1234", 5, 4, json_tokener_success, 1, 0}, + + /* INT64_MAX */ + {"[9223372036854775807]", 22, 21, json_tokener_success, 1, 0}, + /* INT64_MAX+1 => parsed as uint64 */ + {"[9223372036854775808]", 22, 21, json_tokener_success, 1, 0}, + + /* INT64_MIN */ + {"[-9223372036854775808]", 23, 22, json_tokener_success, 1, 0}, + + /* INT64_MIN-1 => success, but value ends up capped */ + {"[-9223372036854775809]", 23, 22, json_tokener_success, 1, 0}, + + /* INT64_MIN-1 => failure due to underflow detected */ + {"[-9223372036854775809]", 23, 21, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, + + /* UINT64_MAX */ + {"[18446744073709551615]", 23, 22, json_tokener_success, 1, 0}, + + /* UINT64_MAX+1 => success, but value ends up capped */ + {"[18446744073709551616]", 23, 22, json_tokener_success, 1, 0}, + + /* UINT64_MAX+1 => failure due to overflow detected */ + {"[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 */ + {"18446744073709551616", 21, 20, json_tokener_error_parse_eof, 1, JSON_TOKENER_STRICT}, + + /* Exceeding integer limits as double parse OK */ + {"[9223372036854775808.0]", 24, 23, json_tokener_success, 1, 0}, + {"[-9223372036854775809.0]", 25, 24, json_tokener_success, 1, JSON_TOKENER_STRICT}, + {"[18446744073709551615.0]", 25, 24, json_tokener_success, 1, 0}, + {"[18446744073709551616.0]", 25, 24, json_tokener_success, 1, JSON_TOKENER_STRICT}, /* offset=1 because "n" is the start of "null". hmm... */ - {"noodle", 7, 1, json_tokener_error_parse_null, 1}, + {"noodle", 7, 1, json_tokener_error_parse_null, 1, 0}, /* offset=2 because "na" is the start of "nan". hmm... */ - {"naodle", 7, 2, json_tokener_error_parse_null, 1}, + {"naodle", 7, 2, json_tokener_error_parse_null, 1, 0}, /* offset=2 because "tr" is the start of "true". hmm... */ - {"track", 6, 2, json_tokener_error_parse_boolean, 1}, - {"fail", 5, 2, json_tokener_error_parse_boolean, 1}, + {"track", 6, 2, json_tokener_error_parse_boolean, 1, 0}, + {"fail", 5, 2, json_tokener_error_parse_boolean, 1, 0}, /* Although they may initially look like they should fail, * the next few tests check that parsing multiple sequential * json objects in the input works as expected */ - {"null123", 8, 4, json_tokener_success, 0}, - {&"null123"[4], 4, 3, json_tokener_success, 1}, - {"nullx", 6, 4, json_tokener_success, 0}, - {&"nullx"[4], 2, 0, json_tokener_error_parse_unexpected, 1}, - {"{\"a\":1}{\"b\":2}", 15, 7, json_tokener_success, 0}, - {&"{\"a\":1}{\"b\":2}"[7], 8, 7, json_tokener_success, 1}, + {"null123", 8, 4, json_tokener_success, 0, 0}, + {&"null123"[4], 4, 3, json_tokener_success, 1, 0}, + {"nullx", 6, 4, json_tokener_success, 0, 0}, + {&"nullx"[4], 2, 0, json_tokener_error_parse_unexpected, 1, 0}, + {"{\"a\":1}{\"b\":2}", 15, 7, json_tokener_success, 0, 0}, + {&"{\"a\":1}{\"b\":2}"[7], 8, 7, json_tokener_success, 1, 0}, /* * Though this may seem invalid at first glance, it @@ -463,52 +499,52 @@ struct incremental_step * or json_type_double objects without some other delimiter. * e.g. whitespace */ - {&"2015-01-15"[0], 11, 4, json_tokener_success, 1}, - {&"2015-01-15"[4], 7, 3, json_tokener_success, 1}, - {&"2015-01-15"[7], 4, 3, json_tokener_success, 1}, - {&"2015 01 15"[0], 11, 5, json_tokener_success, 1}, - {&"2015 01 15"[4], 7, 4, json_tokener_success, 1}, - {&"2015 01 15"[7], 4, 3, json_tokener_success, 1}, + {&"2015-01-15"[0], 11, 4, json_tokener_success, 1, 0}, + {&"2015-01-15"[4], 7, 3, json_tokener_success, 1, 0}, + {&"2015-01-15"[7], 4, 3, json_tokener_success, 1, 0}, + {&"2015 01 15"[0], 11, 5, json_tokener_success, 1, 0}, + {&"2015 01 15"[4], 7, 4, json_tokener_success, 1, 0}, + {&"2015 01 15"[7], 4, 3, json_tokener_success, 1, 0}, /* Strings have a well defined end point, so we can stop at the quote */ - {"\"blue\"", -1, -1, json_tokener_success, 0}, + {"\"blue\"", -1, -1, json_tokener_success, 0, 0}, /* Check each of the escape sequences defined by the spec */ - {"\"\\\"\"", -1, -1, json_tokener_success, 0}, - {"\"\\\\\"", -1, -1, json_tokener_success, 0}, - {"\"\\b\"", -1, -1, json_tokener_success, 0}, - {"\"\\f\"", -1, -1, json_tokener_success, 0}, - {"\"\\n\"", -1, -1, json_tokener_success, 0}, - {"\"\\r\"", -1, -1, json_tokener_success, 0}, - {"\"\\t\"", -1, -1, json_tokener_success, 0}, - {"\"\\/\"", -1, -1, json_tokener_success, 0}, + {"\"\\\"\"", -1, -1, json_tokener_success, 0, 0}, + {"\"\\\\\"", -1, -1, json_tokener_success, 0, 0}, + {"\"\\b\"", -1, -1, json_tokener_success, 0, 0}, + {"\"\\f\"", -1, -1, json_tokener_success, 0, 0}, + {"\"\\n\"", -1, -1, json_tokener_success, 0, 0}, + {"\"\\r\"", -1, -1, json_tokener_success, 0, 0}, + {"\"\\t\"", -1, -1, json_tokener_success, 0, 0}, + {"\"\\/\"", -1, -1, json_tokener_success, 0, 0}, // Escaping a forward slash is optional - {"\"/\"", -1, -1, json_tokener_success, 0}, + {"\"/\"", -1, -1, json_tokener_success, 0, 0}, /* Check wrong escape sequences */ - {"\"\\a\"", -1, 2, json_tokener_error_parse_string, 1}, + {"\"\\a\"", -1, 2, json_tokener_error_parse_string, 1, 0}, /* Check '\'' in strict model */ {"\'foo\'", -1, 0, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT}, /* Parse array/object */ - {"[1,2,3]", -1, -1, json_tokener_success, 0}, - {"[1,2,3}", -1, 6, json_tokener_error_parse_array, 1}, - {"{\"a\"}", -1, 4, json_tokener_error_parse_object_key_sep, 1}, - {"{\"a\":1]", -1, 6, json_tokener_error_parse_object_value_sep, 1}, - {"{\"a\"::1}", -1, 5, json_tokener_error_parse_unexpected, 1}, - {"{\"a\":}", -1, 5, json_tokener_error_parse_unexpected, 1}, - {"{\"a\":1,\"a\":2}", -1, -1, json_tokener_success, 1}, - {"\"a\":1}", -1, 3, json_tokener_success, 1}, - {"{\"a\":1", -1, -1, json_tokener_continue, 1}, - {"[,]", -1, 1, json_tokener_error_parse_unexpected, 1}, - {"[,1]", -1, 1, json_tokener_error_parse_unexpected, 1}, + {"[1,2,3]", -1, -1, json_tokener_success, 0, 0}, + {"[1,2,3}", -1, 6, json_tokener_error_parse_array, 1, 0}, + {"{\"a\"}", -1, 4, json_tokener_error_parse_object_key_sep, 1, 0}, + {"{\"a\":1]", -1, 6, json_tokener_error_parse_object_value_sep, 1, 0}, + {"{\"a\"::1}", -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}", -1, 3, json_tokener_success, 1, 0}, + {"{\"a\":1", -1, -1, json_tokener_continue, 1, 0}, + {"[,]", -1, 1, json_tokener_error_parse_unexpected, 1, 0}, + {"[,1]", -1, 1, json_tokener_error_parse_unexpected, 1, 0}, /* This behaviour doesn't entirely follow the json spec, but until we have * a way to specify how strict to be we follow Postel's Law and be liberal * in what we accept (up to a point). */ - {"[1,2,3,]", -1, -1, json_tokener_success, 0}, - {"[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0}, + {"[1,2,3,]", -1, -1, json_tokener_success, 0, 0}, + {"[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0, 0}, {"[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}, @@ -517,24 +553,24 @@ struct incremental_step // acsll encoding {"\x22\x31\x32\x33\x61\x73\x63\x24\x25\x26\x22", -1, -1, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8}, - {"\x22\x31\x32\x33\x61\x73\x63\x24\x25\x26\x22", -1, -1, json_tokener_success, 1}, + {"\x22\x31\x32\x33\x61\x73\x63\x24\x25\x26\x22", -1, -1, json_tokener_success, 1, 0}, // utf-8 encoding {"\x22\xe4\xb8\x96\xe7\x95\x8c\x22", -1, -1, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8}, {"\x22\xe4\xb8", -1, 3, json_tokener_error_parse_utf8_string, 0, JSON_TOKENER_VALIDATE_UTF8}, {"\x96\xe7\x95\x8c\x22", -1, 0, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8}, - {"\x22\xe4\xb8\x96\xe7\x95\x8c\x22", -1, -1, json_tokener_success, 1}, + {"\x22\xe4\xb8\x96\xe7\x95\x8c\x22", -1, -1, json_tokener_success, 1, 0}, {"\x22\xcf\x80\xcf\x86\x22", -1, -1, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8}, {"\x22\xf0\xa5\x91\x95\x22", -1, -1, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8}, // wrong utf-8 encoding {"\x22\xe6\x9d\x4e\x22", -1, 3, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8}, - {"\x22\xe6\x9d\x4e\x22", -1, 5, json_tokener_success, 1}, + {"\x22\xe6\x9d\x4e\x22", -1, 5, json_tokener_success, 1, 0}, // GBK encoding {"\x22\xc0\xee\xc5\xf4\x22", -1, 2, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8}, - {"\x22\xc0\xee\xc5\xf4\x22", -1, 6, json_tokener_success, 1}, + {"\x22\xc0\xee\xc5\xf4\x22", -1, 6, json_tokener_success, 1, 0}, // char after space {"\x20\x20\x22\xe4\xb8\x96\x22", -1, -1, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8}, {"\x20\x20\x81\x22\xe4\xb8\x96\x22", -1, 2, json_tokener_error_parse_utf8_string, 1, @@ -542,7 +578,7 @@ struct incremental_step {"\x5b\x20\x81\x31\x5d", -1, 2, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8}, // char in state inf - {"\x49\x6e\x66\x69\x6e\x69\x74\x79", 9, 8, json_tokener_success, 1}, + {"\x49\x6e\x66\x69\x6e\x69\x74\x79", 9, 8, json_tokener_success, 1, 0}, {"\x49\x6e\x66\x81\x6e\x69\x74\x79", -1, 3, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8}, // char in escape unicode @@ -559,10 +595,10 @@ struct incremental_step {"\x7b\x22\x31\x81\x22\x3a\x31\x7d", -1, 3, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8}, - {NULL, -1, -1, json_tokener_success, 0}, + {NULL, -1, -1, json_tokener_success, 0, 0}, }; -static void test_incremental_parse() +static void test_incremental_parse(void) { json_object *new_obj; enum json_tokener_error jerr; diff --git a/tests/test_parse.expected b/tests/test_parse.expected index 37db44d..50fb6d8 100644 --- a/tests/test_parse.expected +++ b/tests/test_parse.expected @@ -210,6 +210,19 @@ json_tokener_parse_ex(tok, 1234 , 5) ... OK: got object of type [int]: json_tokener_parse_ex(tok, Infinity9999, 8) ... OK: got correct error: continue json_tokener_parse_ex(tok, 1234 , 5) ... OK: got object of type [double]: Infinity json_tokener_parse_ex(tok, 1234 , 5) ... OK: got object of type [int]: 1234 +json_tokener_parse_ex(tok, [9223372036854775807], 22) ... OK: got object of type [array]: [ 9223372036854775807 ] +json_tokener_parse_ex(tok, [9223372036854775808], 22) ... OK: got object of type [array]: [ 9223372036854775808 ] +json_tokener_parse_ex(tok, [-9223372036854775808], 23) ... OK: got object of type [array]: [ -9223372036854775808 ] +json_tokener_parse_ex(tok, [-9223372036854775809], 23) ... OK: got object of type [array]: [ -9223372036854775808 ] +json_tokener_parse_ex(tok, [-9223372036854775809], 23) ... OK: got correct error: number expected +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 correct error: number expected +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, [-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, [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, naodle , 7) ... OK: got correct error: null expected json_tokener_parse_ex(tok, track , 6) ... OK: got correct error: boolean expected @@ -275,5 +288,5 @@ json_tokener_parse_ex(tok, "\ud855 json_tokener_parse_ex(tok, "\ud0031À" , 10) ... OK: got correct error: invalid utf-8 string json_tokener_parse_ex(tok, 11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 -End Incremental Tests OK=185 ERROR=0 +End Incremental Tests OK=198 ERROR=0 ================================== diff --git a/tests/test_parse_int64.c b/tests/test_parse_int64.c index 6c20d75..5710b08 100644 --- a/tests/test_parse_int64.c +++ b/tests/test_parse_int64.c @@ -1,4 +1,7 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include #include @@ -31,7 +34,7 @@ void checkit_uint(const char *buf) * This always exits with a 0 exit value. The output should be compared * against previously saved expected output. */ -int main() +int main(int argc, char **argv) { char buf[100]; diff --git a/tests/test_printbuf.c b/tests/test_printbuf.c index d0fb918..3b1540f 100644 --- a/tests/test_printbuf.c +++ b/tests/test_printbuf.c @@ -1,3 +1,6 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include #include #include @@ -16,7 +19,7 @@ static void test_printbuf_memset_length(void); #define __func__ __FUNCTION__ #endif -static void test_basic_printbuf_memset() +static void test_basic_printbuf_memset(void) { struct printbuf *pb; @@ -29,7 +32,7 @@ static void test_basic_printbuf_memset() printf("%s: end test\n", __func__); } -static void test_printbuf_memset_length() +static void test_printbuf_memset_length(void) { struct printbuf *pb; diff --git a/tests/test_set_serializer.c b/tests/test_set_serializer.c index b5c1979..27598f4 100644 --- a/tests/test_set_serializer.c +++ b/tests/test_set_serializer.c @@ -1,3 +1,6 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include #include #include @@ -73,7 +76,8 @@ int main(int argc, char **argv) my_sub_object = json_object_new_double(1.0); json_object_object_add(my_object, "double", my_sub_object); printf("Check that the custom serializer does not include nul byte:\n"); - json_object_set_serializer(my_sub_object, json_object_double_to_json_string, "%125.0f,", NULL); +#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a)) + json_object_set_serializer(my_sub_object, json_object_double_to_json_string, UNCONST("%125.0f"), NULL); printf("my_object.to_string(custom serializer)=%s\n", json_object_to_json_string_ext(my_object, JSON_C_TO_STRING_NOZERO)); diff --git a/tests/test_set_serializer.expected b/tests/test_set_serializer.expected index 9629dd6..9a13512 100644 --- a/tests/test_set_serializer.expected +++ b/tests/test_set_serializer.expected @@ -9,4 +9,4 @@ my_object.to_string(custom serializer)=Custom Output Next line of output should be from the custom freeit function: freeit, value=123 Check that the custom serializer does not include nul byte: -my_object.to_string(custom serializer)={"double": 1.} +my_object.to_string(custom serializer)={"double": 1} diff --git a/tests/test_set_value.c b/tests/test_set_value.c index 157e64f..a8ebbfe 100644 --- a/tests/test_set_value.c +++ b/tests/test_set_value.c @@ -1,3 +1,6 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include #include #include @@ -68,6 +71,14 @@ int main(int argc, char **argv) json_object_set_string(tmp, SHORT); assert(strcmp(json_object_get_string(tmp), SHORT) == 0); assert(strcmp(json_object_to_json_string(tmp), "\"" SHORT "\"") == 0); + + // Set an empty string a couple times to try to trigger + // a case that used to leak memory. + json_object_set_string(tmp, ""); + json_object_set_string(tmp, HUGE); + json_object_set_string(tmp, ""); + json_object_set_string(tmp, HUGE); + json_object_put(tmp); printf("STRING PASSED\n"); diff --git a/tests/test_strerror.c b/tests/test_strerror.c new file mode 100644 index 0000000..773b1aa --- /dev/null +++ b/tests/test_strerror.c @@ -0,0 +1,13 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif +#include "strerror_override.h" + +#include + +int main(int argc, char **argv) +{ + puts(strerror(10000)); + puts(strerror(999)); + return 0; +} diff --git a/tests/test_strerror.expected b/tests/test_strerror.expected new file mode 100644 index 0000000..b6b3bb6 --- /dev/null +++ b/tests/test_strerror.expected @@ -0,0 +1,2 @@ +ERRNO=10000 +ERRNO=999 diff --git a/tests/test_strerror.test b/tests/test_strerror.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_strerror.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file diff --git a/tests/test_util_file.c b/tests/test_util_file.c index 9150586..036dcbc 100644 --- a/tests/test_util_file.c +++ b/tests/test_util_file.c @@ -1,5 +1,7 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include "strerror_override.h" -#include "strerror_override_private.h" #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include @@ -35,7 +37,7 @@ static void test_read_fd_equal(const char *testdir); #define PATH_MAX 256 #endif -static void test_write_to_file() +static void test_write_to_file(void) { json_object *jso; @@ -90,7 +92,7 @@ static void test_write_to_file() static void stat_and_cat(const char *file) { struct stat sb; - int d = open(file, O_RDONLY, 0600); + int d = open(file, O_RDONLY); if (d < 0) { printf("FAIL: unable to open %s: %s\n", file, strerror(errno)); @@ -168,7 +170,7 @@ static void test_read_valid_with_fd(const char *testdir) char filename[PATH_MAX]; (void)snprintf(filename, sizeof(filename), "%s/valid.json", testdir); - int d = open(filename, O_RDONLY, 0); + int d = open(filename, O_RDONLY); if (d < 0) { fprintf(stderr, "FAIL: unable to open %s: %s\n", filename, strerror(errno)); @@ -193,7 +195,7 @@ static void test_read_valid_nested_with_fd(const char *testdir) char filename[PATH_MAX]; (void)snprintf(filename, sizeof(filename), "%s/valid_nested.json", testdir); - int d = open(filename, O_RDONLY, 0); + int d = open(filename, O_RDONLY); if (d < 0) { fprintf(stderr, "FAIL: unable to open %s: %s\n", filename, strerror(errno)); @@ -231,7 +233,7 @@ static void test_read_valid_nested_with_fd(const char *testdir) close(d); } -static void test_read_nonexistant() +static void test_read_nonexistant(void) { const char *filename = "./not_present.json"; @@ -249,10 +251,10 @@ static void test_read_nonexistant() } } -static void test_read_closed() +static void test_read_closed(void) { // Test reading from a closed fd - int d = open("/dev/null", O_RDONLY, 0); + int d = open("/dev/null", O_RDONLY); if (d < 0) { puts("FAIL: unable to open"); @@ -287,7 +289,7 @@ static void test_read_fd_equal(const char *testdir) json_object *jso = json_object_from_file(filename); - int d = open(filename, O_RDONLY, 0); + int d = open(filename, O_RDONLY); if (d < 0) { fprintf(stderr, "FAIL: unable to open %s: %s\n", filename, strerror(errno)); diff --git a/tests/test_util_file.expected b/tests/test_util_file.expected index f149f85..4a8aea5 100644 --- a/tests/test_util_file.expected +++ b/tests/test_util_file.expected @@ -4,7 +4,7 @@ OK: correctly unable to parse contents of valid_nested.json with low max depth: OK: json_object_from_file(./not_present.json) correctly returned NULL: json_object_from_file: error opening file ./not_present.json: ERRNO=ENOENT -OK: json_object_from_fd(closed_fd), expecting NULL, EBADF, got:NULL, json_object_from_fd: error reading fd 10: ERRNO=EBADF +OK: json_object_from_fd(closed_fd), expecting NULL, EBADF, got:NULL, json_object_from_fd_ex: error reading fd 10: ERRNO=EBADF OK: json_object_to_file(json.out, jso)=0 file[json.out], size=336, contents={"foo":1234,"foo1":"abcdefghijklmnopqrstuvwxyz","foo2":"abcdefghijklmnopqrstuvwxyz","foo3":"abcdefghijklmnopqrstuvwxyz","foo4":"abcdefghijklmnopqrstuvwxyz","foo5":"abcdefghijklmnopqrstuvwxyz","foo6":"abcdefghijklmnopqrstuvwxyz","foo7":"abcdefghijklmnopqrstuvwxyz","foo8":"abcdefghijklmnopqrstuvwxyz","foo9":"abcdefghijklmnopqrstuvwxyz"} diff --git a/tests/test_visit.c b/tests/test_visit.c index eee469e..3283a55 100644 --- a/tests/test_visit.c +++ b/tests/test_visit.c @@ -1,3 +1,6 @@ +#ifdef NDEBUG +#undef NDEBUG +#endif #include #include #include diff --git a/vasprintf_compat.h b/vasprintf_compat.h index 5264272..59b2e96 100644 --- a/vasprintf_compat.h +++ b/vasprintf_compat.h @@ -8,6 +8,10 @@ #include "snprintf_compat.h" +#ifndef WIN32 +#include +#endif /* !defined(WIN32) */ +#include #include #if !defined(HAVE_VASPRINTF) @@ -16,6 +20,7 @@ static int vasprintf(char **buf, const char *fmt, va_list ap) { #ifndef WIN32 static char _T_emptybuffer = '\0'; + va_list ap2; #endif /* !defined(WIN32) */ int chars; char *b; @@ -26,19 +31,21 @@ static int vasprintf(char **buf, const char *fmt, va_list ap) } #ifdef WIN32 - chars = _vscprintf(fmt, ap) + 1; + chars = _vscprintf(fmt, ap); #else /* !defined(WIN32) */ /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite - * our buffer like on some 64bit sun systems.... but hey, its time to move on + * our buffer like on some 64bit sun systems... but hey, it's time to move on */ - chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap) + 1; - if (chars < 0) - { - chars *= -1; - } /* CAW: old glibc versions have this problem */ + va_copy(ap2, ap); + chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap2); + va_end(ap2); #endif /* defined(WIN32) */ + if (chars < 0 || (size_t)chars + 1 > SIZE_MAX / sizeof(char)) + { + return -1; + } - b = (char *)malloc(sizeof(char) * chars); + b = (char *)malloc(sizeof(char) * ((size_t)chars + 1)); if (!b) { return -1; -- 2.7.4