diff options
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 @@ -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") @@ -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. @@ -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 @@ -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 @@ -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)) @@ -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. |