Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71c4e8ec21 | ||
|
|
10afd33efb | ||
|
|
2a31c4f475 | ||
|
|
f44c137a84 | ||
|
|
7197810714 | ||
|
|
4ba5c7cc5d | ||
|
|
e262ea5fcd | ||
|
|
6ac0eefed0 | ||
|
|
226b34d546 | ||
|
|
d115953347 | ||
|
|
15f77c8f47 | ||
|
|
ef080d17b5 | ||
|
|
4f91b1d072 | ||
|
|
8d659113d5 | ||
|
|
5df5fc5b13 | ||
|
|
e65a490c44 | ||
|
|
fc591913ac | ||
|
|
d83d3d9172 | ||
|
|
020cc26b5c | ||
|
|
360b1ef5a1 | ||
|
|
37147b8a23 | ||
|
|
8a00a56ec4 | ||
|
|
401ece058d | ||
|
|
66e4ee795d | ||
|
|
3e13f514ce | ||
|
|
81fe13eeed | ||
|
|
aed855e692 | ||
|
|
b59ac57617 | ||
|
|
904f5c28ac | ||
|
|
80cea73bf9 | ||
|
|
e28bcfeac8 | ||
|
|
fda9288b5f | ||
|
|
9ff08f6312 | ||
|
|
dd4743a51d | ||
|
|
50f29f9b1a | ||
|
|
e5dbe7bb64 | ||
|
|
15105b66b4 | ||
|
|
b23025d72b | ||
|
|
2c98c30a02 | ||
|
|
bb71db204f | ||
|
|
92760bb363 | ||
|
|
fe7873e963 | ||
|
|
a586c0654f | ||
|
|
6d7a02beb0 | ||
|
|
b70364b362 | ||
|
|
6d1ae86e1c | ||
|
|
a324d18940 | ||
|
|
44f6606df8 | ||
|
|
d8798468c6 | ||
|
|
749bef0b6a | ||
|
|
e37e52549f | ||
|
|
ea664722d4 | ||
|
|
d098c0ff86 | ||
|
|
2d494c169f | ||
|
|
a5af280bac | ||
|
|
73c22de516 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -31,3 +31,5 @@ stamp-h1
|
||||
/jansson_private_config.h
|
||||
/build
|
||||
*.exe
|
||||
.idea
|
||||
cmake-build-debug/
|
||||
|
||||
40
CHANGES
40
CHANGES
@@ -1,3 +1,43 @@
|
||||
Version 2.12
|
||||
|
||||
Released 2018-11-25
|
||||
|
||||
* Bug fixes:
|
||||
|
||||
- Fix error message in `json_pack()` for NULL object (#409).
|
||||
|
||||
- Avoid invalid memory read in `json_pack()` (#421).
|
||||
|
||||
- Call va_end after va_copy in `json_vsprintf()` (#427).
|
||||
|
||||
- Improve handling of formats with '?' and '*' in `json_pack()` (#438).
|
||||
|
||||
- Remove inappropriate `jsonp_free()` which caused segmentation fault in
|
||||
error handling (#444).
|
||||
|
||||
* Build:
|
||||
|
||||
- Add function attributes for GCC and CLANG to provide warnings on improper
|
||||
use of jansson routines (#404).
|
||||
|
||||
- Many CMake fixes (#408, #412, #415).
|
||||
|
||||
- Enable -Bsymbolic-functions linker flag whenever possible.
|
||||
|
||||
- Resolve various compiler warnings (#423, #430, #435, #436).
|
||||
|
||||
- Fix code coverage ignored paths (#439).
|
||||
|
||||
* Other:
|
||||
|
||||
- Test coverage improvements (#398, #400).
|
||||
|
||||
- Add VS 2017 to appveyor, update Visual Studio documentation (#417).
|
||||
|
||||
- Update copyright for 2018 (#424).
|
||||
|
||||
- Update install instructions in README (#401).
|
||||
|
||||
Version 2.11
|
||||
============
|
||||
|
||||
|
||||
191
CMakeLists.txt
191
CMakeLists.txt
@@ -46,9 +46,8 @@
|
||||
|
||||
|
||||
|
||||
cmake_minimum_required (VERSION 2.8)
|
||||
# required for exports? cmake_minimum_required (VERSION 2.8.6)
|
||||
project (jansson C)
|
||||
cmake_minimum_required (VERSION 3.1)
|
||||
project(jansson C)
|
||||
|
||||
# Options
|
||||
option(JANSSON_BUILD_SHARED_LIBS "Build shared libraries." OFF)
|
||||
@@ -70,26 +69,26 @@ if (UNIX)
|
||||
endif ()
|
||||
|
||||
# Set some nicer output dirs.
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
||||
set(JANSSON_TEMP_DIR ${PROJECT_BINARY_DIR}/tmp)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
||||
set(JANSSON_TEMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/tmp)
|
||||
|
||||
# Give the debug version a different postfix for windows,
|
||||
# so both the debug and release version can be built in the
|
||||
# same build-tree on Windows (MSVC).
|
||||
if (WIN32)
|
||||
if (WIN32 AND NOT CMAKE_DEBUG_POSTFIX)
|
||||
set(CMAKE_DEBUG_POSTFIX "_d")
|
||||
endif (WIN32)
|
||||
endif()
|
||||
|
||||
# This is how I thought it should go
|
||||
# set (JANSSON_VERSION "2.3.1")
|
||||
# set (JANSSON_SOVERSION 2)
|
||||
|
||||
set(JANSSON_DISPLAY_VERSION "2.11")
|
||||
set(JANSSON_DISPLAY_VERSION "2.12")
|
||||
|
||||
# This is what is required to match the same numbers as automake's
|
||||
set(JANSSON_VERSION "4.11.0")
|
||||
set(JANSSON_VERSION "4.11.1")
|
||||
set(JANSSON_SOVERSION 4)
|
||||
|
||||
# for CheckFunctionKeywords
|
||||
@@ -104,16 +103,11 @@ include (CheckTypeSize)
|
||||
if (MSVC)
|
||||
# Turn off Microsofts "security" warnings.
|
||||
add_definitions( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo" )
|
||||
|
||||
|
||||
if (JANSSON_STATIC_CRT)
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
if (NOT WIN32 AND (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX))
|
||||
add_definitions("-fPIC")
|
||||
endif()
|
||||
|
||||
message("C compiler: ${CMAKE_C_COMPILER_ID}")
|
||||
@@ -164,9 +158,9 @@ if (HAVE_INT32_T)
|
||||
set (JSON_INT32 int32_t)
|
||||
elseif (HAVE___INT32)
|
||||
set (JSON_INT32 __int32)
|
||||
elseif (HAVE_LONG_INT AND (${LONG_INT} EQUAL 4))
|
||||
elseif (HAVE_LONG_INT AND (LONG_INT EQUAL 4))
|
||||
set (JSON_INT32 long)
|
||||
elseif (HAVE_INT AND (${INT} EQUAL 4))
|
||||
elseif (HAVE_INT AND (INT EQUAL 4))
|
||||
set (JSON_INT32 int)
|
||||
else ()
|
||||
message (FATAL_ERROR "Could not detect a valid 32-bit integer type")
|
||||
@@ -182,12 +176,12 @@ if (HAVE_UINT32_T)
|
||||
set (JSON_UINT32 uint32_t)
|
||||
elseif (HAVE___UINT32)
|
||||
set (JSON_UINT32 __uint32)
|
||||
elseif (HAVE_UNSIGNED_LONG_INT AND (${UNSIGNED_LONG_INT} EQUAL 4))
|
||||
elseif (HAVE_UNSIGNED_LONG_INT AND (UNSIGNED_LONG_INT EQUAL 4))
|
||||
set (JSON_UINT32 "unsigned long")
|
||||
elseif (HAVE_UNSIGNED_INT AND (${UNSIGNED_INT} EQUAL 4))
|
||||
elseif (HAVE_UNSIGNED_INT AND (UNSIGNED_INT EQUAL 4))
|
||||
set (JSON_UINT32 "unsigned int")
|
||||
else ()
|
||||
message (FATAL_ERROR "Could not detect a valid unsigned 32-bit integer type")
|
||||
message (FATAL_ERROR "Could not detect a valid unsigned 32-bit integer type")
|
||||
endif ()
|
||||
|
||||
check_type_size (uint16_t UINT16_T)
|
||||
@@ -196,12 +190,12 @@ if (HAVE_UINT16_T)
|
||||
set (JSON_UINT16 uint16_t)
|
||||
elseif (HAVE___UINT16)
|
||||
set (JSON_UINT16 __uint16)
|
||||
elseif (HAVE_UNSIGNED_INT AND (${UNSIGNED_INT} EQUAL 2))
|
||||
elseif (HAVE_UNSIGNED_INT AND (UNSIGNED_INT EQUAL 2))
|
||||
set (JSON_UINT16 "unsigned int")
|
||||
elseif (HAVE_UNSIGNED_SHORT AND (${UNSIGNED_SHORT} EQUAL 2))
|
||||
elseif (HAVE_UNSIGNED_SHORT AND (UNSIGNED_SHORT EQUAL 2))
|
||||
set (JSON_UINT16 "unsigned short")
|
||||
else ()
|
||||
message (FATAL_ERROR "Could not detect a valid unsigned 16-bit integer type")
|
||||
message (FATAL_ERROR "Could not detect a valid unsigned 16-bit integer type")
|
||||
endif ()
|
||||
|
||||
check_type_size (uint8_t UINT8_T)
|
||||
@@ -250,7 +244,7 @@ endif ()
|
||||
# detect what to use for the 64 bit type.
|
||||
# Note: I will prefer long long if I can get it, as that is what the automake system aimed for.
|
||||
if (NOT DEFINED JSON_INT_T)
|
||||
if (HAVE_LONG_LONG_INT AND (${LONG_LONG_INT} EQUAL 8))
|
||||
if (HAVE_LONG_LONG_INT AND (LONG_LONG_INT EQUAL 8))
|
||||
set (JSON_INT_T "long long")
|
||||
elseif (HAVE_INT64_T)
|
||||
set (JSON_INT_T int64_t)
|
||||
@@ -306,6 +300,18 @@ endif()
|
||||
check_c_source_compiles ("int main() { unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1); __sync_add_and_fetch(&val, 1); __sync_sub_and_fetch(&val, 1); return 0; } " HAVE_SYNC_BUILTINS)
|
||||
check_c_source_compiles ("int main() { char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_RELEASE); __atomic_load_n(&v, __ATOMIC_ACQUIRE); __atomic_add_fetch(&v, 1, __ATOMIC_ACQUIRE); __atomic_sub_fetch(&v, 1, __ATOMIC_RELEASE); return 0; }" HAVE_ATOMIC_BUILTINS)
|
||||
|
||||
if (HAVE_SYNC_BUILTINS)
|
||||
set(JSON_HAVE_SYNC_BUILTINS 1)
|
||||
else()
|
||||
set(JSON_HAVE_SYNC_BUILTINS 0)
|
||||
endif()
|
||||
|
||||
if (HAVE_ATOMIC_BUILTINS)
|
||||
set(JSON_HAVE_ATOMIC_BUILTINS 1)
|
||||
else()
|
||||
set(JSON_HAVE_ATOMIC_BUILTINS 0)
|
||||
endif()
|
||||
|
||||
set (JANSSON_INITIAL_HASHTABLE_ORDER 3 CACHE STRING "Number of buckets new object hashtables contain is 2 raised to this power. The default is 3, so empty hashtables contain 2^3 = 8 buckets.")
|
||||
|
||||
# configure the public config file
|
||||
@@ -338,7 +344,7 @@ set(JANSSON_HDR_PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/utf.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/private_include/jansson_private_config.h)
|
||||
|
||||
set(JANSSON_HDR_PUBLIC
|
||||
set(JANSSON_HDR_PUBLIC
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h)
|
||||
|
||||
@@ -347,24 +353,26 @@ source_group("Library Private Headers" FILES ${JANSSON_HDR_PRIVATE})
|
||||
source_group("Library Public Headers" FILES ${JANSSON_HDR_PUBLIC})
|
||||
|
||||
if(JANSSON_BUILD_SHARED_LIBS)
|
||||
add_library(jansson SHARED
|
||||
${JANSSON_SRC}
|
||||
${JANSSON_HDR_PRIVATE}
|
||||
${JANSSON_HDR_PUBLIC}
|
||||
add_library(jansson SHARED
|
||||
${JANSSON_SRC}
|
||||
${JANSSON_HDR_PRIVATE}
|
||||
${JANSSON_HDR_PUBLIC}
|
||||
src/jansson.def)
|
||||
|
||||
set_target_properties(jansson PROPERTIES
|
||||
VERSION ${JANSSON_VERSION}
|
||||
SOVERSION ${JANSSON_SOVERSION})
|
||||
else()
|
||||
add_library(jansson
|
||||
add_library(jansson STATIC
|
||||
${JANSSON_SRC}
|
||||
${JANSSON_HDR_PRIVATE}
|
||||
${JANSSON_HDR_PRIVATE}
|
||||
${JANSSON_HDR_PUBLIC})
|
||||
set_target_properties(jansson PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE true)
|
||||
endif()
|
||||
|
||||
if (JANSSON_EXAMPLES)
|
||||
add_executable(simple_parse "${PROJECT_SOURCE_DIR}/examples/simple_parse.c")
|
||||
add_executable(simple_parse "${CMAKE_CURRENT_SOURCE_DIR}/examples/simple_parse.c")
|
||||
target_link_libraries(simple_parse jansson)
|
||||
endif()
|
||||
|
||||
@@ -374,12 +382,12 @@ if (JANSSON_BUILD_DOCS)
|
||||
find_package(Sphinx)
|
||||
|
||||
if (NOT SPHINX_FOUND)
|
||||
message(WARNING "Sphinx not found. Cannot generate documentation!
|
||||
message(WARNING "Sphinx not found. Cannot generate documentation!
|
||||
Set -DJANSSON_BUILD_DOCS=OFF to get rid of this message.")
|
||||
else()
|
||||
if (Sphinx_VERSION_STRING VERSION_LESS 1.0)
|
||||
message(WARNING "Your Sphinx version is too old!
|
||||
This project requires Sphinx v1.0 or above to produce
|
||||
message(WARNING "Your Sphinx version is too old!
|
||||
This project requires Sphinx v1.0 or above to produce
|
||||
proper documentation (you have v${Sphinx_VERSION_STRING}).
|
||||
You will get output but it will have errors.")
|
||||
endif()
|
||||
@@ -432,7 +440,7 @@ if (JANSSON_BUILD_DOCS)
|
||||
list(APPEND DOC_TARGETS latex)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# The doc target will build all documentation targets.
|
||||
add_custom_target(doc)
|
||||
|
||||
@@ -487,11 +495,13 @@ if (NOT JANSSON_WITHOUT_TESTS)
|
||||
set(api_tests
|
||||
test_array
|
||||
test_copy
|
||||
test_chaos
|
||||
test_dump
|
||||
test_dump_callback
|
||||
test_equal
|
||||
test_load
|
||||
test_loadb
|
||||
test_load_callback
|
||||
test_number
|
||||
test_object
|
||||
test_pack
|
||||
@@ -514,7 +524,7 @@ if (NOT JANSSON_WITHOUT_TESTS)
|
||||
|
||||
# Create executables and tests/valgrind tests for API tests.
|
||||
foreach (test ${api_tests})
|
||||
build_testprog(${test} ${PROJECT_SOURCE_DIR}/test/suites/api)
|
||||
build_testprog(${test} ${CMAKE_CURRENT_SOURCE_DIR}/test/suites/api)
|
||||
|
||||
if (JANSSON_TEST_WITH_VALGRIND)
|
||||
add_test(memcheck__${test}
|
||||
@@ -528,12 +538,12 @@ if (NOT JANSSON_WITHOUT_TESTS)
|
||||
endforeach ()
|
||||
|
||||
# Test harness for the suites tests.
|
||||
build_testprog(json_process ${PROJECT_SOURCE_DIR}/test/bin)
|
||||
build_testprog(json_process ${CMAKE_CURRENT_SOURCE_DIR}/test/bin)
|
||||
|
||||
set(SUITE_TEST_CMD ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/json_process)
|
||||
set(SUITES encoding-flags valid invalid invalid-unicode)
|
||||
foreach (SUITE ${SUITES})
|
||||
file(GLOB TESTDIRS ${jansson_SOURCE_DIR}/test/suites/${SUITE}/*)
|
||||
file(GLOB TESTDIRS test/suites/${SUITE}/*)
|
||||
|
||||
foreach (TESTDIR ${TESTDIRS})
|
||||
if (IS_DIRECTORY ${TESTDIR})
|
||||
@@ -575,7 +585,7 @@ if (NOT JANSSON_WITHOUT_TESTS)
|
||||
|
||||
# Enable using "make check" just like the autotools project.
|
||||
# By default cmake creates a target "make test"
|
||||
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}
|
||||
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}
|
||||
DEPENDS json_process ${api_tests})
|
||||
endif ()
|
||||
|
||||
@@ -607,80 +617,67 @@ set(VERSION ${JANSSON_DISPLAY_VERSION})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jansson.pc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/jansson.pc @ONLY)
|
||||
|
||||
# Make sure the paths are absolute.
|
||||
# Make sure the paths are relative.
|
||||
foreach(p LIB BIN INCLUDE CMAKE)
|
||||
set(var JANSSON_INSTALL_${p}_DIR)
|
||||
if(NOT IS_ABSOLUTE "${${var}}")
|
||||
set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Export targets (This is used for other CMake projects to easily find the libraries and include files).
|
||||
export(TARGETS jansson
|
||||
FILE "${PROJECT_BINARY_DIR}/JanssonTargets.cmake")
|
||||
export(PACKAGE jansson)
|
||||
|
||||
# Generate the config file for the build-tree.
|
||||
set(JANSSON__INCLUDE_DIRS
|
||||
"${PROJECT_SOURCE_DIR}/include"
|
||||
"${PROJECT_BINARY_DIR}/include")
|
||||
set(JANSSON__INCLUDE_DIRS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/include")
|
||||
set(JANSSON_INCLUDE_DIRS ${JANSSON__INCLUDE_DIRS} CACHE PATH "Jansson include directories")
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/JanssonConfig.cmake.in
|
||||
${PROJECT_BINARY_DIR}/JanssonConfig.cmake
|
||||
@ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/janssonConfig.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/janssonConfig.cmake
|
||||
@ONLY)
|
||||
|
||||
|
||||
# Generate the config file for the installation tree.
|
||||
file(RELATIVE_PATH
|
||||
REL_INCLUDE_DIR
|
||||
"${JANSSON_INSTALL_CMAKE_DIR}"
|
||||
"${JANSSON_INSTALL_INCLUDE_DIR}") # Calculate the relative directory from the Cmake dir.
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
# Note the EVENT_CMAKE_DIR is defined in JanssonConfig.cmake.in,
|
||||
# we escape it here so it's evaluated when it is included instead
|
||||
# so that the include dirs are given relative to where the
|
||||
# config file is located.
|
||||
set(JANSSON__INCLUDE_DIRS
|
||||
"\${JANSSON_CMAKE_DIR}/${REL_INCLUDE_DIR}")
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/JanssonConfig.cmake.in
|
||||
${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/JanssonConfig.cmake
|
||||
@ONLY)
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfigVersion.cmake"
|
||||
VERSION ${JANSSON_VERSION}
|
||||
COMPATIBILITY ExactVersion
|
||||
)
|
||||
|
||||
# Generate version info for both build-tree and install-tree.
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/JanssonConfigVersion.cmake.in
|
||||
${PROJECT_BINARY_DIR}/JanssonConfigVersion.cmake
|
||||
@ONLY)
|
||||
|
||||
# Define the public headers.
|
||||
set_target_properties(jansson PROPERTIES PUBLIC_HEADER "${JANSSON_HDR_PUBLIC}")
|
||||
#TODO: fix this.
|
||||
configure_package_config_file(
|
||||
"cmake/janssonConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfig.cmake"
|
||||
INSTALL_DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}"
|
||||
)
|
||||
|
||||
#
|
||||
# Install targets.
|
||||
#
|
||||
option(JANSSON_INSTALL "Generate installation target" ON)
|
||||
if (JANSSON_INSTALL)
|
||||
install(TARGETS jansson
|
||||
EXPORT JanssonTargets
|
||||
LIBRARY DESTINATION "${JANSSON_INSTALL_LIB_DIR}" COMPONENT lib
|
||||
ARCHIVE DESTINATION "${JANSSON_INSTALL_LIB_DIR}" COMPONENT lib
|
||||
RUNTIME DESTINATION "${JANSSON_INSTALL_BIN_DIR}" COMPONENT lib # Windows DLLs
|
||||
PUBLIC_HEADER DESTINATION "${JANSSON_INSTALL_INCLUDE_DIR}" COMPONENT dev)
|
||||
install(TARGETS jansson
|
||||
EXPORT janssonTargets
|
||||
LIBRARY DESTINATION "lib"
|
||||
ARCHIVE DESTINATION "lib"
|
||||
RUNTIME DESTINATION "bin"
|
||||
INCLUDES DESTINATION "include")
|
||||
|
||||
# Install the pkg-config.
|
||||
install (FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/jansson.pc
|
||||
DESTINATION ${JANSSON_INSTALL_LIB_DIR}/pkgconfig COMPONENT dev)
|
||||
install(FILES ${JANSSON_HDR_PUBLIC}
|
||||
DESTINATION "include")
|
||||
|
||||
# Install the configs.
|
||||
install(FILES
|
||||
${PROJECT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/JanssonConfig.cmake
|
||||
${PROJECT_BINARY_DIR}/JanssonConfigVersion.cmake
|
||||
DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}" COMPONENT dev)
|
||||
# Install the pkg-config.
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/jansson.pc
|
||||
DESTINATION lib/pkgconfig)
|
||||
|
||||
# Install exports for the install-tree.
|
||||
install(EXPORT JanssonTargets
|
||||
DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}" COMPONENT dev)
|
||||
# Install the configs.
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfig.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfigVersion.cmake
|
||||
DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}")
|
||||
|
||||
# Install exports for the install-tree.
|
||||
install(EXPORT janssonTargets
|
||||
NAMESPACE jansson::
|
||||
DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}")
|
||||
endif()
|
||||
|
||||
# For use when simply using add_library from a parent project to build jansson.
|
||||
set(JANSSON_LIBRARIES jansson CACHE STRING "Jansson libraries")
|
||||
set(JANSSON_LIBRARIES jansson CACHE STRING "jansson libraries")
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
|
||||
Copyright (c) 2009-2018 Petri Lehtinen <petri@digip.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -30,8 +30,8 @@ source distribution for details.
|
||||
Compilation and Installation
|
||||
----------------------------
|
||||
|
||||
If you obtained a source tarball, just use the standard autotools
|
||||
commands::
|
||||
If you obtained a `source tarball`_ from the "Releases" section of the main
|
||||
site just use the standard autotools commands::
|
||||
|
||||
$ ./configure
|
||||
$ make
|
||||
@@ -65,4 +65,5 @@ Then, point your browser to ``doc/_build/html/index.html``. Sphinx_
|
||||
.. _Jansson: http://www.digip.org/jansson/
|
||||
.. _`Comprehensive documentation`: http://jansson.readthedocs.io/en/latest/
|
||||
.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php
|
||||
.. _`source tarball`: http://www.digip.org/jansson#releases
|
||||
.. _Sphinx: http://sphinx.pocoo.org/
|
||||
|
||||
@@ -5,6 +5,8 @@ environment:
|
||||
- VS: Visual Studio 11 2012
|
||||
- VS: Visual Studio 12 2013
|
||||
- VS: Visual Studio 14 2015
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
VS: Visual Studio 15 2017
|
||||
|
||||
build_script:
|
||||
- md build
|
||||
|
||||
@@ -110,9 +110,9 @@ FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _outputname _testrunner)
|
||||
COMMAND ${_testrunner} ${ARGV3}
|
||||
|
||||
# Capturing lcov counters and generating report
|
||||
COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info
|
||||
COMMAND ${LCOV_PATH} --remove ${_outputname}.info 'tests/*' '/usr/*' --output-file ${_outputname}.info.cleaned
|
||||
COMMAND ${GENHTML_PATH} -o ${_outputname} ${_outputname}.info.cleaned
|
||||
COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info --rc lcov_branch_coverage=1
|
||||
COMMAND ${LCOV_PATH} --remove ${_outputname}.info '*/build/include/*' '*/test/*' '/usr/include/*' --output-file ${_outputname}.info.cleaned --rc lcov_branch_coverage=1
|
||||
COMMAND ${GENHTML_PATH} --branch-coverage -o ${_outputname} ${_outputname}.info.cleaned
|
||||
COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned
|
||||
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# - Config file for the jansson package
|
||||
# It defines the following variables
|
||||
# JANSSON_INCLUDE_DIRS - include directories for FooBar
|
||||
# JANSSON_LIBRARIES - libraries to link against
|
||||
|
||||
# Get the path of the current file.
|
||||
get_filename_component(JANSSON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
|
||||
# Set the include directories.
|
||||
set(JANSSON_INCLUDE_DIRS "@JANSSON__INCLUDE_DIRS@")
|
||||
|
||||
# Include the project Targets file, this contains definitions for IMPORTED targets.
|
||||
include(${JANSSON_CMAKE_DIR}/JanssonTargets.cmake)
|
||||
|
||||
# IMPORTED targets from JanssonTargets.cmake
|
||||
set(JANSSON_LIBRARIES jansson)
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
set(PACKAGE_VERSION "@JANSSON_DISPLAY_VERSION@")
|
||||
|
||||
# Check whether the requested PACKAGE_FIND_VERSION is compatible
|
||||
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
4
cmake/janssonConfig.cmake.in
Normal file
4
cmake/janssonConfig.cmake.in
Normal file
@@ -0,0 +1,4 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/janssonTargets.cmake")
|
||||
check_required_components("@PROJECT_NAME@")
|
||||
@@ -59,10 +59,16 @@
|
||||
/* If locale.h and localeconv() are available, define to 1, otherwise to 0. */
|
||||
#define JSON_HAVE_LOCALECONV @JSON_HAVE_LOCALECONV@
|
||||
|
||||
/* If __atomic builtins are available they will be used to manage
|
||||
reference counts of json_t. */
|
||||
#define JSON_HAVE_ATOMIC_BUILTINS @JSON_HAVE_ATOMIC_BUILTINS@
|
||||
|
||||
/* If __atomic builtins are not available we try using __sync builtins
|
||||
to manage reference counts of json_t. */
|
||||
#define JSON_HAVE_SYNC_BUILTINS @JSON_HAVE_SYNC_BUILTINS@
|
||||
|
||||
/* Maximum recursion depth for parsing JSON input.
|
||||
This limits the depth of e.g. array-within-array constructions. */
|
||||
#define JSON_PARSER_MAX_DEPTH 2048
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
40
configure.ac
40
configure.ac
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ([2.60])
|
||||
AC_INIT([jansson], [2.11], [petri@digip.org])
|
||||
AC_INIT([jansson], [2.12], [petri@digip.org])
|
||||
|
||||
AC_CONFIG_AUX_DIR([.])
|
||||
AM_INIT_AUTOMAKE([1.10 foreign])
|
||||
@@ -107,8 +107,44 @@ AC_ARG_ENABLE([initial-hashtable-order],
|
||||
AC_DEFINE_UNQUOTED([INITIAL_HASHTABLE_ORDER], [$initial_hashtable_order],
|
||||
[Number of buckets new object hashtables contain is 2 raised to this power. E.g. 3 -> 2^3 = 8.])
|
||||
|
||||
AC_ARG_ENABLE([Bsymbolic],
|
||||
[AS_HELP_STRING([--disable-Bsymbolic],
|
||||
[Avoid linking with -Bsymbolic-function])],
|
||||
[], [with_Bsymbolic=check])
|
||||
|
||||
if test "x$with_Bsymbolic" != "xno" ; then
|
||||
AC_MSG_CHECKING([for -Bsymbolic-functions linker flag])
|
||||
saved_LDFLAGS="${LDFLAGS}"
|
||||
LDFLAGS=-Wl,-Bsymbolic-functions
|
||||
AC_TRY_LINK(
|
||||
[], [int main (void) { return 0; }],
|
||||
[AC_MSG_RESULT([yes])
|
||||
have_Bsymbolic=yes],
|
||||
[AC_MSG_RESULT([no])
|
||||
have_Bsymbolic=no]
|
||||
)
|
||||
LDFLAGS="${saved_LDFLAGS}"
|
||||
|
||||
if test "x$with_Bsymbolic" = "xcheck" ; then
|
||||
with_Bsymbolic=$have_Bsymbolic;
|
||||
fi
|
||||
if test "x$with_Bsymbolic:x$have_Bsymbolic" = "xyes:xno" ; then
|
||||
AC_MSG_ERROR([linker support is required for -Bsymbolic])
|
||||
fi
|
||||
fi
|
||||
|
||||
AS_IF([test "x$with_Bsymbolic" = "xyes"], [JSON_BSYMBOLIC_LDFLAGS=-Wl[,]-Bsymbolic-functions])
|
||||
AC_SUBST(JSON_BSYMBOLIC_LDFLAGS)
|
||||
|
||||
if test x$GCC = xyes; then
|
||||
AM_CFLAGS="-Wall -Wextra -Wdeclaration-after-statement"
|
||||
AC_MSG_CHECKING(for -Wno-format-truncation)
|
||||
wnoformat_truncation="-Wno-format-truncation"
|
||||
AS_IF([${CC} -Wno-format-truncation -Werror -S -o /dev/null -xc /dev/null > /dev/null 2>&1],
|
||||
[AC_MSG_RESULT(yes)],
|
||||
[AC_MSG_RESULT(no)
|
||||
wnoformat_truncation=""])
|
||||
|
||||
AM_CFLAGS="-Wall -Wextra -Wdeclaration-after-statement -Wshadow ${wnoformat_truncation}"
|
||||
fi
|
||||
AC_SUBST([AM_CFLAGS])
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ copyright = u'2009-2016, Petri Lehtinen'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '2.11'
|
||||
version = '2.12'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = version
|
||||
|
||||
|
||||
@@ -101,7 +101,22 @@ Creating Visual Studio project files from the command line:
|
||||
|
||||
md build
|
||||
cd build
|
||||
cmake -G "Visual Studio 10" ..
|
||||
cmake -G "Visual Studio 15 2017" ..
|
||||
|
||||
.. note::
|
||||
|
||||
You should replace the name of the generator (``-G`` flag) matching
|
||||
the Visual Studio version installed on your system. Currently, the
|
||||
following versions are supported:
|
||||
|
||||
- ``Visual Studio 9 2008``
|
||||
- ``Visual Studio 10 2010``
|
||||
- ``Visual Studio 11 2012``
|
||||
- ``Visual Studio 12 2013``
|
||||
- ``Visual Studio 14 2015``
|
||||
- ``Visual Studio 15 2017``
|
||||
|
||||
Any later version should also work.
|
||||
|
||||
You will now have a *Visual Studio Solution* in your build directory.
|
||||
To run the unit tests build the ``RUN_TESTS`` project.
|
||||
|
||||
@@ -24,4 +24,5 @@ libjansson_la_SOURCES = \
|
||||
libjansson_la_LDFLAGS = \
|
||||
-no-undefined \
|
||||
-export-symbols-regex '^json_' \
|
||||
-version-info 15:0:11
|
||||
-version-info 15:1:11 \
|
||||
@JSON_BSYMBOLIC_LDFLAGS@
|
||||
|
||||
12
src/dump.c
12
src/dump.c
@@ -61,8 +61,8 @@ static int dump_to_file(const char *buffer, size_t size, void *data)
|
||||
|
||||
static int dump_to_fd(const char *buffer, size_t size, void *data)
|
||||
{
|
||||
int *dest = (int *)data;
|
||||
#ifdef HAVE_UNISTD_H
|
||||
int *dest = (int *)data;
|
||||
if(write(*dest, buffer, size) == (ssize_t)size)
|
||||
return 0;
|
||||
#endif
|
||||
@@ -101,7 +101,7 @@ static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t
|
||||
static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags)
|
||||
{
|
||||
const char *pos, *end, *lim;
|
||||
int32_t codepoint;
|
||||
int32_t codepoint = 0;
|
||||
|
||||
if(dump("\"", 1, data))
|
||||
return -1;
|
||||
@@ -306,7 +306,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
|
||||
const char *separator;
|
||||
int separator_length;
|
||||
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
|
||||
char key[2 + (sizeof(json) * 2) + 1];
|
||||
char loop_key[2 + (sizeof(json) * 2) + 1];
|
||||
|
||||
if(flags & JSON_COMPACT) {
|
||||
separator = ":";
|
||||
@@ -318,7 +318,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
|
||||
}
|
||||
|
||||
/* detect circular references */
|
||||
if (loop_check(parents, json, key, sizeof(key)))
|
||||
if (loop_check(parents, json, loop_key, sizeof(loop_key)))
|
||||
return -1;
|
||||
|
||||
iter = json_object_iter((json_t *)json);
|
||||
@@ -326,7 +326,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
|
||||
if(!embed && dump("{", 1, data))
|
||||
return -1;
|
||||
if(!iter) {
|
||||
hashtable_del(parents, key);
|
||||
hashtable_del(parents, loop_key);
|
||||
return embed ? 0 : dump("}", 1, data);
|
||||
}
|
||||
if(dump_indent(flags, depth + 1, 0, dump, data))
|
||||
@@ -422,7 +422,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
|
||||
}
|
||||
}
|
||||
|
||||
hashtable_del(parents, key);
|
||||
hashtable_del(parents, loop_key);
|
||||
return embed ? 0 : dump("}", 1, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ void jsonp_error_set_source(json_error_t *error, const char *source)
|
||||
strncpy(error->source, source, length + 1);
|
||||
else {
|
||||
size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4;
|
||||
strncpy(error->source, "...", 3);
|
||||
memcpy(error->source, "...", 3);
|
||||
strncpy(error->source + 3, source + extra, length - extra + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ typedef struct hashtable {
|
||||
*
|
||||
* Returns 0 on success, -1 on error (out of memory).
|
||||
*/
|
||||
int hashtable_init(hashtable_t *hashtable);
|
||||
int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS(warn_unused_result);
|
||||
|
||||
/**
|
||||
* hashtable_close - Release all resources used by a hashtable object
|
||||
|
||||
@@ -164,7 +164,7 @@ static int seed_from_timestamp_and_pid(uint32_t *seed) {
|
||||
}
|
||||
|
||||
static uint32_t generate_seed() {
|
||||
uint32_t seed;
|
||||
uint32_t seed = 0;
|
||||
int done = 0;
|
||||
|
||||
#if !defined(_WIN32) && defined(USE_URANDOM)
|
||||
|
||||
@@ -21,11 +21,11 @@ extern "C" {
|
||||
/* version */
|
||||
|
||||
#define JANSSON_MAJOR_VERSION 2
|
||||
#define JANSSON_MINOR_VERSION 11
|
||||
#define JANSSON_MINOR_VERSION 12
|
||||
#define JANSSON_MICRO_VERSION 0
|
||||
|
||||
/* Micro version is omitted if it's 0 */
|
||||
#define JANSSON_VERSION "2.11"
|
||||
#define JANSSON_VERSION "2.12"
|
||||
|
||||
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
|
||||
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
|
||||
@@ -39,6 +39,12 @@ extern "C" {
|
||||
#define JANSSON_THREAD_SAFE_REFCOUNT 1
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define JANSSON_ATTRS(...) __attribute__((__VA_ARGS__))
|
||||
#else
|
||||
#define JANSSON_ATTRS(...)
|
||||
#endif
|
||||
|
||||
/* types */
|
||||
|
||||
typedef enum {
|
||||
@@ -185,7 +191,7 @@ static JSON_INLINE enum json_error_code json_error_code(const json_error_t *e) {
|
||||
|
||||
void json_object_seed(size_t seed);
|
||||
size_t json_object_size(const json_t *object);
|
||||
json_t *json_object_get(const json_t *object, const char *key);
|
||||
json_t *json_object_get(const json_t *object, const char *key) JANSSON_ATTRS(warn_unused_result);
|
||||
int json_object_set_new(json_t *object, const char *key, json_t *value);
|
||||
int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
|
||||
int json_object_del(json_t *object, const char *key);
|
||||
@@ -237,7 +243,7 @@ int json_object_iter_set(json_t *object, void *iter, json_t *value)
|
||||
}
|
||||
|
||||
size_t json_array_size(const json_t *array);
|
||||
json_t *json_array_get(const json_t *array, size_t index);
|
||||
json_t *json_array_get(const json_t *array, size_t index) JANSSON_ATTRS(warn_unused_result);
|
||||
int json_array_set_new(json_t *array, size_t index, json_t *value);
|
||||
int json_array_append_new(json_t *array, json_t *value);
|
||||
int json_array_insert_new(json_t *array, size_t index, json_t *value);
|
||||
@@ -278,9 +284,9 @@ int json_real_set(json_t *real, double value);
|
||||
|
||||
/* pack, unpack */
|
||||
|
||||
json_t *json_pack(const char *fmt, ...);
|
||||
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...);
|
||||
json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap);
|
||||
json_t *json_pack(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result);
|
||||
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) JANSSON_ATTRS(warn_unused_result);
|
||||
json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result);
|
||||
|
||||
#define JSON_VALIDATE_ONLY 0x1
|
||||
#define JSON_STRICT 0x2
|
||||
@@ -291,8 +297,8 @@ int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char
|
||||
|
||||
/* sprintf */
|
||||
|
||||
json_t *json_sprintf(const char *fmt, ...);
|
||||
json_t *json_vsprintf(const char *fmt, va_list ap);
|
||||
json_t *json_sprintf(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 2));
|
||||
json_t *json_vsprintf(const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 0));
|
||||
|
||||
|
||||
/* equality */
|
||||
@@ -302,8 +308,8 @@ int json_equal(const json_t *value1, const json_t *value2);
|
||||
|
||||
/* copying */
|
||||
|
||||
json_t *json_copy(json_t *value);
|
||||
json_t *json_deep_copy(const json_t *value);
|
||||
json_t *json_copy(json_t *value) JANSSON_ATTRS(warn_unused_result);
|
||||
json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS(warn_unused_result);
|
||||
|
||||
|
||||
/* decoding */
|
||||
@@ -316,12 +322,12 @@ json_t *json_deep_copy(const json_t *value);
|
||||
|
||||
typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
|
||||
|
||||
json_t *json_loads(const char *input, size_t flags, json_error_t *error);
|
||||
json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error);
|
||||
json_t *json_loadf(FILE *input, size_t flags, json_error_t *error);
|
||||
json_t *json_loadfd(int input, size_t flags, json_error_t *error);
|
||||
json_t *json_load_file(const char *path, size_t flags, json_error_t *error);
|
||||
json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error);
|
||||
json_t *json_loads(const char *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
|
||||
json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
|
||||
json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
|
||||
json_t *json_loadfd(int input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
|
||||
json_t *json_load_file(const char *path, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
|
||||
json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result);
|
||||
|
||||
|
||||
/* encoding */
|
||||
@@ -339,7 +345,7 @@ json_t *json_load_callback(json_load_callback_t callback, void *data, size_t fla
|
||||
|
||||
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
|
||||
|
||||
char *json_dumps(const json_t *json, size_t flags);
|
||||
char *json_dumps(const json_t *json, size_t flags) JANSSON_ATTRS(warn_unused_result);
|
||||
size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags);
|
||||
int json_dumpf(const json_t *json, FILE *output, size_t flags);
|
||||
int json_dumpfd(const json_t *json, int output, size_t flags);
|
||||
|
||||
@@ -84,11 +84,11 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out);
|
||||
int jsonp_dtostr(char *buffer, size_t size, double value, int prec);
|
||||
|
||||
/* Wrappers for custom memory functions */
|
||||
void* jsonp_malloc(size_t size);
|
||||
void* jsonp_malloc(size_t size) JANSSON_ATTRS(warn_unused_result);
|
||||
void jsonp_free(void *ptr);
|
||||
char *jsonp_strndup(const char *str, size_t length);
|
||||
char *jsonp_strdup(const char *str);
|
||||
char *jsonp_strndup(const char *str, size_t len);
|
||||
char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS(warn_unused_result);
|
||||
char *jsonp_strdup(const char *str) JANSSON_ATTRS(warn_unused_result);
|
||||
char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS(warn_unused_result);
|
||||
|
||||
|
||||
/* Windows compatibility */
|
||||
|
||||
@@ -829,10 +829,8 @@ static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
|
||||
}
|
||||
|
||||
json = jsonp_stringn_nocheck_own(value, len);
|
||||
if(json) {
|
||||
lex->value.string.val = NULL;
|
||||
lex->value.string.len = 0;
|
||||
}
|
||||
lex->value.string.val = NULL;
|
||||
lex->value.string.len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1036,8 +1034,8 @@ json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
|
||||
|
||||
static int fd_get_func(int *fd)
|
||||
{
|
||||
uint8_t c;
|
||||
#ifdef HAVE_UNISTD_H
|
||||
uint8_t c;
|
||||
if (read(*fd, &c, 1) == 1)
|
||||
return c;
|
||||
#endif
|
||||
|
||||
@@ -75,6 +75,9 @@ static void next_token(scanner_t *s)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!token(s) && !*s->fmt)
|
||||
return;
|
||||
|
||||
t = s->fmt;
|
||||
s->column++;
|
||||
s->pos++;
|
||||
@@ -97,7 +100,7 @@ static void next_token(scanner_t *s)
|
||||
s->token.column = s->column;
|
||||
s->token.pos = s->pos;
|
||||
|
||||
t++;
|
||||
if (*t) t++;
|
||||
s->fmt = t;
|
||||
}
|
||||
|
||||
@@ -127,7 +130,7 @@ static json_t *pack(scanner_t *s, va_list *ap);
|
||||
/* ours will be set to 1 if jsonp_free() must be called for the result
|
||||
afterwards */
|
||||
static char *read_string(scanner_t *s, va_list *ap,
|
||||
const char *purpose, size_t *out_len, int *ours)
|
||||
const char *purpose, size_t *out_len, int *ours, int optional)
|
||||
{
|
||||
char t;
|
||||
strbuffer_t strbuff;
|
||||
@@ -144,7 +147,10 @@ static char *read_string(scanner_t *s, va_list *ap,
|
||||
str = va_arg(*ap, const char *);
|
||||
|
||||
if(!str) {
|
||||
set_error(s, "<args>", json_error_null_value, "NULL string argument");
|
||||
if (!optional) {
|
||||
set_error(s, "<args>", json_error_null_value, "NULL %s", purpose);
|
||||
s->has_error = 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -152,19 +158,28 @@ static char *read_string(scanner_t *s, va_list *ap,
|
||||
|
||||
if(!utf8_check_string(str, length)) {
|
||||
set_error(s, "<args>", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose);
|
||||
s->has_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*out_len = length;
|
||||
return (char *)str;
|
||||
} else if (optional) {
|
||||
set_error(s, "<format>", json_error_invalid_format, "Cannot use '%c' on optional strings", t);
|
||||
s->has_error = 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strbuffer_init(&strbuff);
|
||||
if(strbuffer_init(&strbuff)) {
|
||||
set_error(s, "<internal>", json_error_out_of_memory, "Out of memory");
|
||||
s->has_error = 1;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
str = va_arg(*ap, const char *);
|
||||
if(!str) {
|
||||
set_error(s, "<args>", json_error_null_value, "NULL string argument");
|
||||
set_error(s, "<args>", json_error_null_value, "NULL %s", purpose);
|
||||
s->has_error = 1;
|
||||
}
|
||||
|
||||
@@ -220,6 +235,7 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
|
||||
size_t len;
|
||||
int ours;
|
||||
json_t *value;
|
||||
char valueOptional;
|
||||
|
||||
if(!token(s)) {
|
||||
set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
|
||||
@@ -231,20 +247,21 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
|
||||
goto error;
|
||||
}
|
||||
|
||||
key = read_string(s, ap, "object key", &len, &ours);
|
||||
if (!key)
|
||||
s->has_error = 1;
|
||||
key = read_string(s, ap, "object key", &len, &ours, 0);
|
||||
|
||||
next_token(s);
|
||||
|
||||
next_token(s);
|
||||
valueOptional = token(s);
|
||||
prev_token(s);
|
||||
|
||||
value = pack(s, ap);
|
||||
if(!value) {
|
||||
if(ours)
|
||||
jsonp_free(key);
|
||||
|
||||
if(strchr("soO", token(s)) && s->next_token.token == '*') {
|
||||
next_token(s);
|
||||
} else {
|
||||
if(valueOptional != '*') {
|
||||
set_error(s, "<args>", json_error_null_value, "NULL object value");
|
||||
s->has_error = 1;
|
||||
}
|
||||
|
||||
@@ -263,8 +280,6 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
|
||||
if(ours)
|
||||
jsonp_free(key);
|
||||
|
||||
if(strchr("soO", token(s)) && s->next_token.token == '*')
|
||||
next_token(s);
|
||||
next_token(s);
|
||||
}
|
||||
|
||||
@@ -283,6 +298,7 @@ static json_t *pack_array(scanner_t *s, va_list *ap)
|
||||
|
||||
while(token(s) != ']') {
|
||||
json_t *value;
|
||||
char valueOptional;
|
||||
|
||||
if(!token(s)) {
|
||||
set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
|
||||
@@ -290,11 +306,13 @@ static json_t *pack_array(scanner_t *s, va_list *ap)
|
||||
goto error;
|
||||
}
|
||||
|
||||
next_token(s);
|
||||
valueOptional = token(s);
|
||||
prev_token(s);
|
||||
|
||||
value = pack(s, ap);
|
||||
if(!value) {
|
||||
if(strchr("soO", token(s)) && s->next_token.token == '*') {
|
||||
next_token(s);
|
||||
} else {
|
||||
if(valueOptional != '*') {
|
||||
s->has_error = 1;
|
||||
}
|
||||
|
||||
@@ -310,8 +328,6 @@ static json_t *pack_array(scanner_t *s, va_list *ap)
|
||||
s->has_error = 1;
|
||||
}
|
||||
|
||||
if(strchr("soO", token(s)) && s->next_token.token == '*')
|
||||
next_token(s);
|
||||
next_token(s);
|
||||
}
|
||||
|
||||
@@ -326,23 +342,97 @@ error:
|
||||
static json_t *pack_string(scanner_t *s, va_list *ap)
|
||||
{
|
||||
char *str;
|
||||
char t;
|
||||
size_t len;
|
||||
int ours;
|
||||
int nullable;
|
||||
int optional;
|
||||
|
||||
next_token(s);
|
||||
nullable = token(s) == '?';
|
||||
if (!nullable)
|
||||
t = token(s);
|
||||
optional = t == '?' || t == '*';
|
||||
if (!optional)
|
||||
prev_token(s);
|
||||
|
||||
str = read_string(s, ap, "string", &len, &ours);
|
||||
if (!str) {
|
||||
return nullable ? json_null() : NULL;
|
||||
} else if (ours) {
|
||||
return jsonp_stringn_nocheck_own(str, len);
|
||||
} else {
|
||||
return json_stringn_nocheck(str, len);
|
||||
str = read_string(s, ap, "string", &len, &ours, optional);
|
||||
|
||||
if (!str)
|
||||
return t == '?' && !s->has_error ? json_null() : NULL;
|
||||
|
||||
if (s->has_error) {
|
||||
/* It's impossible to reach this point if ours != 0, do not free str. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ours)
|
||||
return jsonp_stringn_nocheck_own(str, len);
|
||||
|
||||
return json_stringn_nocheck(str, len);
|
||||
}
|
||||
|
||||
static json_t *pack_object_inter(scanner_t *s, va_list *ap, int need_incref)
|
||||
{
|
||||
json_t *json;
|
||||
char ntoken;
|
||||
|
||||
next_token(s);
|
||||
ntoken = token(s);
|
||||
|
||||
if (ntoken != '?' && ntoken != '*')
|
||||
prev_token(s);
|
||||
|
||||
json = va_arg(*ap, json_t *);
|
||||
|
||||
if (json)
|
||||
return need_incref ? json_incref(json) : json;
|
||||
|
||||
switch (ntoken) {
|
||||
case '?':
|
||||
return json_null();
|
||||
case '*':
|
||||
return NULL;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
set_error(s, "<args>", json_error_null_value, "NULL object");
|
||||
s->has_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static json_t *pack_integer(scanner_t *s, json_int_t value)
|
||||
{
|
||||
json_t *json = json_integer(value);
|
||||
|
||||
if (!json) {
|
||||
set_error(s, "<internal>", json_error_out_of_memory, "Out of memory");
|
||||
s->has_error = 1;
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
static json_t *pack_real(scanner_t *s, double value)
|
||||
{
|
||||
/* Allocate without setting value so we can identify OOM error. */
|
||||
json_t *json = json_real(0.0);
|
||||
|
||||
if (!json) {
|
||||
set_error(s, "<internal>", json_error_out_of_memory, "Out of memory");
|
||||
s->has_error = 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (json_real_set(json, value)) {
|
||||
json_decref(json);
|
||||
|
||||
set_error(s, "<args>", json_error_numeric_overflow, "Invalid floating point value");
|
||||
s->has_error = 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
static json_t *pack(scanner_t *s, va_list *ap)
|
||||
@@ -364,49 +454,19 @@ static json_t *pack(scanner_t *s, va_list *ap)
|
||||
return va_arg(*ap, int) ? json_true() : json_false();
|
||||
|
||||
case 'i': /* integer from int */
|
||||
return json_integer(va_arg(*ap, int));
|
||||
return pack_integer(s, va_arg(*ap, int));
|
||||
|
||||
case 'I': /* integer from json_int_t */
|
||||
return json_integer(va_arg(*ap, json_int_t));
|
||||
return pack_integer(s, va_arg(*ap, json_int_t));
|
||||
|
||||
case 'f': /* real */
|
||||
return json_real(va_arg(*ap, double));
|
||||
return pack_real(s, va_arg(*ap, double));
|
||||
|
||||
case 'O': /* a json_t object; increments refcount */
|
||||
{
|
||||
int nullable;
|
||||
json_t *json;
|
||||
|
||||
next_token(s);
|
||||
nullable = token(s) == '?';
|
||||
if (!nullable)
|
||||
prev_token(s);
|
||||
|
||||
json = va_arg(*ap, json_t *);
|
||||
if (!json && nullable) {
|
||||
return json_null();
|
||||
} else {
|
||||
return json_incref(json);
|
||||
}
|
||||
}
|
||||
return pack_object_inter(s, ap, 1);
|
||||
|
||||
case 'o': /* a json_t object; doesn't increment refcount */
|
||||
{
|
||||
int nullable;
|
||||
json_t *json;
|
||||
|
||||
next_token(s);
|
||||
nullable = token(s) == '?';
|
||||
if (!nullable)
|
||||
prev_token(s);
|
||||
|
||||
json = va_arg(*ap, json_t *);
|
||||
if (!json && nullable) {
|
||||
return json_null();
|
||||
} else {
|
||||
return json;
|
||||
}
|
||||
}
|
||||
return pack_object_inter(s, ap, 0);
|
||||
|
||||
default:
|
||||
set_error(s, "<format>", json_error_invalid_format, "Unexpected format character '%c'",
|
||||
@@ -508,48 +568,34 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
|
||||
if(root && strict == 1) {
|
||||
/* We need to check that all non optional items have been parsed */
|
||||
const char *key;
|
||||
int have_unrecognized_keys = 0;
|
||||
/* keys_res is 1 for uninitialized, 0 for success, -1 for error. */
|
||||
int keys_res = 1;
|
||||
strbuffer_t unrecognized_keys;
|
||||
json_t *value;
|
||||
long unpacked = 0;
|
||||
if (gotopt) {
|
||||
/* We have optional keys, we need to iter on each key */
|
||||
|
||||
if (gotopt || json_object_size(root) != key_set.size) {
|
||||
json_object_foreach(root, key, value) {
|
||||
if(!hashtable_get(&key_set, key)) {
|
||||
unpacked++;
|
||||
|
||||
/* Save unrecognized keys for the error message */
|
||||
if (!have_unrecognized_keys) {
|
||||
strbuffer_init(&unrecognized_keys);
|
||||
have_unrecognized_keys = 1;
|
||||
} else {
|
||||
strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
|
||||
if (keys_res == 1) {
|
||||
keys_res = strbuffer_init(&unrecognized_keys);
|
||||
} else if (!keys_res) {
|
||||
keys_res = strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
|
||||
}
|
||||
strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
|
||||
|
||||
if (!keys_res)
|
||||
keys_res = strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* No optional keys, we can just compare the number of items */
|
||||
unpacked = (long)json_object_size(root) - (long)key_set.size;
|
||||
}
|
||||
if (unpacked) {
|
||||
if (!gotopt) {
|
||||
/* Save unrecognized keys for the error message */
|
||||
json_object_foreach(root, key, value) {
|
||||
if(!hashtable_get(&key_set, key)) {
|
||||
if (!have_unrecognized_keys) {
|
||||
strbuffer_init(&unrecognized_keys);
|
||||
have_unrecognized_keys = 1;
|
||||
} else {
|
||||
strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
|
||||
}
|
||||
strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
set_error(s, "<validation>", json_error_end_of_input_expected,
|
||||
"%li object item(s) left unpacked: %s",
|
||||
unpacked, strbuffer_value(&unrecognized_keys));
|
||||
unpacked,
|
||||
keys_res ? "<unknown>" : strbuffer_value(&unrecognized_keys));
|
||||
strbuffer_close(&unrecognized_keys);
|
||||
goto out;
|
||||
}
|
||||
@@ -805,6 +851,7 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags,
|
||||
value = pack(&s, &ap_copy);
|
||||
va_end(ap_copy);
|
||||
|
||||
/* This will cover all situations where s.has_error is true */
|
||||
if(!value)
|
||||
return NULL;
|
||||
|
||||
@@ -814,10 +861,6 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags,
|
||||
set_error(&s, "<format>", json_error_invalid_format, "Garbage after format string");
|
||||
return NULL;
|
||||
}
|
||||
if(s.has_error) {
|
||||
json_decref(value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ typedef struct {
|
||||
size_t size; /* bytes allocated */
|
||||
} strbuffer_t;
|
||||
|
||||
int strbuffer_init(strbuffer_t *strbuff);
|
||||
int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS(warn_unused_result);
|
||||
void strbuffer_close(strbuffer_t *strbuff);
|
||||
|
||||
void strbuffer_clear(strbuffer_t *strbuff);
|
||||
|
||||
30
src/value.c
30
src/value.c
@@ -652,8 +652,7 @@ static json_t *string_create(const char *value, size_t len, int own)
|
||||
|
||||
string = jsonp_malloc(sizeof(json_string_t));
|
||||
if(!string) {
|
||||
if(!own)
|
||||
jsonp_free(v);
|
||||
jsonp_free(v);
|
||||
return NULL;
|
||||
}
|
||||
json_init(&string->json, JSON_STRING);
|
||||
@@ -768,9 +767,6 @@ static int json_string_equal(const json_t *string1, const json_t *string2)
|
||||
{
|
||||
json_string_t *s1, *s2;
|
||||
|
||||
if(!json_is_string(string1) || !json_is_string(string2))
|
||||
return 0;
|
||||
|
||||
s1 = json_to_string(string1);
|
||||
s2 = json_to_string(string2);
|
||||
return s1->length == s2->length && !memcmp(s1->value, s2->value, s1->length);
|
||||
@@ -780,34 +776,38 @@ static json_t *json_string_copy(const json_t *string)
|
||||
{
|
||||
json_string_t *s;
|
||||
|
||||
if(!json_is_string(string))
|
||||
return NULL;
|
||||
|
||||
s = json_to_string(string);
|
||||
return json_stringn_nocheck(s->value, s->length);
|
||||
}
|
||||
|
||||
json_t *json_vsprintf(const char *fmt, va_list ap) {
|
||||
json_t *json = NULL;
|
||||
int length;
|
||||
char *buf;
|
||||
va_list aq;
|
||||
va_copy(aq, ap);
|
||||
|
||||
length = vsnprintf(NULL, 0, fmt, ap);
|
||||
if (length == 0)
|
||||
return json_string("");
|
||||
if (length == 0) {
|
||||
json = json_string("");
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = jsonp_malloc(length + 1);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
goto out;
|
||||
|
||||
vsnprintf(buf, length + 1, fmt, aq);
|
||||
if (!utf8_check_string(buf, length)) {
|
||||
jsonp_free(buf);
|
||||
return NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return jsonp_stringn_nocheck_own(buf, length);
|
||||
json = jsonp_stringn_nocheck_own(buf, length);
|
||||
|
||||
out:
|
||||
va_end(aq);
|
||||
return json;
|
||||
}
|
||||
|
||||
json_t *json_sprintf(const char *fmt, ...) {
|
||||
@@ -1044,8 +1044,6 @@ json_t *json_copy(json_t *json)
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
json_t *json_deep_copy(const json_t *json)
|
||||
@@ -1073,6 +1071,4 @@ json_t *json_deep_copy(const json_t *json)
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
1
test/.gitignore
vendored
1
test/.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
logs
|
||||
bin/json_process
|
||||
suites/api/test_array
|
||||
suites/api/test_chaos
|
||||
suites/api/test_copy
|
||||
suites/api/test_cpp
|
||||
suites/api/test_dump
|
||||
|
||||
@@ -2,6 +2,7 @@ EXTRA_DIST = run check-exports
|
||||
|
||||
check_PROGRAMS = \
|
||||
test_array \
|
||||
test_chaos \
|
||||
test_copy \
|
||||
test_dump \
|
||||
test_dump_callback \
|
||||
@@ -18,6 +19,7 @@ check_PROGRAMS = \
|
||||
test_unpack
|
||||
|
||||
test_array_SOURCES = test_array.c util.h
|
||||
test_chaos_SOURCES = test_chaos.c util.h
|
||||
test_copy_SOURCES = test_copy.c util.h
|
||||
test_dump_SOURCES = test_dump.c util.h
|
||||
test_dump_callback_SOURCES = test_dump_callback.c util.h
|
||||
|
||||
@@ -419,6 +419,78 @@ static void test_array_foreach()
|
||||
json_decref(array2);
|
||||
}
|
||||
|
||||
static void test_bad_args(void)
|
||||
{
|
||||
json_t *arr = json_array();
|
||||
json_t *num = json_integer(1);
|
||||
|
||||
if(!arr || !num)
|
||||
fail("failed to create required objects");
|
||||
|
||||
if(json_array_size(NULL) != 0)
|
||||
fail("NULL array has nonzero size");
|
||||
if(json_array_size(num) != 0)
|
||||
fail("non-array has nonzero array size");
|
||||
|
||||
if(json_array_get(NULL, 0))
|
||||
fail("json_array_get did not return NULL for non-array");
|
||||
if(json_array_get(num, 0))
|
||||
fail("json_array_get did not return NULL for non-array");
|
||||
|
||||
if(!json_array_set_new(NULL, 0, json_incref(num)))
|
||||
fail("json_array_set_new did not return error for non-array");
|
||||
if(!json_array_set_new(num, 0, json_incref(num)))
|
||||
fail("json_array_set_new did not return error for non-array");
|
||||
if(!json_array_set_new(arr, 0, NULL))
|
||||
fail("json_array_set_new did not return error for NULL value");
|
||||
if(!json_array_set_new(arr, 0, json_incref(arr)))
|
||||
fail("json_array_set_new did not return error for value == array");
|
||||
|
||||
if(!json_array_remove(NULL, 0))
|
||||
fail("json_array_remove did not return error for non-array");
|
||||
if(!json_array_remove(num, 0))
|
||||
fail("json_array_remove did not return error for non-array");
|
||||
|
||||
if(!json_array_clear(NULL))
|
||||
fail("json_array_clear did not return error for non-array");
|
||||
if(!json_array_clear(num))
|
||||
fail("json_array_clear did not return error for non-array");
|
||||
|
||||
if(!json_array_append_new(NULL, json_incref(num)))
|
||||
fail("json_array_append_new did not return error for non-array");
|
||||
if(!json_array_append_new(num, json_incref(num)))
|
||||
fail("json_array_append_new did not return error for non-array");
|
||||
if(!json_array_append_new(arr, NULL))
|
||||
fail("json_array_append_new did not return error for NULL value");
|
||||
if(!json_array_append_new(arr, json_incref(arr)))
|
||||
fail("json_array_append_new did not return error for value == array");
|
||||
|
||||
if(!json_array_insert_new(NULL, 0, json_incref(num)))
|
||||
fail("json_array_insert_new did not return error for non-array");
|
||||
if(!json_array_insert_new(num, 0, json_incref(num)))
|
||||
fail("json_array_insert_new did not return error for non-array");
|
||||
if(!json_array_insert_new(arr, 0, NULL))
|
||||
fail("json_array_insert_new did not return error for NULL value");
|
||||
if(!json_array_insert_new(arr, 0, json_incref(arr)))
|
||||
fail("json_array_insert_new did not return error for value == array");
|
||||
|
||||
if(!json_array_extend(NULL, arr))
|
||||
fail("json_array_extend did not return error for first argument non-array");
|
||||
if(!json_array_extend(num, arr))
|
||||
fail("json_array_extend did not return error for first argument non-array");
|
||||
if(!json_array_extend(arr, NULL))
|
||||
fail("json_array_extend did not return error for second arguemnt non-array");
|
||||
if(!json_array_extend(arr, num))
|
||||
fail("json_array_extend did not return error for second arguemnt non-array");
|
||||
|
||||
if(num->refcount != 1)
|
||||
fail("unexpected reference count on num");
|
||||
if(arr->refcount != 1)
|
||||
fail("unexpected reference count on arr");
|
||||
|
||||
json_decref(num);
|
||||
json_decref(arr);
|
||||
}
|
||||
|
||||
static void run_tests()
|
||||
{
|
||||
@@ -429,4 +501,5 @@ static void run_tests()
|
||||
test_extend();
|
||||
test_circular();
|
||||
test_array_foreach();
|
||||
test_bad_args();
|
||||
}
|
||||
|
||||
177
test/suites/api/test_chaos.c
Normal file
177
test/suites/api/test_chaos.c
Normal file
@@ -0,0 +1,177 @@
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <jansson.h>
|
||||
#include "util.h"
|
||||
|
||||
static int chaos_pos = 0;
|
||||
static int chaos_fail = 0;
|
||||
#define CHAOS_MAX_FAILURE 100
|
||||
|
||||
void *chaos_malloc(size_t size)
|
||||
{
|
||||
if (chaos_pos == chaos_fail)
|
||||
return NULL;
|
||||
|
||||
chaos_pos++;
|
||||
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void chaos_free(void *obj)
|
||||
{
|
||||
free(obj);
|
||||
}
|
||||
|
||||
/* Test all potential allocation failures. */
|
||||
#define chaos_loop(condition, code, cleanup) \
|
||||
{ \
|
||||
chaos_pos = chaos_fail = 0; \
|
||||
while (condition) { \
|
||||
if (chaos_fail > CHAOS_MAX_FAILURE) \
|
||||
fail("too many chaos failures"); \
|
||||
code \
|
||||
chaos_pos = 0; \
|
||||
chaos_fail++; \
|
||||
} \
|
||||
cleanup \
|
||||
}
|
||||
|
||||
#define chaos_loop_new_value(json, initcall) \
|
||||
chaos_loop(!json, json = initcall;, json_decref(json); json = NULL;)
|
||||
|
||||
int test_unpack()
|
||||
{
|
||||
int ret = -1;
|
||||
int v1;
|
||||
int v2;
|
||||
json_error_t error;
|
||||
json_t *root = json_pack("{s:i, s:i, s:i, s:i}", "n1", 1, "n2", 2, "n3", 3, "n4", 4);
|
||||
|
||||
if (!root)
|
||||
return -1;
|
||||
|
||||
if (!json_unpack_ex(root, &error, JSON_STRICT, "{s:i, s:i}", "n1", &v1, "n2", &v2))
|
||||
fail("Unexpected success");
|
||||
|
||||
if (json_error_code(&error) != json_error_end_of_input_expected) {
|
||||
if (json_error_code(&error) != json_error_out_of_memory)
|
||||
fail("Unexpected error code");
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strcmp(error.text, "2 object item(s) left unpacked: n3, n4"))
|
||||
goto out;
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
json_decref(root);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dump_chaos_callback(const char *buffer, size_t size, void *data)
|
||||
{
|
||||
json_t *obj = json_object();
|
||||
|
||||
(void)buffer;
|
||||
(void)size;
|
||||
(void)data;
|
||||
|
||||
if (!obj)
|
||||
return -1;
|
||||
|
||||
json_decref(obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_chaos()
|
||||
{
|
||||
json_malloc_t orig_malloc;
|
||||
json_free_t orig_free;
|
||||
json_t *json = NULL;
|
||||
json_t *obj = json_object();
|
||||
json_t *arr1 = json_array();
|
||||
json_t *arr2 = json_array();
|
||||
json_t *txt = json_string("test");
|
||||
json_t *intnum = json_integer(1);
|
||||
json_t *dblnum = json_real(0.5);
|
||||
char *dumptxt = NULL;
|
||||
json_t *dumpobj = json_pack("{s:[iiis], s:s}",
|
||||
"key1", 1, 2, 3, "txt",
|
||||
"key2", "v2");
|
||||
int keyno;
|
||||
|
||||
if (!obj || !arr1 || !arr2 || !txt || !intnum || !dblnum || !dumpobj)
|
||||
fail("failed to allocate basic objects");
|
||||
|
||||
json_get_alloc_funcs(&orig_malloc, &orig_free);
|
||||
json_set_alloc_funcs(chaos_malloc, chaos_free);
|
||||
|
||||
chaos_loop_new_value(json, json_pack("{s:s}", "key", "value"));
|
||||
chaos_loop_new_value(json, json_pack("{s:[]}", "key"));
|
||||
chaos_loop_new_value(json, json_pack("[biIf]", 1, 1, (json_int_t)1, 1.0));
|
||||
chaos_loop_new_value(json, json_pack("[s*,s*]", "v1", "v2"));
|
||||
chaos_loop_new_value(json, json_pack("o", json_incref(txt)));
|
||||
chaos_loop_new_value(json, json_pack("O", txt));
|
||||
chaos_loop_new_value(json, json_pack("s++", "a",
|
||||
"long string to force realloc",
|
||||
"another long string to force yet another reallocation of the string because "
|
||||
"that's what we are testing."));
|
||||
|
||||
chaos_loop(test_unpack(),,);
|
||||
|
||||
chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL, JSON_INDENT(1)),,);
|
||||
chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL, JSON_INDENT(1) | JSON_SORT_KEYS),,);
|
||||
chaos_loop(!dumptxt, dumptxt = json_dumps(dumpobj, JSON_COMPACT);, free(dumptxt); dumptxt = NULL;);
|
||||
|
||||
chaos_loop_new_value(json, json_copy(obj));
|
||||
chaos_loop_new_value(json, json_deep_copy(obj));
|
||||
|
||||
chaos_loop_new_value(json, json_copy(arr1));
|
||||
chaos_loop_new_value(json, json_deep_copy(arr1));
|
||||
|
||||
chaos_loop_new_value(json, json_copy(txt));
|
||||
chaos_loop_new_value(json, json_copy(intnum));
|
||||
chaos_loop_new_value(json, json_copy(dblnum));
|
||||
|
||||
#define JSON_LOAD_TXT "{\"n\":[1,2,3,4,5,6,7,8,9,10]}"
|
||||
chaos_loop_new_value(json, json_loads(JSON_LOAD_TXT, 0, NULL));
|
||||
chaos_loop_new_value(json, json_loadb(JSON_LOAD_TXT, strlen(JSON_LOAD_TXT), 0, NULL));
|
||||
|
||||
chaos_loop_new_value(json, json_sprintf("%s", "string"));
|
||||
|
||||
for (keyno = 0; keyno < 100; ++keyno) {
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1900
|
||||
/* Skip this test on old Windows compilers. */
|
||||
char testkey[10];
|
||||
|
||||
snprintf(testkey, sizeof(testkey), "test%d", keyno);
|
||||
chaos_loop(json_object_set_new_nocheck(obj, testkey, json_object()),,);
|
||||
#endif
|
||||
chaos_loop(json_array_append_new(arr1, json_null()),,);
|
||||
chaos_loop(json_array_insert_new(arr2, 0, json_null()),,);
|
||||
}
|
||||
|
||||
chaos_loop(json_array_extend(arr1, arr2),,);
|
||||
chaos_loop(json_string_set_nocheck(txt, "test"),,);
|
||||
|
||||
json_set_alloc_funcs(orig_malloc, orig_free);
|
||||
json_decref(obj);
|
||||
json_decref(arr1);
|
||||
json_decref(arr2);
|
||||
json_decref(txt);
|
||||
json_decref(intnum);
|
||||
json_decref(dblnum);
|
||||
json_decref(dumpobj);
|
||||
}
|
||||
|
||||
static void run_tests()
|
||||
{
|
||||
test_chaos();
|
||||
}
|
||||
@@ -74,6 +74,13 @@ static void test_equal_simple()
|
||||
fail("unable to create an string");
|
||||
if(json_equal(value1, value2))
|
||||
fail("json_equal fails for two inequal strings");
|
||||
json_decref(value2);
|
||||
|
||||
value2 = json_string("bar2");
|
||||
if(!value2)
|
||||
fail("unable to create an string");
|
||||
if(json_equal(value1, value2))
|
||||
fail("json_equal fails for two inequal length strings");
|
||||
|
||||
json_decref(value1);
|
||||
json_decref(value2);
|
||||
|
||||
@@ -122,9 +122,16 @@ static void test_secure_funcs(void)
|
||||
create_and_free_complex_object();
|
||||
}
|
||||
|
||||
static void test_bad_args(void)
|
||||
{
|
||||
/* The result of this test is not crashing. */
|
||||
json_get_alloc_funcs(NULL, NULL);
|
||||
}
|
||||
|
||||
static void run_tests()
|
||||
{
|
||||
test_simple();
|
||||
test_secure_funcs();
|
||||
test_oom();
|
||||
test_bad_args();
|
||||
}
|
||||
|
||||
@@ -37,6 +37,41 @@ static void test_inifity()
|
||||
}
|
||||
#endif // INFINITY
|
||||
|
||||
static void test_bad_args(void)
|
||||
{
|
||||
json_t *txt = json_string("test");
|
||||
|
||||
if(json_integer_value(NULL) != 0)
|
||||
fail("json_integer_value did not return 0 for non-integer");
|
||||
if(json_integer_value(txt) != 0)
|
||||
fail("json_integer_value did not return 0 for non-integer");
|
||||
|
||||
if(!json_integer_set(NULL, 0))
|
||||
fail("json_integer_set did not return error for non-integer");
|
||||
if(!json_integer_set(txt, 0))
|
||||
fail("json_integer_set did not return error for non-integer");
|
||||
|
||||
if(json_real_value(NULL) != 0.0)
|
||||
fail("json_real_value did not return 0.0 for non-real");
|
||||
if(json_real_value(txt) != 0.0)
|
||||
fail("json_real_value did not return 0.0 for non-real");
|
||||
|
||||
if(!json_real_set(NULL, 0.0))
|
||||
fail("json_real_set did not return error for non-real");
|
||||
if(!json_real_set(txt, 0.0))
|
||||
fail("json_real_set did not return error for non-real");
|
||||
|
||||
if(json_number_value(NULL) != 0.0)
|
||||
fail("json_number_value did not return 0.0 for non-numeric");
|
||||
if(json_number_value(txt) != 0.0)
|
||||
fail("json_number_value did not return 0.0 for non-numeric");
|
||||
|
||||
if (txt->refcount != 1)
|
||||
fail("unexpected reference count for txt");
|
||||
|
||||
json_decref(txt);
|
||||
}
|
||||
|
||||
static void run_tests()
|
||||
{
|
||||
json_t *integer, *real;
|
||||
@@ -87,4 +122,5 @@ static void run_tests()
|
||||
#ifdef INFINITY
|
||||
test_inifity();
|
||||
#endif
|
||||
test_bad_args();
|
||||
}
|
||||
|
||||
@@ -539,6 +539,127 @@ static void test_object_foreach_safe()
|
||||
json_decref(object);
|
||||
}
|
||||
|
||||
static void test_bad_args(void)
|
||||
{
|
||||
json_t *obj = json_object();
|
||||
json_t *num = json_integer(1);
|
||||
void *iter;
|
||||
|
||||
if (!obj || !num)
|
||||
fail("failed to allocate test objects");
|
||||
|
||||
if (json_object_set(obj, "testkey", json_null()))
|
||||
fail("failed to set testkey on object");
|
||||
|
||||
iter = json_object_iter(obj);
|
||||
if (!iter)
|
||||
fail("failed to retrieve test iterator");
|
||||
|
||||
if(json_object_size(NULL) != 0)
|
||||
fail("json_object_size with non-object argument returned non-zero");
|
||||
if(json_object_size(num) != 0)
|
||||
fail("json_object_size with non-object argument returned non-zero");
|
||||
|
||||
if(json_object_get(NULL, "test") != NULL)
|
||||
fail("json_object_get with non-object argument returned non-NULL");
|
||||
if(json_object_get(num, "test") != NULL)
|
||||
fail("json_object_get with non-object argument returned non-NULL");
|
||||
if(json_object_get(obj, NULL) != NULL)
|
||||
fail("json_object_get with NULL key returned non-NULL");
|
||||
|
||||
if(!json_object_set_new_nocheck(NULL, "test", json_null()))
|
||||
fail("json_object_set_new_nocheck with non-object argument did not return error");
|
||||
if(!json_object_set_new_nocheck(num, "test", json_null()))
|
||||
fail("json_object_set_new_nocheck with non-object argument did not return error");
|
||||
if(!json_object_set_new_nocheck(obj, "test", json_incref(obj)))
|
||||
fail("json_object_set_new_nocheck with object == value did not return error");
|
||||
if(!json_object_set_new_nocheck(obj, NULL, json_object()))
|
||||
fail("json_object_set_new_nocheck with NULL key did not return error");
|
||||
|
||||
if(!json_object_del(NULL, "test"))
|
||||
fail("json_object_del with non-object argument did not return error");
|
||||
if(!json_object_del(num, "test"))
|
||||
fail("json_object_del with non-object argument did not return error");
|
||||
if(!json_object_del(obj, NULL))
|
||||
fail("json_object_del with NULL key did not return error");
|
||||
|
||||
if(!json_object_clear(NULL))
|
||||
fail("json_object_clear with non-object argument did not return error");
|
||||
if(!json_object_clear(num))
|
||||
fail("json_object_clear with non-object argument did not return error");
|
||||
|
||||
if(!json_object_update(NULL, obj))
|
||||
fail("json_object_update with non-object first argument did not return error");
|
||||
if(!json_object_update(num, obj))
|
||||
fail("json_object_update with non-object first argument did not return error");
|
||||
if(!json_object_update(obj, NULL))
|
||||
fail("json_object_update with non-object second argument did not return error");
|
||||
if(!json_object_update(obj, num))
|
||||
fail("json_object_update with non-object second argument did not return error");
|
||||
|
||||
if(!json_object_update_existing(NULL, obj))
|
||||
fail("json_object_update_existing with non-object first argument did not return error");
|
||||
if(!json_object_update_existing(num, obj))
|
||||
fail("json_object_update_existing with non-object first argument did not return error");
|
||||
if(!json_object_update_existing(obj, NULL))
|
||||
fail("json_object_update_existing with non-object second argument did not return error");
|
||||
if(!json_object_update_existing(obj, num))
|
||||
fail("json_object_update_existing with non-object second argument did not return error");
|
||||
|
||||
if(!json_object_update_missing(NULL, obj))
|
||||
fail("json_object_update_missing with non-object first argument did not return error");
|
||||
if(!json_object_update_missing(num, obj))
|
||||
fail("json_object_update_missing with non-object first argument did not return error");
|
||||
if(!json_object_update_missing(obj, NULL))
|
||||
fail("json_object_update_missing with non-object second argument did not return error");
|
||||
if(!json_object_update_missing(obj, num))
|
||||
fail("json_object_update_missing with non-object second argument did not return error");
|
||||
|
||||
if(json_object_iter(NULL) != NULL)
|
||||
fail("json_object_iter with non-object argument returned non-NULL");
|
||||
if(json_object_iter(num) != NULL)
|
||||
fail("json_object_iter with non-object argument returned non-NULL");
|
||||
|
||||
if(json_object_iter_at(NULL, "test") != NULL)
|
||||
fail("json_object_iter_at with non-object argument returned non-NULL");
|
||||
if(json_object_iter_at(num, "test") != NULL)
|
||||
fail("json_object_iter_at with non-object argument returned non-NULL");
|
||||
if(json_object_iter_at(obj, NULL) != NULL)
|
||||
fail("json_object_iter_at with NULL iter returned non-NULL");
|
||||
|
||||
if(json_object_iter_next(obj, NULL) != NULL)
|
||||
fail("json_object_iter_next with NULL iter returned non-NULL");
|
||||
if(json_object_iter_next(num, iter) != NULL)
|
||||
fail("json_object_iter_next with non-object argument returned non-NULL");
|
||||
|
||||
if(json_object_iter_key(NULL) != NULL)
|
||||
fail("json_object_iter_key with NULL iter returned non-NULL");
|
||||
|
||||
if(json_object_key_to_iter(NULL) != NULL)
|
||||
fail("json_object_key_to_iter with NULL iter returned non-NULL");
|
||||
|
||||
if(json_object_iter_value(NULL) != NULL)
|
||||
fail("json_object_iter_value with NULL iter returned non-NULL");
|
||||
|
||||
if(!json_object_iter_set_new(NULL, iter, json_incref(num)))
|
||||
fail("json_object_iter_set_new with non-object argument did not return error");
|
||||
if(!json_object_iter_set_new(num, iter, json_incref(num)))
|
||||
fail("json_object_iter_set_new with non-object argument did not return error");
|
||||
if(!json_object_iter_set_new(obj, NULL, json_incref(num)))
|
||||
fail("json_object_iter_set_new with NULL iter did not return error");
|
||||
if(!json_object_iter_set_new(obj, iter, NULL))
|
||||
fail("json_object_iter_set_new with NULL value did not return error");
|
||||
|
||||
if (obj->refcount != 1)
|
||||
fail("unexpected reference count for obj");
|
||||
|
||||
if (num->refcount != 1)
|
||||
fail("unexpected reference count for num");
|
||||
|
||||
json_decref(obj);
|
||||
json_decref(num);
|
||||
}
|
||||
|
||||
static void run_tests()
|
||||
{
|
||||
test_misc();
|
||||
@@ -552,4 +673,5 @@ static void run_tests()
|
||||
test_preserve_order();
|
||||
test_object_foreach();
|
||||
test_object_foreach_safe();
|
||||
test_bad_args();
|
||||
}
|
||||
|
||||
@@ -15,8 +15,39 @@
|
||||
#include <string.h>
|
||||
#include <jansson.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "util.h"
|
||||
|
||||
#ifdef INFINITY
|
||||
// This test triggers "warning C4756: overflow in constant arithmetic"
|
||||
// in Visual Studio. This warning is triggered here by design, so disable it.
|
||||
// (This can only be done on function level so we keep these tests separate)
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning (disable: 4756)
|
||||
#endif
|
||||
static void test_inifity()
|
||||
{
|
||||
json_error_t error;
|
||||
|
||||
if (json_pack_ex(&error, 0, "f", INFINITY))
|
||||
fail("json_pack infinity incorrectly succeeded");
|
||||
check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1, 1, 1);
|
||||
|
||||
if (json_pack_ex(&error, 0, "[f]", INFINITY))
|
||||
fail("json_pack infinity array element incorrectly succeeded");
|
||||
check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1, 2, 2);
|
||||
|
||||
if (json_pack_ex(&error, 0, "{s:f}", "key", INFINITY))
|
||||
fail("json_pack infinity object value incorrectly succeeded");
|
||||
check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1, 4, 4);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
#endif // INFINITY
|
||||
|
||||
static void run_tests()
|
||||
{
|
||||
json_t *value;
|
||||
@@ -99,6 +130,16 @@ static void run_tests()
|
||||
fail("json_pack nullable string (NULL case) refcount failed");
|
||||
json_decref(value);
|
||||
|
||||
/* nullable string concatenation */
|
||||
if(json_pack_ex(&error, 0, "s?+", "test", "ing"))
|
||||
fail("json_pack failed to catch invalid format 's?+'");
|
||||
check_error(json_error_invalid_format, "Cannot use '+' on optional strings", "<format>", 1, 2, 2);
|
||||
|
||||
/* nullable string with integer length */
|
||||
if(json_pack_ex(&error, 0, "s?#", "test", 4))
|
||||
fail("json_pack failed to catch invalid format 's?#'");
|
||||
check_error(json_error_invalid_format, "Cannot use '#' on optional strings", "<format>", 1, 2, 2);
|
||||
|
||||
/* string and length (int) */
|
||||
value = json_pack("s#", "test asdf", 4);
|
||||
if(!json_is_string(value) || strcmp("test", json_string_value(value)))
|
||||
@@ -132,6 +173,9 @@ static void run_tests()
|
||||
json_decref(value);
|
||||
|
||||
/* string concatenation */
|
||||
if (json_pack("s+", "test", NULL))
|
||||
fail("json_pack string concatenation succeeded with NULL string");
|
||||
|
||||
value = json_pack("s++", "te", "st", "ing");
|
||||
if(!json_is_string(value) || strcmp("testing", json_string_value(value)))
|
||||
fail("json_pack string concatenation failed");
|
||||
@@ -244,14 +288,32 @@ static void run_tests()
|
||||
value = json_pack("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
|
||||
if(value)
|
||||
fail("json_pack object optional incorrectly succeeded");
|
||||
|
||||
value = json_pack("{s:**}", "a", NULL);
|
||||
if(value)
|
||||
fail("json_pack object optional invalid incorrectly succeeded");
|
||||
|
||||
if (json_pack_ex(&error, 0, "{s:i*}", "a", 1))
|
||||
fail("json_pack object optional invalid incorrectly succeeded");
|
||||
check_error(json_error_invalid_format, "Expected format 's', got '*'", "<format>", 1, 5, 5);
|
||||
|
||||
value = json_pack("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
|
||||
if(!json_is_object(value) || json_object_size(value) != 0)
|
||||
fail("json_pack object optional failed");
|
||||
json_decref(value);
|
||||
|
||||
value = json_pack("{s:s*}", "key", "\xff\xff");
|
||||
if(value)
|
||||
fail("json_pack object optional with invalid UTF-8 incorrectly succeeded");
|
||||
|
||||
if(json_pack_ex(&error, 0, "{s: s*#}", "key", "test", 1))
|
||||
fail("json_pack failed to catch invalid format 's*#'");
|
||||
check_error(json_error_invalid_format, "Cannot use '#' on optional strings", "<format>", 1, 6, 6);
|
||||
|
||||
if(json_pack_ex(&error, 0, "{s: s*+}", "key", "test", "ing"))
|
||||
fail("json_pack failed to catch invalid format 's*+'");
|
||||
check_error(json_error_invalid_format, "Cannot use '+' on optional strings", "<format>", 1, 6, 6);
|
||||
|
||||
/* simple array */
|
||||
value = json_pack("[i,i,i]", 0, 1, 2);
|
||||
if(!json_is_array(value) || json_array_size(value) != 3)
|
||||
@@ -269,6 +331,11 @@ static void run_tests()
|
||||
value = json_pack("[s,o,O]", NULL, NULL, NULL);
|
||||
if(value)
|
||||
fail("json_pack array optional incorrectly succeeded");
|
||||
|
||||
if (json_pack_ex(&error, 0, "[i*]", 1))
|
||||
fail("json_pack array optional invalid incorrectly succeeded");
|
||||
check_error(json_error_invalid_format, "Unexpected format character '*'", "<format>", 1, 3, 3);
|
||||
|
||||
value = json_pack("[**]", NULL);
|
||||
if(value)
|
||||
fail("json_pack array optional invalid incorrectly succeeded");
|
||||
@@ -277,8 +344,27 @@ static void run_tests()
|
||||
fail("json_pack array optional failed");
|
||||
json_decref(value);
|
||||
|
||||
#ifdef NAN
|
||||
/* Invalid float values */
|
||||
if (json_pack_ex(&error, 0, "f", NAN))
|
||||
fail("json_pack NAN incorrectly succeeded");
|
||||
check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1, 1, 1);
|
||||
|
||||
if (json_pack_ex(&error, 0, "[f]", NAN))
|
||||
fail("json_pack NAN array element incorrectly succeeded");
|
||||
check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1, 2, 2);
|
||||
|
||||
if (json_pack_ex(&error, 0, "{s:f}", "key", NAN))
|
||||
fail("json_pack NAN object value incorrectly succeeded");
|
||||
check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1, 4, 4);
|
||||
#endif
|
||||
|
||||
#ifdef INFINITY
|
||||
test_inifity();
|
||||
#endif
|
||||
|
||||
/* Whitespace; regular string */
|
||||
value = json_pack(" s ", "test");
|
||||
value = json_pack(" s\t ", "test");
|
||||
if(!json_is_string(value) || strcmp("test", json_string_value(value)))
|
||||
fail("json_pack string (with whitespace) failed");
|
||||
json_decref(value);
|
||||
@@ -335,13 +421,18 @@ static void run_tests()
|
||||
/* NULL string */
|
||||
if(json_pack_ex(&error, 0, "s", NULL))
|
||||
fail("json_pack failed to catch null argument string");
|
||||
check_error(json_error_null_value, "NULL string argument", "<args>", 1, 1, 1);
|
||||
check_error(json_error_null_value, "NULL string", "<args>", 1, 1, 1);
|
||||
|
||||
/* + on its own */
|
||||
if(json_pack_ex(&error, 0, "+", NULL))
|
||||
fail("json_pack failed to a lone +");
|
||||
check_error(json_error_invalid_format, "Unexpected format character '+'", "<format>", 1, 1, 1);
|
||||
|
||||
/* Empty format */
|
||||
if(json_pack_ex(&error, 0, ""))
|
||||
fail("json_pack failed to catch empty format string");
|
||||
check_error(json_error_invalid_argument, "NULL or empty format string", "<format>", -1, -1, 0);
|
||||
|
||||
/* NULL format */
|
||||
if(json_pack_ex(&error, 0, NULL))
|
||||
fail("json_pack failed to catch NULL format string");
|
||||
@@ -350,13 +441,13 @@ static void run_tests()
|
||||
/* NULL key */
|
||||
if(json_pack_ex(&error, 0, "{s:i}", NULL, 1))
|
||||
fail("json_pack failed to catch NULL key");
|
||||
check_error(json_error_null_value, "NULL string argument", "<args>", 1, 2, 2);
|
||||
check_error(json_error_null_value, "NULL object key", "<args>", 1, 2, 2);
|
||||
|
||||
/* NULL value followed by object still steals the object's ref */
|
||||
value = json_incref(json_object());
|
||||
if(json_pack_ex(&error, 0, "{s:s,s:o}", "badnull", NULL, "dontleak", value))
|
||||
fail("json_pack failed to catch NULL value");
|
||||
check_error(json_error_null_value, "NULL string argument", "<args>", 1, 4, 4);
|
||||
check_error(json_error_null_value, "NULL string", "<args>", 1, 4, 4);
|
||||
if(value->refcount != (size_t)1)
|
||||
fail("json_pack failed to steal reference after error.");
|
||||
json_decref(value);
|
||||
@@ -385,4 +476,43 @@ static void run_tests()
|
||||
if(json_pack_ex(&error, 0, "{s:s}", "foo", "\xff\xff"))
|
||||
fail("json_pack failed to catch invalid UTF-8 in a string");
|
||||
check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "<args>", 1, 4, 4);
|
||||
|
||||
/* Invalid UTF-8 in an optional '?' string */
|
||||
if(json_pack_ex(&error, 0, "{s:s?}", "foo", "\xff\xff"))
|
||||
fail("json_pack failed to catch invalid UTF-8 in an optional '?' string");
|
||||
check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "<args>", 1, 5, 5);
|
||||
|
||||
/* Invalid UTF-8 in an optional '*' string */
|
||||
if(json_pack_ex(&error, 0, "{s:s*}", "foo", "\xff\xff"))
|
||||
fail("json_pack failed to catch invalid UTF-8 in an optional '*' string");
|
||||
check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "<args>", 1, 5, 5);
|
||||
|
||||
/* Invalid UTF-8 in a concatenated key */
|
||||
if(json_pack_ex(&error, 0, "{s+:i}", "\xff\xff", "concat", 42))
|
||||
fail("json_pack failed to catch invalid UTF-8 in an object key");
|
||||
check_error(json_error_invalid_utf8, "Invalid UTF-8 object key", "<args>", 1, 3, 3);
|
||||
|
||||
if(json_pack_ex(&error, 0, "{s:o}", "foo", NULL))
|
||||
fail("json_pack failed to catch nullable object");
|
||||
check_error(json_error_null_value, "NULL object", "<args>", 1, 4, 4);
|
||||
|
||||
if(json_pack_ex(&error, 0, "{s:O}", "foo", NULL))
|
||||
fail("json_pack failed to catch nullable incref object");
|
||||
check_error(json_error_null_value, "NULL object", "<args>", 1, 4, 4);
|
||||
|
||||
if(json_pack_ex(&error, 0, "{s+:o}", "foo", "bar", NULL))
|
||||
fail("json_pack failed to catch non-nullable object value");
|
||||
check_error(json_error_null_value, "NULL object", "<args>", 1, 5, 5);
|
||||
|
||||
if(json_pack_ex(&error, 0, "[1s", "Hi"))
|
||||
fail("json_pack failed to catch invalid format");
|
||||
check_error(json_error_invalid_format, "Unexpected format character '1'", "<format>", 1, 2, 2);
|
||||
|
||||
if(json_pack_ex(&error, 0, "[1s+", "Hi", "ya"))
|
||||
fail("json_pack failed to catch invalid format");
|
||||
check_error(json_error_invalid_format, "Unexpected format character '1'", "<format>", 1, 2, 2);
|
||||
|
||||
if(json_pack_ex(&error, 0, "[so]", NULL, json_object()))
|
||||
fail("json_pack failed to catch NULL value");
|
||||
check_error(json_error_null_value, "NULL string", "<args>", 1, 2, 2);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,56 @@
|
||||
#include <jansson.h>
|
||||
#include "util.h"
|
||||
|
||||
static void test_bad_args(void)
|
||||
{
|
||||
json_t *num = json_integer(1);
|
||||
json_t *txt = json_string("test");
|
||||
|
||||
if (!num || !txt)
|
||||
fail("failed to allocate test objects");
|
||||
|
||||
if(json_string_nocheck(NULL) != NULL)
|
||||
fail("json_string_nocheck with NULL argument did not return NULL");
|
||||
if(json_stringn_nocheck(NULL, 0) != NULL)
|
||||
fail("json_stringn_nocheck with NULL argument did not return NULL");
|
||||
if(json_string(NULL) != NULL)
|
||||
fail("json_string with NULL argument did not return NULL");
|
||||
if(json_stringn(NULL, 0) != NULL)
|
||||
fail("json_stringn with NULL argument did not return NULL");
|
||||
|
||||
if(json_string_length(NULL) != 0)
|
||||
fail("json_string_length with non-string argument did not return 0");
|
||||
if(json_string_length(num) != 0)
|
||||
fail("json_string_length with non-string argument did not return 0");
|
||||
|
||||
if(json_string_value(NULL) != NULL)
|
||||
fail("json_string_value with non-string argument did not return NULL");
|
||||
if(json_string_value(num) != NULL)
|
||||
fail("json_string_value with non-string argument did not return NULL");
|
||||
|
||||
if(!json_string_setn_nocheck(NULL, "", 0))
|
||||
fail("json_string_setn with non-string argument did not return error");
|
||||
if(!json_string_setn_nocheck(num, "", 0))
|
||||
fail("json_string_setn with non-string argument did not return error");
|
||||
if(!json_string_setn_nocheck(txt, NULL, 0))
|
||||
fail("json_string_setn_nocheck with NULL value did not return error");
|
||||
|
||||
if(!json_string_set_nocheck(txt, NULL))
|
||||
fail("json_string_set_nocheck with NULL value did not return error");
|
||||
if(!json_string_set(txt, NULL))
|
||||
fail("json_string_set with NULL value did not return error");
|
||||
if(!json_string_setn(txt, NULL, 0))
|
||||
fail("json_string_setn with NULL value did not return error");
|
||||
|
||||
if(num->refcount != 1)
|
||||
fail("unexpected reference count for num");
|
||||
if(txt->refcount != 1)
|
||||
fail("unexpected reference count for txt");
|
||||
|
||||
json_decref(num);
|
||||
json_decref(txt);
|
||||
}
|
||||
|
||||
/* Call the simple functions not covered by other tests of the public API */
|
||||
static void run_tests()
|
||||
{
|
||||
@@ -237,4 +287,6 @@ static void run_tests()
|
||||
fail("automatic decrement failed");
|
||||
json_decref(value);
|
||||
#endif
|
||||
|
||||
test_bad_args();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,18 @@ static void test_sprintf() {
|
||||
fail("json_sprintf generated an unexpected string");
|
||||
|
||||
json_decref(s);
|
||||
|
||||
s = json_sprintf("%s", "");
|
||||
if (!s)
|
||||
fail("json_sprintf returned NULL");
|
||||
if (!json_is_string(s))
|
||||
fail("json_sprintf didn't return a JSON string");
|
||||
if (json_string_length(s) != 0)
|
||||
fail("string is not empty");
|
||||
json_decref(s);
|
||||
|
||||
if (json_sprintf("%s", "\xff\xff"))
|
||||
fail("json_sprintf unexpected success with invalid UTF");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user