aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml11
-rw-r--r--CHANGES32
-rw-r--r--CMakeLists.txt270
-rw-r--r--LICENSE2
-rw-r--r--android/jansson_config.h2
-rw-r--r--cmake/JanssonConfig.cmake.in17
-rw-r--r--cmake/JanssonConfigVersion.cmake.in11
-rw-r--r--cmake/jansson_config.h.cmake4
-rw-r--r--cmake/jansson_private_config.h.cmake (renamed from cmake/config.h.cmake)0
-rw-r--r--configure.ac2
-rw-r--r--doc/apiref.rst71
-rw-r--r--doc/conf.py2
-rw-r--r--doc/conformance.rst12
-rw-r--r--doc/ext/refcounting.py2
-rw-r--r--doc/github_commits.c2
-rw-r--r--src/dump.c22
-rw-r--r--src/hashtable.c13
-rw-r--r--src/hashtable.h2
-rw-r--r--src/hashtable_seed.c2
-rw-r--r--src/jansson.def5
-rw-r--r--src/jansson.h26
-rw-r--r--src/jansson_config.h.in2
-rw-r--r--src/jansson_private.h10
-rw-r--r--src/load.c92
-rw-r--r--src/lookup3.h2
-rw-r--r--src/memory.c19
-rw-r--r--src/pack_unpack.c74
-rw-r--r--src/strbuffer.c2
-rw-r--r--src/strbuffer.h2
-rw-r--r--src/strconv.c4
-rw-r--r--src/utf.c29
-rw-r--r--src/utf.h14
-rw-r--r--src/value.c111
-rw-r--r--test/bin/json_process.c4
-rw-r--r--test/scripts/run-tests.sh2
-rw-r--r--test/scripts/valgrind.sh2
-rwxr-xr-xtest/suites/api/run2
-rw-r--r--test/suites/api/test_array.c2
-rw-r--r--test/suites/api/test_copy.c2
-rw-r--r--test/suites/api/test_dump.c17
-rw-r--r--test/suites/api/test_dump_callback.c2
-rw-r--r--test/suites/api/test_equal.c2
-rw-r--r--test/suites/api/test_load.c23
-rw-r--r--test/suites/api/test_loadb.c2
-rw-r--r--test/suites/api/test_number.c2
-rw-r--r--test/suites/api/test_object.c2
-rw-r--r--test/suites/api/test_pack.c40
-rw-r--r--test/suites/api/test_simple.c38
-rw-r--r--test/suites/api/test_unpack.c10
-rw-r--r--test/suites/api/util.h4
-rw-r--r--test/suites/encoding-flags/ensure-ascii/output2
-rwxr-xr-xtest/suites/encoding-flags/run2
-rwxr-xr-xtest/suites/invalid-unicode/run2
-rw-r--r--test/suites/invalid/escaped-null-byte-in-string/error2
-rw-r--r--test/suites/invalid/escaped-null-byte-in-string/input1
-rw-r--r--test/suites/invalid/null-byte-in-object-key/error2
-rw-r--r--test/suites/invalid/null-byte-in-object-key/input1
-rwxr-xr-xtest/suites/invalid/run2
-rwxr-xr-xtest/suites/valid/run2
-rw-r--r--win32/jansson_config.h2
60 files changed, 775 insertions, 270 deletions
diff --git a/.travis.yml b/.travis.yml
index 1cca274..452ed17 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,14 @@
+env:
+ matrix:
+ - JANSSON_BUILD_METHOD=cmake JANSSON_CMAKE_OPTIONS="-DJANSSON_TEST_WITH_VALGRIND=ON" JANSSON_EXTRA_INSTALL="valgrind"
+ - JANSSON_BUILD_METHOD=autotools
language: c
compiler:
- gcc
- clang
-script: autoreconf -f -i && CFLAGS=-Werror ./configure && make check
+install:
+ - sudo apt-get update -qq
+ - sudo apt-get install -y -qq cmake $JANSSON_EXTRA_INSTALL
+script:
+ - if [ "$JANSSON_BUILD_METHOD" = "autotools" ]; then autoreconf -f -i && CFLAGS=-Werror ./configure && make check; fi
+ - if [ "$JANSSON_BUILD_METHOD" = "cmake" ]; then mkdir build && cd build && cmake .. $JANSSON_CMAKE_OPTIONS && cmake --build . && ctest --output-on-failure; fi
diff --git a/CHANGES b/CHANGES
index 99d1647..3be522c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,35 @@
+Version 2.7 (in development)
+============================
+
+Released XXXX-XX-XX
+
+* New features:
+
+ - `json_pack()` and friends: Add format specifiers ``s%`` and ``+%``
+ for a size_t string length.
+
+ - `json_unpack()` and friends: Add format specifier ``s%`` for
+ unpacking the string length along with the string itself.
+
+ - Add length-aware string constructors `json_stringn()` and
+ `json_stringn_nocheck()`, length-aware string mutators
+ `json_string_setn()` and `json_string_setn_nocheck()`, and a
+ function for getting string's length `json_string_length()`.
+
+ - Support ``\u0000`` escapes in the decoder. The support can be
+ enabled by using the ``JSON_ALLOW_NUL`` decoding flag.
+
+* Bug fixes:
+
+ - Some malformed ``\uNNNN`` escapes could crash the decoder with an
+ assertion failure.
+
+* Other changes:
+
+ - ``\uNNNN`` escapes are now encoded in upper case for better
+ readability.
+
+
Version 2.6
===========
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5e6b9e0..979fb63 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -51,26 +51,26 @@ cmake_minimum_required (VERSION 2.8)
project (jansson C)
# Options
-OPTION (BUILD_SHARED_LIBS "Build shared libraries." OFF)
-OPTION (USE_URANDOM "Use /dev/urandom to seed the hash function." ON)
-OPTION (USE_WINDOWS_CRYPTOAPI "Use CryptGenRandom to seed the hash function." ON)
+option(JANSSON_BUILD_SHARED_LIBS "Build shared libraries." OFF)
+option(USE_URANDOM "Use /dev/urandom to seed the hash function." ON)
+option(USE_WINDOWS_CRYPTOAPI "Use CryptGenRandom to seed the hash function." ON)
if (MSVC)
# This option must match the settings used in your program, in particular if you
# are linking statically
- OPTION( STATIC_CRT "Link the static CRT libraries" OFF )
+ option(JANSSON_STATIC_CRT "Link the static CRT libraries" OFF )
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(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)
# 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)
- SET (CMAKE_DEBUG_POSTFIX "_d")
+ set(CMAKE_DEBUG_POSTFIX "_d")
else (WIN32)
endif (WIN32)
@@ -81,13 +81,13 @@ endif (WIN32)
set(JANSSON_DISPLAY_VERSION "2.6")
# This is what is required to match the same numbers as automake's
-set (JANSSON_VERSION "4.6.0")
-set (JANSSON_SOVERSION 4)
+set(JANSSON_VERSION "4.6.0")
+set(JANSSON_SOVERSION 4)
# for CheckFunctionKeywords
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
-INCLUDE (CheckCSourceCompiles)
+include (CheckCSourceCompiles)
include (CheckFunctionExists)
include (CheckFunctionKeywords)
include (CheckIncludeFiles)
@@ -104,7 +104,7 @@ if (MSVC)
endif()
-if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
+if (NOT WIN32 AND (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX))
set(CMAKE_C_FLAGS "-fPIC")
endif()
@@ -232,10 +232,10 @@ if (HAVE_LOCALECONV AND HAVE_LOCALE_H)
set (JSON_HAVE_LOCALECONV 1)
else ()
set (JSON_HAVE_LOCALECONV 0)
-endif ()
+endif()
# check if we have setlocale
-check_function_exists (setlocale HAVE_SETLOCALE)
+check_function_exists(setlocale HAVE_SETLOCALE)
# Check what the inline keyword is.
# Note that the original JSON_INLINE was always set to just 'inline', so this goes further.
@@ -244,25 +244,25 @@ check_function_keywords("__inline")
check_function_keywords("__inline__")
if (HAVE_INLINE)
- set (JSON_INLINE inline)
+ set(JSON_INLINE inline)
elseif (HAVE___INLINE)
- set (JSON_INLINE __inline)
+ set(JSON_INLINE __inline)
elseif (HAVE___INLINE__)
- set (JSON_INLINE __inline__)
-else (HAVE_INLINE)
+ set(JSON_INLINE __inline__)
+else()
# no inline on this platform
set (JSON_INLINE)
-endif (HAVE_INLINE)
+endif()
# Find our snprintf
check_function_exists (snprintf HAVE_SNPRINTF)
check_function_exists (_snprintf HAVE__SNPRINTF)
if (HAVE_SNPRINTF)
- set (JSON_SNPRINTF snprintf)
+ set(JSON_SNPRINTF snprintf)
elseif (HAVE__SNPRINTF)
- set (JSON_SNPRINTF _snprintf)
-endif ()
+ set(JSON_SNPRINTF _snprintf)
+endif ()
check_c_source_compiles ("int main() { unsigned long val; __sync_bool_compare_and_swap(&val, 0, 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_ACQ_REL); __atomic_load_n(&v, __ATOMIC_ACQUIRE); return 0; }" HAVE_ATOMIC_BUILTINS)
@@ -288,59 +288,62 @@ configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_config.h.cmake
file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/)
+add_definitions(-DJANSSON_USING_CMAKE)
# configure the private config file
-configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.cmake
- ${CMAKE_CURRENT_BINARY_DIR}/private_include/config.h)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_private_config.h.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/private_include/jansson_private_config.h)
# and tell the source code to include it
-add_definitions (-DHAVE_CONFIG_H)
+add_definitions(-DHAVE_CONFIG_H)
include_directories (${CMAKE_CURRENT_BINARY_DIR}/include)
include_directories (${CMAKE_CURRENT_BINARY_DIR}/private_include)
# Add the lib sources.
-file (GLOB C_FILES src/*.c)
-
-if (BUILD_SHARED_LIBS)
-
- add_library (jansson SHARED ${C_FILES} src/jansson.def)
-
- set_target_properties (jansson PROPERTIES
+file(GLOB JANSSON_SRC src/*.c)
+
+set(JANSSON_HDR_PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/hashtable.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson_private.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/strbuffer.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/utf.h
+ ${CMAKE_CURRENT_BINARY_DIR}/private_include/jansson_private_config.h)
+
+set(JANSSON_HDR_PUBLIC
+ ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h)
+
+source_group("Library Sources" FILES ${JANSSON_SRC})
+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}
+ src/jansson.def)
+
+ set_target_properties(jansson PROPERTIES
VERSION ${JANSSON_VERSION}
SOVERSION ${JANSSON_SOVERSION})
+else()
+ add_library(jansson
+ ${JANSSON_SRC}
+ ${JANSSON_HDR_PRIVATE}
+ ${JANSSON_HDR_PUBLIC})
+endif()
-else ()
-
- add_library (jansson ${C_FILES})
-
-endif ()
-
-# LIBRARY for linux
-# RUNTIME for windows (when building shared)
-install (TARGETS jansson
- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
- RUNTIME DESTINATION bin
-)
-
-install (FILES
- ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h
- ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h
- DESTINATION include)
-
-install (FILES
- ${CMAKE_CURRENT_BINARY_DIR}/jansson.pc
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
# For building Documentation (uses Sphinx)
-OPTION (BUILD_DOCS "Build documentation (uses python-sphinx)." ON)
-if (BUILD_DOCS)
+option(JANSSON_BUILD_DOCS "Build documentation (uses python-sphinx)." ON)
+if (JANSSON_BUILD_DOCS)
find_package(Sphinx)
if (NOT SPHINX_FOUND)
message(WARNING "Sphinx not found. Cannot generate documentation!
- Set -DBUILD_DOCS=0 to get rid of this message.")
+ 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!
@@ -375,9 +378,9 @@ if (BUILD_DOCS)
# Add documentation targets.
set(DOC_TARGETS html)
- OPTION(BUILD_MAN "Create a target for building man pages." ON)
+ option(JANSSON_BUILD_MAN "Create a target for building man pages." ON)
- if (BUILD_MAN)
+ if (JANSSON_BUILD_MAN)
if (Sphinx_VERSION_STRING VERSION_LESS 1.0)
message(WARNING "Sphinx version 1.0 > is required to build man pages. You have v${Sphinx_VERSION_STRING}.")
else()
@@ -385,9 +388,9 @@ if (BUILD_DOCS)
endif()
endif()
- OPTION(BUILD_LATEX "Create a target for building latex docs (to create PDF)." OFF)
+ option(JANSSON_BUILD_LATEX "Create a target for building latex docs (to create PDF)." OFF)
- if (BUILD_LATEX)
+ if (JANSSON_BUILD_LATEX)
find_package(LATEX)
if (NOT LATEX_COMPILER)
@@ -420,20 +423,20 @@ if (BUILD_DOCS)
endif ()
-OPTION (WITHOUT_TESTS "Don't build tests ('make test' to execute tests)" OFF)
+option(JANSSON_WITHOUT_TESTS "Don't build tests ('make test' to execute tests)" OFF)
-if (NOT WITHOUT_TESTS)
- OPTION (TEST_WITH_VALGRIND "Enable valgrind tests." OFF)
+if (NOT JANSSON_WITHOUT_TESTS)
+ option(JANSSON_TEST_WITH_VALGRIND "Enable valgrind tests." OFF)
ENABLE_TESTING()
- if (TEST_WITH_VALGRIND)
+ if (JANSSON_TEST_WITH_VALGRIND)
# TODO: Add FindValgrind.cmake instead of having a hardcoded path.
# enable valgrind
set(CMAKE_MEMORYCHECK_COMMAND valgrind)
set(CMAKE_MEMORYCHECK_COMMAND_OPTIONS
- "--leak-check=full --show-reachable=yes --track-origins=yes -q")
+ "--error-exitcode=1 --leak-check=full --show-reachable=yes --track-origins=yes -q")
set(MEMCHECK_COMMAND
"${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS}")
@@ -444,7 +447,7 @@ if (NOT WITHOUT_TESTS)
# Test suites.
#
if (CMAKE_COMPILER_IS_GNUCC)
- add_definitions(-Wall -Wextra -Wdeclaration-after-statement -Werror)
+ add_definitions(-Wall -Wextra -Wdeclaration-after-statement)
endif ()
set(api_tests
@@ -477,11 +480,12 @@ if (NOT WITHOUT_TESTS)
# Create executables and tests/valgrind tests for API tests.
foreach (test ${api_tests})
build_testprog(${test} ${PROJECT_SOURCE_DIR}/test/suites/api)
- add_test(${test} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test})
- if (TEST_WITH_VALGRIND)
- add_test(memcheck_${test} ${MEMCHECK_COMMAND}
- ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test})
+ if (JANSSON_TEST_WITH_VALGRIND)
+ add_test(memcheck__${test}
+ ${MEMCHECK_COMMAND} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test})
+ else()
+ add_test(${test} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test})
endif ()
endforeach ()
@@ -491,14 +495,29 @@ if (NOT WITHOUT_TESTS)
set(SUITES encoding-flags valid invalid invalid-unicode)
foreach (SUITE ${SUITES})
file(GLOB TESTDIRS ${jansson_SOURCE_DIR}/test/suites/${SUITE}/*)
+
foreach (TESTDIR ${TESTDIRS})
if (IS_DIRECTORY ${TESTDIR})
get_filename_component(TNAME ${TESTDIR} NAME)
- add_test(${SUITE}__${TNAME}
- ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/json_process ${TESTDIR})
+
+ set(SUITE_TEST_CMD ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/json_process)
+
+ if (JANSSON_TEST_WITH_VALGRIND)
+ add_test(memcheck__${SUITE}__${TNAME}
+ ${MEMCHECK_COMMAND} ${SUITE_TEST_CMD} ${TESTDIR})
+ else()
+ add_test(${SUITE}__${TNAME}
+ ${SUITE_TEST_CMD} ${TESTDIR})
+ endif()
+
if ((${SUITE} STREQUAL "valid" OR ${SUITE} STREQUAL "invalid") AND NOT EXISTS ${TESTDIR}/nostrip)
- add_test(${SUITE}__${TNAME}__strip
- ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/json_process --strip ${TESTDIR})
+ if (JANSSON_TEST_WITH_VALGRIND)
+ add_test(memcheck__${SUITE}__${TNAME}__strip
+ ${MEMCHECK_COMMAND} ${SUITE_TEST_CMD} --strip ${TESTDIR})
+ else()
+ add_test(${SUITE}__${TNAME}__strip
+ ${SUITE_TEST_CMD} --strip ${TESTDIR})
+ endif()
endif ()
endif ()
endforeach ()
@@ -508,3 +527,104 @@ if (NOT WITHOUT_TESTS)
DEPENDS json_process ${api_tests})
endif ()
+#
+# Installation preparation.
+#
+
+# Allow the user to override installation directories.
+set(JANSSON_INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries")
+set(JANSSON_INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables")
+set(JANSSON_INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
+
+if(WIN32 AND NOT CYGWIN)
+ set(DEF_INSTALL_CMAKE_DIR cmake)
+else()
+ set(DEF_INSTALL_CMAKE_DIR lib/cmake/jansson)
+endif()
+
+set(JANSSON_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files")
+
+# Make sure the paths are absolute.
+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 ${JANSSON__INCLUDE_DIRS} CACHE PATH "Jansson include directories")
+configure_file(${PROJECT_SOURCE_DIR}/cmake/JanssonConfig.cmake.in
+ ${PROJECT_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.
+
+# 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)
+
+# 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.
+
+# Create pkg-conf file.
+# (We use the same files as ./configure does, so we
+# have to defined the same variables used there).
+set(prefix ${CMAKE_INSTALL_PREFIX})
+set(exec_prefix ${CMAKE_INSTALL_PREFIX})
+set(libdir ${CMAKE_INSTALL_PREFIX}/${JANSSON_INSTALL_LIB_DIR})
+set(VERSION ${JANSSON_DISPLAY_VERSION})
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jansson.pc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/jansson.pc @ONLY)
+
+#
+# Install targets.
+#
+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 the pkg-config.
+install (FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/jansson.pc
+ DESTINATION ${JANSSON_INSTALL_LIB_DIR}/pkgconfig COMPONENT dev)
+
+# 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 exports for the install-tree.
+install(EXPORT JanssonTargets
+ DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}" COMPONENT dev)
+
+# For use when simply using add_library from a parent project to build jansson.
+set(JANSSON_LIBRARIES jansson CACHE STRING "Jansson libraries")
diff --git a/LICENSE b/LICENSE
index a8fb5b8..8ae43e0 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+Copyright (c) 2009-2014 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
diff --git a/android/jansson_config.h b/android/jansson_config.h
index c76940b..0a313a0 100644
--- a/android/jansson_config.h
+++ b/android/jansson_config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2010-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/cmake/JanssonConfig.cmake.in b/cmake/JanssonConfig.cmake.in
new file mode 100644
index 0000000..d00b3c4
--- /dev/null
+++ b/cmake/JanssonConfig.cmake.in
@@ -0,0 +1,17 @@
+# - 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)
+
diff --git a/cmake/JanssonConfigVersion.cmake.in b/cmake/JanssonConfigVersion.cmake.in
new file mode 100644
index 0000000..83b0d74
--- /dev/null
+++ b/cmake/JanssonConfigVersion.cmake.in
@@ -0,0 +1,11 @@
+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()
diff --git a/cmake/jansson_config.h.cmake b/cmake/jansson_config.h.cmake
index 8c500b5..43e36c5 100644
--- a/cmake/jansson_config.h.cmake
+++ b/cmake/jansson_config.h.cmake
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2010-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -17,7 +17,9 @@
#define JANSSON_CONFIG_H
/* Define this so that we can disable scattered automake configuration in source files */
+#ifndef JANSSON_USING_CMAKE
#define JANSSON_USING_CMAKE
+#endif
/* Note: when using cmake, JSON_INTEGER_IS_LONG_LONG is not defined nor used,
* as we will also check for __int64 etc types.
diff --git a/cmake/config.h.cmake b/cmake/jansson_private_config.h.cmake
index b27b9a3..b27b9a3 100644
--- a/cmake/config.h.cmake
+++ b/cmake/jansson_private_config.h.cmake
diff --git a/configure.ac b/configure.ac
index e871f5f..1dffd48 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@ AC_INIT([jansson], [2.6], [petri@digip.org])
AM_INIT_AUTOMAKE([1.10 foreign])
AC_CONFIG_SRCDIR([src/value.c])
-AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_HEADERS([jansson_private_config.h])
# Checks for programs.
AC_PROG_CC
diff --git a/doc/apiref.rst b/doc/apiref.rst
index 60ad48a..d3f6227 100644
--- a/doc/apiref.rst
+++ b/doc/apiref.rst
@@ -150,6 +150,11 @@ functions:
Returns true for types ``JSON_TRUE`` and ``JSON_FALSE``, and false
for values of other types and for *NULL*.
+.. function:: json_boolean_value(const json_t *json)
+
+ Alias of :func:`json_is_true()`, i.e. returns 1 for ``JSON_TRUE``
+ and 0 otherwise.
+
.. _apiref-reference-count:
@@ -294,8 +299,9 @@ String
Jansson uses UTF-8 as the character encoding. All JSON strings must be
valid UTF-8 (or ASCII, as it's a subset of UTF-8). Normal null
terminated C strings are used, so JSON strings may not contain
-embedded null characters. All other Unicode codepoints U+0001 through
-U+10FFFF are allowed.
+embedded null characters. All other Unicode codepoints U+0000 through
+U+10FFFF are allowed, but you must use length-aware functions if you
+wish to embed NUL bytes in strings.
.. function:: json_t *json_string(const char *value)
@@ -304,6 +310,13 @@ U+10FFFF are allowed.
Returns a new JSON string, or *NULL* on error. *value* must be a
valid UTF-8 encoded Unicode string.
+.. function:: json_t *json_stringn(const char *value, size_t len)
+
+ .. refcounting:: new
+
+ Like :func:`json_string`, but with explicit length, so *value* may
+ contain null characters or not be null terminated.
+
.. function:: json_t *json_string_nocheck(const char *value)
.. refcounting:: new
@@ -312,6 +325,13 @@ U+10FFFF are allowed.
UTF-8. Use this function only if you are certain that this really
is the case (e.g. you have already checked it by other means).
+.. function:: json_t *json_stringn_nocheck(const char *value, size_t len)
+
+ .. refcounting:: new
+
+ Like :func:`json_string_nocheck`, but with explicit length, so
+ *value* may contain null characters or not be null terminated.
+
.. function:: const char *json_string_value(const json_t *string)
Returns the associated value of *string* as a null terminated UTF-8
@@ -321,12 +341,22 @@ U+10FFFF are allowed.
the user. It is valid as long as *string* exists, i.e. as long as
its reference count has not dropped to zero.
+.. function:: size_t json_string_length(const json_t *string)
+
+ Returns the length of *string* in its UTF-8 presentation, or zero
+ if *string* is not a JSON string.
+
.. function:: int json_string_set(const json_t *string, const char *value)
Sets the associated value of *string* to *value*. *value* must be a
valid UTF-8 encoded Unicode string. Returns 0 on success and -1 on
error.
+.. function:: int json_string_setn(json_t *string, const char *value, size_t len)
+
+ Like :func:`json_string_set`, but with explicit length, so *value*
+ may contain null characters or not be null terminated.
+
.. function:: int json_string_set_nocheck(const json_t *string, const char *value)
Like :func:`json_string_set`, but doesn't check that *value* is
@@ -334,6 +364,11 @@ U+10FFFF are allowed.
really is the case (e.g. you have already checked it by other
means).
+.. function:: int json_string_setn_nocheck(json_t *string, const char *value, size_t len)
+
+ Like :func:`json_string_set_nocheck`, but with explicit length,
+ so *value* may contain null characters or not be null terminated.
+
Number
======
@@ -539,6 +574,9 @@ Object
A JSON object is a dictionary of key-value pairs, where the key is a
Unicode string and the value is any JSON value.
+Even though NUL bytes are allowed in string values, they are not
+allowed in object keys.
+
.. function:: json_t *json_object(void)
.. refcounting:: new
@@ -984,6 +1022,19 @@ macros can be ORed together to obtain *flags*.
.. versionadded:: 2.5
+``JSON_ALLOW_NUL``
+ Allow ``\u0000`` escape inside string values. This is a safety
+ measure; If you know your input can contain NUL bytes, use this
+ flag. If you don't use this flag, you don't have to worry about NUL
+ bytes inside strings unless you explicitly create themselves by
+ using e.g. :func:`json_stringn()` or ``s#`` format specifier for
+ :func:`json_pack()`.
+
+ Object keys cannot have embedded NUL bytes even if this flag is
+ used.
+
+ .. versionadded:: 2.6
+
Each function also takes an optional :type:`json_error_t` parameter
that is filled with error information if decoding fails. It's also
updated on success; the number of bytes of input read is written to
@@ -1110,6 +1161,11 @@ arguments.
.. versionadded:: 2.5
+``s%`` (string) [const char \*, size_t]
+ Like ``s#`` but the length argument is of type :type:`size_t`.
+
+ .. versionadded:: 2.6
+
``+`` [const char \*]
Like ``s``, but concatenate to the previous string. Only valid
after ``s``, ``s#``, ``+`` or ``+#``.
@@ -1122,6 +1178,11 @@ arguments.
.. versionadded:: 2.5
+``+%`` (string) [const char \*, size_t]
+ Like ``+#`` but the length argument is of type :type:`size_t`.
+
+ .. versionadded:: 2.6
+
``n`` (null)
Output a JSON null value. No argument is consumed.
@@ -1236,6 +1297,12 @@ type whose address should be passed.
:func:`json_string_value()` internally, so it exists as long as
there are still references to the corresponding JSON string.
+``s%`` (string) [const char \*, size_t *]
+ Convert a JSON string to a pointer to a NULL terminated UTF-8
+ string and its length.
+
+ .. versionadded:: 2.6
+
``n`` (null)
Expect a JSON null value. Nothing is extracted.
diff --git a/doc/conf.py b/doc/conf.py
index 98d03f8..a9adf9f 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -41,7 +41,7 @@ master_doc = 'index'
# General information about the project.
project = u'Jansson'
-copyright = u'2009-2013, Petri Lehtinen'
+copyright = u'2009-2014, Petri Lehtinen'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
diff --git a/doc/conformance.rst b/doc/conformance.rst
index 19f603d..de3947d 100644
--- a/doc/conformance.rst
+++ b/doc/conformance.rst
@@ -19,15 +19,11 @@ Strings
=======
JSON strings are mapped to C-style null-terminated character arrays,
-and UTF-8 encoding is used internally. Strings may not contain
-embedded null characters, not even escaped ones.
+and UTF-8 encoding is used internally.
-For example, trying to decode the following JSON text leads to a parse
-error::
-
- ["this string contains the null character: \u0000"]
-
-All other Unicode codepoints U+0001 through U+10FFFF are allowed.
+All Unicode codepoints U+0000 through U+10FFFF are allowed in string
+values. However, U+0000 is not allowed in object keys because of API
+restrictions.
Unicode normalization or any other transformation is never performed
on any strings (string values or object keys). When checking for
diff --git a/doc/ext/refcounting.py b/doc/ext/refcounting.py
index 4af3084..b714c88 100644
--- a/doc/ext/refcounting.py
+++ b/doc/ext/refcounting.py
@@ -19,7 +19,7 @@
<description of the json_object function>
- :copyright: Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ :copyright: Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
:license: MIT, see LICENSE for details.
"""
diff --git a/doc/github_commits.c b/doc/github_commits.c
index 94fb8b7..a1136d6 100644
--- a/doc/github_commits.c
+++ b/doc/github_commits.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/src/dump.c b/src/dump.c
index 3b19c73..7eddd5a 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -65,24 +65,25 @@ static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t
return 0;
}
-static int dump_string(const char *str, json_dump_callback_t dump, void *data, size_t flags)
+static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags)
{
- const char *pos, *end;
+ const char *pos, *end, *lim;
int32_t codepoint;
if(dump("\"", 1, data))
return -1;
end = pos = str;
+ lim = str + len;
while(1)
{
const char *text;
char seq[13];
int length;
- while(*end)
+ while(end < lim)
{
- end = utf8_iterate(pos, &codepoint);
+ end = utf8_iterate(pos, lim - pos, &codepoint);
if(!end)
return -1;
@@ -126,7 +127,7 @@ static int dump_string(const char *str, json_dump_callback_t dump, void *data, s
/* codepoint is in BMP */
if(codepoint < 0x10000)
{
- sprintf(seq, "\\u%04x", codepoint);
+ sprintf(seq, "\\u%04X", codepoint);
length = 6;
}
@@ -139,7 +140,7 @@ static int dump_string(const char *str, json_dump_callback_t dump, void *data, s
first = 0xD800 | ((codepoint & 0xffc00) >> 10);
last = 0xDC00 | (codepoint & 0x003ff);
- sprintf(seq, "\\u%04x\\u%04x", first, last);
+ sprintf(seq, "\\u%04X\\u%04X", first, last);
length = 12;
}
@@ -215,7 +216,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
}
case JSON_STRING:
- return dump_string(json_string_value(json), dump, data, flags);
+ return dump_string(json_string_value(json), json_string_length(json), dump, data, flags);
case JSON_ARRAY:
{
@@ -336,7 +337,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
value = json_object_get(json, key);
assert(value);
- dump_string(key, dump, data, flags);
+ dump_string(key, strlen(key), dump, data, flags);
if(dump(separator, separator_length, data) ||
do_dump(value, flags, depth + 1, dump, data))
{
@@ -372,8 +373,9 @@ static int do_dump(const json_t *json, size_t flags, int depth,
while(iter)
{
void *next = json_object_iter_next((json_t *)json, iter);
+ const char *key = json_object_iter_key(iter);
- dump_string(json_object_iter_key(iter), dump, data, flags);
+ dump_string(key, strlen(key), dump, data, flags);
if(dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1,
dump, data))
diff --git a/src/hashtable.c b/src/hashtable.c
index abd4bf1..4c4b565 100644
--- a/src/hashtable.c
+++ b/src/hashtable.c
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#if HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#include <stdlib.h>
@@ -234,7 +234,14 @@ int hashtable_set(hashtable_t *hashtable,
/* offsetof(...) returns the size of pair_t without the last,
flexible member. This way, the correct amount is
allocated. */
- pair = jsonp_malloc(offsetof(pair_t, key) + strlen(key) + 1);
+
+ size_t len = strlen(key);
+ if(len >= (size_t)-1 - offsetof(pair_t, key)) {
+ /* Avoid an overflow if the key is very long */
+ return -1;
+ }
+
+ pair = jsonp_malloc(offsetof(pair_t, key) + len + 1);
if(!pair)
return -1;
diff --git a/src/hashtable.h b/src/hashtable.h
index 469c6ec..f54c3fe 100644
--- a/src/hashtable.h
+++ b/src/hashtable.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/src/hashtable_seed.c b/src/hashtable_seed.c
index a07d145..1789b07 100644
--- a/src/hashtable_seed.c
+++ b/src/hashtable_seed.c
@@ -3,7 +3,7 @@
*/
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#include <stdio.h>
diff --git a/src/jansson.def b/src/jansson.def
index 19096d4..da4cfd4 100644
--- a/src/jansson.def
+++ b/src/jansson.def
@@ -4,10 +4,15 @@ EXPORTS
json_false
json_null
json_string
+ json_stringn
json_string_nocheck
+ json_stringn_nocheck
json_string_value
+ json_string_length
json_string_set
+ json_string_setn
json_string_set_nocheck
+ json_string_setn_nocheck
json_integer
json_integer_value
json_integer_set
diff --git a/src/jansson.h b/src/jansson.h
index 3f67edf..85215f4 100644
--- a/src/jansson.h
+++ b/src/jansson.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -67,23 +67,26 @@ typedef long json_int_t;
#endif
#define json_typeof(json) ((json)->type)
-#define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT)
-#define json_is_array(json) (json && json_typeof(json) == JSON_ARRAY)
-#define json_is_string(json) (json && json_typeof(json) == JSON_STRING)
-#define json_is_integer(json) (json && json_typeof(json) == JSON_INTEGER)
-#define json_is_real(json) (json && json_typeof(json) == JSON_REAL)
+#define json_is_object(json) ((json) && json_typeof(json) == JSON_OBJECT)
+#define json_is_array(json) ((json) && json_typeof(json) == JSON_ARRAY)
+#define json_is_string(json) ((json) && json_typeof(json) == JSON_STRING)
+#define json_is_integer(json) ((json) && json_typeof(json) == JSON_INTEGER)
+#define json_is_real(json) ((json) && json_typeof(json) == JSON_REAL)
#define json_is_number(json) (json_is_integer(json) || json_is_real(json))
-#define json_is_true(json) (json && json_typeof(json) == JSON_TRUE)
-#define json_is_false(json) (json && json_typeof(json) == JSON_FALSE)
+#define json_is_true(json) ((json) && json_typeof(json) == JSON_TRUE)
+#define json_is_false(json) ((json) && json_typeof(json) == JSON_FALSE)
+#define json_boolean_value json_is_true
#define json_is_boolean(json) (json_is_true(json) || json_is_false(json))
-#define json_is_null(json) (json && json_typeof(json) == JSON_NULL)
+#define json_is_null(json) ((json) && json_typeof(json) == JSON_NULL)
/* construction, destruction, reference counting */
json_t *json_object(void);
json_t *json_array(void);
json_t *json_string(const char *value);
+json_t *json_stringn(const char *value, size_t len);
json_t *json_string_nocheck(const char *value);
+json_t *json_stringn_nocheck(const char *value, size_t len);
json_t *json_integer(json_int_t value);
json_t *json_real(double value);
json_t *json_true(void);
@@ -200,16 +203,18 @@ int json_array_insert(json_t *array, size_t ind, json_t *value)
}
const char *json_string_value(const json_t *string);
+size_t json_string_length(const json_t *string);
json_int_t json_integer_value(const json_t *integer);
double json_real_value(const json_t *real);
double json_number_value(const json_t *json);
int json_string_set(json_t *string, const char *value);
+int json_string_setn(json_t *string, const char *value, size_t len);
int json_string_set_nocheck(json_t *string, const char *value);
+int json_string_setn_nocheck(json_t *string, const char *value, size_t len);
int json_integer_set(json_t *integer, json_int_t value);
int json_real_set(json_t *real, double value);
-
/* pack, unpack */
json_t *json_pack(const char *fmt, ...);
@@ -241,6 +246,7 @@ json_t *json_deep_copy(const json_t *value);
#define JSON_DISABLE_EOF_CHECK 0x2
#define JSON_DECODE_ANY 0x4
#define JSON_DECODE_INT_AS_REAL 0x8
+#define JSON_ALLOW_NUL 0x10
typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
diff --git a/src/jansson_config.h.in b/src/jansson_config.h.in
index 785801f..12580a0 100644
--- a/src/jansson_config.h.in
+++ b/src/jansson_config.h.in
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2010-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/src/jansson_private.h b/src/jansson_private.h
index 403b53a..c6f437c 100644
--- a/src/jansson_private.h
+++ b/src/jansson_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -49,6 +49,7 @@ typedef struct {
typedef struct {
json_t json;
char *value;
+ size_t length;
} json_string_t;
typedef struct {
@@ -64,9 +65,13 @@ typedef struct {
#define json_to_object(json_) container_of(json_, json_object_t, json)
#define json_to_array(json_) container_of(json_, json_array_t, json)
#define json_to_string(json_) container_of(json_, json_string_t, json)
-#define json_to_real(json_) container_of(json_, json_real_t, json)
+#define json_to_real(json_) container_of(json_, json_real_t, json)
#define json_to_integer(json_) container_of(json_, json_integer_t, json)
+/* Create a string by taking ownership of an existing buffer */
+json_t *jsonp_stringn_nocheck_own(const char *value, size_t len);
+
+/* Error message formatting */
void jsonp_error_init(json_error_t *error, const char *source);
void jsonp_error_set_source(json_error_t *error, const char *source);
void jsonp_error_set(json_error_t *error, int line, int column,
@@ -83,6 +88,7 @@ void* jsonp_malloc(size_t size);
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);
/* Windows compatibility */
#ifdef _WIN32
diff --git a/src/load.c b/src/load.c
index c5536f5..56c8ee3 100644
--- a/src/load.c
+++ b/src/load.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -63,7 +63,10 @@ typedef struct {
strbuffer_t saved_text;
int token;
union {
- char *string;
+ struct {
+ char *val;
+ size_t len;
+ } string;
json_int_t integer;
double real;
} value;
@@ -279,6 +282,13 @@ static void lex_save_cached(lex_t *lex)
}
}
+static void lex_free_string(lex_t *lex)
+{
+ jsonp_free(lex->value.string.val);
+ lex->value.string.val = NULL;
+ lex->value.string.len = 0;
+}
+
/* assumes that str points to 'u' plus at least 4 valid hex digits */
static int32_t decode_unicode_escape(const char *str)
{
@@ -297,7 +307,7 @@ static int32_t decode_unicode_escape(const char *str)
else if(l_isupper(c))
value += c - 'A' + 10;
else
- assert(0);
+ return -1;
}
return value;
@@ -310,7 +320,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
char *t;
int i;
- lex->value.string = NULL;
+ lex->value.string.val = NULL;
lex->token = TOKEN_INVALID;
c = lex_get_save(lex, error);
@@ -365,14 +375,12 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
- two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair
are converted to 4 bytes
*/
- lex->value.string = jsonp_malloc(lex->saved_text.length + 1);
- if(!lex->value.string) {
+ t = jsonp_malloc(lex->saved_text.length + 1);
+ if(!t) {
/* this is not very nice, since TOKEN_INVALID is returned */
goto out;
}
-
- /* the target */
- t = lex->value.string;
+ lex->value.string.val = t;
/* + 1 to skip the " */
p = strbuffer_value(&lex->saved_text) + 1;
@@ -381,17 +389,24 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
if(*p == '\\') {
p++;
if(*p == 'u') {
- char buffer[4];
- int length;
+ size_t length;
int32_t value;
value = decode_unicode_escape(p);
+ if(value < 0) {
+ error_set(error, lex, "invalid Unicode escape '%.6s'", p - 1);
+ goto out;
+ }
p += 5;
if(0xD800 <= value && value <= 0xDBFF) {
/* surrogate pair */
if(*p == '\\' && *(p + 1) == 'u') {
int32_t value2 = decode_unicode_escape(++p);
+ if(value2 < 0) {
+ error_set(error, lex, "invalid Unicode escape '%.6s'", p - 1);
+ goto out;
+ }
p += 5;
if(0xDC00 <= value2 && value2 <= 0xDFFF) {
@@ -420,16 +435,9 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
error_set(error, lex, "invalid Unicode '\\u%04X'", value);
goto out;
}
- else if(value == 0)
- {
- error_set(error, lex, "\\u0000 is not allowed");
- goto out;
- }
- if(utf8_encode(value, buffer, &length))
+ if(utf8_encode(value, t, &length))
assert(0);
-
- memcpy(t, buffer, length);
t += length;
}
else {
@@ -451,11 +459,12 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
*(t++) = *(p++);
}
*t = '\0';
+ lex->value.string.len = t - lex->value.string.val;
lex->token = TOKEN_STRING;
return;
out:
- jsonp_free(lex->value.string);
+ lex_free_string(lex);
}
#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */
@@ -571,10 +580,8 @@ static int lex_scan(lex_t *lex, json_error_t *error)
strbuffer_clear(&lex->saved_text);
- if(lex->token == TOKEN_STRING) {
- jsonp_free(lex->value.string);
- lex->value.string = NULL;
- }
+ if(lex->token == TOKEN_STRING)
+ lex_free_string(lex);
c = lex_get(lex, error);
while(c == ' ' || c == '\t' || c == '\n' || c == '\r')
@@ -635,13 +642,14 @@ out:
return lex->token;
}
-static char *lex_steal_string(lex_t *lex)
+static char *lex_steal_string(lex_t *lex, size_t *out_len)
{
char *result = NULL;
- if(lex->token == TOKEN_STRING)
- {
- result = lex->value.string;
- lex->value.string = NULL;
+ if(lex->token == TOKEN_STRING) {
+ result = lex->value.string.val;
+ *out_len = lex->value.string.len;
+ lex->value.string.val = NULL;
+ lex->value.string.len = 0;
}
return result;
}
@@ -659,7 +667,7 @@ static int lex_init(lex_t *lex, get_func get, void *data)
static void lex_close(lex_t *lex)
{
if(lex->token == TOKEN_STRING)
- jsonp_free(lex->value.string);
+ lex_free_string(lex);
strbuffer_close(&lex->saved_text);
}
@@ -680,6 +688,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error)
while(1) {
char *key;
+ size_t len;
json_t *value;
if(lex->token != TOKEN_STRING) {
@@ -687,9 +696,14 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error)
goto error;
}
- key = lex_steal_string(lex);
+ key = lex_steal_string(lex, &len);
if(!key)
return NULL;
+ if (memchr(key, '\0', len)) {
+ jsonp_free(key);
+ error_set(error, lex, "NUL byte in object key not supported");
+ goto error;
+ }
if(flags & JSON_REJECT_DUPLICATES) {
if(json_object_get(object, key)) {
@@ -788,7 +802,21 @@ static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
switch(lex->token) {
case TOKEN_STRING: {
- json = json_string_nocheck(lex->value.string);
+ const char *value = lex->value.string.val;
+ size_t len = lex->value.string.len;
+
+ if(!(flags & JSON_ALLOW_NUL)) {
+ if(memchr(value, '\0', len)) {
+ error_set(error, lex, "\\u0000 is not allowed without JSON_ALLOW_NUL");
+ return NULL;
+ }
+ }
+
+ json = jsonp_stringn_nocheck_own(value, len);
+ if(json) {
+ lex->value.string.val = NULL;
+ lex->value.string.len = 0;
+ }
break;
}
diff --git a/src/lookup3.h b/src/lookup3.h
index dc76138..8847483 100644
--- a/src/lookup3.h
+++ b/src/lookup3.h
@@ -37,7 +37,7 @@ on 1 byte), but shoehorning those bytes into integers efficiently is messy.
#include <stdlib.h>
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#ifdef HAVE_STDINT_H
diff --git a/src/memory.c b/src/memory.c
index eb6cec5..ca44d6b 100644
--- a/src/memory.c
+++ b/src/memory.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011-2012 Basile Starynkevitch <basile@starynkevitch.net>
*
* Jansson is free software; you can redistribute it and/or modify it
@@ -12,6 +12,10 @@
#include "jansson.h"
#include "jansson_private.h"
+/* C89 allows these to be macros */
+#undef malloc
+#undef free
+
/* memory function pointers */
static json_malloc_t do_malloc = malloc;
static json_free_t do_free = free;
@@ -34,18 +38,19 @@ void jsonp_free(void *ptr)
char *jsonp_strdup(const char *str)
{
- char *new_str;
- size_t len;
+ return jsonp_strndup(str, strlen(str));
+}
- len = strlen(str);
- if(len == (size_t)-1)
- return NULL;
+char *jsonp_strndup(const char *str, size_t len)
+{
+ char *new_str;
new_str = jsonp_malloc(len + 1);
if(!new_str)
return NULL;
- memcpy(new_str, str, len + 1);
+ memcpy(new_str, str, len);
+ new_str[len] = '\0';
return new_str;
}
diff --git a/src/pack_unpack.c b/src/pack_unpack.c
index 0d932f7..76d946b 100644
--- a/src/pack_unpack.c
+++ b/src/pack_unpack.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
*
* Jansson is free software; you can redistribute it and/or modify
@@ -125,19 +125,18 @@ 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, int *ours)
+ const char *purpose, size_t *out_len, int *ours)
{
char t;
strbuffer_t strbuff;
const char *str;
size_t length;
- char *result;
next_token(s);
t = token(s);
prev_token(s);
- if(t != '#' && t != '+') {
+ if(t != '#' && t != '%' && t != '+') {
/* Optimize the simple case */
str = va_arg(*ap, const char *);
@@ -146,11 +145,14 @@ static char *read_string(scanner_t *s, va_list *ap,
return NULL;
}
- if(!utf8_check_string(str, -1)) {
+ length = strlen(str);
+
+ if(!utf8_check_string(str, length)) {
set_error(s, "<args>", "Invalid UTF-8 %s", purpose);
return NULL;
}
+ *out_len = length;
*ours = 0;
return (char *)str;
}
@@ -170,6 +172,9 @@ static char *read_string(scanner_t *s, va_list *ap,
if(token(s) == '#') {
length = va_arg(*ap, int);
}
+ else if(token(s) == '%') {
+ length = va_arg(*ap, size_t);
+ }
else {
prev_token(s);
length = strlen(str);
@@ -188,15 +193,15 @@ static char *read_string(scanner_t *s, va_list *ap,
}
}
- result = strbuffer_steal_value(&strbuff);
-
- if(!utf8_check_string(result, -1)) {
+ if(!utf8_check_string(strbuff.value, strbuff.length)) {
set_error(s, "<args>", "Invalid UTF-8 %s", purpose);
+ strbuffer_close(&strbuff);
return NULL;
}
+ *out_len = strbuff.length;
*ours = 1;
- return result;
+ return strbuffer_steal_value(&strbuff);
}
static json_t *pack_object(scanner_t *s, va_list *ap)
@@ -206,6 +211,7 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
while(token(s) != '}') {
char *key;
+ size_t len;
int ours;
json_t *value;
@@ -219,15 +225,19 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
goto error;
}
- key = read_string(s, ap, "object key", &ours);
+ key = read_string(s, ap, "object key", &len, &ours);
if(!key)
goto error;
next_token(s);
value = pack(s, ap);
- if(!value)
+ if(!value) {
+ if(ours)
+ jsonp_free(key);
+
goto error;
+ }
if(json_object_set_new_nocheck(object, key, value)) {
if(ours)
@@ -290,20 +300,20 @@ static json_t *pack(scanner_t *s, va_list *ap)
case '[':
return pack_array(s, ap);
- case 's': { /* string */
+ case 's': /* string */
+ {
char *str;
+ size_t len;
int ours;
- json_t *result;
- str = read_string(s, ap, "string", &ours);
+ str = read_string(s, ap, "string", &len, &ours);
if(!str)
return NULL;
- result = json_string_nocheck(str);
- if(ours)
- jsonp_free(str);
-
- return result;
+ if (ours)
+ return jsonp_stringn_nocheck_own(str, len);
+ else
+ return json_stringn_nocheck(str, len);
}
case 'n': /* null */
@@ -523,16 +533,32 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap)
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
- const char **target;
+ const char **str_target;
+ size_t *len_target = NULL;
- target = va_arg(*ap, const char **);
- if(!target) {
+ str_target = va_arg(*ap, const char **);
+ if(!str_target) {
set_error(s, "<args>", "NULL string argument");
return -1;
}
- if(root)
- *target = json_string_value(root);
+ next_token(s);
+
+ if(token(s) == '%') {
+ len_target = va_arg(*ap, size_t *);
+ if(!len_target) {
+ set_error(s, "<args>", "NULL string length argument");
+ return -1;
+ }
+ }
+ else
+ prev_token(s);
+
+ if(root) {
+ *str_target = json_string_value(root);
+ if(len_target)
+ *len_target = json_string_length(root);
+ }
}
return 0;
diff --git a/src/strbuffer.c b/src/strbuffer.c
index 2d6ff31..b3ddd0e 100644
--- a/src/strbuffer.c
+++ b/src/strbuffer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/src/strbuffer.h b/src/strbuffer.h
index 06fd065..fc11ec0 100644
--- a/src/strbuffer.h
+++ b/src/strbuffer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/src/strconv.c b/src/strconv.c
index 3e2cb7c..3a70c6f 100644
--- a/src/strconv.c
+++ b/src/strconv.c
@@ -5,9 +5,9 @@
#include "jansson_private.h"
#include "strbuffer.h"
-/* need config.h to get the correct snprintf */
+/* need jansson_private_config.h to get the correct snprintf */
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#if JSON_HAVE_LOCALECONV
diff --git a/src/utf.c b/src/utf.c
index 65b849b..b56e125 100644
--- a/src/utf.c
+++ b/src/utf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -8,7 +8,7 @@
#include <string.h>
#include "utf.h"
-int utf8_encode(int32_t codepoint, char *buffer, int *size)
+int utf8_encode(int32_t codepoint, char *buffer, size_t *size)
{
if(codepoint < 0)
return -1;
@@ -44,7 +44,7 @@ int utf8_encode(int32_t codepoint, char *buffer, int *size)
return 0;
}
-int utf8_check_first(char byte)
+size_t utf8_check_first(char byte)
{
unsigned char u = (unsigned char)byte;
@@ -80,9 +80,9 @@ int utf8_check_first(char byte)
}
}
-int utf8_check_full(const char *buffer, int size, int32_t *codepoint)
+size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint)
{
- int i;
+ size_t i;
int32_t value = 0;
unsigned char u = (unsigned char)buffer[0];
@@ -136,12 +136,12 @@ int utf8_check_full(const char *buffer, int size, int32_t *codepoint)
return 1;
}
-const char *utf8_iterate(const char *buffer, int32_t *codepoint)
+const char *utf8_iterate(const char *buffer, size_t bufsize, int32_t *codepoint)
{
- int count;
+ size_t count;
int32_t value;
- if(!*buffer)
+ if(!bufsize)
return buffer;
count = utf8_check_first(buffer[0]);
@@ -152,7 +152,7 @@ const char *utf8_iterate(const char *buffer, int32_t *codepoint)
value = (unsigned char)buffer[0];
else
{
- if(!utf8_check_full(buffer, count, &value))
+ if(count > bufsize || !utf8_check_full(buffer, count, &value))
return NULL;
}
@@ -162,21 +162,18 @@ const char *utf8_iterate(const char *buffer, int32_t *codepoint)
return buffer + count;
}
-int utf8_check_string(const char *string, int length)
+int utf8_check_string(const char *string, size_t length)
{
- int i;
-
- if(length == -1)
- length = strlen(string);
+ size_t i;
for(i = 0; i < length; i++)
{
- int count = utf8_check_first(string[i]);
+ size_t count = utf8_check_first(string[i]);
if(count == 0)
return 0;
else if(count > 1)
{
- if(i + count > length)
+ if(count > length - i)
return 0;
if(!utf8_check_full(&string[i], count, NULL))
diff --git a/src/utf.h b/src/utf.h
index b4f1091..2cebea0 100644
--- a/src/utf.h
+++ b/src/utf.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -9,19 +9,19 @@
#define UTF_H
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
-int utf8_encode(int codepoint, char *buffer, int *size);
+int utf8_encode(int32_t codepoint, char *buffer, size_t *size);
-int utf8_check_first(char byte);
-int utf8_check_full(const char *buffer, int size, int32_t *codepoint);
-const char *utf8_iterate(const char *buffer, int32_t *codepoint);
+size_t utf8_check_first(char byte);
+size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint);
+const char *utf8_iterate(const char *buffer, size_t size, int32_t *codepoint);
-int utf8_check_string(const char *string, int length);
+int utf8_check_string(const char *string, size_t length);
#endif
diff --git a/src/value.c b/src/value.c
index 1b02d90..644bc87 100644
--- a/src/value.c
+++ b/src/value.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -10,7 +10,7 @@
#endif
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#include <stddef.h>
@@ -92,7 +92,7 @@ json_t *json_object_get(const json_t *json, const char *key)
{
json_object_t *object;
- if(!json_is_object(json))
+ if(!key || !json_is_object(json))
return NULL;
object = json_to_object(json);
@@ -124,7 +124,7 @@ int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value)
int json_object_set_new(json_t *json, const char *key, json_t *value)
{
- if(!key || !utf8_check_string(key, -1))
+ if(!key || !utf8_check_string(key, strlen(key)))
{
json_decref(value);
return -1;
@@ -137,7 +137,7 @@ int json_object_del(json_t *json, const char *key)
{
json_object_t *object;
- if(!json_is_object(json))
+ if(!key || !json_is_object(json))
return -1;
object = json_to_object(json);
@@ -636,33 +636,68 @@ static json_t *json_array_deep_copy(const json_t *array)
/*** string ***/
-json_t *json_string_nocheck(const char *value)
+static json_t *string_create(const char *value, size_t len, int own)
{
+ char *v;
json_string_t *string;
if(!value)
return NULL;
+ if(own)
+ v = (char *)value;
+ else {
+ v = jsonp_strndup(value, len);
+ if(!v)
+ return NULL;
+ }
+
string = jsonp_malloc(sizeof(json_string_t));
- if(!string)
+ if(!string) {
+ if(!own)
+ jsonp_free(v);
return NULL;
+ }
json_init(&string->json, JSON_STRING);
+ string->value = v;
+ string->length = len;
+
+ return &string->json;
+}
- string->value = jsonp_strdup(value);
- if(!string->value) {
- jsonp_free(string);
+json_t *json_string_nocheck(const char *value)
+{
+ if(!value)
return NULL;
- }
- return &string->json;
+ return string_create(value, strlen(value), 0);
+}
+
+json_t *json_stringn_nocheck(const char *value, size_t len)
+{
+ return string_create(value, len, 0);
+}
+
+/* this is private; "steal" is not a public API concept */
+json_t *jsonp_stringn_nocheck_own(const char *value, size_t len)
+{
+ return string_create(value, len, 1);
}
json_t *json_string(const char *value)
{
- if(!value || !utf8_check_string(value, -1))
+ if(!value)
+ return NULL;
+
+ return json_stringn(value, strlen(value));
+}
+
+json_t *json_stringn(const char *value, size_t len)
+{
+ if(!value || !utf8_check_string(value, len))
return NULL;
- return json_string_nocheck(value);
+ return json_stringn_nocheck(value, len);
}
const char *json_string_value(const json_t *json)
@@ -673,31 +708,56 @@ const char *json_string_value(const json_t *json)
return json_to_string(json)->value;
}
+size_t json_string_length(const json_t *json)
+{
+ if(!json_is_string(json))
+ return 0;
+
+ return json_to_string(json)->length;
+}
+
int json_string_set_nocheck(json_t *json, const char *value)
{
+ if(!value)
+ return -1;
+
+ return json_string_setn_nocheck(json, value, strlen(value));
+}
+
+int json_string_setn_nocheck(json_t *json, const char *value, size_t len)
+{
char *dup;
json_string_t *string;
if(!json_is_string(json) || !value)
return -1;
- dup = jsonp_strdup(value);
+ dup = jsonp_strndup(value, len);
if(!dup)
return -1;
string = json_to_string(json);
jsonp_free(string->value);
string->value = dup;
+ string->length = len;
return 0;
}
int json_string_set(json_t *json, const char *value)
{
- if(!value || !utf8_check_string(value, -1))
+ if(!value)
+ return -1;
+
+ return json_string_setn(json, value, strlen(value));
+}
+
+int json_string_setn(json_t *json, const char *value, size_t len)
+{
+ if(!value || !utf8_check_string(value, len))
return -1;
- return json_string_set_nocheck(json, value);
+ return json_string_setn_nocheck(json, value, len);
}
static void json_delete_string(json_string_t *string)
@@ -708,12 +768,25 @@ static void json_delete_string(json_string_t *string)
static int json_string_equal(json_t *string1, json_t *string2)
{
- return strcmp(json_string_value(string1), json_string_value(string2)) == 0;
+ 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);
}
static json_t *json_string_copy(const json_t *string)
{
- return json_string_nocheck(json_string_value(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);
}
diff --git a/test/bin/json_process.c b/test/bin/json_process.c
index e2c54bd..724648c 100644
--- a/test/bin/json_process.c
+++ b/test/bin/json_process.c
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#include <stdio.h>
diff --git a/test/scripts/run-tests.sh b/test/scripts/run-tests.sh
index 5ed3b9f..b4433cb 100644
--- a/test/scripts/run-tests.sh
+++ b/test/scripts/run-tests.sh
@@ -1,4 +1,4 @@
-# Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
diff --git a/test/scripts/valgrind.sh b/test/scripts/valgrind.sh
index 9b00438..7ddc7ea 100644
--- a/test/scripts/valgrind.sh
+++ b/test/scripts/valgrind.sh
@@ -1,4 +1,4 @@
-# Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
diff --git a/test/suites/api/run b/test/suites/api/run
index 5f8e959..c127f3a 100755
--- a/test/suites/api/run
+++ b/test/suites/api/run
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
diff --git a/test/suites/api/test_array.c b/test/suites/api/test_array.c
index 0a9447f..f4927b4 100644
--- a/test/suites/api/test_array.c
+++ b/test/suites/api/test_array.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/test/suites/api/test_copy.c b/test/suites/api/test_copy.c
index 580488d..cf1f25a 100644
--- a/test/suites/api/test_copy.c
+++ b/test/suites/api/test_copy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/test/suites/api/test_dump.c b/test/suites/api/test_dump.c
index 64c0863..8731752 100644
--- a/test/suites/api/test_dump.c
+++ b/test/suites/api/test_dump.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -180,6 +180,20 @@ static void escape_slashes()
json_decref(json);
}
+static void encode_nul_byte()
+{
+ json_t *json;
+ char *result;
+
+ json = json_stringn("nul byte \0 in string", 20);
+ result = json_dumps(json, JSON_ENCODE_ANY);
+ if(!result || memcmp(result, "\"nul byte \\u0000 in string\"", 27))
+ fail("json_dumps failed to dump an embedded NUL byte");
+
+ free(result);
+ json_decref(json);
+}
+
static void run_tests()
{
encode_null();
@@ -187,4 +201,5 @@ static void run_tests()
circular_references();
encode_other_than_array_or_object();
escape_slashes();
+ encode_nul_byte();
}
diff --git a/test/suites/api/test_dump_callback.c b/test/suites/api/test_dump_callback.c
index 4536d56..33c3c86 100644
--- a/test/suites/api/test_dump_callback.c
+++ b/test/suites/api/test_dump_callback.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/test/suites/api/test_equal.c b/test/suites/api/test_equal.c
index 354e5c9..31c43ba 100644
--- a/test/suites/api/test_equal.c
+++ b/test/suites/api/test_equal.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/test/suites/api/test_load.c b/test/suites/api/test_load.c
index 944b4d8..d451853 100644
--- a/test/suites/api/test_load.c
+++ b/test/suites/api/test_load.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -115,6 +115,26 @@ static void decode_int_as_real()
#endif
}
+static void allow_nul()
+{
+ const char *text = "\"nul byte \\u0000 in string\"";
+ const char *expected = "nul byte \0 in string";
+ size_t len = 20;
+ json_t *json;
+
+ json = json_loads(text, JSON_ALLOW_NUL | JSON_DECODE_ANY, NULL);
+ if(!json || !json_is_string(json))
+ fail("unable to decode embedded NUL byte");
+
+ if(json_string_length(json) != len)
+ fail("decoder returned wrong string length");
+
+ if(memcmp(json_string_value(json), expected, len + 1))
+ fail("decoder returned wrong string content");
+
+ json_decref(json);
+}
+
static void load_wrong_args()
{
json_t *json;
@@ -161,6 +181,7 @@ static void run_tests()
disable_eof_check();
decode_any();
decode_int_as_real();
+ allow_nul();
load_wrong_args();
position();
}
diff --git a/test/suites/api/test_loadb.c b/test/suites/api/test_loadb.c
index fa5e967..589f484 100644
--- a/test/suites/api/test_loadb.c
+++ b/test/suites/api/test_loadb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/test/suites/api/test_number.c b/test/suites/api/test_number.c
index b506a2b..4651819 100644
--- a/test/suites/api/test_number.c
+++ b/test/suites/api/test_number.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/test/suites/api/test_object.c b/test/suites/api/test_object.c
index 92e5208..5b30738 100644
--- a/test/suites/api/test_object.c
+++ b/test/suites/api/test_object.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
diff --git a/test/suites/api/test_pack.c b/test/suites/api/test_pack.c
index b6ac2e5..9a8a62c 100644
--- a/test/suites/api/test_pack.c
+++ b/test/suites/api/test_pack.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2010-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
*
* Jansson is free software; you can redistribute it and/or modify
@@ -7,7 +7,7 @@
*/
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#include <jansson_config.h>
@@ -83,7 +83,7 @@ static void run_tests()
fail("json_pack string refcount failed");
json_decref(value);
- /* string and length */
+ /* string and length (int) */
value = json_pack("s#", "test asdf", 4);
if(!json_is_string(value) || strcmp("test", json_string_value(value)))
fail("json_pack string and length failed");
@@ -91,14 +91,30 @@ static void run_tests()
fail("json_pack string and length refcount failed");
json_decref(value);
- /* string and length, non-NUL terminated string */
- value = json_pack("s#", buffer, 4);
+ /* string and length (size_t) */
+ value = json_pack("s%", "test asdf", (size_t)4);
if(!json_is_string(value) || strcmp("test", json_string_value(value)))
fail("json_pack string and length failed");
if(value->refcount != (size_t)1)
fail("json_pack string and length refcount failed");
json_decref(value);
+ /* string and length (int), non-NUL terminated string */
+ value = json_pack("s#", buffer, 4);
+ if(!json_is_string(value) || strcmp("test", json_string_value(value)))
+ fail("json_pack string and length (int) failed");
+ if(value->refcount != (size_t)1)
+ fail("json_pack string and length (int) refcount failed");
+ json_decref(value);
+
+ /* string and length (size_t), non-NUL terminated string */
+ value = json_pack("s%", buffer, (size_t)4);
+ if(!json_is_string(value) || strcmp("test", json_string_value(value)))
+ fail("json_pack string and length (size_t) failed");
+ if(value->refcount != (size_t)1)
+ fail("json_pack string and length (size_t) refcount failed");
+ json_decref(value);
+
/* string concatenation */
value = json_pack("s++", "te", "st", "ing");
if(!json_is_string(value) || strcmp("testing", json_string_value(value)))
@@ -107,12 +123,20 @@ static void run_tests()
fail("json_pack string concatenation refcount failed");
json_decref(value);
- /* string concatenation and length */
+ /* string concatenation and length (int) */
value = json_pack("s#+#+", "test", 1, "test", 2, "test");
if(!json_is_string(value) || strcmp("ttetest", json_string_value(value)))
- fail("json_pack string concatenation and length failed");
+ fail("json_pack string concatenation and length (int) failed");
+ if(value->refcount != (size_t)1)
+ fail("json_pack string concatenation and length (int) refcount failed");
+ json_decref(value);
+
+ /* string concatenation and length (size_t) */
+ value = json_pack("s%+%+", "test", (size_t)1, "test", (size_t)2, "test");
+ if(!json_is_string(value) || strcmp("ttetest", json_string_value(value)))
+ fail("json_pack string concatenation and length (size_t) failed");
if(value->refcount != (size_t)1)
- fail("json_pack string concatenation and length refcount failed");
+ fail("json_pack string concatenation and length (size_t) refcount failed");
json_decref(value);
/* empty object */
diff --git a/test/suites/api/test_simple.c b/test/suites/api/test_simple.c
index d24d84e..8b56954 100644
--- a/test/suites/api/test_simple.c
+++ b/test/suites/api/test_simple.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -27,6 +27,8 @@ static void run_tests()
value = json_boolean(0);
if(!json_is_false(value))
fail("json_boolean(0) failed");
+ if(json_boolean_value(value) != 0)
+ fail("json_boolean_value failed");
json_decref(value);
@@ -72,11 +74,22 @@ static void run_tests()
fail("json_string failed");
if(strcmp(json_string_value(value), "foo"))
fail("invalid string value");
+ if (json_string_length(value) != 3)
+ fail("invalid string length");
- if(json_string_set(value, "bar"))
+ if(json_string_set(value, "barr"))
fail("json_string_set failed");
- if(strcmp(json_string_value(value), "bar"))
+ if(strcmp(json_string_value(value), "barr"))
fail("invalid string value");
+ if (json_string_length(value) != 4)
+ fail("invalid string length");
+
+ if(json_string_setn(value, "hi\0ho", 5))
+ fail("json_string_set failed");
+ if(memcmp(json_string_value(value), "hi\0ho\0", 6))
+ fail("invalid string value");
+ if (json_string_length(value) != 5)
+ fail("invalid string length");
json_decref(value);
@@ -94,11 +107,22 @@ static void run_tests()
fail("json_string_nocheck failed");
if(strcmp(json_string_value(value), "foo"))
fail("invalid string value");
+ if (json_string_length(value) != 3)
+ fail("invalid string length");
- if(json_string_set_nocheck(value, "bar"))
+ if(json_string_set_nocheck(value, "barr"))
fail("json_string_set_nocheck failed");
- if(strcmp(json_string_value(value), "bar"))
+ if(strcmp(json_string_value(value), "barr"))
+ fail("invalid string value");
+ if (json_string_length(value) != 4)
+ fail("invalid string length");
+
+ if(json_string_setn_nocheck(value, "hi\0ho", 5))
+ fail("json_string_set failed");
+ if(memcmp(json_string_value(value), "hi\0ho\0", 6))
fail("invalid string value");
+ if (json_string_length(value) != 5)
+ fail("invalid string length");
json_decref(value);
@@ -108,11 +132,15 @@ static void run_tests()
fail("json_string_nocheck failed");
if(strcmp(json_string_value(value), "qu\xff"))
fail("invalid string value");
+ if (json_string_length(value) != 3)
+ fail("invalid string length");
if(json_string_set_nocheck(value, "\xfd\xfe\xff"))
fail("json_string_set_nocheck failed");
if(strcmp(json_string_value(value), "\xfd\xfe\xff"))
fail("invalid string value");
+ if (json_string_length(value) != 3)
+ fail("invalid string length");
json_decref(value);
diff --git a/test/suites/api/test_unpack.c b/test/suites/api/test_unpack.c
index bec8666..fac1be3 100644
--- a/test/suites/api/test_unpack.c
+++ b/test/suites/api/test_unpack.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2010-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
*
* Jansson is free software; you can redistribute it and/or modify
@@ -17,6 +17,7 @@ static void run_tests()
int i1, i2, i3;
json_int_t I1;
int rv;
+ size_t z;
double f;
char *s;
@@ -81,6 +82,13 @@ static void run_tests()
fail("json_unpack string failed");
json_decref(j);
+ /* string with length (size_t) */
+ j = json_string("foo");
+ rv = json_unpack(j, "s%", &s, &z);
+ if(rv || strcmp(s, "foo") || z != 3)
+ fail("json_unpack string with length (size_t) failed");
+ json_decref(j);
+
/* empty object */
j = json_object();
if(json_unpack(j, "{}"))
diff --git a/test/suites/api/util.h b/test/suites/api/util.h
index b86a546..2ee7f4f 100644
--- a/test/suites/api/util.h
+++ b/test/suites/api/util.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -9,7 +9,7 @@
#define UTIL_H
#ifdef HAVE_CONFIG_H
-#include <config.h>
+#include <jansson_private_config.h>
#endif
#include <stdio.h>
diff --git a/test/suites/encoding-flags/ensure-ascii/output b/test/suites/encoding-flags/ensure-ascii/output
index 36f8eb5..94fa79d 100644
--- a/test/suites/encoding-flags/ensure-ascii/output
+++ b/test/suites/encoding-flags/ensure-ascii/output
@@ -1 +1 @@
-["foo", "\u00e5 \u00e4 \u00f6", "foo \u00e5\u00e4", "\u00e5\u00e4 foo", "\u00e5 foo \u00e4", "clef g: \ud834\udd1e"] \ No newline at end of file
+["foo", "\u00E5 \u00E4 \u00F6", "foo \u00E5\u00E4", "\u00E5\u00E4 foo", "\u00E5 foo \u00E4", "clef g: \uD834\uDD1E"] \ No newline at end of file
diff --git a/test/suites/encoding-flags/run b/test/suites/encoding-flags/run
index 1920f7f..e1c88c9 100755
--- a/test/suites/encoding-flags/run
+++ b/test/suites/encoding-flags/run
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
diff --git a/test/suites/invalid-unicode/run b/test/suites/invalid-unicode/run
index ac584f6..b2c6648 100755
--- a/test/suites/invalid-unicode/run
+++ b/test/suites/invalid-unicode/run
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
diff --git a/test/suites/invalid/escaped-null-byte-in-string/error b/test/suites/invalid/escaped-null-byte-in-string/error
deleted file mode 100644
index 9795f18..0000000
--- a/test/suites/invalid/escaped-null-byte-in-string/error
+++ /dev/null
@@ -1,2 +0,0 @@
-1 33 33
-\u0000 is not allowed
diff --git a/test/suites/invalid/escaped-null-byte-in-string/input b/test/suites/invalid/escaped-null-byte-in-string/input
deleted file mode 100644
index 22ae82b..0000000
--- a/test/suites/invalid/escaped-null-byte-in-string/input
+++ /dev/null
@@ -1 +0,0 @@
-["\u0000 (null byte not allowed)"]
diff --git a/test/suites/invalid/null-byte-in-object-key/error b/test/suites/invalid/null-byte-in-object-key/error
new file mode 100644
index 0000000..3ec685b
--- /dev/null
+++ b/test/suites/invalid/null-byte-in-object-key/error
@@ -0,0 +1,2 @@
+1 15 15
+NUL byte in object key not supported near '"foo\u0000bar"'
diff --git a/test/suites/invalid/null-byte-in-object-key/input b/test/suites/invalid/null-byte-in-object-key/input
new file mode 100644
index 0000000..593f0f6
--- /dev/null
+++ b/test/suites/invalid/null-byte-in-object-key/input
@@ -0,0 +1 @@
+{"foo\u0000bar": 42} \ No newline at end of file
diff --git a/test/suites/invalid/run b/test/suites/invalid/run
index a640ea0..4f2325b 100755
--- a/test/suites/invalid/run
+++ b/test/suites/invalid/run
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
diff --git a/test/suites/valid/run b/test/suites/valid/run
index c30d94a..72f1918 100755
--- a/test/suites/valid/run
+++ b/test/suites/valid/run
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
+# Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org>
#
# Jansson is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
diff --git a/win32/jansson_config.h b/win32/jansson_config.h
index ab1da5d..87f8d51 100644
--- a/win32/jansson_config.h
+++ b/win32/jansson_config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2013 Petri Lehtinen <petri@digip.org>
+ * Copyright (c) 2010-2014 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.