Преглед изворни кода

Updated to Jansson 2.14.e23f558

Brucey пре 2 година
родитељ
комит
32754bd131
100 измењених фајлова са 6640 додато и 828 уклоњено
  1. 2 0
      .gitignore
  2. 5 3
      jansson.mod/jansson.bmx
  3. 5 0
      jansson.mod/jansson/.clang-format
  4. 31 0
      jansson.mod/jansson/.github/workflows/fuzz.yml
  5. 80 0
      jansson.mod/jansson/.github/workflows/tests.yml
  6. 0 34
      jansson.mod/jansson/.travis.yml
  7. 27 2
      jansson.mod/jansson/CHANGES
  8. 45 73
      jansson.mod/jansson/CMakeLists.txt
  9. 3 0
      jansson.mod/jansson/CONTRIBUTING.md
  10. 15 22
      jansson.mod/jansson/README.rst
  11. 2 0
      jansson.mod/jansson/appveyor.yml
  12. 3 3
      jansson.mod/jansson/cmake/CodeCoverage.cmake
  13. 0 111
      jansson.mod/jansson/cmake/Coveralls.cmake
  14. 0 24
      jansson.mod/jansson/cmake/CoverallsClear.cmake
  15. 0 380
      jansson.mod/jansson/cmake/CoverallsGenerateGcov.cmake
  16. 5 1
      jansson.mod/jansson/configure.ac
  17. 2 2
      jansson.mod/jansson/doc/Makefile.am
  18. 187 34
      jansson.mod/jansson/doc/apiref.rst
  19. 1 1
      jansson.mod/jansson/doc/conf.py
  20. 2 3
      jansson.mod/jansson/doc/conformance.rst
  21. 20 11
      jansson.mod/jansson/doc/ext/refcounting.py
  22. 1 0
      jansson.mod/jansson/doc/github_commits.c
  23. 1 1
      jansson.mod/jansson/doc/index.rst
  24. 4 7
      jansson.mod/jansson/doc/threadsafety.rst
  25. 8 8
      jansson.mod/jansson/doc/upgrading.rst
  26. 4 0
      jansson.mod/jansson/examples/README.rst
  27. 200 0
      jansson.mod/jansson/examples/simple_parse.c
  28. 3 0
      jansson.mod/jansson/release.sh
  29. 27 0
      jansson.mod/jansson/scripts/clang-format-check
  30. 2 1
      jansson.mod/jansson/src/Makefile.am
  31. 38 17
      jansson.mod/jansson/src/dump.c
  32. 57 35
      jansson.mod/jansson/src/hashtable.c
  33. 16 4
      jansson.mod/jansson/src/hashtable.h
  34. 5 0
      jansson.mod/jansson/src/jansson.def
  35. 36 4
      jansson.mod/jansson/src/jansson.h
  36. 3 3
      jansson.mod/jansson/src/jansson_private.h
  37. 2 2
      jansson.mod/jansson/src/load.c
  38. 1 1
      jansson.mod/jansson/src/lookup3.h
  39. 5 4
      jansson.mod/jansson/src/pack_unpack.c
  40. 2 3
      jansson.mod/jansson/src/strconv.c
  41. 92 34
      jansson.mod/jansson/src/value.c
  42. 20 0
      jansson.mod/jansson/test/.gitignore
  43. 10 0
      jansson.mod/jansson/test/Makefile.am
  44. 5 0
      jansson.mod/jansson/test/bin/Makefile.am
  45. 366 0
      jansson.mod/jansson/test/bin/json_process.c
  46. 1 0
      jansson.mod/jansson/test/ossfuzz/.gitignore
  47. 32 0
      jansson.mod/jansson/test/ossfuzz/Makefile.am
  48. 132 0
      jansson.mod/jansson/test/ossfuzz/json_load_dump_fuzzer.cc
  49. 30 0
      jansson.mod/jansson/test/ossfuzz/ossfuzz.sh
  50. 74 0
      jansson.mod/jansson/test/ossfuzz/standaloneengine.cc
  51. 3 0
      jansson.mod/jansson/test/ossfuzz/testinput.h
  52. 50 0
      jansson.mod/jansson/test/run-suites
  53. 100 0
      jansson.mod/jansson/test/scripts/run-tests.sh
  54. 35 0
      jansson.mod/jansson/test/scripts/valgrind.sh
  55. 2 0
      jansson.mod/jansson/test/suites/.gitattributes
  56. 2 0
      jansson.mod/jansson/test/suites/Makefile.am
  57. 42 0
      jansson.mod/jansson/test/suites/api/Makefile.am
  58. 23 0
      jansson.mod/jansson/test/suites/api/check-exports
  59. 36 0
      jansson.mod/jansson/test/suites/api/run
  60. 484 0
      jansson.mod/jansson/test/suites/api/test_array.c
  61. 168 0
      jansson.mod/jansson/test/suites/api/test_chaos.c
  62. 375 0
      jansson.mod/jansson/test/suites/api/test_copy.c
  63. 311 0
      jansson.mod/jansson/test/suites/api/test_dump.c
  64. 82 0
      jansson.mod/jansson/test/suites/api/test_dump_callback.c
  65. 202 0
      jansson.mod/jansson/test/suites/api/test_equal.c
  66. 228 0
      jansson.mod/jansson/test/suites/api/test_fixed_size.c
  67. 238 0
      jansson.mod/jansson/test/suites/api/test_load.c
  68. 77 0
      jansson.mod/jansson/test/suites/api/test_load_callback.c
  69. 37 0
      jansson.mod/jansson/test/suites/api/test_loadb.c
  70. 115 0
      jansson.mod/jansson/test/suites/api/test_memory_funcs.c
  71. 123 0
      jansson.mod/jansson/test/suites/api/test_number.c
  72. 797 0
      jansson.mod/jansson/test/suites/api/test_object.c
  73. 547 0
      jansson.mod/jansson/test/suites/api/test_pack.c
  74. 287 0
      jansson.mod/jansson/test/suites/api/test_simple.c
  75. 29 0
      jansson.mod/jansson/test/suites/api/test_sprintf.c
  76. 431 0
      jansson.mod/jansson/test/suites/api/test_unpack.c
  77. 61 0
      jansson.mod/jansson/test/suites/api/test_version.c
  78. 93 0
      jansson.mod/jansson/test/suites/api/util.h
  79. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/array/input
  80. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/array/output
  81. 2 0
      jansson.mod/jansson/test/suites/encoding-flags/compact-array/env
  82. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/compact-array/input
  83. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/compact-array/output
  84. 3 0
      jansson.mod/jansson/test/suites/encoding-flags/compact-object/env
  85. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/compact-object/input
  86. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/compact-object/output
  87. 2 0
      jansson.mod/jansson/test/suites/encoding-flags/ensure-ascii/env
  88. 8 0
      jansson.mod/jansson/test/suites/encoding-flags/ensure-ascii/input
  89. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/ensure-ascii/output
  90. 2 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-array/env
  91. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-array/input
  92. 4 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-array/output
  93. 3 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-compact-array/env
  94. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-compact-array/input
  95. 4 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-compact-array/output
  96. 4 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-compact-object/env
  97. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-compact-object/input
  98. 4 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-compact-object/output
  99. 3 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-object/env
  100. 1 0
      jansson.mod/jansson/test/suites/encoding-flags/indent-object/input

+ 2 - 0
.gitignore

@@ -5,3 +5,5 @@
 *.bak
 *.bak
 *.exe
 *.exe
 commands.html
 commands.html
+
+.DS_Store

+ 5 - 3
jansson.mod/jansson.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2014-2020 Bruce A Henderson
+' Copyright (c) 2014-2022 Bruce A Henderson
 ' 
 ' 
 ' Permission is hereby granted, free of charge, to any person obtaining a copy
 ' Permission is hereby granted, free of charge, to any person obtaining a copy
 ' of this software and associated documentation files (the "Software"), to deal
 ' of this software and associated documentation files (the "Software"), to deal
@@ -22,11 +22,13 @@ SuperStrict
 
 
 Module Text.Jansson
 Module Text.Jansson
 
 
-ModuleInfo "Version: 1.06"
+ModuleInfo "Version: 1.07"
 ModuleInfo "Author: Bruce A Henderson"
 ModuleInfo "Author: Bruce A Henderson"
 ModuleInfo "License: MIT"
 ModuleInfo "License: MIT"
-ModuleInfo "Copyright: 2014-2020 Bruce A Henderson"
+ModuleInfo "Copyright: 2014-2022 Bruce A Henderson"
 
 
+ModuleInfo "History: 1.07"
+ModuleInfo "History: Updated to Jansson 2.14.e23f558"
 ModuleInfo "History: 1.06"
 ModuleInfo "History: 1.06"
 ModuleInfo "History: Updated to Jansson 2.13.1."
 ModuleInfo "History: Updated to Jansson 2.13.1."
 ModuleInfo "History: 1.05"
 ModuleInfo "History: 1.05"

+ 5 - 0
jansson.mod/jansson/.clang-format

@@ -0,0 +1,5 @@
+BasedOnStyle: LLVM
+AlignConsecutiveMacros: true
+ColumnLimit: 90
+IndentCaseLabels: true
+IndentWidth: 4

+ 31 - 0
jansson.mod/jansson/.github/workflows/fuzz.yml

@@ -0,0 +1,31 @@
+name: oss-fuzz
+
+on:
+  pull_request:
+    branches: [ master ]
+    paths:
+      - '**.c'
+      - '**.h'
+
+jobs:
+  fuzz:
+    runs-on: ubuntu-latest
+    steps:
+    - name: Build Fuzzers
+      id: build
+      uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
+      with:
+        oss-fuzz-project-name: 'jansson'
+        dry-run: false
+    - name: Run Fuzzers
+      uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
+      with:
+        oss-fuzz-project-name: 'jansson'
+        fuzz-seconds: 600
+        dry-run: false
+    - name: Upload Crash
+      uses: actions/upload-artifact@v1
+      if: failure() && steps.build.outcome == 'success'
+      with:
+        name: artifacts
+        path: ./out/artifacts

+ 80 - 0
jansson.mod/jansson/.github/workflows/tests.yml

@@ -0,0 +1,80 @@
+name: tests
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+jobs:
+  lint:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - run: ./scripts/clang-format-check
+
+  autotools:
+    strategy:
+      matrix:
+        os: ["ubuntu-latest", "macos-latest"]
+        cc: ["gcc", "clang"]
+
+    runs-on: ${{matrix.os}}
+
+    steps:
+      - if: ${{runner.os == 'macOS'}}
+        run: brew install autoconf automake libtool
+      - uses: actions/checkout@v2
+      - run: autoreconf -fi
+      - env:
+          CC: ${{matrix.cc}}
+          CFLAGS: -Werror
+        run: ./configure
+      - run: make check
+
+  cmake:
+    strategy:
+      matrix:
+        os: ["ubuntu-latest", "macos-latest", "windows-latest"]
+        cc: ["gcc", "clang"]
+        exclude:
+          - os: windows-latest
+            cc: gcc
+          - os: windows-latest
+            cc: clang
+        include:
+          - os: windows-latest
+            cc: 'msvc'  # Doesn't really matter, MSVC is always used on Windows
+
+    runs-on: ${{matrix.os}}
+
+    steps:
+      - uses: actions/checkout@v2
+      - env:
+          CC: ${{matrix.cc}}
+        run: cmake .
+      - run: cmake --build .
+      - run: ctest
+
+  valgrind:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - run: sudo apt update && sudo apt install valgrind
+      - run: cmake -DJANSSON_TEST_WITH_VALGRIND=ON .
+      - run: cmake --build .
+      - run: ctest
+
+  coveralls:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - run: sudo apt update && sudo apt install curl lcov
+      - run: cmake -DJANSSON_COVERAGE=ON -DCMAKE_BUILD_TYPE=Debug .
+      - run: cmake --build .
+      - run: cmake --build . --target coverage
+      - name: Coveralls
+        uses: coverallsapp/github-action@master
+        with:
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          path-to-lcov: coverage.info

+ 0 - 34
jansson.mod/jansson/.travis.yml

@@ -1,34 +0,0 @@
-env:
-  global:
-    - CLANG_FORMAT_VERSION=9
-  matrix:
-    - JANSSON_BUILD_METHOD=cmake JANSSON_CMAKE_OPTIONS="-DJANSSON_TEST_WITH_VALGRIND=ON" JANSSON_EXTRA_INSTALL="valgrind"
-    - JANSSON_BUILD_METHOD=autotools
-    - JANSSON_BUILD_METHOD=coverage JANSSON_CMAKE_OPTIONS="-DJANSSON_COVERAGE=ON -DJANSSON_COVERALLS=ON -DCMAKE_BUILD_TYPE=Debug" JANSSON_EXTRA_INSTALL="lcov curl"
-    - JANSSON_BUILD_METHOD=fuzzer
-    - JANSSON_BUILD_METHOD=lint CLANG_FORMAT=clang-format-9
-dist: bionic
-language: c
-compiler:
-  - gcc
-  - clang
-matrix:
-  exclude:
-    - compiler: clang
-      env: JANSSON_BUILD_METHOD=coverage JANSSON_CMAKE_OPTIONS="-DJANSSON_COVERAGE=ON -DJANSSON_COVERALLS=ON -DCMAKE_BUILD_TYPE=Debug" JANSSON_EXTRA_INSTALL="lcov curl"
-    - compiler: clang
-      env: JANSSON_BUILD_METHOD=fuzzer
-    - compiler: gcc
-      env: JANSSON_BUILD_METHOD=lint CLANG_FORMAT=clang-format-9
-  allow_failures:
-    - env: JANSSON_BUILD_METHOD=coverage JANSSON_CMAKE_OPTIONS="-DJANSSON_COVERAGE=ON -DJANSSON_COVERALLS=ON -DCMAKE_BUILD_TYPE=Debug" JANSSON_EXTRA_INSTALL="lcov curl"
-install:
-  - sudo apt-get update -qq
-  - sudo apt-get install -y -qq cmake $JANSSON_EXTRA_INSTALL
-  - if [ "$TRAVIS_COMPILER" = "clang" ]; then sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y && wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - && sudo apt-add-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" -y && sudo apt-get install -y -qq clang-9 clang-format-9; fi
-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
-  - if [ "$JANSSON_BUILD_METHOD" = "coverage" ]; then mkdir build && cd build && cmake $JANSSON_CMAKE_OPTIONS .. && cmake --build . && cmake --build . --target coveralls; fi
-  - if [ "$JANSSON_BUILD_METHOD" = "fuzzer" ]; then ./test/ossfuzz/travisoss.sh; fi
-  - if [ "$JANSSON_BUILD_METHOD" = "lint" ]; then ./scripts/clang-format-check; fi

+ 27 - 2
jansson.mod/jansson/CHANGES

@@ -1,3 +1,28 @@
+Version 2.14
+============
+
+Released 2021-09-09
+
+* New Features:
+
+  - Add `json_object_getn`, `json_object_setn`, `json_object_deln`, and the
+    corresponding `nocheck` functions. (#520, by Maxim Zhukov)
+
+* Fixes:
+
+  - Handle `sprintf` corner cases (#537, by Tobias Stoeckmann)
+
+* Build:
+
+  - Symbol versioning for all exported symbols (#540, by Simon McVittie)
+  - Fix compiler warnings (#555, by Kelvin Lee)
+
+* Documentation:
+
+  - Small fixes (#544, #546, by @i-ky)
+  - Sphinx 3 compatibility (#543, by Pierce Lopez)
+
+
 Version 2.13.1
 Version 2.13.1
 ==============
 ==============
 
 
@@ -8,7 +33,7 @@ Released 2020-05-07
   - Include `jansson_version_str()` and `jansson_version_cmp()` in
   - Include `jansson_version_str()` and `jansson_version_cmp()` in
     shared library. (#534)
     shared library. (#534)
 
 
-  - Include `scripts/` in tarball. (#535)
+  - Include ``scripts/`` in tarball. (#535)
 
 
 
 
 Version 2.13
 Version 2.13
@@ -127,7 +152,7 @@ Released 2018-02-09
 
 
   - Work around gcc's -Wimplicit-fallthrough.
   - Work around gcc's -Wimplicit-fallthrough.
 
 
-  - Fix CMake detection of `sys/types.h` header (#375).
+  - Fix CMake detection of ``sys/types.h`` header (#375).
 
 
   - Fix `jansson.pc` generated by CMake to be more consistent with the one
   - Fix `jansson.pc` generated by CMake to be more consistent with the one
     generated using GNU Autotools (#368).
     generated using GNU Autotools (#368).

+ 45 - 73
jansson.mod/jansson/CMakeLists.txt

@@ -1,51 +1,3 @@
-# Notes:
-#
-# Author: Paul Harris, June 2012
-# Additions: Joakim Soderberg, February 2013
-#
-# Supports: building static/shared, release/debug/etc, can also build html docs
-# and some of the tests.
-# Note that its designed for out-of-tree builds, so it will not pollute your
-# source tree.
-#
-# TODO 1: Finish implementing tests. api tests are working, but the valgrind
-# variants are not flagging problems.
-#
-# TODO 2: There is a check_exports script that would try and incorporate.
-#
-# TODO 3: Consolidate version numbers, currently the version number is written
-# into: * cmake (here) * autotools (the configure) * source code header files.
-# Should not be written directly into header files, autotools/cmake can do
-# that job.
-#
-# Brief intro on how to use cmake:
-# > mkdir build (somewhere - we do out-of-tree builds)
-# > use cmake, ccmake, or cmake-gui to configure the project. for linux, you
-# can only choose one variant: release,debug,etc... and static or shared.
-# >> example:
-# >> cd build
-# >> ccmake -i ../path_to_jansson_dir
-# >>  inside, configure your options. press C until there are no lines
-#     with * next to them.
-# >>  note, I like to configure the 'install' path to ../install, so I get
-#     self-contained clean installs I can point other projects to.
-# >>  press G to 'generate' the project files.
-# >> make (to build the project)
-# >> make install
-# >> make test (to run the tests, if you enabled them)
-#
-# Brief description on how it works:
-# There is a small hierarchy of CMakeLists.txt files which define how the
-# project is built.
-# Header file detection etc is done, and the results are written into config.h
-# and jansson_config.h, which are generated from the corresponding
-# config.h.cmake and jansson_config.h.cmake template files.
-# The generated header files end up in the build directory - not in
-# the source directory.
-# The rest is down to the usual make process.
-
-
-
 cmake_minimum_required (VERSION 3.1)
 cmake_minimum_required (VERSION 3.1)
 project(jansson C)
 project(jansson C)
 
 
@@ -64,8 +16,6 @@ option(JANSSON_EXAMPLES "Compile example applications" ON)
 
 
 if (UNIX)
 if (UNIX)
    option(JANSSON_COVERAGE "(GCC Only! Requires gcov/lcov to be installed). Include target for doing coverage analysis for the test suite. Note that -DCMAKE_BUILD_TYPE=Debug must be set" OFF)
    option(JANSSON_COVERAGE "(GCC Only! Requires gcov/lcov to be installed). Include target for doing coverage analysis for the test suite. Note that -DCMAKE_BUILD_TYPE=Debug must be set" OFF)
-   option(JANSSON_COVERALLS "Generate coverage info for Coveralls" OFF)
-   option(JANSSON_COVERALLS_UPLOAD "Upload coverage info to Coveralls (Only works via Travis)" ON)
 endif ()
 endif ()
 
 
 # Set some nicer output dirs.
 # Set some nicer output dirs.
@@ -85,10 +35,10 @@ endif()
 # set (JANSSON_VERSION "2.3.1")
 # set (JANSSON_VERSION "2.3.1")
 # set (JANSSON_SOVERSION 2)
 # set (JANSSON_SOVERSION 2)
 
 
-set(JANSSON_DISPLAY_VERSION "2.13.1")
+set(JANSSON_DISPLAY_VERSION "2.14")
 
 
 # This is what is required to match the same numbers as automake's
 # This is what is required to match the same numbers as automake's
-set(JANSSON_VERSION "4.13.0")
+set(JANSSON_VERSION "4.14.0")
 set(JANSSON_SOVERSION 4)
 set(JANSSON_SOVERSION 4)
 
 
 # for CheckFunctionKeywords
 # for CheckFunctionKeywords
@@ -119,17 +69,9 @@ endif()
 
 
 message("C compiler: ${CMAKE_C_COMPILER_ID}")
 message("C compiler: ${CMAKE_C_COMPILER_ID}")
 
 
-# Coverage only works with GCC for a debug build.
-if (JANSSON_COVERALLS)
-   set(JANSSON_COVERAGE ON)
-endif()
-
 if (JANSSON_COVERAGE)
 if (JANSSON_COVERAGE)
    include(CodeCoverage)
    include(CodeCoverage)
-   include(Coveralls)
-
-   # This adds coverage arguments to gcc/clang.
-   coveralls_turn_on_coverage()
+   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
 endif()
 endif()
 
 
 check_include_files (endian.h HAVE_ENDIAN_H)
 check_include_files (endian.h HAVE_ENDIAN_H)
@@ -366,6 +308,44 @@ if(JANSSON_BUILD_SHARED_LIBS)
       ${JANSSON_HDR_PUBLIC}
       ${JANSSON_HDR_PUBLIC}
       src/jansson.def)
       src/jansson.def)
 
 
+# check if linker support --default-symver
+   list(APPEND CMAKE_REQUIRED_LIBRARIES "-Wl,--default-symver")
+   check_c_source_compiles(
+   "
+   int main (void)
+   {
+      return 0;
+   }
+   "
+   DSYMVER_WORKS
+   )
+   list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "-Wl,--default-symver")
+
+   if (SYMVER_WORKS)
+      set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--default-symver")
+   else()
+# some linkers may only support --version-script
+      file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/jansson.sym" "JANSSON_${JANSSON_SOVERSION} {
+    global:
+          *;
+};
+")
+      list(APPEND CMAKE_REQUIRED_LIBRARIES "-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/jansson.sym")
+      check_c_source_compiles(
+   "
+   int main (void)
+   {
+      return 0;
+   }
+   "
+   VSCRIPT_WORKS
+   )
+      list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/jansson.sym")
+      if (VSCRIPT_WORKS)
+         set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/jansson.sym")
+      endif()
+   endif()
+
    set_target_properties(jansson PROPERTIES
    set_target_properties(jansson PROPERTIES
       VERSION ${JANSSON_VERSION}
       VERSION ${JANSSON_VERSION}
       SOVERSION ${JANSSON_SOVERSION})
       SOVERSION ${JANSSON_SOVERSION})
@@ -501,14 +481,15 @@ if (NOT JANSSON_WITHOUT_TESTS)
 
 
    set(api_tests
    set(api_tests
          test_array
          test_array
-         test_copy
          test_chaos
          test_chaos
+         test_copy
          test_dump
          test_dump
          test_dump_callback
          test_dump_callback
          test_equal
          test_equal
+         test_fixed_size
          test_load
          test_load
-         test_loadb
          test_load_callback
          test_load_callback
+         test_loadb
          test_number
          test_number
          test_object
          test_object
          test_pack
          test_pack
@@ -578,16 +559,7 @@ if (NOT JANSSON_WITHOUT_TESTS)
    endforeach ()
    endforeach ()
 
 
    if (JANSSON_COVERAGE)
    if (JANSSON_COVERAGE)
-      setup_target_for_coverage(
-            coverage             # Coverage make target "make coverage".
-            coverage             # Name of output directory.
-            make                 # Name of test runner executable.
-            test)                # Arguments to the test runner above (make test).
-
-      if (JANSSON_COVERALLS)
-         set(COVERAGE_SRCS ${JANSSON_SRC})
-         coveralls_setup("${COVERAGE_SRCS}" ${JANSSON_COVERALLS_UPLOAD})
-      endif ()
+      SETUP_TARGET_FOR_COVERAGE(coverage coverage ctest)
    endif ()
    endif ()
 
 
    # Enable using "make check" just like the autotools project.
    # Enable using "make check" just like the autotools project.

+ 3 - 0
jansson.mod/jansson/CONTRIBUTING.md

@@ -0,0 +1,3 @@
+Hi, and thanks for contributing!
+
+Please remember to add tests and documentation for new functionality. Backwards incompatible changes or features that are not directly related to JSON are likely to be rejected.

+ 15 - 22
jansson.mod/jansson/README.rst

@@ -1,9 +1,9 @@
 Jansson README
 Jansson README
 ==============
 ==============
 
 
-.. image:: https://travis-ci.org/akheron/jansson.png
-  :target: https://travis-ci.org/akheron/jansson
-  
+.. image:: https://github.com/akheron/jansson/workflows/tests/badge.svg
+  :target: https://github.com/akheron/jansson/actions
+
 .. image:: https://ci.appveyor.com/api/projects/status/lmhkkc4q8cwc65ko
 .. image:: https://ci.appveyor.com/api/projects/status/lmhkkc4q8cwc65ko
   :target: https://ci.appveyor.com/project/akheron/jansson
   :target: https://ci.appveyor.com/project/akheron/jansson
 
 
@@ -26,24 +26,11 @@ data. Its main features and design principles are:
 Jansson is licensed under the `MIT license`_; see LICENSE in the
 Jansson is licensed under the `MIT license`_; see LICENSE in the
 source distribution for details.
 source distribution for details.
 
 
-
 Compilation and Installation
 Compilation and Installation
 ----------------------------
 ----------------------------
 
 
-You can download and install Jansson using the `vcpkg <https://github.com/Microsoft/vcpkg/>`_ dependency manager:
-
-.. code-block:: bash
-
-    git clone https://github.com/Microsoft/vcpkg.git
-    cd vcpkg
-    ./bootstrap-vcpkg.sh
-    ./vcpkg integrate install
-    vcpkg install jansson
-
-The Jansson port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please `create an issue or pull request <https://github.com/Microsoft/vcpkg/>`_ on the vcpkg repository.
-
-If you obtained a `source tarball`_ from the "Releases" section of the main
-site just use the standard autotools commands::
+If you obtained a ``jansson-X.Y.tar.*`` tarball from GitHub Releases, just use
+the standard autotools commands::
 
 
    $ ./configure
    $ ./configure
    $ make
    $ make
@@ -53,9 +40,8 @@ To run the test suite, invoke::
 
 
    $ make check
    $ make check
 
 
-If the source has been checked out from a Git repository, the
-./configure script has to be generated first. The easiest way is to
-use autoreconf::
+If the source has been checked out from a Git repository, the ``configure``
+script has to be generated first. The easiest way is to use autoreconf::
 
 
    $ autoreconf -i
    $ autoreconf -i
 
 
@@ -74,8 +60,15 @@ Then, point your browser to ``doc/_build/html/index.html``. Sphinx_
 1.0 or newer is required to generate the documentation.
 1.0 or newer is required to generate the documentation.
 
 
 
 
+Community
+---------
+
+* `Documentation <http://jansson.readthedocs.io/en/latest/>`_
+* `Issue tracker <https://github.com/akheron/jansson/issues>`_
+* `Mailing list <http://groups.google.com/group/jansson-users>`_
+* `Wiki <https://github.com/akheron/jansson/wiki>`_ contains some development documentation
+
 .. _Jansson: http://www.digip.org/jansson/
 .. _Jansson: http://www.digip.org/jansson/
 .. _`Comprehensive documentation`: http://jansson.readthedocs.io/en/latest/
 .. _`Comprehensive documentation`: http://jansson.readthedocs.io/en/latest/
 .. _`MIT license`: http://www.opensource.org/licenses/mit-license.php
 .. _`MIT license`: http://www.opensource.org/licenses/mit-license.php
-.. _`source tarball`: http://www.digip.org/jansson#releases
 .. _Sphinx: http://sphinx.pocoo.org/
 .. _Sphinx: http://sphinx.pocoo.org/

+ 2 - 0
jansson.mod/jansson/appveyor.yml

@@ -7,6 +7,8 @@ environment:
     - VS: Visual Studio 14 2015
     - VS: Visual Studio 14 2015
     - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
     - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
       VS: Visual Studio 15 2017
       VS: Visual Studio 15 2017
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+      VS: Visual Studio 16 2019
 
 
 build_script:
 build_script:
   - md build
   - md build

+ 3 - 3
jansson.mod/jansson/cmake/CodeCoverage.cmake

@@ -111,9 +111,9 @@ FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _outputname _testrunner)
 		
 		
 		# Capturing lcov counters and generating report
 		# Capturing lcov counters and generating report
 		COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info --rc lcov_branch_coverage=1
 		COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info --rc lcov_branch_coverage=1
-		COMMAND ${LCOV_PATH} --remove ${_outputname}.info '*/build/include/*' '*/test/*' '/usr/include/*' --output-file ${_outputname}.info.cleaned --rc lcov_branch_coverage=1
-		COMMAND ${GENHTML_PATH} --branch-coverage -o ${_outputname} ${_outputname}.info.cleaned
-		COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned
+		COMMAND ${LCOV_PATH} --remove ${_outputname}.info '*/build/include/*' '*/test/*' '/usr/include/*' --output-file ${_outputname}.info --rc lcov_branch_coverage=1
+		# COMMAND ${GENHTML_PATH} --branch-coverage -o ${_outputname} ${_outputname}.info.cleaned
+		# COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned
 		
 		
 		WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
 		WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
 		COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
 		COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."

+ 0 - 111
jansson.mod/jansson/cmake/Coveralls.cmake

@@ -1,111 +0,0 @@
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-# Copyright (C) 2014 Joakim Söderberg <[email protected]>
-#
-
-
-#
-# Param _COVERAGE_SRCS	A list of source files that coverage should be collected for.
-# Param _COVERALLS_UPLOAD Upload the result to coveralls?
-#
-function(coveralls_setup _COVERAGE_SRCS _COVERALLS_UPLOAD)
-	# When passing a CMake list to an external process, the list
-	# will be converted from the format "1;2;3" to "1 2 3".
-	# This means the script we're calling won't see it as a list
-	# of sources, but rather just one long path. We remedy this
-	# by replacing ";" with "*" and then reversing that in the script
-	# that we're calling.
-	# http://cmake.3232098.n2.nabble.com/Passing-a-CMake-list-quot-as-is-quot-to-a-custom-target-td6505681.html
-	set(COVERAGE_SRCS_TMP ${_COVERAGE_SRCS})
-	set(COVERAGE_SRCS "")
-	foreach (COVERAGE_SRC ${COVERAGE_SRCS_TMP})
-		set(COVERAGE_SRCS "${COVERAGE_SRCS}*${COVERAGE_SRC}")
-	endforeach()
-
-	#message("Coverage sources: ${COVERAGE_SRCS}")
-	set(COVERALLS_FILE ${PROJECT_BINARY_DIR}/coveralls.json)
-
-	add_custom_target(coveralls_generate
-
-		# Zero the coverage counters.
-		COMMAND ${CMAKE_COMMAND}
-				-P "${PROJECT_SOURCE_DIR}/cmake/CoverallsClear.cmake"
-
-		# Run regress tests.
-		COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
-
-		# Generate Gcov and translate it into coveralls JSON.
-		# We do this by executing an external CMake script.
-		# (We don't want this to run at CMake generation time, but after compilation and everything has run).
-		COMMAND ${CMAKE_COMMAND}
-				-DCOVERAGE_SRCS="${COVERAGE_SRCS}" # TODO: This is passed like: "a b c", not "a;b;c"
-				-DCOVERALLS_OUTPUT_FILE="${COVERALLS_FILE}"
-				-DCOV_PATH="${PROJECT_BINARY_DIR}"
-				-DPROJECT_ROOT="${PROJECT_SOURCE_DIR}"
-				-P "${PROJECT_SOURCE_DIR}/cmake/CoverallsGenerateGcov.cmake"
-
-		WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
-		COMMENT "Generating coveralls output..."
-		)
-
-	if (_COVERALLS_UPLOAD)
-		message("COVERALLS UPLOAD: ON")
-
-		find_program(CURL_EXECUTABLE curl)
-
-		if (NOT CURL_EXECUTABLE)
-			message(FATAL_ERROR "Coveralls: curl not found! Aborting")
-		endif()
-
-		add_custom_target(coveralls_upload
-			# Upload the JSON to coveralls.
-			COMMAND ${CURL_EXECUTABLE}
-					-S -F json_file=@${COVERALLS_FILE}
-					https://coveralls.io/api/v1/jobs
-
-			DEPENDS coveralls_generate
-
-			WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
-			COMMENT "Uploading coveralls output...")
-
-		add_custom_target(coveralls DEPENDS coveralls_upload)
-	else()
-		message("COVERALLS UPLOAD: OFF")
-		add_custom_target(coveralls DEPENDS coveralls_generate)
-	endif()
-
-endfunction()
-
-macro(coveralls_turn_on_coverage)
-	if(NOT (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
-		AND (NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang"))
-		message(FATAL_ERROR "Coveralls: Compiler ${CMAKE_C_COMPILER_ID} is not GNU gcc! Aborting... You can set this on the command line using CC=/usr/bin/gcc CXX=/usr/bin/g++ cmake <options> ..")
-	endif()
-
-	if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
-		message(FATAL_ERROR "Coveralls: Code coverage results with an optimised (non-Debug) build may be misleading! Add -DCMAKE_BUILD_TYPE=Debug")
-	endif()
-
-	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
-	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
-endmacro()
-
-
-

+ 0 - 24
jansson.mod/jansson/cmake/CoverallsClear.cmake

@@ -1,24 +0,0 @@
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-# Copyright (C) 2014 Joakim Söderberg <[email protected]>
-#
-
-file(REMOVE_RECURSE ${PROJECT_BINARY_DIR}/*.gcda)
-

+ 0 - 380
jansson.mod/jansson/cmake/CoverallsGenerateGcov.cmake

@@ -1,380 +0,0 @@
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-# Copyright (C) 2014 Joakim Söderberg <[email protected]>
-#
-# This is intended to be run by a custom target in a CMake project like this.
-# 0. Compile program with coverage support.
-# 1. Clear coverage data. (Recursively delete *.gcda in build dir)
-# 2. Run the unit tests.
-# 3. Run this script specifying which source files the coverage should be performed on.
-#
-# This script will then use gcov to generate .gcov files in the directory specified
-# via the COV_PATH var. This should probably be the same as your cmake build dir.
-#
-# It then parses the .gcov files to convert them into the Coveralls JSON format:
-# https://coveralls.io/docs/api
-#
-# Example for running as standalone CMake script from the command line:
-# (Note it is important the -P is at the end...)
-# $ cmake -DCOV_PATH=$(pwd) 
-#         -DCOVERAGE_SRCS="catcierge_rfid.c;catcierge_timer.c" 
-#         -P ../cmake/CoverallsGcovUpload.cmake
-#
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
-
-
-#
-# Make sure we have the needed arguments.
-#
-if (NOT COVERALLS_OUTPUT_FILE)
-	message(FATAL_ERROR "Coveralls: No coveralls output file specified. Please set COVERALLS_OUTPUT_FILE")
-endif()
-
-if (NOT COV_PATH)
-	message(FATAL_ERROR "Coveralls: Missing coverage directory path where gcov files will be generated. Please set COV_PATH")
-endif()
-
-if (NOT COVERAGE_SRCS)
-	message(FATAL_ERROR "Coveralls: Missing the list of source files that we should get the coverage data for COVERAGE_SRCS")
-endif()
-
-if (NOT PROJECT_ROOT)
-	message(FATAL_ERROR "Coveralls: Missing PROJECT_ROOT.")
-endif()
-
-# Since it's not possible to pass a CMake list properly in the
-# "1;2;3" format to an external process, we have replaced the
-# ";" with "*", so reverse that here so we get it back into the
-# CMake list format.
-string(REGEX REPLACE "\\*" ";" COVERAGE_SRCS ${COVERAGE_SRCS})
-
-find_program(GCOV_EXECUTABLE gcov)
-
-if (NOT GCOV_EXECUTABLE)
-	message(FATAL_ERROR "gcov not found! Aborting...")
-endif()
-
-find_package(Git)
-
-# TODO: Add these git things to the coveralls json.
-if (GIT_FOUND)
-	# Branch.
-	execute_process(
-		COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
-		WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-		OUTPUT_VARIABLE GIT_BRANCH
-		OUTPUT_STRIP_TRAILING_WHITESPACE
-	)
-
-	macro (git_log_format FORMAT_CHARS VAR_NAME)
-		execute_process(
-			COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%${FORMAT_CHARS}
-			WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-			OUTPUT_VARIABLE ${VAR_NAME}
-			OUTPUT_STRIP_TRAILING_WHITESPACE
-		)
-	endmacro()
-
-	git_log_format(an GIT_AUTHOR_EMAIL)
-	git_log_format(ae GIT_AUTHOR_EMAIL)
-	git_log_format(cn GIT_COMMITTER_NAME)
-	git_log_format(ce GIT_COMMITTER_EMAIL)
-	git_log_format(B GIT_COMMIT_MESSAGE)
-
-	message("Git exe: ${GIT_EXECUTABLE}")
-	message("Git branch: ${GIT_BRANCH}")
-	message("Git author: ${GIT_AUTHOR_NAME}")
-	message("Git e-mail: ${GIT_AUTHOR_EMAIL}")
-	message("Git committer name: ${GIT_COMMITTER_NAME}")
-	message("Git committer e-mail: ${GIT_COMMITTER_EMAIL}")
-	message("Git commit message: ${GIT_COMMIT_MESSAGE}")
-
-endif()
-
-############################# Macros #########################################
-
-#
-# This macro converts from the full path format gcov outputs:
-#
-#    /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov
-#
-# to the original source file path the .gcov is for:
-#
-#   /path/to/project/root/subdir/the_file.c
-#
-macro(get_source_path_from_gcov_filename _SRC_FILENAME _GCOV_FILENAME)
-
-	# /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 
-	# -> 
-	# #path#to#project#root#subdir#the_file.c.gcov   
-	get_filename_component(_GCOV_FILENAME_WEXT ${_GCOV_FILENAME} NAME)
-
-	# #path#to#project#root#subdir#the_file.c.gcov -> /path/to/project/root/subdir/the_file.c
-	string(REGEX REPLACE "\\.gcov$" "" SRC_FILENAME_TMP ${_GCOV_FILENAME_WEXT})
-	string(REGEX REPLACE "\#" "/" SRC_FILENAME_TMP ${SRC_FILENAME_TMP})
-	set(${_SRC_FILENAME} "${SRC_FILENAME_TMP}")
-endmacro()
-
-##############################################################################
-
-# Get the coverage data.
-file(GLOB_RECURSE GCDA_FILES "${COV_PATH}/*.gcda")
-message("GCDA files:")
-
-# Get a list of all the object directories needed by gcov
-# (The directories the .gcda files and .o files are found in)
-# and run gcov on those.
-foreach(GCDA ${GCDA_FILES})
-	message("Process: ${GCDA}")
-	message("------------------------------------------------------------------------------")
-	get_filename_component(GCDA_DIR ${GCDA} PATH)
-
-	#
-	# The -p below refers to "Preserve path components",
-	# This means that the generated gcov filename of a source file will
-	# keep the original files entire filepath, but / is replaced with #.
-	# Example:
-	#
-	# /path/to/project/root/build/CMakeFiles/the_file.dir/subdir/the_file.c.gcda
-	# ------------------------------------------------------------------------------
-	# File '/path/to/project/root/subdir/the_file.c'
-	# Lines executed:68.34% of 199
-	# /path/to/project/root/subdir/the_file.c:creating '#path#to#project#root#subdir#the_file.c.gcov'
-	#
-	# If -p is not specified then the file is named only "the_file.c.gcov"
-	#
-	execute_process(
-		COMMAND ${GCOV_EXECUTABLE} -p -o ${GCDA_DIR} ${GCDA}
-		WORKING_DIRECTORY ${COV_PATH}
-	)
-endforeach()
-
-# TODO: Make these be absolute path
-file(GLOB ALL_GCOV_FILES ${COV_PATH}/*.gcov)
-
-# Get only the filenames to use for filtering.
-#set(COVERAGE_SRCS_NAMES "")
-#foreach (COVSRC ${COVERAGE_SRCS})
-#	get_filename_component(COVSRC_NAME ${COVSRC} NAME)
-#	message("${COVSRC} -> ${COVSRC_NAME}")
-#	list(APPEND COVERAGE_SRCS_NAMES "${COVSRC_NAME}")
-#endforeach()
-
-#
-# Filter out all but the gcov files we want.
-#
-# We do this by comparing the list of COVERAGE_SRCS filepaths that the
-# user wants the coverage data for with the paths of the generated .gcov files,
-# so that we only keep the relevant gcov files.
-#
-# Example:
-# COVERAGE_SRCS =
-#				/path/to/project/root/subdir/the_file.c
-#
-# ALL_GCOV_FILES =
-#				/path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov
-#				/path/to/project/root/build/#path#to#project#root#subdir#other_file.c.gcov
-# 
-# Result should be:
-# GCOV_FILES = 
-#				/path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov
-#
-set(GCOV_FILES "")
-#message("Look in coverage sources: ${COVERAGE_SRCS}")
-message("\nFilter out unwanted GCOV files:")
-message("===============================")
-
-set(COVERAGE_SRCS_REMAINING ${COVERAGE_SRCS})
-
-foreach (GCOV_FILE ${ALL_GCOV_FILES})
-
-	#
-	# /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov 
-	# -> 
-	# /path/to/project/root/subdir/the_file.c 
-	get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE})
-
-	# Is this in the list of source files?
-	# TODO: We want to match against relative path filenames from the source file root...
-	list(FIND COVERAGE_SRCS ${GCOV_SRC_PATH} WAS_FOUND)
-
-	if (NOT WAS_FOUND EQUAL -1)
-		message("YES: ${GCOV_FILE}")
-		list(APPEND GCOV_FILES ${GCOV_FILE})
-
-		# We remove it from the list, so we don't bother searching for it again.
-		# Also files left in COVERAGE_SRCS_REMAINING after this loop ends should
-		# have coverage data generated from them (no lines are covered).
-		list(REMOVE_ITEM COVERAGE_SRCS_REMAINING ${GCOV_SRC_PATH})
-	else()
-		message("NO:  ${GCOV_FILE}")
-	endif()
-endforeach()
-
-# TODO: Enable setting these
-set(JSON_SERVICE_NAME "travis-ci")
-set(JSON_SERVICE_JOB_ID $ENV{TRAVIS_JOB_ID})
-
-set(JSON_TEMPLATE
-"{
-  \"service_name\": \"\@JSON_SERVICE_NAME\@\",
-  \"service_job_id\": \"\@JSON_SERVICE_JOB_ID\@\",
-  \"source_files\": \@JSON_GCOV_FILES\@
-}"
-)
-
-set(SRC_FILE_TEMPLATE
-"{
-  \"name\": \"\@GCOV_SRC_REL_PATH\@\",
-  \"source\": \"\@GCOV_FILE_SOURCE\@\",
-  \"coverage\": \@GCOV_FILE_COVERAGE\@
-}"
-)
-
-message("\nGenerate JSON for files:")
-message("=========================")
-
-set(JSON_GCOV_FILES "[")
-
-# Read the GCOV files line by line and get the coverage data.
-foreach (GCOV_FILE ${GCOV_FILES})
-
-	get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE})
-	file(RELATIVE_PATH GCOV_SRC_REL_PATH "${PROJECT_ROOT}" "${GCOV_SRC_PATH}")
-
-	# Loads the gcov file as a list of lines.
-	file(STRINGS ${GCOV_FILE} GCOV_LINES)
-
-	# Instead of trying to parse the source from the
-	# gcov file, simply read the file contents from the source file.
-	# (Parsing it from the gcov is hard because C-code uses ; in many places
-	#  which also happens to be the same as the CMake list delimiter).
-	file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE)
-
-	string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	string(REGEX REPLACE "\"" "\\\\\"" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	string(REPLACE "\t" "\\\\t" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	string(REPLACE "\r" "\\\\r" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	string(REPLACE "\n" "\\\\n" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	# According to http://json.org/ these should be escaped as well.
-	# Don't know how to do that in CMake however...
-	#string(REPLACE "\b" "\\\\b" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	#string(REPLACE "\f" "\\\\f" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-	#string(REGEX REPLACE "\u([a-fA-F0-9]{4})" "\\\\u\\1" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
-
-	# We want a json array of coverage data as a single string
-	# start building them from the contents of the .gcov
-	set(GCOV_FILE_COVERAGE "[")
-
-	foreach (GCOV_LINE ${GCOV_LINES})
-		# Example of what we're parsing:
-		# Hitcount  |Line | Source
-		# "        8:   26:        if (!allowed || (strlen(allowed) == 0))"
-		string(REGEX REPLACE 
-			"^([^:]*):([^:]*):(.*)$" 
-			"\\1;\\2;\\3"
-			RES
-			"${GCOV_LINE}")
-
-		list(LENGTH RES RES_COUNT)
-		if (RES_COUNT GREATER 2)
-			list(GET RES 0 HITCOUNT)
-			list(GET RES 1 LINE)
-			list(GET RES 2 SOURCE)
-
-			string(STRIP ${HITCOUNT} HITCOUNT)
-			string(STRIP ${LINE} LINE)
-
-			# Lines with 0 line numbers are metadata and can be ignored.
-			if (NOT ${LINE} EQUAL 0)
-				
-				# Translate the hitcount into valid JSON values.
-				if (${HITCOUNT} STREQUAL "#####")
-					set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ")
-				elseif (${HITCOUNT} STREQUAL "-")
-					set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ")
-				else()
-					set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}${HITCOUNT}, ")
-				endif()
-				# TODO: Look for LCOV_EXCL_LINE in SOURCE to get rid of false positives.
-			endif()
-		else()
-			message(WARNING "Failed to properly parse line --> ${GCOV_LINE}")
-		endif()
-	endforeach()
-
-	# Advanced way of removing the trailing comma in the JSON array.
-	# "[1, 2, 3, " -> "[1, 2, 3"
-	string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE})
-
-	# Append the trailing ] to complete the JSON array.
-	set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]")
-
-	# Generate the final JSON for this file.
-	message("Generate JSON for file: ${GCOV_SRC_REL_PATH}...")
-	string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON)
-
-	set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ")
-endforeach()
-
-# Loop through all files we couldn't find any coverage for
-# as well, and generate JSON for those as well with 0% coverage.
-foreach(NOT_COVERED_SRC ${COVERAGE_SRCS_REMAINING})
-
-	# Loads the source file as a list of lines.
-	file(STRINGS ${NOT_COVERED_SRC} SRC_LINES)
-
-	set(GCOV_FILE_COVERAGE "[")
-	set(GCOV_FILE_SOURCE "")
-
-	foreach (SOURCE ${SRC_LINES})
-		set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ")
-
-		string(REPLACE "\\" "\\\\" SOURCE "${SOURCE}")
-		string(REGEX REPLACE "\"" "\\\\\"" SOURCE "${SOURCE}")
-		string(REPLACE "\t" "\\\\t" SOURCE "${SOURCE}")
-		string(REPLACE "\r" "\\\\r" SOURCE "${SOURCE}")
-		set(GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}${SOURCE}\\n")
-	endforeach()
-
-	# Remove trailing comma, and complete JSON array with ]
-	string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE})
-	set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]")
-
-	# Generate the final JSON for this file.
-	message("Generate JSON for non-gcov file: ${NOT_COVERED_SRC}...")
-	string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON)
-	set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ")
-endforeach()
-
-# Get rid of trailing comma.
-string(REGEX REPLACE ",[ ]*$" "" JSON_GCOV_FILES ${JSON_GCOV_FILES})
-set(JSON_GCOV_FILES "${JSON_GCOV_FILES}]")
-
-# Generate the final complete JSON!
-message("Generate final JSON...")
-string(CONFIGURE ${JSON_TEMPLATE} JSON)
-
-file(WRITE "${COVERALLS_OUTPUT_FILE}" "${JSON}")
-message("###########################################################################")
-message("Generated coveralls JSON containing coverage data:") 
-message("${COVERALLS_OUTPUT_FILE}")
-message("###########################################################################")
-

+ 5 - 1
jansson.mod/jansson/configure.ac

@@ -1,5 +1,5 @@
 AC_PREREQ([2.60])
 AC_PREREQ([2.60])
-AC_INIT([jansson], [2.13.1], [https://github.com/akheron/jansson/issues])
+AC_INIT([jansson], [2.14], [https://github.com/akheron/jansson/issues])
 
 
 AC_CONFIG_AUX_DIR([.])
 AC_CONFIG_AUX_DIR([.])
 AM_INIT_AUTOMAKE([1.10 foreign])
 AM_INIT_AUTOMAKE([1.10 foreign])
@@ -137,6 +137,10 @@ fi
 AS_IF([test "x$with_Bsymbolic" = "xyes"], [JSON_BSYMBOLIC_LDFLAGS=-Wl[,]-Bsymbolic-functions])
 AS_IF([test "x$with_Bsymbolic" = "xyes"], [JSON_BSYMBOLIC_LDFLAGS=-Wl[,]-Bsymbolic-functions])
 AC_SUBST(JSON_BSYMBOLIC_LDFLAGS)
 AC_SUBST(JSON_BSYMBOLIC_LDFLAGS)
 
 
+# Enable symbol versioning on GNU libc
+JSON_SYMVER_LDFLAGS=
+AC_CHECK_DECL([__GLIBC__], [JSON_SYMVER_LDFLAGS=-Wl,--default-symver])
+AC_SUBST([JSON_SYMVER_LDFLAGS])
 
 
 AC_ARG_ENABLE([ossfuzzers],
 AC_ARG_ENABLE([ossfuzzers],
   [AS_HELP_STRING([--enable-ossfuzzers],
   [AS_HELP_STRING([--enable-ossfuzzers],

+ 2 - 2
jansson.mod/jansson/doc/Makefile.am

@@ -1,5 +1,5 @@
-EXTRA_DIST = conf.py apiref.rst changes.rst conformance.rst		\
-	gettingstarted.rst github_commits.c index.rst portability.rst	\
+EXTRA_DIST = conf.py apiref.rst changes.rst conformance.rst  \
+	gettingstarted.rst github_commits.c index.rst threadsafety.rst  \
 	tutorial.rst upgrading.rst ext/refcounting.py
 	tutorial.rst upgrading.rst ext/refcounting.py
 
 
 SPHINXBUILD = sphinx-build
 SPHINXBUILD = sphinx-build

+ 187 - 34
jansson.mod/jansson/doc/apiref.rst

@@ -114,7 +114,7 @@ also cause errors.
 Type
 Type
 ----
 ----
 
 
-.. type:: enum json_type
+.. c:enum:: json_type
 
 
    The type of a JSON value. The following members are defined:
    The type of a JSON value. The following members are defined:
 
 
@@ -145,33 +145,33 @@ Type
 .. function:: int json_typeof(const json_t *json)
 .. function:: int json_typeof(const json_t *json)
 
 
    Return the type of the JSON value (a :type:`json_type` cast to
    Return the type of the JSON value (a :type:`json_type` cast to
-   :type:`int`). *json* MUST NOT be *NULL*. This function is actually
+   ``int``). *json* MUST NOT be *NULL*. This function is actually
    implemented as a macro for speed.
    implemented as a macro for speed.
 
 
-.. function:: json_is_object(const json_t *json)
-               json_is_array(const json_t *json)
-               json_is_string(const json_t *json)
-               json_is_integer(const json_t *json)
-               json_is_real(const json_t *json)
-               json_is_true(const json_t *json)
-               json_is_false(const json_t *json)
-               json_is_null(const json_t *json)
+.. function:: int json_is_object(const json_t *json)
+              int json_is_array(const json_t *json)
+              int json_is_string(const json_t *json)
+              int json_is_integer(const json_t *json)
+              int json_is_real(const json_t *json)
+              int json_is_true(const json_t *json)
+              int json_is_false(const json_t *json)
+              int json_is_null(const json_t *json)
 
 
    These functions (actually macros) return true (non-zero) for values
    These functions (actually macros) return true (non-zero) for values
    of the given type, and false (zero) for values of other types and
    of the given type, and false (zero) for values of other types and
    for *NULL*.
    for *NULL*.
 
 
-.. function:: json_is_number(const json_t *json)
+.. function:: int json_is_number(const json_t *json)
 
 
    Returns true for values of types ``JSON_INTEGER`` and
    Returns true for values of types ``JSON_INTEGER`` and
    ``JSON_REAL``, and false for other types and for *NULL*.
    ``JSON_REAL``, and false for other types and for *NULL*.
 
 
-.. function:: json_is_boolean(const json_t *json)
+.. function:: int json_is_boolean(const json_t *json)
 
 
    Returns true for types ``JSON_TRUE`` and ``JSON_FALSE``, and false
    Returns true for types ``JSON_TRUE`` and ``JSON_FALSE``, and false
    for values of other types and for *NULL*.
    for values of other types and for *NULL*.
 
 
-.. function:: json_boolean_value(const json_t *json)
+.. function:: int json_boolean_value(const json_t *json)
 
 
    Alias of :func:`json_is_true()`, i.e. returns 1 for ``JSON_TRUE``
    Alias of :func:`json_is_true()`, i.e. returns 1 for ``JSON_TRUE``
    and 0 otherwise.
    and 0 otherwise.
@@ -594,12 +594,12 @@ A JSON array is an ordered collection of other JSON values.
    Appends all elements in *other_array* to the end of *array*.
    Appends all elements in *other_array* to the end of *array*.
    Returns 0 on success and -1 on error.
    Returns 0 on success and -1 on error.
 
 
-.. function:: json_array_foreach(array, index, value)
+.. function:: void json_array_foreach(array, index, value)
 
 
    Iterate over every element of ``array``, running the block
    Iterate over every element of ``array``, running the block
    of code that follows each time with the proper values set to
    of code that follows each time with the proper values set to
    variables ``index`` and ``value``, of types :type:`size_t` and
    variables ``index`` and ``value``, of types :type:`size_t` and
-   :type:`json_t *` respectively. Example::
+   :type:`json_t` pointer respectively. Example::
 
 
        /* array is a JSON array */
        /* array is a JSON array */
        size_t index;
        size_t index;
@@ -648,6 +648,15 @@ allowed in object keys.
    Get a value corresponding to *key* from *object*. Returns *NULL* if
    Get a value corresponding to *key* from *object*. Returns *NULL* if
    *key* is not found and on error.
    *key* is not found and on error.
 
 
+.. function:: json_t *json_object_getn(const json_t *object, const char *key, size_t key_len)
+
+   .. refcounting:: borrow
+
+   Like :func:`json_object_get`, but give the fixed-length *key* with length *key_len*.
+   See :ref:`fixed_length_keys` for details.
+
+   .. versionadded:: 2.14
+
 .. function:: int json_object_set(json_t *object, const char *key, json_t *value)
 .. function:: int json_object_set(json_t *object, const char *key, json_t *value)
 
 
    Set the value of *key* to *value* in *object*. *key* must be a
    Set the value of *key* to *value* in *object*. *key* must be a
@@ -655,6 +664,13 @@ allowed in object keys.
    already is a value for *key*, it is replaced by the new value.
    already is a value for *key*, it is replaced by the new value.
    Returns 0 on success and -1 on error.
    Returns 0 on success and -1 on error.
 
 
+.. function:: int json_object_setn(json_t *object, const char *key, size_t key_len, json_t *value)
+
+   Like :func:`json_object_set`, but give the fixed-length *key* with length *key_len*.
+   See :ref:`fixed_length_keys` for details.
+
+   .. versionadded:: 2.14
+
 .. function:: int json_object_set_nocheck(json_t *object, const char *key, json_t *value)
 .. function:: int json_object_set_nocheck(json_t *object, const char *key, json_t *value)
 
 
    Like :func:`json_object_set`, but doesn't check that *key* is
    Like :func:`json_object_set`, but doesn't check that *key* is
@@ -662,12 +678,26 @@ allowed in object keys.
    really is the case (e.g. you have already checked it by other
    really is the case (e.g. you have already checked it by other
    means).
    means).
 
 
+.. function:: int json_object_setn_nocheck(json_t *object, const char *key, size_t key_len, json_t *value)
+
+   Like :func:`json_object_set_nocheck`, but give the fixed-length *key* with length *key_len*.
+   See :ref:`fixed_length_keys` for details.
+
+   .. versionadded:: 2.14
+
 .. function:: int json_object_set_new(json_t *object, const char *key, json_t *value)
 .. function:: int json_object_set_new(json_t *object, const char *key, json_t *value)
 
 
    Like :func:`json_object_set()` but steals the reference to
    Like :func:`json_object_set()` but steals the reference to
    *value*. This is useful when *value* is newly created and not used
    *value*. This is useful when *value* is newly created and not used
    after the call.
    after the call.
 
 
+.. function:: int json_object_setn_new(json_t *object, const char *key, size_t key_len, json_t *value)
+
+   Like :func:`json_object_set_new`, but give the fixed-length *key* with length *key_len*.
+   See :ref:`fixed_length_keys` for details.
+
+   .. versionadded:: 2.14
+
 .. function:: int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value)
 .. function:: int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value)
 
 
    Like :func:`json_object_set_new`, but doesn't check that *key* is
    Like :func:`json_object_set_new`, but doesn't check that *key* is
@@ -675,12 +705,26 @@ allowed in object keys.
    really is the case (e.g. you have already checked it by other
    really is the case (e.g. you have already checked it by other
    means).
    means).
 
 
+.. function:: int json_object_setn_new_nocheck(json_t *object, const char *key, size_t key_len, json_t *value)
+
+   Like :func:`json_object_set_new_nocheck`, but give the fixed-length *key* with length *key_len*.
+   See :ref:`fixed_length_keys` for details.
+
+   .. versionadded:: 2.14
+
 .. function:: int json_object_del(json_t *object, const char *key)
 .. function:: int json_object_del(json_t *object, const char *key)
 
 
    Delete *key* from *object* if it exists. Returns 0 on success, or
    Delete *key* from *object* if it exists. Returns 0 on success, or
    -1 if *key* was not found. The reference count of the removed value
    -1 if *key* was not found. The reference count of the removed value
    is decremented.
    is decremented.
 
 
+.. function:: int json_object_deln(json_t *object, const char *key, size_t key_len)
+
+   Like :func:`json_object_del`, but give the fixed-length *key* with length *key_len*.
+   See :ref:`fixed_length_keys` for details.
+
+   .. versionadded:: 2.14
+
 .. function:: int json_object_clear(json_t *object)
 .. function:: int json_object_clear(json_t *object)
 
 
    Remove all elements from *object*. Returns 0 on success and -1 if
    Remove all elements from *object*. Returns 0 on success and -1 if
@@ -732,12 +776,12 @@ allowed in object keys.
    recursively merged with the corresponding values in *object* if they are also
    recursively merged with the corresponding values in *object* if they are also
    objects, instead of overwriting them. Returns 0 on success or -1 on error.
    objects, instead of overwriting them. Returns 0 on success or -1 on error.
 
 
-.. function:: json_object_foreach(object, key, value)
+.. function:: void json_object_foreach(object, key, value)
 
 
    Iterate over every key-value pair of ``object``, running the block
    Iterate over every key-value pair of ``object``, running the block
    of code that follows each time with the proper values set to
    of code that follows each time with the proper values set to
-   variables ``key`` and ``value``, of types :type:`const char *` and
-   :type:`json_t *` respectively. Example::
+   variables ``key`` and ``value``, of types ``const char *`` and
+   :type:`json_t` pointer respectively. Example::
 
 
        /* obj is a JSON object */
        /* obj is a JSON object */
        const char *key;
        const char *key;
@@ -750,7 +794,7 @@ allowed in object keys.
    The items are returned in the order they were inserted to the
    The items are returned in the order they were inserted to the
    object.
    object.
 
 
-   **Note:** It's not safe to call ``json_object_del(object, key)``
+   **Note:** It's not safe to call ``json_object_del(object, key)`` or ``json_object_deln(object, key, key_len)``
    during iteration. If you need to, use
    during iteration. If you need to, use
    :func:`json_object_foreach_safe` instead.
    :func:`json_object_foreach_safe` instead.
 
 
@@ -764,14 +808,42 @@ allowed in object keys.
    .. versionadded:: 2.3
    .. versionadded:: 2.3
 
 
 
 
-.. function:: json_object_foreach_safe(object, tmp, key, value)
+.. function:: void json_object_foreach_safe(object, tmp, key, value)
 
 
    Like :func:`json_object_foreach()`, but it's safe to call
    Like :func:`json_object_foreach()`, but it's safe to call
-   ``json_object_del(object, key)`` during iteration. You need to pass
-   an extra ``void *`` parameter ``tmp`` that is used for temporary storage.
+   ``json_object_del(object, key)`` or ``json_object_deln(object, key, key_len)`` during iteration.
+   You need to pass an extra ``void *`` parameter ``tmp`` that is used for temporary storage.
 
 
    .. versionadded:: 2.8
    .. versionadded:: 2.8
 
 
+.. function:: void json_object_keylen_foreach(object, key, key_len, value)
+
+   Like :c:func:`json_object_foreach`, but in *key_len* stored length of the *key*.
+   Example::
+
+       /* obj is a JSON object */
+       const char *key;
+       json_t *value;
+       size_t len;
+
+       json_object_keylen_foreach(obj, key, len, value) {
+            printf("got key %s with length %zu\n", key, len);
+       }
+
+   **Note:** It's not safe to call ``json_object_deln(object, key, key_len)``
+   during iteration. If you need to, use
+   :func:`json_object_keylen_foreach_safe` instead.
+
+   .. versionadded:: 2.14
+
+
+.. function:: void json_object_keylen_foreach_safe(object, tmp, key, key_len, value)
+
+   Like :func:`json_object_keylen_foreach()`, but it's safe to call
+   ``json_object_deln(object, key, key_len)`` during iteration.
+   You need to pass an extra ``void *`` parameter ``tmp`` that is used for temporary storage.
+
+   .. versionadded:: 2.14
 
 
 The following functions can be used to iterate through all key-value
 The following functions can be used to iterate through all key-value
 pairs in an object. The items are returned in the order they were
 pairs in an object. The items are returned in the order they were
@@ -800,6 +872,12 @@ inserted to the object.
 
 
    Extract the associated key from *iter*.
    Extract the associated key from *iter*.
 
 
+.. function:: size_t json_object_iter_key_len(void *iter)
+
+   Extract the associated key length from *iter*.
+
+   .. versionadded:: 2.14
+
 .. function:: json_t *json_object_iter_value(void *iter)
 .. function:: json_t *json_object_iter_value(void *iter)
 
 
    .. refcounting:: borrow
    .. refcounting:: borrow
@@ -855,8 +933,7 @@ inserted to the object.
     :func:`json_object()`, either explicit or implicit. If this
     :func:`json_object()`, either explicit or implicit. If this
     function is not called by the user, the first call to
     function is not called by the user, the first call to
     :func:`json_object()` (either explicit or implicit) seeds the hash
     :func:`json_object()` (either explicit or implicit) seeds the hash
-    function. See :ref:`portability-thread-safety` for notes on thread
-    safety.
+    function. See :ref:`thread-safety` for notes on thread safety.
 
 
     If repeatable results are required, for e.g. unit tests, the hash
     If repeatable results are required, for e.g. unit tests, the hash
     function can be "unrandomized" by calling :func:`json_object_seed`
     function can be "unrandomized" by calling :func:`json_object_seed`
@@ -926,7 +1003,7 @@ success. See :ref:`apiref-decoding` for more info.
 All functions also accept *NULL* as the :type:`json_error_t` pointer,
 All functions also accept *NULL* as the :type:`json_error_t` pointer,
 in which case no error information is returned to the caller.
 in which case no error information is returned to the caller.
 
 
-.. type:: enum json_error_code
+.. c:enum:: json_error_code
 
 
    An enumeration containing numeric error codes.  The following errors are
    An enumeration containing numeric error codes.  The following errors are
    currently defined:
    currently defined:
@@ -1021,7 +1098,7 @@ in which case no error information is returned to the caller.
 Encoding
 Encoding
 ========
 ========
 
 
-This sections describes the functions that can be used to encode
+This section describes the functions that can be used to encode
 values to JSON. By default, only objects and arrays can be encoded
 values to JSON. By default, only objects and arrays can be encoded
 directly, since they are the only valid *root* values of a JSON text.
 directly, since they are the only valid *root* values of a JSON text.
 To encode any JSON value, use the ``JSON_ENCODE_ANY`` flag (see
 To encode any JSON value, use the ``JSON_ENCODE_ANY`` flag (see
@@ -1206,7 +1283,7 @@ These functions output UTF-8:
 Decoding
 Decoding
 ========
 ========
 
 
-This sections describes the functions that can be used to decode JSON
+This section describes the functions that can be used to decode JSON
 text to the Jansson representation of JSON data. The JSON
 text to the Jansson representation of JSON data. The JSON
 specification requires that a JSON text is either a serialized array
 specification requires that a JSON text is either a serialized array
 or object, and this requirement is also enforced with the following
 or object, and this requirement is also enforced with the following
@@ -1488,17 +1565,17 @@ arguments.
     Output a JSON null value. No argument is consumed.
     Output a JSON null value. No argument is consumed.
 
 
 ``b`` (boolean) [int]
 ``b`` (boolean) [int]
-    Convert a C :type:`int` to JSON boolean value. Zero is converted
+    Convert a C ``int`` to JSON boolean value. Zero is converted
     to ``false`` and non-zero to ``true``.
     to ``false`` and non-zero to ``true``.
 
 
 ``i`` (integer) [int]
 ``i`` (integer) [int]
-    Convert a C :type:`int` to JSON integer.
+    Convert a C ``int`` to JSON integer.
 
 
 ``I`` (integer) [json_int_t]
 ``I`` (integer) [json_int_t]
     Convert a C :type:`json_int_t` to JSON integer.
     Convert a C :type:`json_int_t` to JSON integer.
 
 
 ``f`` (real) [double]
 ``f`` (real) [double]
-    Convert a C :type:`double` to JSON real.
+    Convert a C ``double`` to JSON real.
 
 
 ``o`` (any value) [json_t \*]
 ``o`` (any value) [json_t \*]
     Output any given JSON value as-is. If the value is added to an
     Output any given JSON value as-is. If the value is added to an
@@ -1625,20 +1702,20 @@ type whose address should be passed.
     Expect a JSON null value. Nothing is extracted.
     Expect a JSON null value. Nothing is extracted.
 
 
 ``b`` (boolean) [int]
 ``b`` (boolean) [int]
-    Convert a JSON boolean value to a C :type:`int`, so that ``true``
+    Convert a JSON boolean value to a C ``int``, so that ``true``
     is converted to 1 and ``false`` to 0.
     is converted to 1 and ``false`` to 0.
 
 
 ``i`` (integer) [int]
 ``i`` (integer) [int]
-    Convert a JSON integer to C :type:`int`.
+    Convert a JSON integer to C ``int``.
 
 
 ``I`` (integer) [json_int_t]
 ``I`` (integer) [json_int_t]
     Convert a JSON integer to C :type:`json_int_t`.
     Convert a JSON integer to C :type:`json_int_t`.
 
 
 ``f`` (real) [double]
 ``f`` (real) [double]
-    Convert a JSON real to C :type:`double`.
+    Convert a JSON real to C ``double``.
 
 
 ``F`` (integer or real) [double]
 ``F`` (integer or real) [double]
-    Convert a JSON number (integer or real) to C :type:`double`.
+    Convert a JSON number (integer or real) to C ``double``.
 
 
 ``o`` (any value) [json_t \*]
 ``o`` (any value) [json_t \*]
     Store a JSON value with no conversion to a :type:`json_t` pointer.
     Store a JSON value with no conversion to a :type:`json_t` pointer.
@@ -1909,3 +1986,79 @@ memory, see
 http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/protect-secrets.html.
 http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/protect-secrets.html.
 The page also explains the :func:`guaranteed_memset()` function used
 The page also explains the :func:`guaranteed_memset()` function used
 in the example and gives a sample implementation for it.
 in the example and gives a sample implementation for it.
+
+.. _fixed_length_keys:
+
+Fixed-Length keys
+=================
+
+The Jansson API allows work with fixed-length keys. This can be useful in the following cases:
+
+* The key is contained inside a buffer and is not null-terminated. In this case creating a new temporary buffer is not needed.
+* The key contains U+0000 inside it.
+
+List of API for fixed-length keys:
+
+* :c:func:`json_object_getn`
+* :c:func:`json_object_setn`
+* :c:func:`json_object_setn_nocheck`
+* :c:func:`json_object_setn_new`
+* :c:func:`json_object_setn_new_nocheck`
+* :c:func:`json_object_deln`
+* :c:func:`json_object_iter_key_len`
+* :c:func:`json_object_keylen_foreach`
+* :c:func:`json_object_keylen_foreach_safe`
+
+**Examples:**
+
+Try to write a new function to get :c:struct:`json_t` by path separated by ``.``
+
+This requires:
+
+* string iterator (no need to modify the input for better performance)
+* API for working with fixed-size keys
+
+The iterator::
+
+    struct string {
+        const char *string;
+        size_t length;
+    };
+
+    size_t string_try_next(struct string *str, const char *delimiter) {
+        str->string += strspn(str->string, delimiter);
+        str->length = strcspn(str->string, delimiter);
+        return str->length;
+    }
+
+    #define string_foreach(_string, _delimiter) \
+            for (; string_try_next(&(_string), _delimiter); (_string).string += (_string).length)
+
+
+The function::
+
+    json_t *json_object_get_by_path(json_t *object, const char *path) {
+        struct string str;
+        json_t *out = object;
+
+        str.string = path;
+
+        string_foreach(str, ".") {
+            out = json_object_getn(out, str.string, str.length);
+            if (out == NULL)
+                return NULL;
+        }
+
+        return out;
+    }
+
+And usage::
+
+    int main(void) {
+        json_t *obj = json_pack("{s:{s:{s:b}}}", "a", "b", "c", 1);
+
+        json_t *c = json_object_get_by_path(obj, "a.b.c");
+        assert(json_is_true(c));
+
+        json_decref(obj);
+    }

+ 1 - 1
jansson.mod/jansson/doc/conf.py

@@ -48,7 +48,7 @@ copyright = u'2009-2020, Petri Lehtinen'
 # built documents.
 # built documents.
 #
 #
 # The short X.Y version.
 # The short X.Y version.
-version = '2.13.1'
+version = '2.14'
 # The full version, including alpha/beta/rc tags.
 # The full version, including alpha/beta/rc tags.
 release = version
 release = version
 
 

+ 2 - 3
jansson.mod/jansson/doc/conformance.rst

@@ -22,8 +22,7 @@ JSON strings are mapped to C-style null-terminated character arrays,
 and UTF-8 encoding is used internally.
 and UTF-8 encoding is used internally.
 
 
 All Unicode codepoints U+0000 through U+10FFFF are allowed in string
 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.
+values. However, U+0000 is allowed in object keys only for length-aware functions.
 
 
 Unicode normalization or any other transformation is never performed
 Unicode normalization or any other transformation is never performed
 on any strings (string values or object keys). When checking for
 on any strings (string values or object keys). When checking for
@@ -110,7 +109,7 @@ to overflow semantics). Also, no support or hooks are provided for any
 supplemental "bignum" type add-on packages.
 supplemental "bignum" type add-on packages.
 
 
 Depth of nested values
 Depth of nested values
-----------------------
+======================
 
 
 To avoid stack exhaustion, Jansson currently limits the nesting depth
 To avoid stack exhaustion, Jansson currently limits the nesting depth
 for arrays and objects to a certain value (default: 2048), defined as
 for arrays and objects to a certain value (default: 2048), defined as

+ 20 - 11
jansson.mod/jansson/doc/ext/refcounting.py

@@ -24,8 +24,8 @@
 """
 """
 
 
 from docutils import nodes
 from docutils import nodes
+from docutils.parsers.rst import Directive
 
 
-class refcounting(nodes.emphasis): pass
 
 
 def visit(self, node):
 def visit(self, node):
     self.visit_emphasis(node)
     self.visit_emphasis(node)
@@ -40,16 +40,25 @@ def html_depart(self, node):
     self.body.append('</em>')
     self.body.append('</em>')
 
 
 
 
-def refcounting_directive(name, arguments, options, content, lineno,
-                   content_offset, block_text, state, state_machine):
-    if arguments[0] == 'borrow':
-        text = 'Return value: Borrowed reference.'
-    elif arguments[0] == 'new':
-        text = 'Return value: New reference.'
-    else:
-        raise Error('Valid arguments: new, borrow')
+class refcounting(nodes.emphasis):
+    pass
+
+class refcounting_directive(Directive):
+    has_content = False
+    required_arguments = 1
+    optional_arguments = 0
+    final_argument_whitespace = False
+
+    def run(self):
+        if self.arguments[0] == 'borrow':
+            text = 'Return value: Borrowed reference.'
+        elif self.arguments[0] == 'new':
+            text = 'Return value: New reference.'
+        else:
+            raise Error('Valid arguments: new, borrow')
+
+        return [refcounting(text, text)]
 
 
-    return [refcounting(text, text)]
 
 
 def setup(app):
 def setup(app):
     app.add_node(refcounting,
     app.add_node(refcounting,
@@ -57,4 +66,4 @@ def setup(app):
                  latex=(visit, depart),
                  latex=(visit, depart),
                  text=(visit, depart),
                  text=(visit, depart),
                  man=(visit, depart))
                  man=(visit, depart))
-    app.add_directive('refcounting', refcounting_directive, 0, (1, 0, 0))
+    app.add_directive('refcounting', refcounting_directive)

+ 1 - 0
jansson.mod/jansson/doc/github_commits.c

@@ -153,6 +153,7 @@ int main(int argc, char *argv[]) {
         sha = json_object_get(data, "sha");
         sha = json_object_get(data, "sha");
         if (!json_is_string(sha)) {
         if (!json_is_string(sha)) {
             fprintf(stderr, "error: commit %d: sha is not a string\n", (int)(i + 1));
             fprintf(stderr, "error: commit %d: sha is not a string\n", (int)(i + 1));
+            json_decref(root);
             return 1;
             return 1;
         }
         }
 
 

+ 1 - 1
jansson.mod/jansson/doc/index.rst

@@ -41,7 +41,7 @@ Contents
    upgrading
    upgrading
    tutorial
    tutorial
    conformance
    conformance
-   portability
+   threadsafety
    apiref
    apiref
    changes
    changes
 
 

+ 4 - 7
jansson.mod/jansson/doc/portability.rst → jansson.mod/jansson/doc/threadsafety.rst

@@ -1,11 +1,8 @@
-***********
-Portability
-***********
-
-.. _portability-thread-safety:
+.. _thread-safety:
 
 
+*************
 Thread safety
 Thread safety
--------------
+*************
 
 
 Jansson as a library is thread safe and has no mutable global state.
 Jansson as a library is thread safe and has no mutable global state.
 The only exceptions are the hash function seed and memory allocation
 The only exceptions are the hash function seed and memory allocation
@@ -64,7 +61,7 @@ program startup. See :ref:`apiref-custom-memory-allocation`.
 
 
 
 
 Locale
 Locale
-------
+======
 
 
 Jansson works fine under any locale.
 Jansson works fine under any locale.
 
 

+ 8 - 8
jansson.mod/jansson/doc/upgrading.rst

@@ -47,13 +47,13 @@ List of Incompatible Changes
 
 
 **Underlying type of JSON integers**
 **Underlying type of JSON integers**
     The underlying C type of JSON integers has been changed from
     The underlying C type of JSON integers has been changed from
-    :type:`int` to the widest available signed integer type, i.e.
-    :type:`long long` or :type:`long`, depending on whether
-    :type:`long long` is supported on your system or not. This makes
+    ``int`` to the widest available signed integer type, i.e.
+    ``long long`` or ``long``, depending on whether
+    ``long long`` is supported on your system or not. This makes
     the whole 64-bit integer range available on most modern systems.
     the whole 64-bit integer range available on most modern systems.
 
 
     ``jansson.h`` has a typedef :type:`json_int_t` to the underlying
     ``jansson.h`` has a typedef :type:`json_int_t` to the underlying
-    integer type. :type:`int` should still be used in most cases when
+    integer type. ``int`` should still be used in most cases when
     dealing with smallish JSON integers, as the compiler handles
     dealing with smallish JSON integers, as the compiler handles
     implicit type coercion. Only when the full 64-bit range is needed,
     implicit type coercion. Only when the full 64-bit range is needed,
     :type:`json_int_t` should be explicitly used.
     :type:`json_int_t` should be explicitly used.
@@ -69,8 +69,8 @@ List of Incompatible Changes
 
 
 **Unsigned integers in API functions**
 **Unsigned integers in API functions**
     Version 2.0 unifies unsigned integer usage in the API. All uses of
     Version 2.0 unifies unsigned integer usage in the API. All uses of
-    :type:`unsigned int` and :type:`unsigned long` have been replaced
-    with :type:`size_t`. This includes flags, container sizes, etc.
+    ``unsigned int`` and ``unsigned long`` have been replaced
+    with ``size_t``. This includes flags, container sizes, etc.
     This should not require source code changes, as both
     This should not require source code changes, as both
-    :type:`unsigned int` and :type:`unsigned long` are usually
-    compatible with :type:`size_t`.
+    ``unsigned int`` and ``unsigned long`` are usually
+    compatible with ``size_t``.

+ 4 - 0
jansson.mod/jansson/examples/README.rst

@@ -0,0 +1,4 @@
+Jansson examples
+================
+
+This directory contains simple example programs that use Jansson.

+ 200 - 0
jansson.mod/jansson/examples/simple_parse.c

@@ -0,0 +1,200 @@
+/*
+ * Simple example of parsing and printing JSON using jansson.
+ *
+ * SYNOPSIS:
+ * $ examples/simple_parse
+ * Type some JSON > [true, false, null, 1, 0.0, -0.0, "", {"name": "barney"}]
+ * JSON Array of 8 elements:
+ *   JSON True
+ *   JSON False
+ *   JSON Null
+ *   JSON Integer: "1"
+ *   JSON Real: 0.000000
+ *   JSON Real: -0.000000
+ *   JSON String: ""
+ *   JSON Object of 1 pair:
+ *     JSON Key: "name"
+ *     JSON String: "barney"
+ *
+ * Copyright (c) 2014 Robert Poor <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <jansson.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* forward refs */
+void print_json(json_t *root);
+void print_json_aux(json_t *element, int indent);
+void print_json_indent(int indent);
+const char *json_plural(size_t count);
+void print_json_object(json_t *element, int indent);
+void print_json_array(json_t *element, int indent);
+void print_json_string(json_t *element, int indent);
+void print_json_integer(json_t *element, int indent);
+void print_json_real(json_t *element, int indent);
+void print_json_true(json_t *element, int indent);
+void print_json_false(json_t *element, int indent);
+void print_json_null(json_t *element, int indent);
+
+void print_json(json_t *root) { print_json_aux(root, 0); }
+
+void print_json_aux(json_t *element, int indent) {
+    switch (json_typeof(element)) {
+        case JSON_OBJECT:
+            print_json_object(element, indent);
+            break;
+        case JSON_ARRAY:
+            print_json_array(element, indent);
+            break;
+        case JSON_STRING:
+            print_json_string(element, indent);
+            break;
+        case JSON_INTEGER:
+            print_json_integer(element, indent);
+            break;
+        case JSON_REAL:
+            print_json_real(element, indent);
+            break;
+        case JSON_TRUE:
+            print_json_true(element, indent);
+            break;
+        case JSON_FALSE:
+            print_json_false(element, indent);
+            break;
+        case JSON_NULL:
+            print_json_null(element, indent);
+            break;
+        default:
+            fprintf(stderr, "unrecognized JSON type %d\n", json_typeof(element));
+    }
+}
+
+void print_json_indent(int indent) {
+    int i;
+    for (i = 0; i < indent; i++) {
+        putchar(' ');
+    }
+}
+
+const char *json_plural(size_t count) { return count == 1 ? "" : "s"; }
+
+void print_json_object(json_t *element, int indent) {
+    size_t size;
+    const char *key;
+    json_t *value;
+
+    print_json_indent(indent);
+    size = json_object_size(element);
+
+    printf("JSON Object of %lld pair%s:\n", (long long)size, json_plural(size));
+    json_object_foreach(element, key, value) {
+        print_json_indent(indent + 2);
+        printf("JSON Key: \"%s\"\n", key);
+        print_json_aux(value, indent + 2);
+    }
+}
+
+void print_json_array(json_t *element, int indent) {
+    size_t i;
+    size_t size = json_array_size(element);
+    print_json_indent(indent);
+
+    printf("JSON Array of %lld element%s:\n", (long long)size, json_plural(size));
+    for (i = 0; i < size; i++) {
+        print_json_aux(json_array_get(element, i), indent + 2);
+    }
+}
+
+void print_json_string(json_t *element, int indent) {
+    print_json_indent(indent);
+    printf("JSON String: \"%s\"\n", json_string_value(element));
+}
+
+void print_json_integer(json_t *element, int indent) {
+    print_json_indent(indent);
+    printf("JSON Integer: \"%" JSON_INTEGER_FORMAT "\"\n", json_integer_value(element));
+}
+
+void print_json_real(json_t *element, int indent) {
+    print_json_indent(indent);
+    printf("JSON Real: %f\n", json_real_value(element));
+}
+
+void print_json_true(json_t *element, int indent) {
+    (void)element;
+    print_json_indent(indent);
+    printf("JSON True\n");
+}
+
+void print_json_false(json_t *element, int indent) {
+    (void)element;
+    print_json_indent(indent);
+    printf("JSON False\n");
+}
+
+void print_json_null(json_t *element, int indent) {
+    (void)element;
+    print_json_indent(indent);
+    printf("JSON Null\n");
+}
+
+/*
+ * Parse text into a JSON object. If text is valid JSON, returns a
+ * json_t structure, otherwise prints and error and returns null.
+ */
+json_t *load_json(const char *text) {
+    json_t *root;
+    json_error_t error;
+
+    root = json_loads(text, 0, &error);
+
+    if (root) {
+        return root;
+    } else {
+        fprintf(stderr, "json error on line %d: %s\n", error.line, error.text);
+        return (json_t *)0;
+    }
+}
+
+/*
+ * Print a prompt and return (by reference) a null-terminated line of
+ * text.  Returns NULL on eof or some error.
+ */
+char *read_line(char *line, int max_chars) {
+    printf("Type some JSON > ");
+    fflush(stdout);
+    return fgets(line, max_chars, stdin);
+}
+
+/* ================================================================
+ * main
+ */
+
+#define MAX_CHARS 4096
+
+int main(int argc, char *argv[]) {
+    char line[MAX_CHARS];
+
+    if (argc != 1) {
+        fprintf(stderr, "Usage: %s\n", argv[0]);
+        exit(-1);
+    }
+
+    while (read_line(line, MAX_CHARS) != (char *)NULL) {
+
+        /* parse text into JSON structure */
+        json_t *root = load_json(line);
+
+        if (root) {
+            /* print and release the JSON structure */
+            print_json(root);
+            json_decref(root);
+        }
+    }
+
+    return 0;
+}

+ 3 - 0
jansson.mod/jansson/release.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+find . -type f -a '(' -name '*.c' -o -name '*.h' ')' | xargs clang-format -i

+ 27 - 0
jansson.mod/jansson/scripts/clang-format-check

@@ -0,0 +1,27 @@
+#!/bin/bash
+
+CLANG_FORMAT=${CLANG_FORMAT:-clang-format}
+CLANG_FORMAT_VERSION=${CLANG_FORMAT_VERSION:-}
+
+if ! type $CLANG_FORMAT >/dev/null || \
+        ! $CLANG_FORMAT --version | grep -q "version ${CLANG_FORMAT_VERSION}"; then
+    # If running tests, mark this test as skipped.
+    exit 77
+fi
+
+errors=0
+paths=$(git ls-files | grep '\.[ch]$')
+for path in $paths; do
+    in=$(cat $path)
+    out=$($CLANG_FORMAT $path)
+
+    if [ "$in" != "$out" ]; then
+        diff -u -L $path -L "$path.formatted" $path - <<<$out
+        errors=1
+    fi
+done
+
+if [ $errors -ne 0 ]; then
+    echo "Formatting errors detected, run ./scripts/clang-format to fix!"
+    exit 1
+fi

+ 2 - 1
jansson.mod/jansson/src/Makefile.am

@@ -25,5 +25,6 @@ libjansson_la_SOURCES = \
 libjansson_la_LDFLAGS = \
 libjansson_la_LDFLAGS = \
 	-no-undefined \
 	-no-undefined \
 	-export-symbols-regex '^json_|^jansson_' \
 	-export-symbols-regex '^json_|^jansson_' \
-	-version-info 17:0:13 \
+	-version-info 18:0:14 \
+	@JSON_SYMVER_LDFLAGS@ \
 	@JSON_BSYMBOLIC_LDFLAGS@
 	@JSON_BSYMBOLIC_LDFLAGS@

+ 38 - 17
jansson.mod/jansson/src/dump.c

@@ -195,8 +195,21 @@ static int dump_string(const char *str, size_t len, json_dump_callback_t dump, v
     return dump("\"", 1, data);
     return dump("\"", 1, data);
 }
 }
 
 
+struct key_len {
+    const char *key;
+    int len;
+};
+
 static int compare_keys(const void *key1, const void *key2) {
 static int compare_keys(const void *key1, const void *key2) {
-    return strcmp(*(const char **)key1, *(const char **)key2);
+    const struct key_len *k1 = key1;
+    const struct key_len *k2 = key2;
+    const size_t min_size = k1->len < k2->len ? k1->len : k2->len;
+    int res = memcmp(k1->key, k2->key, min_size);
+
+    if (res)
+        return res;
+
+    return k1->len - k2->len;
 }
 }
 
 
 static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *parents,
 static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *parents,
@@ -236,7 +249,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
             double value = json_real_value(json);
             double value = json_real_value(json);
 
 
             size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value,
             size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value,
-                                FLAGS_TO_PRECISION(flags), flags & JSON_FRACTIONAL_DIGITS);
+                                FLAGS_TO_PRECISION(flags));
             if (size < 0)
             if (size < 0)
                 return -1;
                 return -1;
 
 
@@ -253,9 +266,10 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
             /* Space for "0x", double the sizeof a pointer for the hex and a
             /* Space for "0x", double the sizeof a pointer for the hex and a
              * terminator. */
              * terminator. */
             char key[2 + (sizeof(json) * 2) + 1];
             char key[2 + (sizeof(json) * 2) + 1];
+            size_t key_len;
 
 
             /* detect circular references */
             /* detect circular references */
-            if (jsonp_loop_check(parents, json, key, sizeof(key)))
+            if (jsonp_loop_check(parents, json, key, sizeof(key), &key_len))
                 return -1;
                 return -1;
 
 
             n = json_array_size(json);
             n = json_array_size(json);
@@ -263,7 +277,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
             if (!embed && dump("[", 1, data))
             if (!embed && dump("[", 1, data))
                 return -1;
                 return -1;
             if (n == 0) {
             if (n == 0) {
-                hashtable_del(parents, key);
+                hashtable_del(parents, key, key_len);
                 return embed ? 0 : dump("]", 1, data);
                 return embed ? 0 : dump("]", 1, data);
             }
             }
             if (dump_indent(flags, depth + 1, 0, dump, data))
             if (dump_indent(flags, depth + 1, 0, dump, data))
@@ -284,7 +298,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
                 }
                 }
             }
             }
 
 
-            hashtable_del(parents, key);
+            hashtable_del(parents, key, key_len);
             return embed ? 0 : dump("]", 1, data);
             return embed ? 0 : dump("]", 1, data);
         }
         }
 
 
@@ -293,6 +307,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
             const char *separator;
             const char *separator;
             int separator_length;
             int separator_length;
             char loop_key[LOOP_KEY_LEN];
             char loop_key[LOOP_KEY_LEN];
+            size_t loop_key_len;
 
 
             if (flags & JSON_COMPACT) {
             if (flags & JSON_COMPACT) {
                 separator = ":";
                 separator = ":";
@@ -303,7 +318,8 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
             }
             }
 
 
             /* detect circular references */
             /* detect circular references */
-            if (jsonp_loop_check(parents, json, loop_key, sizeof(loop_key)))
+            if (jsonp_loop_check(parents, json, loop_key, sizeof(loop_key),
+                                 &loop_key_len))
                 return -1;
                 return -1;
 
 
             iter = json_object_iter((json_t *)json);
             iter = json_object_iter((json_t *)json);
@@ -311,40 +327,44 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
             if (!embed && dump("{", 1, data))
             if (!embed && dump("{", 1, data))
                 return -1;
                 return -1;
             if (!iter) {
             if (!iter) {
-                hashtable_del(parents, loop_key);
+                hashtable_del(parents, loop_key, loop_key_len);
                 return embed ? 0 : dump("}", 1, data);
                 return embed ? 0 : dump("}", 1, data);
             }
             }
             if (dump_indent(flags, depth + 1, 0, dump, data))
             if (dump_indent(flags, depth + 1, 0, dump, data))
                 return -1;
                 return -1;
 
 
             if (flags & JSON_SORT_KEYS) {
             if (flags & JSON_SORT_KEYS) {
-                const char **keys;
+                struct key_len *keys;
                 size_t size, i;
                 size_t size, i;
 
 
                 size = json_object_size(json);
                 size = json_object_size(json);
-                keys = jsonp_malloc(size * sizeof(const char *));
+                keys = jsonp_malloc(size * sizeof(struct key_len));
                 if (!keys)
                 if (!keys)
                     return -1;
                     return -1;
 
 
                 i = 0;
                 i = 0;
                 while (iter) {
                 while (iter) {
-                    keys[i] = json_object_iter_key(iter);
+                    struct key_len *keylen = &keys[i];
+
+                    keylen->key = json_object_iter_key(iter);
+                    keylen->len = json_object_iter_key_len(iter);
+
                     iter = json_object_iter_next((json_t *)json, iter);
                     iter = json_object_iter_next((json_t *)json, iter);
                     i++;
                     i++;
                 }
                 }
                 assert(i == size);
                 assert(i == size);
 
 
-                qsort(keys, size, sizeof(const char *), compare_keys);
+                qsort(keys, size, sizeof(struct key_len), compare_keys);
 
 
                 for (i = 0; i < size; i++) {
                 for (i = 0; i < size; i++) {
-                    const char *key;
+                    const struct key_len *key;
                     json_t *value;
                     json_t *value;
 
 
-                    key = keys[i];
-                    value = json_object_get(json, key);
+                    key = &keys[i];
+                    value = json_object_getn(json, key->key, key->len);
                     assert(value);
                     assert(value);
 
 
-                    dump_string(key, strlen(key), dump, data, flags);
+                    dump_string(key->key, key->len, dump, data, flags);
                     if (dump(separator, separator_length, data) ||
                     if (dump(separator, separator_length, data) ||
                         do_dump(value, flags, depth + 1, parents, dump, data)) {
                         do_dump(value, flags, depth + 1, parents, dump, data)) {
                         jsonp_free(keys);
                         jsonp_free(keys);
@@ -372,8 +392,9 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
                 while (iter) {
                 while (iter) {
                     void *next = json_object_iter_next((json_t *)json, iter);
                     void *next = json_object_iter_next((json_t *)json, iter);
                     const char *key = json_object_iter_key(iter);
                     const char *key = json_object_iter_key(iter);
+                    const size_t key_len = json_object_iter_key_len(iter);
 
 
-                    dump_string(key, strlen(key), dump, data, flags);
+                    dump_string(key, key_len, dump, data, flags);
                     if (dump(separator, separator_length, data) ||
                     if (dump(separator, separator_length, data) ||
                         do_dump(json_object_iter_value(iter), flags, depth + 1, parents,
                         do_dump(json_object_iter_value(iter), flags, depth + 1, parents,
                                 dump, data))
                                 dump, data))
@@ -392,7 +413,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
                 }
                 }
             }
             }
 
 
-            hashtable_del(parents, loop_key);
+            hashtable_del(parents, loop_key, loop_key_len);
             return embed ? 0 : dump("}", 1, data);
             return embed ? 0 : dump("}", 1, data);
         }
         }
 
 

+ 57 - 35
jansson.mod/jansson/src/hashtable.c

@@ -5,14 +5,14 @@
  * it under the terms of the MIT license. See LICENSE for details.
  * it under the terms of the MIT license. See LICENSE for details.
  */
  */
 
 
-#if HAVE_CONFIG_H
+#ifdef HAVE_CONFIG_H
 #include <jansson_private_config.h>
 #include <jansson_private_config.h>
 #endif
 #endif
 
 
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 
 
-#if HAVE_STDINT_H
+#ifdef HAVE_STDINT_H
 #include <stdint.h>
 #include <stdint.h>
 #endif
 #endif
 
 
@@ -35,7 +35,7 @@ extern volatile uint32_t hashtable_seed;
 
 
 #define list_to_pair(list_)         container_of(list_, pair_t, list)
 #define list_to_pair(list_)         container_of(list_, pair_t, list)
 #define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list)
 #define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list)
-#define hash_str(key)               ((size_t)hashlittle((key), strlen(key), hashtable_seed))
+#define hash_str(key, len)          ((size_t)hashlittle((key), len, hashtable_seed))
 
 
 static JSON_INLINE void list_init(list_t *list) {
 static JSON_INLINE void list_init(list_t *list) {
     list->next = list;
     list->next = list;
@@ -69,7 +69,7 @@ static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, list_t *l
 }
 }
 
 
 static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
 static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
-                                   const char *key, size_t hash) {
+                                   const char *key, size_t key_len, size_t hash) {
     list_t *list;
     list_t *list;
     pair_t *pair;
     pair_t *pair;
 
 
@@ -79,7 +79,8 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
     list = bucket->first;
     list = bucket->first;
     while (1) {
     while (1) {
         pair = list_to_pair(list);
         pair = list_to_pair(list);
-        if (pair->hash == hash && strcmp(pair->key, key) == 0)
+        if (pair->hash == hash && pair->key_len == key_len &&
+            memcmp(pair->key, key, key_len) == 0)
             return pair;
             return pair;
 
 
         if (list == bucket->last)
         if (list == bucket->last)
@@ -92,7 +93,8 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
 }
 }
 
 
 /* returns 0 on success, -1 if key was not found */
 /* returns 0 on success, -1 if key was not found */
-static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t hash) {
+static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t key_len,
+                            size_t hash) {
     pair_t *pair;
     pair_t *pair;
     bucket_t *bucket;
     bucket_t *bucket;
     size_t index;
     size_t index;
@@ -100,7 +102,7 @@ static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t hash
     index = hash & hashmask(hashtable->order);
     index = hash & hashmask(hashtable->order);
     bucket = &hashtable->buckets[index];
     bucket = &hashtable->buckets[index];
 
 
-    pair = hashtable_find_pair(hashtable, bucket, key, hash);
+    pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
     if (!pair)
     if (!pair)
         return -1;
         return -1;
 
 
@@ -193,7 +195,37 @@ void hashtable_close(hashtable_t *hashtable) {
     jsonp_free(hashtable->buckets);
     jsonp_free(hashtable->buckets);
 }
 }
 
 
-int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) {
+static pair_t *init_pair(json_t *value, const char *key, size_t key_len, size_t hash) {
+    pair_t *pair;
+
+    /* offsetof(...) returns the size of pair_t without the last,
+   flexible member. This way, the correct amount is
+   allocated. */
+
+    if (key_len >= (size_t)-1 - offsetof(pair_t, key)) {
+        /* Avoid an overflow if the key is very long */
+        return NULL;
+    }
+
+    pair = jsonp_malloc(offsetof(pair_t, key) + key_len + 1);
+
+    if (!pair)
+        return NULL;
+
+    pair->hash = hash;
+    memcpy(pair->key, key, key_len);
+    pair->key[key_len] = '\0';
+    pair->key_len = key_len;
+    pair->value = value;
+
+    list_init(&pair->list);
+    list_init(&pair->ordered_list);
+
+    return pair;
+}
+
+int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len,
+                  json_t *value) {
     pair_t *pair;
     pair_t *pair;
     bucket_t *bucket;
     bucket_t *bucket;
     size_t hash, index;
     size_t hash, index;
@@ -203,35 +235,20 @@ int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) {
         if (hashtable_do_rehash(hashtable))
         if (hashtable_do_rehash(hashtable))
             return -1;
             return -1;
 
 
-    hash = hash_str(key);
+    hash = hash_str(key, key_len);
     index = hash & hashmask(hashtable->order);
     index = hash & hashmask(hashtable->order);
     bucket = &hashtable->buckets[index];
     bucket = &hashtable->buckets[index];
-    pair = hashtable_find_pair(hashtable, bucket, key, hash);
+    pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
 
 
     if (pair) {
     if (pair) {
         json_decref(pair->value);
         json_decref(pair->value);
         pair->value = value;
         pair->value = value;
     } else {
     } else {
-        /* offsetof(...) returns the size of pair_t without the last,
-           flexible member. This way, the correct amount is
-           allocated. */
-
-        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 = init_pair(value, key, key_len, hash);
 
 
-        pair = jsonp_malloc(offsetof(pair_t, key) + len + 1);
         if (!pair)
         if (!pair)
             return -1;
             return -1;
 
 
-        pair->hash = hash;
-        strncpy(pair->key, key, len + 1);
-        pair->value = value;
-        list_init(&pair->list);
-        list_init(&pair->ordered_list);
-
         insert_to_bucket(hashtable, bucket, &pair->list);
         insert_to_bucket(hashtable, bucket, &pair->list);
         list_insert(&hashtable->ordered_list, &pair->ordered_list);
         list_insert(&hashtable->ordered_list, &pair->ordered_list);
 
 
@@ -240,24 +257,24 @@ int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) {
     return 0;
     return 0;
 }
 }
 
 
-void *hashtable_get(hashtable_t *hashtable, const char *key) {
+void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len) {
     pair_t *pair;
     pair_t *pair;
     size_t hash;
     size_t hash;
     bucket_t *bucket;
     bucket_t *bucket;
 
 
-    hash = hash_str(key);
+    hash = hash_str(key, key_len);
     bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
     bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
 
 
-    pair = hashtable_find_pair(hashtable, bucket, key, hash);
+    pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
     if (!pair)
     if (!pair)
         return NULL;
         return NULL;
 
 
     return pair->value;
     return pair->value;
 }
 }
 
 
-int hashtable_del(hashtable_t *hashtable, const char *key) {
-    size_t hash = hash_str(key);
-    return hashtable_do_del(hashtable, key, hash);
+int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len) {
+    size_t hash = hash_str(key, key_len);
+    return hashtable_do_del(hashtable, key, key_len, hash);
 }
 }
 
 
 void hashtable_clear(hashtable_t *hashtable) {
 void hashtable_clear(hashtable_t *hashtable) {
@@ -278,15 +295,15 @@ void *hashtable_iter(hashtable_t *hashtable) {
     return hashtable_iter_next(hashtable, &hashtable->ordered_list);
     return hashtable_iter_next(hashtable, &hashtable->ordered_list);
 }
 }
 
 
-void *hashtable_iter_at(hashtable_t *hashtable, const char *key) {
+void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len) {
     pair_t *pair;
     pair_t *pair;
     size_t hash;
     size_t hash;
     bucket_t *bucket;
     bucket_t *bucket;
 
 
-    hash = hash_str(key);
+    hash = hash_str(key, key_len);
     bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
     bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
 
 
-    pair = hashtable_find_pair(hashtable, bucket, key, hash);
+    pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
     if (!pair)
     if (!pair)
         return NULL;
         return NULL;
 
 
@@ -305,6 +322,11 @@ void *hashtable_iter_key(void *iter) {
     return pair->key;
     return pair->key;
 }
 }
 
 
+size_t hashtable_iter_key_len(void *iter) {
+    pair_t *pair = ordered_list_to_pair((list_t *)iter);
+    return pair->key_len;
+}
+
 void *hashtable_iter_value(void *iter) {
 void *hashtable_iter_value(void *iter) {
     pair_t *pair = ordered_list_to_pair((list_t *)iter);
     pair_t *pair = ordered_list_to_pair((list_t *)iter);
     return pair->value;
     return pair->value;

+ 16 - 4
jansson.mod/jansson/src/hashtable.h

@@ -24,6 +24,7 @@ struct hashtable_pair {
     struct hashtable_list ordered_list;
     struct hashtable_list ordered_list;
     size_t hash;
     size_t hash;
     json_t *value;
     json_t *value;
+    size_t key_len;
     char key[1];
     char key[1];
 };
 };
 
 
@@ -69,6 +70,7 @@ void hashtable_close(hashtable_t *hashtable);
  *
  *
  * @hashtable: The hashtable object
  * @hashtable: The hashtable object
  * @key: The key
  * @key: The key
+ * @key: The length of key
  * @serial: For addition order of keys
  * @serial: For addition order of keys
  * @value: The value
  * @value: The value
  *
  *
@@ -79,27 +81,29 @@ void hashtable_close(hashtable_t *hashtable);
  *
  *
  * Returns 0 on success, -1 on failure (out of memory).
  * Returns 0 on success, -1 on failure (out of memory).
  */
  */
-int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value);
+int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len, json_t *value);
 
 
 /**
 /**
  * hashtable_get - Get a value associated with a key
  * hashtable_get - Get a value associated with a key
  *
  *
  * @hashtable: The hashtable object
  * @hashtable: The hashtable object
  * @key: The key
  * @key: The key
+ * @key: The length of key
  *
  *
  * Returns value if it is found, or NULL otherwise.
  * Returns value if it is found, or NULL otherwise.
  */
  */
-void *hashtable_get(hashtable_t *hashtable, const char *key);
+void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len);
 
 
 /**
 /**
  * hashtable_del - Remove a value from the hashtable
  * hashtable_del - Remove a value from the hashtable
  *
  *
  * @hashtable: The hashtable object
  * @hashtable: The hashtable object
  * @key: The key
  * @key: The key
+ * @key: The length of key
  *
  *
  * Returns 0 on success, or -1 if the key was not found.
  * Returns 0 on success, or -1 if the key was not found.
  */
  */
-int hashtable_del(hashtable_t *hashtable, const char *key);
+int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len);
 
 
 /**
 /**
  * hashtable_clear - Clear hashtable
  * hashtable_clear - Clear hashtable
@@ -132,11 +136,12 @@ void *hashtable_iter(hashtable_t *hashtable);
  *
  *
  * @hashtable: The hashtable object
  * @hashtable: The hashtable object
  * @key: The key that the iterator should point to
  * @key: The key that the iterator should point to
+ * @key: The length of key
  *
  *
  * Like hashtable_iter() but returns an iterator pointing to a
  * Like hashtable_iter() but returns an iterator pointing to a
  * specific key.
  * specific key.
  */
  */
-void *hashtable_iter_at(hashtable_t *hashtable, const char *key);
+void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len);
 
 
 /**
 /**
  * hashtable_iter_next - Advance an iterator
  * hashtable_iter_next - Advance an iterator
@@ -156,6 +161,13 @@ void *hashtable_iter_next(hashtable_t *hashtable, void *iter);
  */
  */
 void *hashtable_iter_key(void *iter);
 void *hashtable_iter_key(void *iter);
 
 
+/**
+ * hashtable_iter_key_len - Retrieve the key length pointed by an iterator
+ *
+ * @iter: The iterator
+ */
+size_t hashtable_iter_key_len(void *iter);
+
 /**
 /**
  * hashtable_iter_value - Retrieve the value pointed by an iterator
  * hashtable_iter_value - Retrieve the value pointed by an iterator
  *
  *

+ 5 - 0
jansson.mod/jansson/src/jansson.def

@@ -34,9 +34,13 @@ EXPORTS
     json_object
     json_object
     json_object_size
     json_object_size
     json_object_get
     json_object_get
+    json_object_getn
     json_object_set_new
     json_object_set_new
+    json_object_setn_new
     json_object_set_new_nocheck
     json_object_set_new_nocheck
+    json_object_setn_new_nocheck
     json_object_del
     json_object_del
+    json_object_deln
     json_object_clear
     json_object_clear
     json_object_update
     json_object_update
     json_object_update_existing
     json_object_update_existing
@@ -46,6 +50,7 @@ EXPORTS
     json_object_iter_at
     json_object_iter_at
     json_object_iter_next
     json_object_iter_next
     json_object_iter_key
     json_object_iter_key
+    json_object_iter_key_len
     json_object_iter_value
     json_object_iter_value
     json_object_iter_set_new
     json_object_iter_set_new
     json_object_key_to_iter
     json_object_key_to_iter

+ 36 - 4
jansson.mod/jansson/src/jansson.h

@@ -21,11 +21,11 @@ extern "C" {
 /* version */
 /* version */
 
 
 #define JANSSON_MAJOR_VERSION 2
 #define JANSSON_MAJOR_VERSION 2
-#define JANSSON_MINOR_VERSION 13
-#define JANSSON_MICRO_VERSION 1
+#define JANSSON_MINOR_VERSION 14
+#define JANSSON_MICRO_VERSION 0
 
 
 /* Micro version is omitted if it's 0 */
 /* Micro version is omitted if it's 0 */
-#define JANSSON_VERSION "2.13.1"
+#define JANSSON_VERSION "2.14"
 
 
 /* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
 /* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
    for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
    for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
@@ -188,9 +188,15 @@ void json_object_seed(size_t seed);
 size_t json_object_size(const json_t *object);
 size_t json_object_size(const json_t *object);
 json_t *json_object_get(const json_t *object, const char *key)
 json_t *json_object_get(const json_t *object, const char *key)
     JANSSON_ATTRS((warn_unused_result));
     JANSSON_ATTRS((warn_unused_result));
+json_t *json_object_getn(const json_t *object, const char *key, size_t key_len)
+    JANSSON_ATTRS((warn_unused_result));
 int json_object_set_new(json_t *object, const char *key, json_t *value);
 int json_object_set_new(json_t *object, const char *key, json_t *value);
+int json_object_setn_new(json_t *object, const char *key, size_t key_len, json_t *value);
 int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
 int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
+int json_object_setn_new_nocheck(json_t *object, const char *key, size_t key_len,
+                                 json_t *value);
 int json_object_del(json_t *object, const char *key);
 int json_object_del(json_t *object, const char *key);
+int json_object_deln(json_t *object, const char *key, size_t key_len);
 int json_object_clear(json_t *object);
 int json_object_clear(json_t *object);
 int json_object_update(json_t *object, json_t *other);
 int json_object_update(json_t *object, json_t *other);
 int json_object_update_existing(json_t *object, json_t *other);
 int json_object_update_existing(json_t *object, json_t *other);
@@ -201,6 +207,7 @@ void *json_object_iter_at(json_t *object, const char *key);
 void *json_object_key_to_iter(const char *key);
 void *json_object_key_to_iter(const char *key);
 void *json_object_iter_next(json_t *object, void *iter);
 void *json_object_iter_next(json_t *object, void *iter);
 const char *json_object_iter_key(void *iter);
 const char *json_object_iter_key(void *iter);
+size_t json_object_iter_key_len(void *iter);
 json_t *json_object_iter_value(void *iter);
 json_t *json_object_iter_value(void *iter);
 int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
 int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
 
 
@@ -210,6 +217,14 @@ int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
          key = json_object_iter_key(                                                     \
          key = json_object_iter_key(                                                     \
              json_object_iter_next(object, json_object_key_to_iter(key))))
              json_object_iter_next(object, json_object_key_to_iter(key))))
 
 
+#define json_object_keylen_foreach(object, key, key_len, value)                          \
+    for (key = json_object_iter_key(json_object_iter(object)),                           \
+        key_len = json_object_iter_key_len(json_object_key_to_iter(key));                \
+         key && (value = json_object_iter_value(json_object_key_to_iter(key)));          \
+         key = json_object_iter_key(                                                     \
+             json_object_iter_next(object, json_object_key_to_iter(key))),               \
+        key_len = json_object_iter_key_len(json_object_key_to_iter(key)))
+
 #define json_object_foreach_safe(object, n, key, value)                                  \
 #define json_object_foreach_safe(object, n, key, value)                                  \
     for (key = json_object_iter_key(json_object_iter(object)),                           \
     for (key = json_object_iter_key(json_object_iter(object)),                           \
         n = json_object_iter_next(object, json_object_key_to_iter(key));                 \
         n = json_object_iter_next(object, json_object_key_to_iter(key));                 \
@@ -217,6 +232,14 @@ int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
          key = json_object_iter_key(n),                                                  \
          key = json_object_iter_key(n),                                                  \
         n = json_object_iter_next(object, json_object_key_to_iter(key)))
         n = json_object_iter_next(object, json_object_key_to_iter(key)))
 
 
+#define json_object_keylen_foreach_safe(object, n, key, key_len, value)                  \
+    for (key = json_object_iter_key(json_object_iter(object)),                           \
+        n = json_object_iter_next(object, json_object_key_to_iter(key)),                 \
+        key_len = json_object_iter_key_len(json_object_key_to_iter(key));                \
+         key && (value = json_object_iter_value(json_object_key_to_iter(key)));          \
+         key = json_object_iter_key(n), key_len = json_object_iter_key_len(n),           \
+        n = json_object_iter_next(object, json_object_key_to_iter(key)))
+
 #define json_array_foreach(array, index, value)                                          \
 #define json_array_foreach(array, index, value)                                          \
     for (index = 0;                                                                      \
     for (index = 0;                                                                      \
          index < json_array_size(array) && (value = json_array_get(array, index));       \
          index < json_array_size(array) && (value = json_array_get(array, index));       \
@@ -226,11 +249,21 @@ static JSON_INLINE int json_object_set(json_t *object, const char *key, json_t *
     return json_object_set_new(object, key, json_incref(value));
     return json_object_set_new(object, key, json_incref(value));
 }
 }
 
 
+static JSON_INLINE int json_object_setn(json_t *object, const char *key, size_t key_len,
+                                        json_t *value) {
+    return json_object_setn_new(object, key, key_len, json_incref(value));
+}
+
 static JSON_INLINE int json_object_set_nocheck(json_t *object, const char *key,
 static JSON_INLINE int json_object_set_nocheck(json_t *object, const char *key,
                                                json_t *value) {
                                                json_t *value) {
     return json_object_set_new_nocheck(object, key, json_incref(value));
     return json_object_set_new_nocheck(object, key, json_incref(value));
 }
 }
 
 
+static JSON_INLINE int json_object_setn_nocheck(json_t *object, const char *key,
+                                                size_t key_len, json_t *value) {
+    return json_object_setn_new_nocheck(object, key, key_len, json_incref(value));
+}
+
 static JSON_INLINE int json_object_iter_set(json_t *object, void *iter, json_t *value) {
 static JSON_INLINE int json_object_iter_set(json_t *object, void *iter, json_t *value) {
     return json_object_iter_set_new(object, iter, json_incref(value));
     return json_object_iter_set_new(object, iter, json_incref(value));
 }
 }
@@ -355,7 +388,6 @@ json_t *json_load_callback(json_load_callback_t callback, void *data, size_t fla
 #define JSON_ESCAPE_SLASH      0x400
 #define JSON_ESCAPE_SLASH      0x400
 #define JSON_REAL_PRECISION(n) (((n)&0x1F) << 11)
 #define JSON_REAL_PRECISION(n) (((n)&0x1F) << 11)
 #define JSON_EMBED             0x10000
 #define JSON_EMBED             0x10000
-#define JSON_FRACTIONAL_DIGITS  0x20000
 
 
 typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
 typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
 
 

+ 3 - 3
jansson.mod/jansson/src/jansson_private.h

@@ -79,7 +79,7 @@ void jsonp_error_vset(json_error_t *error, int line, int column, size_t position
 
 
 /* Locale independent string<->double conversions */
 /* Locale independent string<->double conversions */
 int jsonp_strtod(strbuffer_t *strbuffer, double *out);
 int jsonp_strtod(strbuffer_t *strbuffer, double *out);
-int jsonp_dtostr(char *buffer, size_t size, double value, int prec, int frac_digits);
+int jsonp_dtostr(char *buffer, size_t size, double value, int prec);
 
 
 /* Wrappers for custom memory functions */
 /* Wrappers for custom memory functions */
 void *jsonp_malloc(size_t size) JANSSON_ATTRS((warn_unused_result));
 void *jsonp_malloc(size_t size) JANSSON_ATTRS((warn_unused_result));
@@ -91,8 +91,8 @@ char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS((warn_unused_resu
 /* Circular reference check*/
 /* Circular reference check*/
 /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
 /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
 #define LOOP_KEY_LEN (2 + (sizeof(json_t *) * 2) + 1)
 #define LOOP_KEY_LEN (2 + (sizeof(json_t *) * 2) + 1)
-int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key,
-                     size_t key_size);
+int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size,
+                     size_t *key_len_out);
 
 
 /* Windows compatibility */
 /* Windows compatibility */
 #if defined(_WIN32) || defined(WIN32)
 #if defined(_WIN32) || defined(WIN32)

+ 2 - 2
jansson.mod/jansson/src/load.c

@@ -689,7 +689,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) {
         }
         }
 
 
         if (flags & JSON_REJECT_DUPLICATES) {
         if (flags & JSON_REJECT_DUPLICATES) {
-            if (json_object_get(object, key)) {
+            if (json_object_getn(object, key, len)) {
                 jsonp_free(key);
                 jsonp_free(key);
                 error_set(error, lex, json_error_duplicate_key, "duplicate object key");
                 error_set(error, lex, json_error_duplicate_key, "duplicate object key");
                 goto error;
                 goto error;
@@ -710,7 +710,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) {
             goto error;
             goto error;
         }
         }
 
 
-        if (json_object_set_new_nocheck(object, key, value)) {
+        if (json_object_setn_new_nocheck(object, key, len, value)) {
             jsonp_free(key);
             jsonp_free(key);
             goto error;
             goto error;
         }
         }

+ 1 - 1
jansson.mod/jansson/src/lookup3.h

@@ -73,7 +73,7 @@ on 1 byte), but shoehorning those bytes into integers efficiently is messy.
 # define HASH_BIG_ENDIAN 0
 # define HASH_BIG_ENDIAN 0
 #endif
 #endif
 
 
-#define hashsize(n) ((uint32_t)1<<(n))
+#define hashsize(n) ((size_t)1<<(n))
 #define hashmask(n) (hashsize(n)-1)
 #define hashmask(n) (hashsize(n)-1)
 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
 
 

+ 5 - 4
jansson.mod/jansson/src/pack_unpack.c

@@ -544,7 +544,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) {
         if (unpack(s, value, ap))
         if (unpack(s, value, ap))
             goto out;
             goto out;
 
 
-        hashtable_set(&key_set, key, json_null());
+        hashtable_set(&key_set, key, strlen(key), json_null());
         next_token(s);
         next_token(s);
     }
     }
 
 
@@ -554,6 +554,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) {
     if (root && strict == 1) {
     if (root && strict == 1) {
         /* We need to check that all non optional items have been parsed */
         /* We need to check that all non optional items have been parsed */
         const char *key;
         const char *key;
+        size_t key_len;
         /* keys_res is 1 for uninitialized, 0 for success, -1 for error. */
         /* keys_res is 1 for uninitialized, 0 for success, -1 for error. */
         int keys_res = 1;
         int keys_res = 1;
         strbuffer_t unrecognized_keys;
         strbuffer_t unrecognized_keys;
@@ -561,8 +562,8 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) {
         long unpacked = 0;
         long unpacked = 0;
 
 
         if (gotopt || json_object_size(root) != key_set.size) {
         if (gotopt || json_object_size(root) != key_set.size) {
-            json_object_foreach(root, key, value) {
-                if (!hashtable_get(&key_set, key)) {
+            json_object_keylen_foreach(root, key, key_len, value) {
+                if (!hashtable_get(&key_set, key, key_len)) {
                     unpacked++;
                     unpacked++;
 
 
                     /* Save unrecognized keys for the error message */
                     /* Save unrecognized keys for the error message */
@@ -574,7 +575,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) {
 
 
                     if (!keys_res)
                     if (!keys_res)
                         keys_res =
                         keys_res =
-                            strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
+                            strbuffer_append_bytes(&unrecognized_keys, key, key_len);
                 }
                 }
             }
             }
         }
         }

+ 2 - 3
jansson.mod/jansson/src/strconv.c

@@ -76,8 +76,7 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out) {
     return 0;
     return 0;
 }
 }
 
 
-int jsonp_dtostr(char *buffer, size_t size, double value, int precision, int fractional_digits)
-{
+int jsonp_dtostr(char *buffer, size_t size, double value, int precision) {
     int ret;
     int ret;
     char *start, *end;
     char *start, *end;
     size_t length;
     size_t length;
@@ -85,7 +84,7 @@ int jsonp_dtostr(char *buffer, size_t size, double value, int precision, int fra
     if (precision == 0)
     if (precision == 0)
         precision = 17;
         precision = 17;
 
 
-    ret = snprintf(buffer, size, fractional_digits ? "%.*f" : "%.*g", precision, value);
+    ret = snprintf(buffer, size, "%.*g", precision, value);
     if (ret < 0)
     if (ret < 0)
         return -1;
         return -1;
 
 

+ 92 - 34
jansson.mod/jansson/src/value.c

@@ -44,13 +44,17 @@ static JSON_INLINE void json_init(json_t *json, json_type type) {
     json->refcount = 1;
     json->refcount = 1;
 }
 }
 
 
-int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key,
-                     size_t key_size) {
-    snprintf(key, key_size, "%p", json);
-    if (hashtable_get(parents, key))
+int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size,
+                     size_t *key_len_out) {
+    size_t key_len = snprintf(key, key_size, "%p", json);
+
+    if (key_len_out)
+        *key_len_out = key_len;
+
+    if (hashtable_get(parents, key, key_len))
         return -1;
         return -1;
 
 
-    return hashtable_set(parents, key, json_null());
+    return hashtable_set(parents, key, key_len, json_null());
 }
 }
 
 
 /*** object ***/
 /*** object ***/
@@ -93,16 +97,32 @@ size_t json_object_size(const json_t *json) {
 }
 }
 
 
 json_t *json_object_get(const json_t *json, const char *key) {
 json_t *json_object_get(const json_t *json, const char *key) {
+    if (!key)
+        return NULL;
+
+    return json_object_getn(json, key, strlen(key));
+}
+
+json_t *json_object_getn(const json_t *json, const char *key, size_t key_len) {
     json_object_t *object;
     json_object_t *object;
 
 
     if (!key || !json_is_object(json))
     if (!key || !json_is_object(json))
         return NULL;
         return NULL;
 
 
     object = json_to_object(json);
     object = json_to_object(json);
-    return hashtable_get(&object->hashtable, key);
+    return hashtable_get(&object->hashtable, key, key_len);
 }
 }
 
 
 int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) {
 int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) {
+    if (!key) {
+        json_decref(value);
+        return -1;
+    }
+    return json_object_setn_new_nocheck(json, key, strlen(key), value);
+}
+
+int json_object_setn_new_nocheck(json_t *json, const char *key, size_t key_len,
+                                 json_t *value) {
     json_object_t *object;
     json_object_t *object;
 
 
     if (!value)
     if (!value)
@@ -114,7 +134,7 @@ int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) {
     }
     }
     object = json_to_object(json);
     object = json_to_object(json);
 
 
-    if (hashtable_set(&object->hashtable, key, value)) {
+    if (hashtable_set(&object->hashtable, key, key_len, value)) {
         json_decref(value);
         json_decref(value);
         return -1;
         return -1;
     }
     }
@@ -123,22 +143,38 @@ 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) {
 int json_object_set_new(json_t *json, const char *key, json_t *value) {
-    if (!key || !utf8_check_string(key, strlen(key))) {
+    if (!key) {
         json_decref(value);
         json_decref(value);
         return -1;
         return -1;
     }
     }
 
 
-    return json_object_set_new_nocheck(json, key, value);
+    return json_object_setn_new(json, key, strlen(key), value);
+}
+
+int json_object_setn_new(json_t *json, const char *key, size_t key_len, json_t *value) {
+    if (!key || !utf8_check_string(key, key_len)) {
+        json_decref(value);
+        return -1;
+    }
+
+    return json_object_setn_new_nocheck(json, key, key_len, value);
 }
 }
 
 
 int json_object_del(json_t *json, const char *key) {
 int json_object_del(json_t *json, const char *key) {
+    if (!key)
+        return -1;
+
+    return json_object_deln(json, key, strlen(key));
+}
+
+int json_object_deln(json_t *json, const char *key, size_t key_len) {
     json_object_t *object;
     json_object_t *object;
 
 
     if (!key || !json_is_object(json))
     if (!key || !json_is_object(json))
         return -1;
         return -1;
 
 
     object = json_to_object(json);
     object = json_to_object(json);
-    return hashtable_del(&object->hashtable, key);
+    return hashtable_del(&object->hashtable, key, key_len);
 }
 }
 
 
 int json_object_clear(json_t *json) {
 int json_object_clear(json_t *json) {
@@ -155,13 +191,14 @@ int json_object_clear(json_t *json) {
 
 
 int json_object_update(json_t *object, json_t *other) {
 int json_object_update(json_t *object, json_t *other) {
     const char *key;
     const char *key;
+    size_t key_len;
     json_t *value;
     json_t *value;
 
 
     if (!json_is_object(object) || !json_is_object(other))
     if (!json_is_object(object) || !json_is_object(other))
         return -1;
         return -1;
 
 
-    json_object_foreach(other, key, value) {
-        if (json_object_set_nocheck(object, key, value))
+    json_object_keylen_foreach(other, key, key_len, value) {
+        if (json_object_setn_nocheck(object, key, key_len, value))
             return -1;
             return -1;
     }
     }
 
 
@@ -170,14 +207,15 @@ int json_object_update(json_t *object, json_t *other) {
 
 
 int json_object_update_existing(json_t *object, json_t *other) {
 int json_object_update_existing(json_t *object, json_t *other) {
     const char *key;
     const char *key;
+    size_t key_len;
     json_t *value;
     json_t *value;
 
 
     if (!json_is_object(object) || !json_is_object(other))
     if (!json_is_object(object) || !json_is_object(other))
         return -1;
         return -1;
 
 
-    json_object_foreach(other, key, value) {
-        if (json_object_get(object, key))
-            json_object_set_nocheck(object, key, value);
+    json_object_keylen_foreach(other, key, key_len, value) {
+        if (json_object_getn(object, key, key_len))
+            json_object_setn_nocheck(object, key, key_len, value);
     }
     }
 
 
     return 0;
     return 0;
@@ -185,14 +223,15 @@ int json_object_update_existing(json_t *object, json_t *other) {
 
 
 int json_object_update_missing(json_t *object, json_t *other) {
 int json_object_update_missing(json_t *object, json_t *other) {
     const char *key;
     const char *key;
+    size_t key_len;
     json_t *value;
     json_t *value;
 
 
     if (!json_is_object(object) || !json_is_object(other))
     if (!json_is_object(object) || !json_is_object(other))
         return -1;
         return -1;
 
 
-    json_object_foreach(other, key, value) {
-        if (!json_object_get(object, key))
-            json_object_set_nocheck(object, key, value);
+    json_object_keylen_foreach(other, key, key_len, value) {
+        if (!json_object_getn(object, key, key_len))
+            json_object_setn_nocheck(object, key, key_len, value);
     }
     }
 
 
     return 0;
     return 0;
@@ -200,18 +239,20 @@ int json_object_update_missing(json_t *object, json_t *other) {
 
 
 int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *parents) {
 int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *parents) {
     const char *key;
     const char *key;
+    size_t key_len;
     json_t *value;
     json_t *value;
     char loop_key[LOOP_KEY_LEN];
     char loop_key[LOOP_KEY_LEN];
     int res = 0;
     int res = 0;
+    size_t loop_key_len;
 
 
     if (!json_is_object(object) || !json_is_object(other))
     if (!json_is_object(object) || !json_is_object(other))
         return -1;
         return -1;
 
 
-    if (jsonp_loop_check(parents, other, loop_key, sizeof(loop_key)))
+    if (jsonp_loop_check(parents, other, loop_key, sizeof(loop_key), &loop_key_len))
         return -1;
         return -1;
 
 
-    json_object_foreach(other, key, value) {
-        json_t *v = json_object_get(object, key);
+    json_object_keylen_foreach(other, key, key_len, value) {
+        json_t *v = json_object_getn(object, key, key_len);
 
 
         if (json_is_object(v) && json_is_object(value)) {
         if (json_is_object(v) && json_is_object(value)) {
             if (do_object_update_recursive(v, value, parents)) {
             if (do_object_update_recursive(v, value, parents)) {
@@ -219,14 +260,14 @@ int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *paren
                 break;
                 break;
             }
             }
         } else {
         } else {
-            if (json_object_set_nocheck(object, key, value)) {
+            if (json_object_setn_nocheck(object, key, key_len, value)) {
                 res = -1;
                 res = -1;
                 break;
                 break;
             }
             }
         }
         }
     }
     }
 
 
-    hashtable_del(parents, loop_key);
+    hashtable_del(parents, loop_key, loop_key_len);
 
 
     return res;
     return res;
 }
 }
@@ -260,7 +301,7 @@ void *json_object_iter_at(json_t *json, const char *key) {
         return NULL;
         return NULL;
 
 
     object = json_to_object(json);
     object = json_to_object(json);
-    return hashtable_iter_at(&object->hashtable, key);
+    return hashtable_iter_at(&object->hashtable, key, strlen(key));
 }
 }
 
 
 void *json_object_iter_next(json_t *json, void *iter) {
 void *json_object_iter_next(json_t *json, void *iter) {
@@ -280,6 +321,13 @@ const char *json_object_iter_key(void *iter) {
     return hashtable_iter_key(iter);
     return hashtable_iter_key(iter);
 }
 }
 
 
+size_t json_object_iter_key_len(void *iter) {
+    if (!iter)
+        return 0;
+
+    return hashtable_iter_key_len(iter);
+}
+
 json_t *json_object_iter_value(void *iter) {
 json_t *json_object_iter_value(void *iter) {
     if (!iter)
     if (!iter)
         return NULL;
         return NULL;
@@ -306,13 +354,14 @@ void *json_object_key_to_iter(const char *key) {
 
 
 static int json_object_equal(const json_t *object1, const json_t *object2) {
 static int json_object_equal(const json_t *object1, const json_t *object2) {
     const char *key;
     const char *key;
+    size_t key_len;
     const json_t *value1, *value2;
     const json_t *value1, *value2;
 
 
     if (json_object_size(object1) != json_object_size(object2))
     if (json_object_size(object1) != json_object_size(object2))
         return 0;
         return 0;
 
 
-    json_object_foreach((json_t *)object1, key, value1) {
-        value2 = json_object_get(object2, key);
+    json_object_keylen_foreach((json_t *)object1, key, key_len, value1) {
+        value2 = json_object_getn(object2, key, key_len);
 
 
         if (!json_equal(value1, value2))
         if (!json_equal(value1, value2))
             return 0;
             return 0;
@@ -325,13 +374,15 @@ static json_t *json_object_copy(json_t *object) {
     json_t *result;
     json_t *result;
 
 
     const char *key;
     const char *key;
+    size_t key_len;
     json_t *value;
     json_t *value;
 
 
     result = json_object();
     result = json_object();
     if (!result)
     if (!result)
         return NULL;
         return NULL;
 
 
-    json_object_foreach(object, key, value) json_object_set_nocheck(result, key, value);
+    json_object_keylen_foreach(object, key, key_len, value)
+        json_object_setn_nocheck(result, key, key_len, value);
 
 
     return result;
     return result;
 }
 }
@@ -340,8 +391,9 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
     json_t *result;
     json_t *result;
     void *iter;
     void *iter;
     char loop_key[LOOP_KEY_LEN];
     char loop_key[LOOP_KEY_LEN];
+    size_t loop_key_len;
 
 
-    if (jsonp_loop_check(parents, object, loop_key, sizeof(loop_key)))
+    if (jsonp_loop_check(parents, object, loop_key, sizeof(loop_key), &loop_key_len))
         return NULL;
         return NULL;
 
 
     result = json_object();
     result = json_object();
@@ -353,11 +405,14 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
     iter = json_object_iter((json_t *)object);
     iter = json_object_iter((json_t *)object);
     while (iter) {
     while (iter) {
         const char *key;
         const char *key;
+        size_t key_len;
         const json_t *value;
         const json_t *value;
         key = json_object_iter_key(iter);
         key = json_object_iter_key(iter);
+        key_len = json_object_iter_key_len(iter);
         value = json_object_iter_value(iter);
         value = json_object_iter_value(iter);
 
 
-        if (json_object_set_new_nocheck(result, key, do_deep_copy(value, parents))) {
+        if (json_object_setn_new_nocheck(result, key, key_len,
+                                         do_deep_copy(value, parents))) {
             json_decref(result);
             json_decref(result);
             result = NULL;
             result = NULL;
             break;
             break;
@@ -366,7 +421,7 @@ static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents)
     }
     }
 
 
 out:
 out:
-    hashtable_del(parents, loop_key);
+    hashtable_del(parents, loop_key, loop_key_len);
 
 
     return result;
     return result;
 }
 }
@@ -633,8 +688,9 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents) {
     json_t *result;
     json_t *result;
     size_t i;
     size_t i;
     char loop_key[LOOP_KEY_LEN];
     char loop_key[LOOP_KEY_LEN];
+    size_t loop_key_len;
 
 
-    if (jsonp_loop_check(parents, array, loop_key, sizeof(loop_key)))
+    if (jsonp_loop_check(parents, array, loop_key, sizeof(loop_key), &loop_key_len))
         return NULL;
         return NULL;
 
 
     result = json_array();
     result = json_array();
@@ -651,7 +707,7 @@ static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents) {
     }
     }
 
 
 out:
 out:
-    hashtable_del(parents, loop_key);
+    hashtable_del(parents, loop_key, loop_key_len);
 
 
     return result;
     return result;
 }
 }
@@ -797,16 +853,18 @@ json_t *json_vsprintf(const char *fmt, va_list ap) {
     va_copy(aq, ap);
     va_copy(aq, ap);
 
 
     length = vsnprintf(NULL, 0, fmt, ap);
     length = vsnprintf(NULL, 0, fmt, ap);
+    if (length < 0)
+        goto out;
     if (length == 0) {
     if (length == 0) {
         json = json_string("");
         json = json_string("");
         goto out;
         goto out;
     }
     }
 
 
-    buf = jsonp_malloc(length + 1);
+    buf = jsonp_malloc((size_t)length + 1);
     if (!buf)
     if (!buf)
         goto out;
         goto out;
 
 
-    vsnprintf(buf, length + 1, fmt, aq);
+    vsnprintf(buf, (size_t)length + 1, fmt, aq);
     if (!utf8_check_string(buf, length)) {
     if (!utf8_check_string(buf, length)) {
         jsonp_free(buf);
         jsonp_free(buf);
         goto out;
         goto out;

+ 20 - 0
jansson.mod/jansson/test/.gitignore

@@ -0,0 +1,20 @@
+logs
+bin/json_process
+suites/api/test_array
+suites/api/test_chaos
+suites/api/test_copy
+suites/api/test_cpp
+suites/api/test_dump
+suites/api/test_dump_callback
+suites/api/test_equal
+suites/api/test_load
+suites/api/test_load_callback
+suites/api/test_loadb
+suites/api/test_memory_funcs
+suites/api/test_number
+suites/api/test_object
+suites/api/test_pack
+suites/api/test_simple
+suites/api/test_sprintf
+suites/api/test_unpack
+suites/api/test_version

+ 10 - 0
jansson.mod/jansson/test/Makefile.am

@@ -0,0 +1,10 @@
+SUBDIRS = bin suites ossfuzz
+EXTRA_DIST = scripts run-suites
+
+TESTS = run-suites
+TESTS_ENVIRONMENT = \
+	top_srcdir=$(top_srcdir) \
+	top_builddir=$(top_builddir)
+
+clean-local:
+	rm -rf logs

+ 5 - 0
jansson.mod/jansson/test/bin/Makefile.am

@@ -0,0 +1,5 @@
+check_PROGRAMS = json_process
+
+AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src
+LDFLAGS = -static  # for speed and Valgrind
+LDADD = $(top_builddir)/src/libjansson.la

+ 366 - 0
jansson.mod/jansson/test/bin/json_process.c

@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * 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 <jansson_private_config.h>
+#endif
+
+#include <ctype.h>
+#include <jansson.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#if _WIN32
+#include <fcntl.h> /* for _O_BINARY */
+#include <io.h>    /* for _setmode() */
+
+static const char dir_sep = '\\';
+#else
+static const char dir_sep = '/';
+#endif
+
+struct config {
+    int indent;
+    int compact;
+    int preserve_order;
+    int ensure_ascii;
+    int sort_keys;
+    int strip;
+    int use_env;
+    int have_hashseed;
+    int hashseed;
+    int precision;
+} conf;
+
+#define l_isspace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t')
+
+/* Return a pointer to the first non-whitespace character of str.
+   Modifies str so that all trailing whitespace characters are
+   replaced by '\0'. */
+static const char *strip(char *str) {
+    size_t length;
+    char *result = str;
+    while (*result && l_isspace(*result))
+        result++;
+
+    length = strlen(result);
+    if (length == 0)
+        return result;
+
+    while (l_isspace(result[length - 1]))
+        result[--length] = '\0';
+
+    return result;
+}
+
+static char *loadfile(FILE *file) {
+    size_t fsize, ret;
+    char *buf;
+
+    fseek(file, 0, SEEK_END);
+    fsize = ftell(file);
+    fseek(file, 0, SEEK_SET);
+
+    buf = malloc(fsize + 1);
+    ret = fread(buf, 1, fsize, file);
+    if (ret != fsize)
+        exit(1);
+    buf[fsize] = '\0';
+
+    return buf;
+}
+
+static void read_conf(FILE *conffile) {
+    char *buffer, *line, *val;
+
+    buffer = loadfile(conffile);
+    for (line = strtok(buffer, "\r\n"); line; line = strtok(NULL, "\r\n")) {
+        if (!strncmp(line, "export ", 7))
+            continue;
+        val = strchr(line, '=');
+        if (!val) {
+            printf("invalid configuration line\n");
+            break;
+        }
+        *val++ = '\0';
+
+        if (!strcmp(line, "JSON_INDENT"))
+            conf.indent = atoi(val);
+        if (!strcmp(line, "JSON_COMPACT"))
+            conf.compact = atoi(val);
+        if (!strcmp(line, "JSON_ENSURE_ASCII"))
+            conf.ensure_ascii = atoi(val);
+        if (!strcmp(line, "JSON_PRESERVE_ORDER"))
+            conf.preserve_order = atoi(val);
+        if (!strcmp(line, "JSON_SORT_KEYS"))
+            conf.sort_keys = atoi(val);
+        if (!strcmp(line, "JSON_REAL_PRECISION"))
+            conf.precision = atoi(val);
+        if (!strcmp(line, "STRIP"))
+            conf.strip = atoi(val);
+        if (!strcmp(line, "HASHSEED")) {
+            conf.have_hashseed = 1;
+            conf.hashseed = atoi(val);
+        } else {
+            conf.have_hashseed = 0;
+        }
+    }
+
+    free(buffer);
+}
+
+static int cmpfile(const char *str, const char *path, const char *fname) {
+    char filename[1024], *buffer;
+    int ret;
+    FILE *file;
+
+    sprintf(filename, "%s%c%s", path, dir_sep, fname);
+    file = fopen(filename, "rb");
+    if (!file) {
+        if (conf.strip)
+            strcat(filename, ".strip");
+        else
+            strcat(filename, ".normal");
+        file = fopen(filename, "rb");
+    }
+    if (!file) {
+        printf("Error: test result file could not be opened.\n");
+        exit(1);
+    }
+
+    buffer = loadfile(file);
+    if (strcmp(buffer, str) != 0)
+        ret = 1;
+    else
+        ret = 0;
+    free(buffer);
+    fclose(file);
+
+    return ret;
+}
+
+int use_conf(char *test_path) {
+    int ret;
+    size_t flags = 0;
+    char filename[1024], errstr[1024];
+    char *buffer;
+    FILE *infile, *conffile;
+    json_t *json;
+    json_error_t error;
+
+    sprintf(filename, "%s%cinput", test_path, dir_sep);
+    if (!(infile = fopen(filename, "rb"))) {
+        fprintf(stderr, "Could not open \"%s\"\n", filename);
+        return 2;
+    }
+
+    sprintf(filename, "%s%cenv", test_path, dir_sep);
+    conffile = fopen(filename, "rb");
+    if (conffile) {
+        read_conf(conffile);
+        fclose(conffile);
+    }
+
+    if (conf.indent < 0 || conf.indent > 31) {
+        fprintf(stderr, "invalid value for JSON_INDENT: %d\n", conf.indent);
+        fclose(infile);
+        return 2;
+    }
+    if (conf.indent)
+        flags |= JSON_INDENT(conf.indent);
+
+    if (conf.compact)
+        flags |= JSON_COMPACT;
+
+    if (conf.ensure_ascii)
+        flags |= JSON_ENSURE_ASCII;
+
+    if (conf.preserve_order)
+        flags |= JSON_PRESERVE_ORDER;
+
+    if (conf.sort_keys)
+        flags |= JSON_SORT_KEYS;
+
+    if (conf.precision < 0 || conf.precision > 31) {
+        fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n", conf.precision);
+        fclose(infile);
+        return 2;
+    }
+    if (conf.precision)
+        flags |= JSON_REAL_PRECISION(conf.precision);
+
+    if (conf.have_hashseed)
+        json_object_seed(conf.hashseed);
+
+    if (conf.strip) {
+        /* Load to memory, strip leading and trailing whitespace */
+        buffer = loadfile(infile);
+        json = json_loads(strip(buffer), 0, &error);
+        free(buffer);
+    } else
+        json = json_loadf(infile, 0, &error);
+
+    fclose(infile);
+
+    if (!json) {
+        sprintf(errstr, "%d %d %d\n%s\n", error.line, error.column, error.position,
+                error.text);
+
+        ret = cmpfile(errstr, test_path, "error");
+        return ret;
+    }
+
+    buffer = json_dumps(json, flags);
+    ret = cmpfile(buffer, test_path, "output");
+    free(buffer);
+    json_decref(json);
+
+    return ret;
+}
+
+static int getenv_int(const char *name) {
+    char *value, *end;
+    long result;
+
+    value = getenv(name);
+    if (!value)
+        return 0;
+
+    result = strtol(value, &end, 10);
+    if (*end != '\0')
+        return 0;
+
+    return (int)result;
+}
+
+int use_env() {
+    int indent, precision;
+    size_t flags = 0;
+    json_t *json;
+    json_error_t error;
+
+#ifdef _WIN32
+    /* On Windows, set stdout and stderr to binary mode to avoid
+       outputting DOS line terminators */
+    _setmode(_fileno(stdout), _O_BINARY);
+    _setmode(_fileno(stderr), _O_BINARY);
+#endif
+
+    indent = getenv_int("JSON_INDENT");
+    if (indent < 0 || indent > 31) {
+        fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent);
+        return 2;
+    }
+    if (indent > 0)
+        flags |= JSON_INDENT(indent);
+
+    if (getenv_int("JSON_COMPACT") > 0)
+        flags |= JSON_COMPACT;
+
+    if (getenv_int("JSON_ENSURE_ASCII"))
+        flags |= JSON_ENSURE_ASCII;
+
+    if (getenv_int("JSON_PRESERVE_ORDER"))
+        flags |= JSON_PRESERVE_ORDER;
+
+    if (getenv_int("JSON_SORT_KEYS"))
+        flags |= JSON_SORT_KEYS;
+
+    precision = getenv_int("JSON_REAL_PRECISION");
+    if (precision < 0 || precision > 31) {
+        fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n", precision);
+        return 2;
+    }
+
+    if (getenv("HASHSEED"))
+        json_object_seed(getenv_int("HASHSEED"));
+
+    if (precision > 0)
+        flags |= JSON_REAL_PRECISION(precision);
+
+    if (getenv_int("STRIP")) {
+        /* Load to memory, strip leading and trailing whitespace */
+        size_t size = 0, used = 0;
+        char *buffer = NULL, *buf_ck = NULL;
+
+        while (1) {
+            size_t count;
+
+            size = (size == 0 ? 128 : size * 2);
+            buf_ck = realloc(buffer, size);
+            if (!buf_ck) {
+                fprintf(stderr, "Unable to allocate %d bytes\n", (int)size);
+                free(buffer);
+                return 1;
+            }
+            buffer = buf_ck;
+
+            count = fread(buffer + used, 1, size - used, stdin);
+            if (count < size - used) {
+                buffer[used + count] = '\0';
+                break;
+            }
+            used += count;
+        }
+
+        json = json_loads(strip(buffer), 0, &error);
+        free(buffer);
+    } else
+        json = json_loadf(stdin, 0, &error);
+
+    if (!json) {
+        fprintf(stderr, "%d %d %d\n%s\n", error.line, error.column, error.position,
+                error.text);
+        return 1;
+    }
+
+    json_dumpf(json, stdout, flags);
+    json_decref(json);
+
+    return 0;
+}
+
+int main(int argc, char *argv[]) {
+    int i;
+    char *test_path = NULL;
+
+#ifdef HAVE_SETLOCALE
+    setlocale(LC_ALL, "");
+#endif
+
+    if (argc < 2) {
+        goto usage;
+    }
+
+    for (i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "--strip"))
+            conf.strip = 1;
+        else if (!strcmp(argv[i], "--env"))
+            conf.use_env = 1;
+        else
+            test_path = argv[i];
+    }
+
+    if (conf.use_env)
+        return use_env();
+    else {
+        if (!test_path)
+            goto usage;
+
+        return use_conf(test_path);
+    }
+
+usage:
+    fprintf(stderr, "argc =%d\n", argc);
+    fprintf(stderr, "usage: %s [--strip] [--env] test_dir\n", argv[0]);
+    return 2;
+}

+ 1 - 0
jansson.mod/jansson/test/ossfuzz/.gitignore

@@ -0,0 +1 @@
+json_load_dump_fuzzer

+ 32 - 0
jansson.mod/jansson/test/ossfuzz/Makefile.am

@@ -0,0 +1,32 @@
+AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src
+LDADD = $(top_builddir)/src/libjansson.la
+
+if USE_OSSFUZZ_FLAG
+FUZZ_FLAG = $(LIB_FUZZING_ENGINE)
+else
+if USE_OSSFUZZ_STATIC
+LDADD += $(LIB_FUZZING_ENGINE)
+FUZZ_FLAG =
+else
+LDADD += libstandaloneengine.a
+FUZZ_FLAG =
+endif
+endif
+
+noinst_PROGRAMS =
+noinst_LIBRARIES =
+
+if USE_OSSFUZZERS
+noinst_PROGRAMS += \
+	json_load_dump_fuzzer
+
+noinst_LIBRARIES += \
+	libstandaloneengine.a
+endif
+
+json_load_dump_fuzzer_SOURCES = json_load_dump_fuzzer.cc testinput.h
+json_load_dump_fuzzer_CXXFLAGS = $(AM_CXXFLAGS) $(FUZZ_FLAG)
+json_load_dump_fuzzer_LDFLAGS = $(AM_LDFLAGS) -static
+
+libstandaloneengine_a_SOURCES = standaloneengine.cc
+libstandaloneengine_a_CXXFLAGS = $(AM_CXXFLAGS)

+ 132 - 0
jansson.mod/jansson/test/ossfuzz/json_load_dump_fuzzer.cc

@@ -0,0 +1,132 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <inttypes.h>
+
+#include "jansson.h"
+
+static int enable_diags;
+
+#define FUZZ_DEBUG(FMT, ...)                                                  \
+        if (enable_diags)                                                     \
+        {                                                                     \
+          fprintf(stderr, FMT, ##__VA_ARGS__);                                \
+          fprintf(stderr, "\n");                                              \
+        }
+
+
+static int json_dump_counter(const char *buffer, size_t size, void *data)
+{
+  uint64_t *counter = reinterpret_cast<uint64_t *>(data);
+  *counter += size;
+  return 0;
+}
+
+
+#define NUM_COMMAND_BYTES  (sizeof(size_t) + sizeof(size_t) + 1)
+
+#define FUZZ_DUMP_CALLBACK 0x00
+#define FUZZ_DUMP_STRING   0x01
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+  json_error_t error;
+  unsigned char dump_mode;
+
+  // Enable or disable diagnostics based on the FUZZ_VERBOSE environment flag.
+  enable_diags = (getenv("FUZZ_VERBOSE") != NULL);
+
+  FUZZ_DEBUG("Input data length: %zd", size);
+
+  if (size < NUM_COMMAND_BYTES)
+  {
+    return 0;
+  }
+
+  // Use the first sizeof(size_t) bytes as load flags.
+  size_t load_flags = *(const size_t*)data;
+  data += sizeof(size_t);
+
+  FUZZ_DEBUG("load_flags: 0x%zx\n"
+             "& JSON_REJECT_DUPLICATES =  0x%zx\n"
+             "& JSON_DECODE_ANY =         0x%zx\n"
+             "& JSON_DISABLE_EOF_CHECK =  0x%zx\n"
+             "& JSON_DECODE_INT_AS_REAL = 0x%zx\n"
+             "& JSON_ALLOW_NUL =          0x%zx\n",
+             load_flags,
+             load_flags & JSON_REJECT_DUPLICATES,
+             load_flags & JSON_DECODE_ANY,
+             load_flags & JSON_DISABLE_EOF_CHECK,
+             load_flags & JSON_DECODE_INT_AS_REAL,
+             load_flags & JSON_ALLOW_NUL);
+
+  // Use the next sizeof(size_t) bytes as dump flags.
+  size_t dump_flags = *(const size_t*)data;
+  data += sizeof(size_t);
+
+  FUZZ_DEBUG("dump_flags: 0x%zx\n"
+             "& JSON_MAX_INDENT =     0x%zx\n"
+             "& JSON_COMPACT =        0x%zx\n"
+             "& JSON_ENSURE_ASCII =   0x%zx\n"
+             "& JSON_SORT_KEYS =      0x%zx\n"
+             "& JSON_PRESERVE_ORDER = 0x%zx\n"
+             "& JSON_ENCODE_ANY =     0x%zx\n"
+             "& JSON_ESCAPE_SLASH =   0x%zx\n"
+             "& JSON_REAL_PRECISION = 0x%zx\n"
+             "& JSON_EMBED =          0x%zx\n",
+             dump_flags,
+             dump_flags & JSON_MAX_INDENT,
+             dump_flags & JSON_COMPACT,
+             dump_flags & JSON_ENSURE_ASCII,
+             dump_flags & JSON_SORT_KEYS,
+             dump_flags & JSON_PRESERVE_ORDER,
+             dump_flags & JSON_ENCODE_ANY,
+             dump_flags & JSON_ESCAPE_SLASH,
+             ((dump_flags >> 11) & 0x1F) << 11,
+             dump_flags & JSON_EMBED);
+
+  // Use the next byte as the dump mode.
+  dump_mode = data[0];
+  data++;
+
+  FUZZ_DEBUG("dump_mode: 0x%x", (unsigned int)dump_mode);
+
+  // Remove the command bytes from the size total.
+  size -= NUM_COMMAND_BYTES;
+
+  // Attempt to load the remainder of the data with the given load flags.
+  const char* text = reinterpret_cast<const char *>(data);
+  json_t* jobj = json_loadb(text, size, load_flags, &error);
+
+  if (jobj == NULL)
+  {
+    return 0;
+  }
+
+  if (dump_mode & FUZZ_DUMP_STRING)
+  {
+    // Dump as a string. Remove indents so that we don't run out of memory.
+    char *out = json_dumps(jobj, dump_flags & ~JSON_MAX_INDENT);
+    if (out != NULL)
+    {
+      free(out);
+    }
+  }
+  else
+  {
+    // Default is callback mode.
+    //
+    // Attempt to dump the loaded json object with the given dump flags.
+    uint64_t counter = 0;
+
+    json_dump_callback(jobj, json_dump_counter, &counter, dump_flags);
+    FUZZ_DEBUG("Counter function counted %" PRIu64 " bytes.", counter);
+  }
+
+  if (jobj)
+  {
+    json_decref(jobj);
+  }
+
+  return 0;
+}

+ 30 - 0
jansson.mod/jansson/test/ossfuzz/ossfuzz.sh

@@ -0,0 +1,30 @@
+#!/bin/bash -eu
+
+# This script is called by the oss-fuzz main project when compiling the fuzz
+# targets. This script is regression tested by travisoss.sh.
+
+# Save off the current folder as the build root.
+export BUILD_ROOT=$PWD
+
+echo "CC: $CC"
+echo "CXX: $CXX"
+echo "LIB_FUZZING_ENGINE: $LIB_FUZZING_ENGINE"
+echo "CFLAGS: $CFLAGS"
+echo "CXXFLAGS: $CXXFLAGS"
+echo "OUT: $OUT"
+
+export MAKEFLAGS+="-j$(nproc)"
+
+# Install dependencies
+apt-get -y install automake libtool
+
+# Compile the fuzzer.
+autoreconf -i
+./configure --enable-ossfuzzers
+make
+
+# Copy the fuzzer to the output directory.
+cp -v test/ossfuzz/json_load_dump_fuzzer $OUT/
+
+# Zip up all input files to use as a test corpus
+find test/suites -name "input" -print | zip $OUT/json_load_dump_fuzzer_seed_corpus.zip -@

+ 74 - 0
jansson.mod/jansson/test/ossfuzz/standaloneengine.cc

@@ -0,0 +1,74 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "testinput.h"
+
+/**
+ * Main procedure for standalone fuzzing engine.
+ *
+ * Reads filenames from the argument array. For each filename, read the file
+ * into memory and then call the fuzzing interface with the data.
+ */
+int main(int argc, char **argv)
+{
+  int ii;
+  for(ii = 1; ii < argc; ii++)
+  {
+    FILE *infile;
+    printf("[%s] ", argv[ii]);
+
+    /* Try and open the file. */
+    infile = fopen(argv[ii], "rb");
+    if(infile)
+    {
+      uint8_t *buffer = NULL;
+      size_t buffer_len;
+
+      printf("Opened.. ");
+
+      /* Get the length of the file. */
+      fseek(infile, 0L, SEEK_END);
+      buffer_len = ftell(infile);
+
+      /* Reset the file indicator to the beginning of the file. */
+      fseek(infile, 0L, SEEK_SET);
+
+      /* Allocate a buffer for the file contents. */
+      buffer = (uint8_t *)calloc(buffer_len, sizeof(uint8_t));
+      if(buffer)
+      {
+        /* Read all the text from the file into the buffer. */
+        fread(buffer, sizeof(uint8_t), buffer_len, infile);
+        printf("Read %zu bytes, fuzzing.. ", buffer_len);
+
+        /* Call the fuzzer with the data. */
+        LLVMFuzzerTestOneInput(buffer, buffer_len);
+
+        printf("complete !!");
+
+        /* Free the buffer as it's no longer needed. */
+        free(buffer);
+        buffer = NULL;
+      }
+      else
+      {
+        fprintf(stderr,
+                "[%s] Failed to allocate %zu bytes \n",
+                argv[ii],
+                buffer_len);
+      }
+
+      /* Close the file as it's no longer needed. */
+      fclose(infile);
+      infile = NULL;
+    }
+    else
+    {
+      /* Failed to open the file. Maybe wrong name or wrong permissions? */
+      fprintf(stderr, "[%s] Open failed. \n", argv[ii]);
+    }
+
+    printf("\n");
+  }
+}

+ 3 - 0
jansson.mod/jansson/test/ossfuzz/testinput.h

@@ -0,0 +1,3 @@
+#include <inttypes.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);

+ 50 - 0
jansson.mod/jansson/test/run-suites

@@ -0,0 +1,50 @@
+#!/bin/sh
+
+while [ -n "$1" ]; do
+    suite=$1
+    if [ -x $top_srcdir/test/suites/$suite/run ]; then
+        SUITES="$SUITES $suite"
+    else
+        echo "No such suite: $suite"
+        exit 1
+    fi
+    shift
+done
+
+if [ -z "$SUITES" ]; then
+    suitedirs=$top_srcdir/test/suites/*
+    for suitedir in $suitedirs; do
+        if [ -d $suitedir ]; then
+            SUITES="$SUITES `basename $suitedir`"
+        fi
+    done
+fi
+
+[ -z "$STOP" ] && STOP=0
+
+suites_srcdir=$top_srcdir/test/suites
+suites_builddir=suites
+scriptdir=$top_srcdir/test/scripts
+logdir=logs
+bindir=bin
+export suites_srcdir suites_builddir scriptdir logdir bindir
+
+passed=0
+failed=0
+for suite in $SUITES; do
+    echo "Suite: $suite"
+    if $suites_srcdir/$suite/run $suite; then
+        passed=`expr $passed + 1`
+    else
+        failed=`expr $failed + 1`
+        [ $STOP -eq 1 ] && break
+    fi
+done
+
+if [ $failed -gt 0 ]; then
+    echo "$failed of `expr $passed + $failed` test suites failed"
+    exit 1
+else
+    echo "$passed test suites passed"
+    rm -rf $logdir
+fi

+ 100 - 0
jansson.mod/jansson/test/scripts/run-tests.sh

@@ -0,0 +1,100 @@
+# Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+#
+# Jansson is free software; you can redistribute it and/or modify
+# it under the terms of the MIT license. See LICENSE for details.
+
+die() {
+    echo "$1" >&2
+    exit 1
+}
+
+[ -n "$1" ] || die "Usage: $0 suite-name"
+[ -n "$bindir" ] || die "Set bindir"
+[ -n "$logdir" ] || die "Set logdir"
+[ -n "$scriptdir" ] || die "Set scriptdir"
+[ -n "$suites_srcdir" ] || die "Set suites_srcdir"
+[ -n "$suites_builddir" ] || die "Set suites_builddir"
+
+json_process=$bindir/json_process
+
+suite_name=$1
+suite_srcdir=$suites_srcdir/$suite_name
+suite_builddir=$suites_builddir/$suite_name
+suite_log=$logdir/$suite_name
+
+[ -z "$VERBOSE" ] && VERBOSE=0
+[ -z "$STOP" ] && STOP=0
+
+. $scriptdir/valgrind.sh
+
+rm -rf $suite_log
+mkdir -p $suite_log
+
+for test_path in $suite_srcdir/*; do
+    test_name=$(basename $test_path)
+    test_builddir=$suite_builddir/$test_name
+    test_log=$suite_log/$test_name
+
+    [ "$test_name" = "run" ] && continue
+    is_test || continue
+
+    rm -rf $test_log
+    mkdir -p $test_log
+    if [ $VERBOSE -eq 1 ]; then
+        printf '%s... ' "$test_name"
+    fi
+
+    run_test
+    case $? in
+        0)
+            # Success
+            if [ $VERBOSE -eq 1 ]; then
+                printf 'ok\n'
+            else
+                printf '.'
+            fi
+            rm -rf $test_log
+            ;;
+
+        77)
+            # Skip
+            if [ $VERBOSE -eq 1 ]; then
+                printf 'skipped\n'
+            else
+                printf 'S'
+            fi
+            rm -rf $test_log
+            ;;
+
+        *)
+            # Failure
+            if [ $VERBOSE -eq 1 ]; then
+                printf 'FAILED\n'
+            else
+                printf 'F'
+            fi
+
+            [ $STOP -eq 1 ] && break
+            ;;
+    esac
+done
+
+if [ $VERBOSE -eq 0 ]; then
+    printf '\n'
+fi
+
+if [ -n "$(ls -A $suite_log)" ]; then
+    for test_log in $suite_log/*; do
+        test_name=$(basename $test_log)
+        test_path=$suite_srcdir/$test_name
+        echo "================================================================="
+        echo "$suite_name/$test_name"
+        echo "================================================================="
+        show_error
+        echo
+    done
+    echo "================================================================="
+    exit 1
+else
+    rm -rf $suite_log
+fi

+ 35 - 0
jansson.mod/jansson/test/scripts/valgrind.sh

@@ -0,0 +1,35 @@
+# Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+#
+# Jansson is free software; you can redistribute it and/or modify
+# it under the terms of the MIT license. See LICENSE for details.
+
+[ -z "$VALGRIND" ] && VALGRIND=0
+
+VALGRIND_CMDLINE="valgrind --leak-check=full --show-reachable=yes --track-origins=yes -q"
+
+if [ $VALGRIND -eq 1 ]; then
+    test_runner="$VALGRIND_CMDLINE"
+    json_process="$VALGRIND_CMDLINE $json_process"
+else
+    test_runner=""
+fi
+
+valgrind_check() {
+    if [ $VALGRIND -eq 1 ]; then
+        # Check for Valgrind error output. The valgrind option
+        # --error-exitcode is not enough because Valgrind doesn't
+        # think unfreed allocs are errors.
+        if grep -E -q '^==[0-9]+== ' $1; then
+            touch $test_log/valgrind_error
+            return 1
+        fi
+    fi
+}
+
+valgrind_show_error() {
+    if [ $VALGRIND -eq 1 -a -f $test_log/valgrind_error ]; then
+        echo "valgrind detected an error"
+        return 0
+    fi
+    return 1
+}

+ 2 - 0
jansson.mod/jansson/test/suites/.gitattributes

@@ -0,0 +1,2 @@
+api/ text=auto
+* text eol=lf

+ 2 - 0
jansson.mod/jansson/test/suites/Makefile.am

@@ -0,0 +1,2 @@
+SUBDIRS = api
+EXTRA_DIST = invalid invalid-unicode valid

+ 42 - 0
jansson.mod/jansson/test/suites/api/Makefile.am

@@ -0,0 +1,42 @@
+EXTRA_DIST = run check-exports
+
+check_PROGRAMS = \
+	test_array \
+	test_chaos \
+	test_copy \
+	test_dump \
+	test_dump_callback \
+	test_equal \
+	test_fixed_size \
+	test_load \
+	test_load_callback \
+	test_loadb \
+	test_memory_funcs \
+	test_number \
+	test_object \
+	test_pack \
+	test_simple \
+	test_sprintf \
+	test_unpack \
+	test_version
+
+test_array_SOURCES = test_array.c util.h
+test_chaos_SOURCES = test_chaos.c util.h
+test_copy_SOURCES = test_copy.c util.h
+test_dump_SOURCES = test_dump.c util.h
+test_dump_callback_SOURCES = test_dump_callback.c util.h
+test_fixed_size_SOURCES = test_fixed_size.c util.h
+test_load_SOURCES = test_load.c util.h
+test_loadb_SOURCES = test_loadb.c util.h
+test_memory_funcs_SOURCES = test_memory_funcs.c util.h
+test_number_SOURCES = test_number.c util.h
+test_object_SOURCES = test_object.c util.h
+test_pack_SOURCES = test_pack.c util.h
+test_simple_SOURCES = test_simple.c util.h
+test_sprintf_SOURCES = test_sprintf.c util.h
+test_unpack_SOURCES = test_unpack.c util.h
+test_version_SOURCES = test_version.c util.h
+
+AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src
+LDFLAGS = -static  # for speed and Valgrind
+LDADD = $(top_builddir)/src/libjansson.la

+ 23 - 0
jansson.mod/jansson/test/suites/api/check-exports

@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# This test checks that libjansson.so exports the correct symbols.
+#
+
+SOFILE="../src/.libs/libjansson.so"
+
+# The list of symbols, which the shared object should export, is read
+# from the def file, which is used in Windows builds
+grep 'json_\|jansson_' $top_srcdir/src/jansson.def \
+    | sed -e 's/ //g' \
+    | sort \
+    >$test_log/exports
+
+nm -D $SOFILE >/dev/null >$test_log/symbols 2>/dev/null \
+    || exit 77  # Skip if "nm -D" doesn't seem to work
+
+grep ' [DT] ' $test_log/symbols | cut -d' ' -f3 | grep -v '^_' | sed 's/@@libjansson.*//' | sort >$test_log/output
+
+if ! cmp -s $test_log/exports $test_log/output; then
+    diff -u $test_log/exports $test_log/output >&2
+    exit 1
+fi

+ 36 - 0
jansson.mod/jansson/test/suites/api/run

@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+#
+# Jansson is free software; you can redistribute it and/or modify
+# it under the terms of the MIT license. See LICENSE for details.
+
+is_test() {
+    case "$test_name" in
+        *.c|check-exports)
+            return 0
+            ;;
+        *)
+            return 1
+            ;;
+    esac
+}
+
+run_test() {
+    if [ "$test_name" = "check-exports" ]; then
+        test_log=$test_log $test_path >$test_log/stdout 2>$test_log/stderr
+    else
+        $test_runner $suite_builddir/${test_name%.c} \
+            >$test_log/stdout \
+            2>$test_log/stderr \
+            || return 1
+        valgrind_check $test_log/stderr || return 1
+    fi
+}
+
+show_error() {
+    valgrind_show_error && return
+    cat $test_log/stderr
+}
+
+. $top_srcdir/test/scripts/run-tests.sh

+ 484 - 0
jansson.mod/jansson/test/suites/api/test_array.c

@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+
+static void test_misc(void) {
+    json_t *array, *five, *seven, *value;
+    size_t i;
+
+    array = json_array();
+    five = json_integer(5);
+    seven = json_integer(7);
+
+    if (!array)
+        fail("unable to create array");
+    if (!five || !seven)
+        fail("unable to create integer");
+
+    if (json_array_size(array) != 0)
+        fail("empty array has nonzero size");
+
+    if (!json_array_append(array, NULL))
+        fail("able to append NULL");
+
+    if (json_array_append(array, five))
+        fail("unable to append");
+
+    if (json_array_size(array) != 1)
+        fail("wrong array size");
+
+    value = json_array_get(array, 0);
+    if (!value)
+        fail("unable to get item");
+    if (value != five)
+        fail("got wrong value");
+
+    if (json_array_append(array, seven))
+        fail("unable to append value");
+
+    if (json_array_size(array) != 2)
+        fail("wrong array size");
+
+    value = json_array_get(array, 1);
+    if (!value)
+        fail("unable to get item");
+    if (value != seven)
+        fail("got wrong value");
+
+    if (json_array_set(array, 0, seven))
+        fail("unable to set value");
+
+    if (!json_array_set(array, 0, NULL))
+        fail("able to set NULL");
+
+    if (json_array_size(array) != 2)
+        fail("wrong array size");
+
+    value = json_array_get(array, 0);
+    if (!value)
+        fail("unable to get item");
+    if (value != seven)
+        fail("got wrong value");
+
+    if (json_array_get(array, 2) != NULL)
+        fail("able to get value out of bounds");
+
+    if (!json_array_set(array, 2, seven))
+        fail("able to set value out of bounds");
+
+    for (i = 2; i < 30; i++) {
+        if (json_array_append(array, seven))
+            fail("unable to append value");
+
+        if (json_array_size(array) != i + 1)
+            fail("wrong array size");
+    }
+
+    for (i = 0; i < 30; i++) {
+        value = json_array_get(array, i);
+        if (!value)
+            fail("unable to get item");
+        if (value != seven)
+            fail("got wrong value");
+    }
+
+    if (json_array_set_new(array, 15, json_integer(123)))
+        fail("unable to set new value");
+
+    value = json_array_get(array, 15);
+    if (!json_is_integer(value) || json_integer_value(value) != 123)
+        fail("json_array_set_new works incorrectly");
+
+    if (!json_array_set_new(array, 15, NULL))
+        fail("able to set_new NULL value");
+
+    if (json_array_append_new(array, json_integer(321)))
+        fail("unable to append new value");
+
+    value = json_array_get(array, json_array_size(array) - 1);
+    if (!json_is_integer(value) || json_integer_value(value) != 321)
+        fail("json_array_append_new works incorrectly");
+
+    if (!json_array_append_new(array, NULL))
+        fail("able to append_new NULL value");
+
+    json_decref(five);
+    json_decref(seven);
+    json_decref(array);
+}
+
+static void test_insert(void) {
+    json_t *array, *five, *seven, *eleven, *value;
+    int i;
+
+    array = json_array();
+    five = json_integer(5);
+    seven = json_integer(7);
+    eleven = json_integer(11);
+
+    if (!array)
+        fail("unable to create array");
+    if (!five || !seven || !eleven)
+        fail("unable to create integer");
+
+    if (!json_array_insert(array, 1, five))
+        fail("able to insert value out of bounds");
+
+    if (json_array_insert(array, 0, five))
+        fail("unable to insert value in an empty array");
+
+    if (json_array_get(array, 0) != five)
+        fail("json_array_insert works incorrectly");
+
+    if (json_array_size(array) != 1)
+        fail("array size is invalid after insertion");
+
+    if (json_array_insert(array, 1, seven))
+        fail("unable to insert value at the end of an array");
+
+    if (json_array_get(array, 0) != five)
+        fail("json_array_insert works incorrectly");
+
+    if (json_array_get(array, 1) != seven)
+        fail("json_array_insert works incorrectly");
+
+    if (json_array_size(array) != 2)
+        fail("array size is invalid after insertion");
+
+    if (json_array_insert(array, 1, eleven))
+        fail("unable to insert value in the middle of an array");
+
+    if (json_array_get(array, 0) != five)
+        fail("json_array_insert works incorrectly");
+
+    if (json_array_get(array, 1) != eleven)
+        fail("json_array_insert works incorrectly");
+
+    if (json_array_get(array, 2) != seven)
+        fail("json_array_insert works incorrectly");
+
+    if (json_array_size(array) != 3)
+        fail("array size is invalid after insertion");
+
+    if (json_array_insert_new(array, 2, json_integer(123)))
+        fail("unable to insert value in the middle of an array");
+
+    value = json_array_get(array, 2);
+    if (!json_is_integer(value) || json_integer_value(value) != 123)
+        fail("json_array_insert_new works incorrectly");
+
+    if (json_array_size(array) != 4)
+        fail("array size is invalid after insertion");
+
+    for (i = 0; i < 20; i++) {
+        if (json_array_insert(array, 0, seven))
+            fail("unable to insert value at the beginning of an array");
+    }
+
+    for (i = 0; i < 20; i++) {
+        if (json_array_get(array, i) != seven)
+            fail("json_aray_insert works incorrectly");
+    }
+
+    if (json_array_size(array) != 24)
+        fail("array size is invalid after loop insertion");
+
+    json_decref(five);
+    json_decref(seven);
+    json_decref(eleven);
+    json_decref(array);
+}
+
+static void test_remove(void) {
+    json_t *array, *five, *seven;
+    int i;
+
+    array = json_array();
+    five = json_integer(5);
+    seven = json_integer(7);
+
+    if (!array)
+        fail("unable to create array");
+    if (!five)
+        fail("unable to create integer");
+    if (!seven)
+        fail("unable to create integer");
+
+    if (!json_array_remove(array, 0))
+        fail("able to remove an unexisting index");
+
+    if (json_array_append(array, five))
+        fail("unable to append");
+
+    if (!json_array_remove(array, 1))
+        fail("able to remove an unexisting index");
+
+    if (json_array_remove(array, 0))
+        fail("unable to remove");
+
+    if (json_array_size(array) != 0)
+        fail("array size is invalid after removing");
+
+    if (json_array_append(array, five) || json_array_append(array, seven) ||
+        json_array_append(array, five) || json_array_append(array, seven))
+        fail("unable to append");
+
+    if (json_array_remove(array, 2))
+        fail("unable to remove");
+
+    if (json_array_size(array) != 3)
+        fail("array size is invalid after removing");
+
+    if (json_array_get(array, 0) != five || json_array_get(array, 1) != seven ||
+        json_array_get(array, 2) != seven)
+        fail("remove works incorrectly");
+
+    json_decref(array);
+
+    array = json_array();
+    for (i = 0; i < 4; i++) {
+        json_array_append(array, five);
+        json_array_append(array, seven);
+    }
+    if (json_array_size(array) != 8)
+        fail("unable to append 8 items to array");
+
+    /* Remove an element from a "full" array. */
+    json_array_remove(array, 5);
+
+    json_decref(five);
+    json_decref(seven);
+    json_decref(array);
+}
+
+static void test_clear(void) {
+    json_t *array, *five, *seven;
+    int i;
+
+    array = json_array();
+    five = json_integer(5);
+    seven = json_integer(7);
+
+    if (!array)
+        fail("unable to create array");
+    if (!five || !seven)
+        fail("unable to create integer");
+
+    for (i = 0; i < 10; i++) {
+        if (json_array_append(array, five))
+            fail("unable to append");
+    }
+    for (i = 0; i < 10; i++) {
+        if (json_array_append(array, seven))
+            fail("unable to append");
+    }
+
+    if (json_array_size(array) != 20)
+        fail("array size is invalid after appending");
+
+    if (json_array_clear(array))
+        fail("unable to clear");
+
+    if (json_array_size(array) != 0)
+        fail("array size is invalid after clearing");
+
+    json_decref(five);
+    json_decref(seven);
+    json_decref(array);
+}
+
+static void test_extend(void) {
+    json_t *array1, *array2, *five, *seven;
+    int i;
+
+    array1 = json_array();
+    array2 = json_array();
+    five = json_integer(5);
+    seven = json_integer(7);
+
+    if (!array1 || !array2)
+        fail("unable to create array");
+    if (!five || !seven)
+        fail("unable to create integer");
+
+    for (i = 0; i < 10; i++) {
+        if (json_array_append(array1, five))
+            fail("unable to append");
+    }
+    for (i = 0; i < 10; i++) {
+        if (json_array_append(array2, seven))
+            fail("unable to append");
+    }
+
+    if (json_array_size(array1) != 10 || json_array_size(array2) != 10)
+        fail("array size is invalid after appending");
+
+    if (json_array_extend(array1, array2))
+        fail("unable to extend");
+
+    for (i = 0; i < 10; i++) {
+        if (json_array_get(array1, i) != five)
+            fail("invalid array contents after extending");
+    }
+    for (i = 10; i < 20; i++) {
+        if (json_array_get(array1, i) != seven)
+            fail("invalid array contents after extending");
+    }
+
+    json_decref(five);
+    json_decref(seven);
+    json_decref(array1);
+    json_decref(array2);
+}
+
+static void test_circular() {
+    json_t *array1, *array2;
+
+    /* the simple cases are checked */
+
+    array1 = json_array();
+    if (!array1)
+        fail("unable to create array");
+
+    if (json_array_append(array1, array1) == 0)
+        fail("able to append self");
+
+    if (json_array_insert(array1, 0, array1) == 0)
+        fail("able to insert self");
+
+    if (json_array_append_new(array1, json_true()))
+        fail("failed to append true");
+
+    if (json_array_set(array1, 0, array1) == 0)
+        fail("able to set self");
+
+    json_decref(array1);
+
+    /* create circular references */
+
+    array1 = json_array();
+    array2 = json_array();
+    if (!array1 || !array2)
+        fail("unable to create array");
+
+    if (json_array_append(array1, array2) || json_array_append(array2, array1))
+        fail("unable to append");
+
+    /* circularity is detected when dumping */
+    if (json_dumps(array1, 0) != NULL)
+        fail("able to dump circulars");
+
+    /* decref twice to deal with the circular references */
+    json_decref(array1);
+    json_decref(array2);
+    json_decref(array1);
+}
+
+static void test_array_foreach() {
+    size_t index;
+    json_t *array1, *array2, *value;
+
+    array1 = json_pack("[sisisi]", "foo", 1, "bar", 2, "baz", 3);
+    array2 = json_array();
+
+    json_array_foreach(array1, index, value) { json_array_append(array2, value); }
+
+    if (!json_equal(array1, array2))
+        fail("json_array_foreach failed to iterate all elements");
+
+    json_decref(array1);
+    json_decref(array2);
+}
+
+static void test_bad_args(void) {
+    json_t *arr = json_array();
+    json_t *num = json_integer(1);
+
+    if (!arr || !num)
+        fail("failed to create required objects");
+
+    if (json_array_size(NULL) != 0)
+        fail("NULL array has nonzero size");
+    if (json_array_size(num) != 0)
+        fail("non-array has nonzero array size");
+
+    if (json_array_get(NULL, 0))
+        fail("json_array_get did not return NULL for non-array");
+    if (json_array_get(num, 0))
+        fail("json_array_get did not return NULL for non-array");
+
+    if (!json_array_set_new(NULL, 0, json_incref(num)))
+        fail("json_array_set_new did not return error for non-array");
+    if (!json_array_set_new(num, 0, json_incref(num)))
+        fail("json_array_set_new did not return error for non-array");
+    if (!json_array_set_new(arr, 0, NULL))
+        fail("json_array_set_new did not return error for NULL value");
+    if (!json_array_set_new(arr, 0, json_incref(arr)))
+        fail("json_array_set_new did not return error for value == array");
+
+    if (!json_array_remove(NULL, 0))
+        fail("json_array_remove did not return error for non-array");
+    if (!json_array_remove(num, 0))
+        fail("json_array_remove did not return error for non-array");
+
+    if (!json_array_clear(NULL))
+        fail("json_array_clear did not return error for non-array");
+    if (!json_array_clear(num))
+        fail("json_array_clear did not return error for non-array");
+
+    if (!json_array_append_new(NULL, json_incref(num)))
+        fail("json_array_append_new did not return error for non-array");
+    if (!json_array_append_new(num, json_incref(num)))
+        fail("json_array_append_new did not return error for non-array");
+    if (!json_array_append_new(arr, NULL))
+        fail("json_array_append_new did not return error for NULL value");
+    if (!json_array_append_new(arr, json_incref(arr)))
+        fail("json_array_append_new did not return error for value == array");
+
+    if (!json_array_insert_new(NULL, 0, json_incref(num)))
+        fail("json_array_insert_new did not return error for non-array");
+    if (!json_array_insert_new(num, 0, json_incref(num)))
+        fail("json_array_insert_new did not return error for non-array");
+    if (!json_array_insert_new(arr, 0, NULL))
+        fail("json_array_insert_new did not return error for NULL value");
+    if (!json_array_insert_new(arr, 0, json_incref(arr)))
+        fail("json_array_insert_new did not return error for value == array");
+
+    if (!json_array_extend(NULL, arr))
+        fail("json_array_extend did not return error for first argument "
+             "non-array");
+    if (!json_array_extend(num, arr))
+        fail("json_array_extend did not return error for first argument "
+             "non-array");
+    if (!json_array_extend(arr, NULL))
+        fail("json_array_extend did not return error for second argument "
+             "non-array");
+    if (!json_array_extend(arr, num))
+        fail("json_array_extend did not return error for second argument "
+             "non-array");
+
+    if (num->refcount != 1)
+        fail("unexpected reference count on num");
+    if (arr->refcount != 1)
+        fail("unexpected reference count on arr");
+
+    json_decref(num);
+    json_decref(arr);
+}
+
+static void run_tests() {
+    test_misc();
+    test_insert();
+    test_remove();
+    test_clear();
+    test_extend();
+    test_circular();
+    test_array_foreach();
+    test_bad_args();
+}

+ 168 - 0
jansson.mod/jansson/test/suites/api/test_chaos.c

@@ -0,0 +1,168 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include "util.h"
+#include <jansson.h>
+#include <stdio.h>
+#include <string.h>
+
+static int chaos_pos = 0;
+static int chaos_fail = 0;
+#define CHAOS_MAX_FAILURE 100
+
+void *chaos_malloc(size_t size) {
+    if (chaos_pos == chaos_fail)
+        return NULL;
+
+    chaos_pos++;
+
+    return malloc(size);
+}
+
+void chaos_free(void *obj) { free(obj); }
+
+/* Test all potential allocation failures. */
+#define chaos_loop(condition, code, cleanup)                                             \
+    {                                                                                    \
+        chaos_pos = chaos_fail = 0;                                                      \
+        while (condition) {                                                              \
+            if (chaos_fail > CHAOS_MAX_FAILURE)                                          \
+                fail("too many chaos failures");                                         \
+            code chaos_pos = 0;                                                          \
+            chaos_fail++;                                                                \
+        }                                                                                \
+        cleanup                                                                          \
+    }
+
+#define chaos_loop_new_value(json, initcall)                                             \
+    chaos_loop(!json, json = initcall;, json_decref(json); json = NULL;)
+
+int test_unpack() {
+    int ret = -1;
+    int v1;
+    int v2;
+    json_error_t error;
+    json_t *root = json_pack("{s:i, s:i, s:i, s:i}", "n1", 1, "n2", 2, "n3", 3, "n4", 4);
+
+    if (!root)
+        return -1;
+
+    if (!json_unpack_ex(root, &error, JSON_STRICT, "{s:i, s:i}", "n1", &v1, "n2", &v2))
+        fail("Unexpected success");
+
+    if (json_error_code(&error) != json_error_end_of_input_expected) {
+        if (json_error_code(&error) != json_error_out_of_memory)
+            fail("Unexpected error code");
+
+        goto out;
+    }
+
+    if (strcmp(error.text, "2 object item(s) left unpacked: n3, n4"))
+        goto out;
+
+    ret = 0;
+
+out:
+    json_decref(root);
+    return ret;
+}
+
+int dump_chaos_callback(const char *buffer, size_t size, void *data) {
+    json_t *obj = json_object();
+
+    (void)buffer;
+    (void)size;
+    (void)data;
+
+    if (!obj)
+        return -1;
+
+    json_decref(obj);
+
+    return 0;
+}
+
+static void test_chaos() {
+    json_malloc_t orig_malloc;
+    json_free_t orig_free;
+    json_t *json = NULL;
+    json_t *obj = json_object();
+    json_t *arr1 = json_array();
+    json_t *arr2 = json_array();
+    json_t *txt = json_string("test");
+    json_t *intnum = json_integer(1);
+    json_t *dblnum = json_real(0.5);
+    char *dumptxt = NULL;
+    json_t *dumpobj = json_pack("{s:[iiis], s:s}", "key1", 1, 2, 3, "txt", "key2", "v2");
+    int keyno;
+
+    if (!obj || !arr1 || !arr2 || !txt || !intnum || !dblnum || !dumpobj)
+        fail("failed to allocate basic objects");
+
+    json_get_alloc_funcs(&orig_malloc, &orig_free);
+    json_set_alloc_funcs(chaos_malloc, chaos_free);
+
+    chaos_loop_new_value(json, json_pack("{s:s}", "key", "value"));
+    chaos_loop_new_value(json, json_pack("{s:[]}", "key"));
+    chaos_loop_new_value(json, json_pack("[biIf]", 1, 1, (json_int_t)1, 1.0));
+    chaos_loop_new_value(json, json_pack("[s*,s*]", "v1", "v2"));
+    chaos_loop_new_value(json, json_pack("o", json_incref(txt)));
+    chaos_loop_new_value(json, json_pack("O", txt));
+    chaos_loop_new_value(json, json_pack("s++", "a", "long string to force realloc",
+                                         "another long string to force yet another "
+                                         "reallocation of the string because "
+                                         "that's what we are testing."));
+
+    chaos_loop(test_unpack(), , );
+
+    chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL, JSON_INDENT(1)),
+               , );
+    chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL,
+                                  JSON_INDENT(1) | JSON_SORT_KEYS),
+               , );
+    chaos_loop(!dumptxt, dumptxt = json_dumps(dumpobj, JSON_COMPACT);, free(dumptxt);
+               dumptxt = NULL;);
+
+    chaos_loop_new_value(json, json_copy(obj));
+    chaos_loop_new_value(json, json_deep_copy(obj));
+
+    chaos_loop_new_value(json, json_copy(arr1));
+    chaos_loop_new_value(json, json_deep_copy(arr1));
+
+    chaos_loop_new_value(json, json_copy(txt));
+    chaos_loop_new_value(json, json_copy(intnum));
+    chaos_loop_new_value(json, json_copy(dblnum));
+
+#define JSON_LOAD_TXT "{\"n\":[1,2,3,4,5,6,7,8,9,10]}"
+    chaos_loop_new_value(json, json_loads(JSON_LOAD_TXT, 0, NULL));
+    chaos_loop_new_value(json, json_loadb(JSON_LOAD_TXT, strlen(JSON_LOAD_TXT), 0, NULL));
+
+    chaos_loop_new_value(json, json_sprintf("%s", "string"));
+
+    for (keyno = 0; keyno < 100; ++keyno) {
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+        /* Skip this test on old Windows compilers. */
+        char testkey[10];
+
+        snprintf(testkey, sizeof(testkey), "test%d", keyno);
+        chaos_loop(json_object_set_new_nocheck(obj, testkey, json_object()), , );
+#endif
+        chaos_loop(json_array_append_new(arr1, json_null()), , );
+        chaos_loop(json_array_insert_new(arr2, 0, json_null()), , );
+    }
+
+    chaos_loop(json_array_extend(arr1, arr2), , );
+    chaos_loop(json_string_set_nocheck(txt, "test"), , );
+
+    json_set_alloc_funcs(orig_malloc, orig_free);
+    json_decref(obj);
+    json_decref(arr1);
+    json_decref(arr2);
+    json_decref(txt);
+    json_decref(intnum);
+    json_decref(dblnum);
+    json_decref(dumpobj);
+}
+
+static void run_tests() { test_chaos(); }

+ 375 - 0
jansson.mod/jansson/test/suites/api/test_copy.c

@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void test_copy_simple(void) {
+    json_t *value, *copy;
+
+    if (json_copy(NULL))
+        fail("copying NULL doesn't return NULL");
+
+    /* true */
+    value = json_true();
+    copy = json_copy(value);
+    if (value != copy)
+        fail("copying true failed");
+    json_decref(value);
+    json_decref(copy);
+
+    /* false */
+    value = json_false();
+    copy = json_copy(value);
+    if (value != copy)
+        fail("copying false failed");
+    json_decref(value);
+    json_decref(copy);
+
+    /* null */
+    value = json_null();
+    copy = json_copy(value);
+    if (value != copy)
+        fail("copying null failed");
+    json_decref(value);
+    json_decref(copy);
+
+    /* string */
+    value = json_string("foo");
+    if (!value)
+        fail("unable to create a string");
+    copy = json_copy(value);
+    if (!copy)
+        fail("unable to copy a string");
+    if (copy == value)
+        fail("copying a string doesn't copy");
+    if (!json_equal(copy, value))
+        fail("copying a string produces an inequal copy");
+    if (value->refcount != 1 || copy->refcount != 1)
+        fail("invalid refcounts");
+    json_decref(value);
+    json_decref(copy);
+
+    /* integer */
+    value = json_integer(543);
+    if (!value)
+        fail("unable to create an integer");
+    copy = json_copy(value);
+    if (!copy)
+        fail("unable to copy an integer");
+    if (copy == value)
+        fail("copying an integer doesn't copy");
+    if (!json_equal(copy, value))
+        fail("copying an integer produces an inequal copy");
+    if (value->refcount != 1 || copy->refcount != 1)
+        fail("invalid refcounts");
+    json_decref(value);
+    json_decref(copy);
+
+    /* real */
+    value = json_real(123e9);
+    if (!value)
+        fail("unable to create a real");
+    copy = json_copy(value);
+    if (!copy)
+        fail("unable to copy a real");
+    if (copy == value)
+        fail("copying a real doesn't copy");
+    if (!json_equal(copy, value))
+        fail("copying a real produces an inequal copy");
+    if (value->refcount != 1 || copy->refcount != 1)
+        fail("invalid refcounts");
+    json_decref(value);
+    json_decref(copy);
+}
+
+static void test_deep_copy_simple(void) {
+    json_t *value, *copy;
+
+    if (json_deep_copy(NULL))
+        fail("deep copying NULL doesn't return NULL");
+
+    /* true */
+    value = json_true();
+    copy = json_deep_copy(value);
+    if (value != copy)
+        fail("deep copying true failed");
+    json_decref(value);
+    json_decref(copy);
+
+    /* false */
+    value = json_false();
+    copy = json_deep_copy(value);
+    if (value != copy)
+        fail("deep copying false failed");
+    json_decref(value);
+    json_decref(copy);
+
+    /* null */
+    value = json_null();
+    copy = json_deep_copy(value);
+    if (value != copy)
+        fail("deep copying null failed");
+    json_decref(value);
+    json_decref(copy);
+
+    /* string */
+    value = json_string("foo");
+    if (!value)
+        fail("unable to create a string");
+    copy = json_deep_copy(value);
+    if (!copy)
+        fail("unable to deep copy a string");
+    if (copy == value)
+        fail("deep copying a string doesn't copy");
+    if (!json_equal(copy, value))
+        fail("deep copying a string produces an inequal copy");
+    if (value->refcount != 1 || copy->refcount != 1)
+        fail("invalid refcounts");
+    json_decref(value);
+    json_decref(copy);
+
+    /* integer */
+    value = json_integer(543);
+    if (!value)
+        fail("unable to create an integer");
+    copy = json_deep_copy(value);
+    if (!copy)
+        fail("unable to deep copy an integer");
+    if (copy == value)
+        fail("deep copying an integer doesn't copy");
+    if (!json_equal(copy, value))
+        fail("deep copying an integer produces an inequal copy");
+    if (value->refcount != 1 || copy->refcount != 1)
+        fail("invalid refcounts");
+    json_decref(value);
+    json_decref(copy);
+
+    /* real */
+    value = json_real(123e9);
+    if (!value)
+        fail("unable to create a real");
+    copy = json_deep_copy(value);
+    if (!copy)
+        fail("unable to deep copy a real");
+    if (copy == value)
+        fail("deep copying a real doesn't copy");
+    if (!json_equal(copy, value))
+        fail("deep copying a real produces an inequal copy");
+    if (value->refcount != 1 || copy->refcount != 1)
+        fail("invalid refcounts");
+    json_decref(value);
+    json_decref(copy);
+}
+
+static void test_copy_array(void) {
+    const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]";
+
+    json_t *array, *copy;
+    size_t i;
+
+    array = json_loads(json_array_text, 0, NULL);
+    if (!array)
+        fail("unable to parse an array");
+
+    copy = json_copy(array);
+    if (!copy)
+        fail("unable to copy an array");
+    if (copy == array)
+        fail("copying an array doesn't copy");
+    if (!json_equal(copy, array))
+        fail("copying an array produces an inequal copy");
+
+    for (i = 0; i < json_array_size(copy); i++) {
+        if (json_array_get(array, i) != json_array_get(copy, i))
+            fail("copying an array modifies its elements");
+    }
+
+    json_decref(array);
+    json_decref(copy);
+}
+
+static void test_deep_copy_array(void) {
+    const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]";
+
+    json_t *array, *copy;
+    size_t i;
+
+    array = json_loads(json_array_text, 0, NULL);
+    if (!array)
+        fail("unable to parse an array");
+
+    copy = json_deep_copy(array);
+    if (!copy)
+        fail("unable to deep copy an array");
+    if (copy == array)
+        fail("deep copying an array doesn't copy");
+    if (!json_equal(copy, array))
+        fail("deep copying an array produces an inequal copy");
+
+    for (i = 0; i < json_array_size(copy); i++) {
+        if (json_array_get(array, i) == json_array_get(copy, i))
+            fail("deep copying an array doesn't copy its elements");
+    }
+
+    json_decref(array);
+    json_decref(copy);
+}
+
+static void test_copy_object(void) {
+    const char *json_object_text =
+        "{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
+
+    const char *keys[] = {"foo", "a", "b", "c"};
+    int i;
+
+    json_t *object, *copy;
+    void *iter;
+
+    object = json_loads(json_object_text, 0, NULL);
+    if (!object)
+        fail("unable to parse an object");
+
+    copy = json_copy(object);
+    if (!copy)
+        fail("unable to copy an object");
+    if (copy == object)
+        fail("copying an object doesn't copy");
+    if (!json_equal(copy, object))
+        fail("copying an object produces an inequal copy");
+
+    i = 0;
+    iter = json_object_iter(object);
+    while (iter) {
+        const char *key;
+        json_t *value1, *value2;
+
+        key = json_object_iter_key(iter);
+        value1 = json_object_iter_value(iter);
+        value2 = json_object_get(copy, key);
+
+        if (value1 != value2)
+            fail("copying an object modifies its items");
+
+        if (strcmp(key, keys[i]) != 0)
+            fail("copying an object doesn't preserve key order");
+
+        iter = json_object_iter_next(object, iter);
+        i++;
+    }
+
+    json_decref(object);
+    json_decref(copy);
+}
+
+static void test_deep_copy_object(void) {
+    const char *json_object_text =
+        "{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
+
+    const char *keys[] = {"foo", "a", "b", "c"};
+    int i;
+
+    json_t *object, *copy;
+    void *iter;
+
+    object = json_loads(json_object_text, 0, NULL);
+    if (!object)
+        fail("unable to parse an object");
+
+    copy = json_deep_copy(object);
+    if (!copy)
+        fail("unable to deep copy an object");
+    if (copy == object)
+        fail("deep copying an object doesn't copy");
+    if (!json_equal(copy, object))
+        fail("deep copying an object produces an inequal copy");
+
+    i = 0;
+    iter = json_object_iter(object);
+    while (iter) {
+        const char *key;
+        json_t *value1, *value2;
+
+        key = json_object_iter_key(iter);
+        value1 = json_object_iter_value(iter);
+        value2 = json_object_get(copy, key);
+
+        if (value1 == value2)
+            fail("deep copying an object doesn't copy its items");
+
+        if (strcmp(key, keys[i]) != 0)
+            fail("deep copying an object doesn't preserve key order");
+
+        iter = json_object_iter_next(object, iter);
+        i++;
+    }
+
+    json_decref(object);
+    json_decref(copy);
+}
+
+static void test_deep_copy_circular_references(void) {
+    /* Construct a JSON object/array with a circular reference:
+
+      object: {"a": {"b": {"c": <circular reference to $.a>}}}
+      array: [[[<circular reference to the $[0] array>]]]
+
+      Deep copy it, remove the circular reference and deep copy again.
+   */
+
+    json_t *json;
+    json_t *copy;
+
+    json = json_object();
+    json_object_set_new(json, "a", json_object());
+    json_object_set_new(json_object_get(json, "a"), "b", json_object());
+    json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c",
+                    json_object_get(json, "a"));
+
+    copy = json_deep_copy(json);
+    if (copy)
+        fail("json_deep_copy copied a circular reference!");
+
+    json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c");
+
+    copy = json_deep_copy(json);
+    if (!copy)
+        fail("json_deep_copy failed!");
+
+    json_decref(copy);
+    json_decref(json);
+
+    json = json_array();
+    json_array_append_new(json, json_array());
+    json_array_append_new(json_array_get(json, 0), json_array());
+    json_array_append(json_array_get(json_array_get(json, 0), 0),
+                      json_array_get(json, 0));
+
+    copy = json_deep_copy(json);
+    if (copy)
+        fail("json_deep_copy copied a circular reference!");
+
+    json_array_remove(json_array_get(json_array_get(json, 0), 0), 0);
+
+    copy = json_deep_copy(json);
+    if (!copy)
+        fail("json_deep_copy failed!");
+
+    json_decref(copy);
+    json_decref(json);
+}
+
+static void run_tests() {
+    test_copy_simple();
+    test_deep_copy_simple();
+    test_copy_array();
+    test_deep_copy_array();
+    test_copy_object();
+    test_deep_copy_object();
+    test_deep_copy_circular_references();
+}

+ 311 - 0
jansson.mod/jansson/test/suites/api/test_dump.c

@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "jansson_private_config.h"
+
+#include <jansson.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "util.h"
+#ifdef __MINGW32__
+#include <fcntl.h>
+#define pipe(fds) _pipe(fds, 1024, _O_BINARY)
+#endif
+
+static int encode_null_callback(const char *buffer, size_t size, void *data) {
+    (void)buffer;
+    (void)size;
+    (void)data;
+    return 0;
+}
+
+static void encode_null() {
+    if (json_dumps(NULL, JSON_ENCODE_ANY) != NULL)
+        fail("json_dumps didn't fail for NULL");
+
+    if (json_dumpb(NULL, NULL, 0, JSON_ENCODE_ANY) != 0)
+        fail("json_dumpb didn't fail for NULL");
+
+    if (json_dumpf(NULL, stderr, JSON_ENCODE_ANY) != -1)
+        fail("json_dumpf didn't fail for NULL");
+
+#ifdef HAVE_UNISTD_H
+    if (json_dumpfd(NULL, STDERR_FILENO, JSON_ENCODE_ANY) != -1)
+        fail("json_dumpfd didn't fail for NULL");
+#endif
+
+    /* Don't test json_dump_file to avoid creating a file */
+
+    if (json_dump_callback(NULL, encode_null_callback, NULL, JSON_ENCODE_ANY) != -1)
+        fail("json_dump_callback didn't fail for NULL");
+}
+
+static void encode_twice() {
+    /* Encode an empty object/array, add an item, encode again */
+
+    json_t *json;
+    char *result;
+
+    json = json_object();
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "{}"))
+        fail("json_dumps failed");
+    free(result);
+
+    json_object_set_new(json, "foo", json_integer(5));
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "{\"foo\": 5}"))
+        fail("json_dumps failed");
+    free(result);
+
+    json_decref(json);
+
+    json = json_array();
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "[]"))
+        fail("json_dumps failed");
+    free(result);
+
+    json_array_append_new(json, json_integer(5));
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "[5]"))
+        fail("json_dumps failed");
+    free(result);
+
+    json_decref(json);
+}
+
+static void circular_references() {
+    /* Construct a JSON object/array with a circular reference:
+
+       object: {"a": {"b": {"c": <circular reference to $.a>}}}
+       array: [[[<circular reference to the $[0] array>]]]
+
+       Encode it, remove the circular reference and encode again.
+    */
+
+    json_t *json;
+    char *result;
+
+    json = json_object();
+    json_object_set_new(json, "a", json_object());
+    json_object_set_new(json_object_get(json, "a"), "b", json_object());
+    json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c",
+                    json_object_get(json, "a"));
+
+    if (json_dumps(json, 0))
+        fail("json_dumps encoded a circular reference!");
+
+    json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c");
+
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "{\"a\": {\"b\": {}}}"))
+        fail("json_dumps failed!");
+    free(result);
+
+    json_decref(json);
+
+    json = json_array();
+    json_array_append_new(json, json_array());
+    json_array_append_new(json_array_get(json, 0), json_array());
+    json_array_append(json_array_get(json_array_get(json, 0), 0),
+                      json_array_get(json, 0));
+
+    if (json_dumps(json, 0))
+        fail("json_dumps encoded a circular reference!");
+
+    json_array_remove(json_array_get(json_array_get(json, 0), 0), 0);
+
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "[[[]]]"))
+        fail("json_dumps failed!");
+    free(result);
+
+    json_decref(json);
+}
+
+static void encode_other_than_array_or_object() {
+    /* Encoding anything other than array or object should only
+     * succeed if the JSON_ENCODE_ANY flag is used */
+
+    json_t *json;
+    char *result;
+
+    json = json_string("foo");
+    if (json_dumps(json, 0) != NULL)
+        fail("json_dumps encoded a string!");
+    if (json_dumpf(json, NULL, 0) == 0)
+        fail("json_dumpf encoded a string!");
+    if (json_dumpfd(json, -1, 0) == 0)
+        fail("json_dumpfd encoded a string!");
+
+    result = json_dumps(json, JSON_ENCODE_ANY);
+    if (!result || strcmp(result, "\"foo\"") != 0)
+        fail("json_dumps failed to encode a string with JSON_ENCODE_ANY");
+
+    free(result);
+    json_decref(json);
+
+    json = json_integer(42);
+    if (json_dumps(json, 0) != NULL)
+        fail("json_dumps encoded an integer!");
+    if (json_dumpf(json, NULL, 0) == 0)
+        fail("json_dumpf encoded an integer!");
+    if (json_dumpfd(json, -1, 0) == 0)
+        fail("json_dumpfd encoded an integer!");
+
+    result = json_dumps(json, JSON_ENCODE_ANY);
+    if (!result || strcmp(result, "42") != 0)
+        fail("json_dumps failed to encode an integer with JSON_ENCODE_ANY");
+
+    free(result);
+    json_decref(json);
+}
+
+static void escape_slashes() {
+    /* Test dump escaping slashes */
+
+    json_t *json;
+    char *result;
+
+    json = json_object();
+    json_object_set_new(json, "url", json_string("https://github.com/akheron/jansson"));
+
+    result = json_dumps(json, 0);
+    if (!result || strcmp(result, "{\"url\": \"https://github.com/akheron/jansson\"}"))
+        fail("json_dumps failed to not escape slashes");
+
+    free(result);
+
+    result = json_dumps(json, JSON_ESCAPE_SLASH);
+    if (!result ||
+        strcmp(result, "{\"url\": \"https:\\/\\/github.com\\/akheron\\/jansson\"}"))
+        fail("json_dumps failed to escape slashes");
+
+    free(result);
+    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 dump_file() {
+    json_t *json;
+    int result;
+
+    result = json_dump_file(NULL, "", 0);
+    if (result != -1)
+        fail("json_dump_file succeeded with invalid args");
+
+    json = json_object();
+    result = json_dump_file(json, "json_dump_file.json", 0);
+    if (result != 0)
+        fail("json_dump_file failed");
+
+    json_decref(json);
+    remove("json_dump_file.json");
+}
+
+static void dumpb() {
+    char buf[2];
+    json_t *obj;
+    size_t size;
+
+    obj = json_object();
+
+    size = json_dumpb(obj, buf, sizeof(buf), 0);
+    if (size != 2 || strncmp(buf, "{}", 2))
+        fail("json_dumpb failed");
+
+    json_decref(obj);
+    obj = json_pack("{s:s}", "foo", "bar");
+
+    size = json_dumpb(obj, buf, sizeof(buf), JSON_COMPACT);
+    if (size != 13)
+        fail("json_dumpb size check failed");
+
+    json_decref(obj);
+}
+
+static void dumpfd() {
+#ifdef HAVE_UNISTD_H
+    int fds[2] = {-1, -1};
+    json_t *a, *b;
+
+    if (pipe(fds))
+        fail("pipe() failed");
+
+    a = json_pack("{s:s}", "foo", "bar");
+
+    if (json_dumpfd(a, fds[1], 0))
+        fail("json_dumpfd() failed");
+    close(fds[1]);
+
+    b = json_loadfd(fds[0], 0, NULL);
+    if (!b)
+        fail("json_loadfd() failed");
+    close(fds[0]);
+
+    if (!json_equal(a, b))
+        fail("json_equal() failed for fd test");
+
+    json_decref(a);
+    json_decref(b);
+#endif
+}
+
+static void embed() {
+    static const char *plains[] = {"{\"bar\":[],\"foo\":{}}", "[[],{}]", "{}", "[]",
+                                   NULL};
+
+    size_t i;
+
+    for (i = 0; plains[i]; i++) {
+        const char *plain = plains[i];
+        json_t *parse = NULL;
+        char *embed = NULL;
+        size_t psize = 0;
+        size_t esize = 0;
+
+        psize = strlen(plain) - 2;
+        embed = calloc(1, psize);
+        parse = json_loads(plain, 0, NULL);
+        esize =
+            json_dumpb(parse, embed, psize, JSON_COMPACT | JSON_SORT_KEYS | JSON_EMBED);
+        json_decref(parse);
+        if (esize != psize)
+            fail("json_dumpb(JSON_EMBED) returned an invalid size");
+        if (strncmp(plain + 1, embed, esize) != 0)
+            fail("json_dumps(JSON_EMBED) returned an invalid value");
+        free(embed);
+    }
+}
+
+static void run_tests() {
+    encode_null();
+    encode_twice();
+    circular_references();
+    encode_other_than_array_or_object();
+    escape_slashes();
+    encode_nul_byte();
+    dump_file();
+    dumpb();
+    dumpfd();
+    embed();
+}

+ 82 - 0
jansson.mod/jansson/test/suites/api/test_dump_callback.c

@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct my_sink {
+    char *buf;
+    size_t off;
+    size_t cap;
+};
+
+static int my_writer(const char *buffer, size_t len, void *data) {
+    struct my_sink *s = data;
+    if (len > s->cap - s->off) {
+        return -1;
+    }
+    memcpy(s->buf + s->off, buffer, len);
+    s->off += len;
+    return 0;
+}
+
+static void run_tests() {
+    struct my_sink s;
+    json_t *json;
+    const char str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]";
+    char *dumped_to_string;
+
+    json = json_loads(str, 0, NULL);
+    if (!json) {
+        fail("json_loads failed");
+    }
+
+    dumped_to_string = json_dumps(json, 0);
+    if (!dumped_to_string) {
+        json_decref(json);
+        fail("json_dumps failed");
+    }
+
+    s.off = 0;
+    s.cap = strlen(dumped_to_string);
+    s.buf = malloc(s.cap);
+    if (!s.buf) {
+        json_decref(json);
+        free(dumped_to_string);
+        fail("malloc failed");
+    }
+
+    if (json_dump_callback(json, my_writer, &s, 0) == -1) {
+        json_decref(json);
+        free(dumped_to_string);
+        free(s.buf);
+        fail("json_dump_callback failed on an exact-length sink buffer");
+    }
+
+    if (strncmp(dumped_to_string, s.buf, s.off) != 0) {
+        json_decref(json);
+        free(dumped_to_string);
+        free(s.buf);
+        fail("json_dump_callback and json_dumps did not produce identical "
+             "output");
+    }
+
+    s.off = 1;
+    if (json_dump_callback(json, my_writer, &s, 0) != -1) {
+        json_decref(json);
+        free(dumped_to_string);
+        free(s.buf);
+        fail("json_dump_callback succeeded on a short buffer when it should "
+             "have failed");
+    }
+
+    json_decref(json);
+    free(dumped_to_string);
+    free(s.buf);
+}

+ 202 - 0
jansson.mod/jansson/test/suites/api/test_equal.c

@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+
+static void test_equal_simple() {
+    json_t *value1, *value2;
+
+    if (json_equal(NULL, NULL))
+        fail("json_equal fails for two NULLs");
+
+    value1 = json_true();
+    if (json_equal(value1, NULL) || json_equal(NULL, value1))
+        fail("json_equal fails for NULL");
+
+    /* this covers true, false and null as they are singletons */
+    if (!json_equal(value1, value1))
+        fail("identical objects are not equal");
+    json_decref(value1);
+
+    /* integer */
+    value1 = json_integer(1);
+    value2 = json_integer(1);
+    if (!value1 || !value2)
+        fail("unable to create integers");
+    if (!json_equal(value1, value2))
+        fail("json_equal fails for two equal integers");
+    json_decref(value2);
+
+    value2 = json_integer(2);
+    if (!value2)
+        fail("unable to create an integer");
+    if (json_equal(value1, value2))
+        fail("json_equal fails for two inequal integers");
+
+    json_decref(value1);
+    json_decref(value2);
+
+    /* real */
+    value1 = json_real(1.2);
+    value2 = json_real(1.2);
+    if (!value1 || !value2)
+        fail("unable to create reals");
+    if (!json_equal(value1, value2))
+        fail("json_equal fails for two equal reals");
+    json_decref(value2);
+
+    value2 = json_real(3.141592);
+    if (!value2)
+        fail("unable to create an real");
+    if (json_equal(value1, value2))
+        fail("json_equal fails for two inequal reals");
+
+    json_decref(value1);
+    json_decref(value2);
+
+    /* string */
+    value1 = json_string("foo");
+    value2 = json_string("foo");
+    if (!value1 || !value2)
+        fail("unable to create strings");
+    if (!json_equal(value1, value2))
+        fail("json_equal fails for two equal strings");
+    json_decref(value2);
+
+    value2 = json_string("bar");
+    if (!value2)
+        fail("unable to create an string");
+    if (json_equal(value1, value2))
+        fail("json_equal fails for two inequal strings");
+    json_decref(value2);
+
+    value2 = json_string("bar2");
+    if (!value2)
+        fail("unable to create an string");
+    if (json_equal(value1, value2))
+        fail("json_equal fails for two inequal length strings");
+
+    json_decref(value1);
+    json_decref(value2);
+}
+
+static void test_equal_array() {
+    json_t *array1, *array2;
+
+    array1 = json_array();
+    array2 = json_array();
+    if (!array1 || !array2)
+        fail("unable to create arrays");
+
+    if (!json_equal(array1, array2))
+        fail("json_equal fails for two empty arrays");
+
+    json_array_append_new(array1, json_integer(1));
+    json_array_append_new(array2, json_integer(1));
+    json_array_append_new(array1, json_string("foo"));
+    json_array_append_new(array2, json_string("foo"));
+    json_array_append_new(array1, json_integer(2));
+    json_array_append_new(array2, json_integer(2));
+    if (!json_equal(array1, array2))
+        fail("json_equal fails for two equal arrays");
+
+    json_array_remove(array2, 2);
+    if (json_equal(array1, array2))
+        fail("json_equal fails for two inequal arrays");
+
+    json_array_append_new(array2, json_integer(3));
+    if (json_equal(array1, array2))
+        fail("json_equal fails for two inequal arrays");
+
+    json_decref(array1);
+    json_decref(array2);
+}
+
+static void test_equal_object() {
+    json_t *object1, *object2;
+
+    object1 = json_object();
+    object2 = json_object();
+    if (!object1 || !object2)
+        fail("unable to create objects");
+
+    if (!json_equal(object1, object2))
+        fail("json_equal fails for two empty objects");
+
+    json_object_set_new(object1, "a", json_integer(1));
+    json_object_set_new(object2, "a", json_integer(1));
+    json_object_set_new(object1, "b", json_string("foo"));
+    json_object_set_new(object2, "b", json_string("foo"));
+    json_object_set_new(object1, "c", json_integer(2));
+    json_object_set_new(object2, "c", json_integer(2));
+    if (!json_equal(object1, object2))
+        fail("json_equal fails for two equal objects");
+
+    json_object_del(object2, "c");
+    if (json_equal(object1, object2))
+        fail("json_equal fails for two inequal objects");
+
+    json_object_set_new(object2, "c", json_integer(3));
+    if (json_equal(object1, object2))
+        fail("json_equal fails for two inequal objects");
+
+    json_object_del(object2, "c");
+    json_object_set_new(object2, "d", json_integer(2));
+    if (json_equal(object1, object2))
+        fail("json_equal fails for two inequal objects");
+
+    json_decref(object1);
+    json_decref(object2);
+}
+
+static void test_equal_complex() {
+    json_t *value1, *value2, *value3;
+
+    const char *complex_json = "{"
+                               "    \"integer\": 1, "
+                               "    \"real\": 3.141592, "
+                               "    \"string\": \"foobar\", "
+                               "    \"true\": true, "
+                               "    \"object\": {"
+                               "        \"array-in-object\": [1,true,\"foo\",{}],"
+                               "        \"object-in-object\": {\"foo\": \"bar\"}"
+                               "    },"
+                               "    \"array\": [\"foo\", false, null, 1.234]"
+                               "}";
+
+    value1 = json_loads(complex_json, 0, NULL);
+    value2 = json_loads(complex_json, 0, NULL);
+    value3 = json_loads(complex_json, 0, NULL);
+    if (!value1 || !value2)
+        fail("unable to parse JSON");
+    if (!json_equal(value1, value2))
+        fail("json_equal fails for two equal objects");
+
+    json_array_set_new(
+        json_object_get(json_object_get(value2, "object"), "array-in-object"), 1,
+        json_false());
+    if (json_equal(value1, value2))
+        fail("json_equal fails for two inequal objects");
+
+    json_object_set_new(
+        json_object_get(json_object_get(value3, "object"), "object-in-object"), "foo",
+        json_string("baz"));
+    if (json_equal(value1, value3))
+        fail("json_equal fails for two inequal objects");
+
+    json_decref(value1);
+    json_decref(value2);
+    json_decref(value3);
+}
+
+static void run_tests() {
+    test_equal_simple();
+    test_equal_array();
+    test_equal_object();
+    test_equal_complex();
+}

+ 228 - 0
jansson.mod/jansson/test/suites/api/test_fixed_size.c

@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2020 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void test_keylen_iterator(json_t *object) {
+    const char key1[] = {'t', 'e', 's', 't', '1'};
+    const char key2[] = {'t', 'e', 's', 't'};
+    const char key3[] = {'t', 'e', 's', '\0', 't'};
+    const char key4[] = {'t', 'e', 's', 't', '\0'};
+    const char *reference_keys[] = {key1, key2, key3, key4};
+    const size_t reference_keys_len[] = {sizeof(key1), sizeof(key2), sizeof(key3),
+                                         sizeof(key4)};
+    size_t index = 0;
+    json_t *value;
+    const char *key;
+    size_t keylen;
+
+    json_object_keylen_foreach(object, key, keylen, value) {
+        if (keylen != reference_keys_len[index])
+            fail("invalid key len in iterator");
+        if (memcmp(key, reference_keys[index], reference_keys_len[index]) != 0)
+            fail("invalid key in iterator");
+
+        index++;
+    }
+}
+
+static void test_keylen(void) {
+    json_t *obj = json_object();
+    const char key[] = {'t', 'e', 's', 't', '1'};
+    const char key2[] = {'t', 'e', 's', 't'};
+    const char key3[] = {'t', 'e', 's', '\0', 't'};
+    const char key4[] = {'t', 'e', 's', 't', '\0'};
+
+    if (json_object_size(obj) != 0)
+        fail("incorrect json");
+
+    json_object_set_new_nocheck(obj, "test1", json_true());
+
+    if (json_object_size(obj) != 1)
+        fail("incorrect json");
+
+    if (json_object_getn(obj, key, sizeof(key)) != json_true())
+        fail("json_object_getn failed");
+
+    if (json_object_getn(obj, key2, sizeof(key2)) != NULL)
+        fail("false positive json_object_getn by key2");
+
+    if (json_object_setn_nocheck(obj, key2, sizeof(key2), json_false()))
+        fail("json_object_setn_nocheck for key2 failed");
+
+    if (json_object_size(obj) != 2)
+        fail("incorrect json");
+
+    if (json_object_get(obj, "test") != json_false())
+        fail("json_object_setn_nocheck for key2 failed");
+
+    if (json_object_getn(obj, key2, sizeof(key2)) != json_false())
+        fail("json_object_getn by key 2 failed");
+
+    if (json_object_getn(obj, key3, sizeof(key3)) != NULL)
+        fail("false positive json_object_getn by key3");
+
+    if (json_object_setn_nocheck(obj, key3, sizeof(key3), json_false()))
+        fail("json_object_setn_nocheck for key3 failed");
+
+    if (json_object_size(obj) != 3)
+        fail("incorrect json");
+
+    if (json_object_getn(obj, key3, sizeof(key3)) != json_false())
+        fail("json_object_getn by key 3 failed");
+
+    if (json_object_getn(obj, key4, sizeof(key4)) != NULL)
+        fail("false positive json_object_getn by key3");
+
+    if (json_object_setn_nocheck(obj, key4, sizeof(key4), json_false()))
+        fail("json_object_setn_nocheck for key3 failed");
+
+    if (json_object_size(obj) != 4)
+        fail("incorrect json");
+
+    test_keylen_iterator(obj);
+
+    if (json_object_getn(obj, key4, sizeof(key4)) != json_false())
+        fail("json_object_getn by key 3 failed");
+
+    if (json_object_size(obj) != 4)
+        fail("incorrect json");
+
+    if (json_object_deln(obj, key4, sizeof(key4)))
+        fail("json_object_deln failed");
+    if (json_object_getn(obj, key4, sizeof(key4)) != NULL)
+        fail("json_object_deln failed");
+    if (json_object_size(obj) != 3)
+        fail("incorrect json");
+
+    if (json_object_deln(obj, key3, sizeof(key3)))
+        fail("json_object_deln failed");
+    if (json_object_getn(obj, key3, sizeof(key3)) != NULL)
+        fail("json_object_deln failed");
+    if (json_object_size(obj) != 2)
+        fail("incorrect json");
+
+    if (json_object_deln(obj, key2, sizeof(key2)))
+        fail("json_object_deln failed");
+    if (json_object_getn(obj, key2, sizeof(key2)) != NULL)
+        fail("json_object_deln failed");
+    if (json_object_size(obj) != 1)
+        fail("incorrect json");
+
+    if (json_object_deln(obj, key, sizeof(key)))
+        fail("json_object_deln failed");
+    if (json_object_getn(obj, key, sizeof(key)) != NULL)
+        fail("json_object_deln failed");
+    if (json_object_size(obj) != 0)
+        fail("incorrect json");
+
+    json_decref(obj);
+}
+
+static void test_invalid_keylen(void) {
+    json_t *obj = json_object();
+    json_t *empty_obj = json_object();
+    const char key[] = {'t', 'e', 's', 't', '1'};
+
+    json_object_set_new_nocheck(obj, "test1", json_true());
+
+    if (json_object_getn(NULL, key, sizeof(key)) != NULL)
+        fail("json_object_getn on NULL failed");
+
+    if (json_object_getn(obj, NULL, sizeof(key)) != NULL)
+        fail("json_object_getn on NULL failed");
+
+    if (json_object_getn(obj, key, 0) != NULL)
+        fail("json_object_getn on NULL failed");
+
+    if (!json_object_setn_new(obj, NULL, sizeof(key), json_true()))
+        fail("json_object_setn_new with NULL key failed");
+
+    if (!json_object_setn_new_nocheck(obj, NULL, sizeof(key), json_true()))
+        fail("json_object_setn_new_nocheck with NULL key failed");
+
+    if (!json_object_del(obj, NULL))
+        fail("json_object_del with NULL failed");
+
+    if (!json_object_deln(empty_obj, key, sizeof(key)))
+        fail("json_object_deln with empty object failed");
+
+    if (!json_object_deln(obj, key, sizeof(key) - 1))
+        fail("json_object_deln with incomplete key failed");
+
+    json_decref(obj);
+    json_decref(empty_obj);
+}
+
+static void test_binary_keys(void) {
+    json_t *obj = json_object();
+    int key1 = 0;
+    int key2 = 1;
+
+    json_object_setn_nocheck(obj, (const char *)&key1, sizeof(key1), json_true());
+    json_object_setn_nocheck(obj, (const char *)&key2, sizeof(key2), json_true());
+
+    if (!json_is_true(json_object_getn(obj, (const char *)&key1, sizeof(key1))))
+        fail("cannot get integer key1");
+
+    if (!json_is_true(json_object_getn(obj, (const char *)&key1, sizeof(key2))))
+        fail("cannot get integer key2");
+
+    if (json_object_size(obj) != 2)
+        fail("binary object size missmatch");
+
+    if (json_object_deln(obj, (const char *)&key1, sizeof(key1)))
+        fail("cannot del integer key1");
+
+    if (json_object_size(obj) != 1)
+        fail("binary object size missmatch");
+
+    if (json_object_deln(obj, (const char *)&key2, sizeof(key2)))
+        fail("cannot del integer key2");
+
+    if (json_object_size(obj) != 0)
+        fail("binary object size missmatch");
+
+    json_decref(obj);
+}
+
+static void test_dump_order(void) {
+    json_t *obj = json_object();
+    char key1[] = {'k', '\0', '-', '2'};
+    char key2[] = {'k', '\0', '-', '1'};
+    const char expected_sorted_str[] =
+        "{\"k\\u0000-1\": \"first\", \"k\\u0000-2\": \"second\"}";
+    const char expected_nonsorted_str[] =
+        "{\"k\\u0000-2\": \"second\", \"k\\u0000-1\": \"first\"}";
+    char *out;
+
+    json_object_setn_new_nocheck(obj, key1, sizeof(key1), json_string("second"));
+    json_object_setn_new_nocheck(obj, key2, sizeof(key2), json_string("first"));
+
+    out = malloc(512);
+
+    json_dumpb(obj, out, 512, 0);
+
+    if (memcmp(expected_nonsorted_str, out, sizeof(expected_nonsorted_str) - 1) != 0)
+        fail("preserve order failed");
+
+    json_dumpb(obj, out, 512, JSON_SORT_KEYS);
+    if (memcmp(expected_sorted_str, out, sizeof(expected_sorted_str) - 1) != 0)
+        fail("utf-8 sort failed");
+
+    free(out);
+    json_decref(obj);
+}
+
+static void run_tests() {
+    test_keylen();
+    test_invalid_keylen();
+    test_binary_keys();
+    test_dump_order();
+}

+ 238 - 0
jansson.mod/jansson/test/suites/api/test_load.c

@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void file_not_found() {
+    json_t *json;
+    json_error_t error;
+    char *pos;
+
+    json = json_load_file("/path/to/nonexistent/file.json", 0, &error);
+    if (json)
+        fail("json_load_file returned non-NULL for a nonexistent file");
+    if (error.line != -1)
+        fail("json_load_file returned an invalid line number");
+
+    /* The error message is locale specific, only check the beginning
+       of the error message. */
+
+    pos = strchr(error.text, ':');
+    if (!pos)
+        fail("json_load_file returne an invalid error message");
+
+    *pos = '\0';
+
+    if (strcmp(error.text, "unable to open /path/to/nonexistent/file.json") != 0)
+        fail("json_load_file returned an invalid error message");
+    if (json_error_code(&error) != json_error_cannot_open_file)
+        fail("json_load_file returned an invalid error code");
+}
+
+static void very_long_file_name() {
+    json_t *json;
+    json_error_t error;
+
+    json = json_load_file("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+                          "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+                          0, &error);
+    if (json)
+        fail("json_load_file returned non-NULL for a nonexistent file");
+    if (error.line != -1)
+        fail("json_load_file returned an invalid line number");
+
+    if (strncmp(error.source, "...aaa", 6) != 0)
+        fail("error source was set incorrectly");
+    if (json_error_code(&error) != json_error_cannot_open_file)
+        fail("error code was set incorrectly");
+}
+
+static void reject_duplicates() {
+    json_error_t error;
+
+    if (json_loads("{\"foo\": 1, \"foo\": 2}", JSON_REJECT_DUPLICATES, &error))
+        fail("json_loads did not detect a duplicate key");
+    check_error(json_error_duplicate_key, "duplicate object key near '\"foo\"'",
+                "<string>", 1, 16, 16);
+}
+
+static void disable_eof_check() {
+    json_error_t error;
+    json_t *json;
+
+    const char *text = "{\"foo\": 1} garbage";
+
+    if (json_loads(text, 0, &error))
+        fail("json_loads did not detect garbage after JSON text");
+    check_error(json_error_end_of_input_expected, "end of file expected near 'garbage'",
+                "<string>", 1, 18, 18);
+
+    json = json_loads(text, JSON_DISABLE_EOF_CHECK, &error);
+    if (!json)
+        fail("json_loads failed with JSON_DISABLE_EOF_CHECK");
+
+    json_decref(json);
+}
+
+static void decode_any() {
+    json_t *json;
+    json_error_t error;
+
+    json = json_loads("\"foo\"", JSON_DECODE_ANY, &error);
+    if (!json || !json_is_string(json))
+        fail("json_load decoded any failed - string");
+    json_decref(json);
+
+    json = json_loads("42", JSON_DECODE_ANY, &error);
+    if (!json || !json_is_integer(json))
+        fail("json_load decoded any failed - integer");
+    json_decref(json);
+
+    json = json_loads("true", JSON_DECODE_ANY, &error);
+    if (!json || !json_is_true(json))
+        fail("json_load decoded any failed - boolean");
+    json_decref(json);
+
+    json = json_loads("null", JSON_DECODE_ANY, &error);
+    if (!json || !json_is_null(json))
+        fail("json_load decoded any failed - null");
+    json_decref(json);
+}
+
+static void decode_int_as_real() {
+    json_t *json;
+    json_error_t error;
+
+#if JSON_INTEGER_IS_LONG_LONG
+    const char *imprecise;
+    json_int_t expected;
+#endif
+
+    char big[311];
+
+    json = json_loads("42", JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error);
+    if (!json || !json_is_real(json) || json_real_value(json) != 42.0)
+        fail("json_load decode int as real failed - int");
+    json_decref(json);
+
+#if JSON_INTEGER_IS_LONG_LONG
+    /* This number cannot be represented exactly by a double */
+    imprecise = "9007199254740993";
+    expected = 9007199254740992ll;
+
+    json = json_loads(imprecise, JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error);
+    if (!json || !json_is_real(json) || expected != (json_int_t)json_real_value(json))
+        fail("json_load decode int as real failed - expected imprecision");
+    json_decref(json);
+#endif
+
+    /* 1E309 overflows. Here we create 1E309 as a decimal number, i.e.
+       1000...(309 zeroes)...0. */
+    big[0] = '1';
+    memset(big + 1, '0', 309);
+    big[310] = '\0';
+
+    json = json_loads(big, JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error);
+    if (json || strcmp(error.text, "real number overflow") != 0 ||
+        json_error_code(&error) != json_error_numeric_overflow)
+        fail("json_load decode int as real failed - expected overflow");
+    json_decref(json);
+}
+
+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;
+    json_error_t error;
+
+    json = json_loads(NULL, 0, &error);
+    if (json)
+        fail("json_loads should return NULL if the first argument is NULL");
+
+    json = json_loadb(NULL, 0, 0, &error);
+    if (json)
+        fail("json_loadb should return NULL if the first argument is NULL");
+
+    json = json_loadf(NULL, 0, &error);
+    if (json)
+        fail("json_loadf should return NULL if the first argument is NULL");
+
+    json = json_loadfd(-1, 0, &error);
+    if (json)
+        fail("json_loadfd should return NULL if the first argument is < 0");
+
+    json = json_load_file(NULL, 0, &error);
+    if (json)
+        fail("json_load_file should return NULL if the first argument is NULL");
+}
+
+static void position() {
+    json_t *json;
+    size_t flags = JSON_DISABLE_EOF_CHECK;
+    json_error_t error;
+
+    json = json_loads("{\"foo\": \"bar\"}", 0, &error);
+    if (error.position != 14)
+        fail("json_loads returned a wrong position");
+    json_decref(json);
+
+    json = json_loads("{\"foo\": \"bar\"} baz quux", flags, &error);
+    if (error.position != 14)
+        fail("json_loads returned a wrong position");
+    json_decref(json);
+}
+
+static void error_code() {
+    json_error_t error;
+    json_t *json = json_loads("[123] garbage", 0, &error);
+    if (json != NULL)
+        fail("json_loads returned not NULL");
+    if (strlen(error.text) >= JSON_ERROR_TEXT_LENGTH)
+        fail("error.text longer than expected");
+    if (json_error_code(&error) != json_error_end_of_input_expected)
+        fail("json_loads returned incorrect error code");
+
+    json = json_loads("{\"foo\": ", 0, &error);
+    if (json != NULL)
+        fail("json_loads returned not NULL");
+    if (strlen(error.text) >= JSON_ERROR_TEXT_LENGTH)
+        fail("error.text longer than expected");
+    if (json_error_code(&error) != json_error_premature_end_of_input)
+        fail("json_loads returned incorrect error code");
+}
+
+static void run_tests() {
+    file_not_found();
+    very_long_file_name();
+    reject_duplicates();
+    disable_eof_check();
+    decode_any();
+    decode_int_as_real();
+    allow_nul();
+    load_wrong_args();
+    position();
+    error_code();
+}

+ 77 - 0
jansson.mod/jansson/test/suites/api/test_load_callback.c

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2009-2011 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct my_source {
+    const char *buf;
+    size_t off;
+    size_t cap;
+};
+
+static const char my_str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]";
+
+static size_t greedy_reader(void *buf, size_t buflen, void *arg) {
+    struct my_source *s = arg;
+    if (buflen > s->cap - s->off)
+        buflen = s->cap - s->off;
+    if (buflen > 0) {
+        memcpy(buf, s->buf + s->off, buflen);
+        s->off += buflen;
+        return buflen;
+    } else {
+        return 0;
+    }
+}
+
+static void run_tests() {
+    struct my_source s;
+    json_t *json;
+    json_error_t error;
+
+    s.off = 0;
+    s.cap = strlen(my_str);
+    s.buf = my_str;
+
+    json = json_load_callback(greedy_reader, &s, 0, &error);
+
+    if (!json)
+        fail("json_load_callback failed on a valid callback");
+    json_decref(json);
+
+    s.off = 0;
+    s.cap = strlen(my_str) - 1;
+    s.buf = my_str;
+
+    json = json_load_callback(greedy_reader, &s, 0, &error);
+    if (json) {
+        json_decref(json);
+        fail("json_load_callback should have failed on an incomplete stream, "
+             "but it didn't");
+    }
+    if (strcmp(error.source, "<callback>") != 0) {
+        fail("json_load_callback returned an invalid error source");
+    }
+    if (strcmp(error.text, "']' expected near end of file") != 0) {
+        fail("json_load_callback returned an invalid error message for an "
+             "unclosed top-level array");
+    }
+
+    json = json_load_callback(NULL, NULL, 0, &error);
+    if (json) {
+        json_decref(json);
+        fail("json_load_callback should have failed on NULL load callback, but "
+             "it didn't");
+    }
+    if (strcmp(error.text, "wrong arguments") != 0) {
+        fail("json_load_callback returned an invalid error message for a NULL "
+             "load callback");
+    }
+}

+ 37 - 0
jansson.mod/jansson/test/suites/api/test_loadb.c

@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void run_tests() {
+    json_t *json;
+    json_error_t error;
+    const char str[] = "[\"A\", {\"B\": \"C\"}, 1, 2, 3]garbage";
+    size_t len = strlen(str) - strlen("garbage");
+
+    json = json_loadb(str, len, 0, &error);
+    if (!json) {
+        fail("json_loadb failed on a valid JSON buffer");
+    }
+    json_decref(json);
+
+    json = json_loadb(str, len - 1, 0, &error);
+    if (json) {
+        json_decref(json);
+        fail("json_loadb should have failed on an incomplete buffer, but it "
+             "didn't");
+    }
+    if (error.line != 1) {
+        fail("json_loadb returned an invalid line number on fail");
+    }
+    if (strcmp(error.text, "']' expected near end of file") != 0) {
+        fail("json_loadb returned an invalid error message for an unclosed "
+             "top-level array");
+    }
+}

+ 115 - 0
jansson.mod/jansson/test/suites/api/test_memory_funcs.c

@@ -0,0 +1,115 @@
+#include <jansson.h>
+#include <string.h>
+
+#include "util.h"
+
+static int malloc_called = 0;
+static int free_called = 0;
+static size_t malloc_used = 0;
+
+/* helpers */
+static void create_and_free_complex_object() {
+    json_t *obj;
+
+    obj = json_pack("{s:i,s:n,s:b,s:b,s:{s:s},s:[i,i,i]}", "foo", 42, "bar", "baz", 1,
+                    "qux", 0, "alice", "bar", "baz", "bob", 9, 8, 7);
+
+    json_decref(obj);
+}
+
+static void create_and_free_object_with_oom() {
+    int i;
+    char key[4];
+    json_t *obj = json_object();
+
+    for (i = 0; i < 10; i++) {
+        snprintf(key, sizeof key, "%d", i);
+        json_object_set_new(obj, key, json_integer(i));
+    }
+
+    json_decref(obj);
+}
+
+static void *my_malloc(size_t size) {
+    malloc_called = 1;
+    return malloc(size);
+}
+
+static void my_free(void *ptr) {
+    free_called = 1;
+    free(ptr);
+}
+
+static void test_simple() {
+    json_malloc_t mfunc = NULL;
+    json_free_t ffunc = NULL;
+
+    json_set_alloc_funcs(my_malloc, my_free);
+    json_get_alloc_funcs(&mfunc, &ffunc);
+    create_and_free_complex_object();
+
+    if (malloc_called != 1 || free_called != 1 || mfunc != my_malloc || ffunc != my_free)
+        fail("Custom allocation failed");
+}
+
+static void *oom_malloc(size_t size) {
+    if (malloc_used + size > 800)
+        return NULL;
+
+    malloc_used += size;
+    return malloc(size);
+}
+
+static void oom_free(void *ptr) {
+    free_called++;
+    free(ptr);
+}
+
+static void test_oom() {
+    free_called = 0;
+    json_set_alloc_funcs(oom_malloc, oom_free);
+    create_and_free_object_with_oom();
+
+    if (free_called == 0)
+        fail("Allocation with OOM failed");
+}
+
+/*
+  Test the secure memory functions code given in the API reference
+  documentation, but by using plain memset instead of
+  guaranteed_memset().
+*/
+
+static void *secure_malloc(size_t size) {
+    /* Store the memory area size in the beginning of the block */
+    void *ptr = malloc(size + 8);
+    *((size_t *)ptr) = size;
+    return (char *)ptr + 8;
+}
+
+static void secure_free(void *ptr) {
+    size_t size;
+
+    ptr = (char *)ptr - 8;
+    size = *((size_t *)ptr);
+
+    /*guaranteed_*/ memset(ptr, 0, size + 8);
+    free(ptr);
+}
+
+static void test_secure_funcs(void) {
+    json_set_alloc_funcs(secure_malloc, secure_free);
+    create_and_free_complex_object();
+}
+
+static void test_bad_args(void) {
+    /* The result of this test is not crashing. */
+    json_get_alloc_funcs(NULL, NULL);
+}
+
+static void run_tests() {
+    test_simple();
+    test_secure_funcs();
+    test_oom();
+    test_bad_args();
+}

+ 123 - 0
jansson.mod/jansson/test/suites/api/test_number.c

@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <math.h>
+
+#ifdef INFINITY
+// This test triggers "warning C4756: overflow in constant arithmetic"
+// in Visual Studio. This warning is triggered here by design, so disable it.
+// (This can only be done on function level so we keep these tests separate)
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4756)
+#endif
+static void test_inifity() {
+    json_t *real = json_real(INFINITY);
+    if (real != NULL)
+        fail("could construct a real from Inf");
+
+    real = json_real(1.0);
+    if (json_real_set(real, INFINITY) != -1)
+        fail("could set a real to Inf");
+
+    if (json_real_value(real) != 1.0)
+        fail("real value changed unexpectedly");
+
+    json_decref(real);
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+}
+#endif // INFINITY
+
+static void test_bad_args(void) {
+    json_t *txt = json_string("test");
+
+    if (json_integer_value(NULL) != 0)
+        fail("json_integer_value did not return 0 for non-integer");
+    if (json_integer_value(txt) != 0)
+        fail("json_integer_value did not return 0 for non-integer");
+
+    if (!json_integer_set(NULL, 0))
+        fail("json_integer_set did not return error for non-integer");
+    if (!json_integer_set(txt, 0))
+        fail("json_integer_set did not return error for non-integer");
+
+    if (json_real_value(NULL) != 0.0)
+        fail("json_real_value did not return 0.0 for non-real");
+    if (json_real_value(txt) != 0.0)
+        fail("json_real_value did not return 0.0 for non-real");
+
+    if (!json_real_set(NULL, 0.0))
+        fail("json_real_set did not return error for non-real");
+    if (!json_real_set(txt, 0.0))
+        fail("json_real_set did not return error for non-real");
+
+    if (json_number_value(NULL) != 0.0)
+        fail("json_number_value did not return 0.0 for non-numeric");
+    if (json_number_value(txt) != 0.0)
+        fail("json_number_value did not return 0.0 for non-numeric");
+
+    if (txt->refcount != 1)
+        fail("unexpected reference count for txt");
+
+    json_decref(txt);
+}
+
+static void run_tests() {
+    json_t *integer, *real;
+    json_int_t i;
+    double d;
+
+    integer = json_integer(5);
+    real = json_real(100.1);
+
+    if (!integer)
+        fail("unable to create integer");
+    if (!real)
+        fail("unable to create real");
+
+    i = json_integer_value(integer);
+    if (i != 5)
+        fail("wrong integer value");
+
+    d = json_real_value(real);
+    if (d != 100.1)
+        fail("wrong real value");
+
+    d = json_number_value(integer);
+    if (d != 5.0)
+        fail("wrong number value");
+    d = json_number_value(real);
+    if (d != 100.1)
+        fail("wrong number value");
+
+    json_decref(integer);
+    json_decref(real);
+
+#ifdef NAN
+    real = json_real(NAN);
+    if (real != NULL)
+        fail("could construct a real from NaN");
+
+    real = json_real(1.0);
+    if (json_real_set(real, NAN) != -1)
+        fail("could set a real to NaN");
+
+    if (json_real_value(real) != 1.0)
+        fail("real value changed unexpectedly");
+
+    json_decref(real);
+#endif
+
+#ifdef INFINITY
+    test_inifity();
+#endif
+    test_bad_args();
+}

+ 797 - 0
jansson.mod/jansson/test/suites/api/test_object.c

@@ -0,0 +1,797 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void test_clear() {
+    json_t *object, *ten;
+
+    object = json_object();
+    ten = json_integer(10);
+
+    if (!object)
+        fail("unable to create object");
+    if (!ten)
+        fail("unable to create integer");
+
+    if (json_object_set(object, "a", ten) || json_object_set(object, "b", ten) ||
+        json_object_set(object, "c", ten) || json_object_set(object, "d", ten) ||
+        json_object_set(object, "e", ten))
+        fail("unable to set value");
+
+    if (json_object_size(object) != 5)
+        fail("invalid size");
+
+    json_object_clear(object);
+
+    if (json_object_size(object) != 0)
+        fail("invalid size after clear");
+
+    json_decref(ten);
+    json_decref(object);
+}
+
+static void test_update() {
+    json_t *object, *other, *nine, *ten;
+
+    object = json_object();
+    other = json_object();
+
+    nine = json_integer(9);
+    ten = json_integer(10);
+
+    if (!object || !other)
+        fail("unable to create object");
+    if (!nine || !ten)
+        fail("unable to create integer");
+
+    /* update an empty object with an empty object */
+
+    if (json_object_update(object, other))
+        fail("unable to update an empty object with an empty object");
+
+    if (json_object_size(object) != 0)
+        fail("invalid size after update");
+
+    if (json_object_size(other) != 0)
+        fail("invalid size for updater after update");
+
+    /* update an empty object with a nonempty object */
+
+    if (json_object_set(other, "a", ten) || json_object_set(other, "b", ten) ||
+        json_object_set(other, "c", ten) || json_object_set(other, "d", ten) ||
+        json_object_set(other, "e", ten))
+        fail("unable to set value");
+
+    if (json_object_update(object, other))
+        fail("unable to update an empty object");
+
+    if (json_object_size(object) != 5)
+        fail("invalid size after update");
+
+    if (json_object_get(object, "a") != ten || json_object_get(object, "b") != ten ||
+        json_object_get(object, "c") != ten || json_object_get(object, "d") != ten ||
+        json_object_get(object, "e") != ten)
+        fail("update works incorrectly");
+
+    /* perform the same update again */
+
+    if (json_object_update(object, other))
+        fail("unable to update a non-empty object");
+
+    if (json_object_size(object) != 5)
+        fail("invalid size after update");
+
+    if (json_object_get(object, "a") != ten || json_object_get(object, "b") != ten ||
+        json_object_get(object, "c") != ten || json_object_get(object, "d") != ten ||
+        json_object_get(object, "e") != ten)
+        fail("update works incorrectly");
+
+    /* update a nonempty object with a nonempty object with both old
+       and new keys */
+
+    if (json_object_clear(other))
+        fail("clear failed");
+
+    if (json_object_set(other, "a", nine) || json_object_set(other, "b", nine) ||
+        json_object_set(other, "f", nine) || json_object_set(other, "g", nine) ||
+        json_object_set(other, "h", nine))
+        fail("unable to set value");
+
+    if (json_object_update(object, other))
+        fail("unable to update a nonempty object");
+
+    if (json_object_size(object) != 8)
+        fail("invalid size after update");
+
+    if (json_object_get(object, "a") != nine || json_object_get(object, "b") != nine ||
+        json_object_get(object, "f") != nine || json_object_get(object, "g") != nine ||
+        json_object_get(object, "h") != nine)
+        fail("update works incorrectly");
+
+    /* update_new check */
+    if (json_object_clear(object))
+        fail("clear failed");
+
+    if (json_object_set(object, "a", ten) || json_object_set(object, "b", ten) ||
+        json_object_set(object, "c", ten) || json_object_set(object, "d", ten) ||
+        json_object_set(object, "e", ten))
+        fail("unable to set value");
+
+    if (json_object_update_new(
+            object, json_pack("{s:O, s:O, s:O}", "b", nine, "f", nine, "g", nine)))
+        fail("unable to update_new a nonempty object");
+
+    if (json_object_size(object) != 7)
+        fail("invalid size after update_new");
+
+    if (json_object_get(object, "a") != ten || json_object_get(object, "b") != nine ||
+        json_object_get(object, "c") != ten || json_object_get(object, "d") != ten ||
+        json_object_get(object, "e") != ten || json_object_get(object, "f") != nine ||
+        json_object_get(object, "g") != nine)
+        fail("update_new works incorrectly");
+
+    json_decref(nine);
+    json_decref(ten);
+    json_decref(other);
+    json_decref(object);
+}
+
+static void test_set_many_keys() {
+    json_t *object, *value;
+    const char *keys = "abcdefghijklmnopqrstuvwxyz";
+    char buf[2];
+    size_t i;
+
+    object = json_object();
+    if (!object)
+        fail("unable to create object");
+
+    value = json_string("a");
+    if (!value)
+        fail("unable to create string");
+
+    buf[1] = '\0';
+    for (i = 0; i < strlen(keys); i++) {
+        buf[0] = keys[i];
+        if (json_object_set(object, buf, value))
+            fail("unable to set object key");
+    }
+
+    json_decref(object);
+    json_decref(value);
+}
+
+static void test_conditional_updates() {
+    json_t *object, *other;
+
+    object = json_pack("{sisi}", "foo", 1, "bar", 2);
+    other = json_pack("{sisi}", "foo", 3, "baz", 4);
+
+    if (json_object_update_existing(object, other))
+        fail("json_object_update_existing failed");
+
+    if (json_object_size(object) != 2)
+        fail("json_object_update_existing added new items");
+
+    if (json_integer_value(json_object_get(object, "foo")) != 3)
+        fail("json_object_update_existing failed to update existing key");
+
+    if (json_integer_value(json_object_get(object, "bar")) != 2)
+        fail("json_object_update_existing updated wrong key");
+
+    json_decref(object);
+
+    /* json_object_update_existing_new check */
+    object = json_pack("{sisi}", "foo", 1, "bar", 2);
+
+    if (json_object_update_existing_new(object, json_pack("{sisi}", "foo", 3, "baz", 4)))
+        fail("json_object_update_existing_new failed");
+
+    if (json_object_size(object) != 2)
+        fail("json_object_update_existing_new added new items");
+
+    if (json_integer_value(json_object_get(object, "foo")) != 3)
+        fail("json_object_update_existing_new failed to update existing key");
+
+    if (json_integer_value(json_object_get(object, "bar")) != 2)
+        fail("json_object_update_existing_new updated wrong key");
+
+    json_decref(object);
+
+    object = json_pack("{sisi}", "foo", 1, "bar", 2);
+
+    if (json_object_update_missing(object, other))
+        fail("json_object_update_missing failed");
+
+    if (json_object_size(object) != 3)
+        fail("json_object_update_missing didn't add new items");
+
+    if (json_integer_value(json_object_get(object, "foo")) != 1)
+        fail("json_object_update_missing updated existing key");
+
+    if (json_integer_value(json_object_get(object, "bar")) != 2)
+        fail("json_object_update_missing updated wrong key");
+
+    if (json_integer_value(json_object_get(object, "baz")) != 4)
+        fail("json_object_update_missing didn't add new items");
+
+    json_decref(object);
+
+    /* json_object_update_missing_new check */
+    object = json_pack("{sisi}", "foo", 1, "bar", 2);
+
+    if (json_object_update_missing_new(object, json_pack("{sisi}", "foo", 3, "baz", 4)))
+        fail("json_object_update_missing_new failed");
+
+    if (json_object_size(object) != 3)
+        fail("json_object_update_missing_new didn't add new items");
+
+    if (json_integer_value(json_object_get(object, "foo")) != 1)
+        fail("json_object_update_missing_new updated existing key");
+
+    if (json_integer_value(json_object_get(object, "bar")) != 2)
+        fail("json_object_update_missing_new updated wrong key");
+
+    if (json_integer_value(json_object_get(object, "baz")) != 4)
+        fail("json_object_update_missing_new didn't add new items");
+
+    json_decref(object);
+    json_decref(other);
+}
+
+static void test_recursive_updates() {
+    json_t *invalid, *object, *other, *barBefore, *barAfter;
+
+    invalid = json_integer(42);
+
+    object = json_pack("{sis{si}}", "foo", 1, "bar", "baz", 2);
+    other = json_pack("{sisisi}", "foo", 3, "bar", 4, "baz", 5);
+
+    if (!json_object_update_recursive(invalid, other))
+        fail("json_object_update_recursive accepted non-object argument");
+
+    json_decref(invalid);
+
+    if (json_object_update_recursive(object, other))
+        fail("json_object_update_recursive failed");
+
+    if (json_object_size(object) != 3)
+        fail("invalid size after update");
+
+    if (json_integer_value(json_object_get(object, "foo")) != 3)
+        fail("json_object_update_recursive failed to update existing key");
+
+    if (json_integer_value(json_object_get(object, "bar")) != 4)
+        fail("json_object_update_recursive failed to overwrite object");
+
+    if (json_integer_value(json_object_get(object, "baz")) != 5)
+        fail("json_object_update_recursive didn't add new item");
+
+    json_decref(object);
+    json_decref(other);
+
+    object = json_pack("{sis{si}}", "foo", 1, "bar", "baz", 2);
+    other = json_pack("{s{si}}", "bar", "baz", 3);
+    barBefore = json_object_get(object, "bar");
+
+    if (!barBefore)
+        fail("can't get bar object before json_object_update_recursive");
+
+    if (json_object_update_recursive(object, other))
+        fail("json_object_update_recursive failed");
+
+    if (json_object_size(object) != 2)
+        fail("invalid size after update");
+
+    if (!json_object_get(object, "foo"))
+        fail("json_object_update_recursive removed existing key");
+
+    if (json_integer_value(json_object_get(json_object_get(object, "bar"), "baz")) != 3)
+        fail("json_object_update_recursive failed to update nested value");
+
+    barAfter = json_object_get(object, "bar");
+    if (!barAfter)
+        fail("can't get bar object after json_object_update_recursive");
+
+    if (barBefore != barAfter)
+        fail("bar object reference changed after json_object_update_recursive");
+
+    json_decref(object);
+    json_decref(other);
+
+    /* check circular reference */
+    object = json_pack("{s{s{s{si}}}}", "foo", "bar", "baz", "xxx", 2);
+    other = json_pack("{s{s{si}}}", "foo", "bar", "baz", 2);
+    json_object_set(json_object_get(json_object_get(other, "foo"), "bar"), "baz",
+                    json_object_get(other, "foo"));
+
+    if (!json_object_update_recursive(object, other))
+        fail("json_object_update_recursive update a circular reference!");
+
+    json_object_set_new(json_object_get(json_object_get(other, "foo"), "bar"), "baz",
+                        json_integer(1));
+
+    if (json_object_update_recursive(object, other))
+        fail("json_object_update_recursive failed!");
+
+    json_decref(object);
+    json_decref(other);
+}
+
+static void test_circular() {
+    json_t *object1, *object2;
+
+    object1 = json_object();
+    object2 = json_object();
+    if (!object1 || !object2)
+        fail("unable to create object");
+
+    /* the simple case is checked */
+    if (json_object_set(object1, "a", object1) == 0)
+        fail("able to set self");
+
+    /* create circular references */
+    if (json_object_set(object1, "a", object2) || json_object_set(object2, "a", object1))
+        fail("unable to set value");
+
+    /* circularity is detected when dumping */
+    if (json_dumps(object1, 0) != NULL)
+        fail("able to dump circulars");
+
+    /* decref twice to deal with the circular references */
+    json_decref(object1);
+    json_decref(object2);
+    json_decref(object1);
+}
+
+static void test_set_nocheck() {
+    json_t *object, *string;
+
+    object = json_object();
+    string = json_string("bar");
+
+    if (!object)
+        fail("unable to create object");
+    if (!string)
+        fail("unable to create string");
+
+    if (json_object_set_nocheck(object, "foo", string))
+        fail("json_object_set_nocheck failed");
+    if (json_object_get(object, "foo") != string)
+        fail("json_object_get after json_object_set_nocheck failed");
+
+    /* invalid UTF-8 in key */
+    if (json_object_set_nocheck(object, "a\xefz", string))
+        fail("json_object_set_nocheck failed for invalid UTF-8");
+    if (json_object_get(object, "a\xefz") != string)
+        fail("json_object_get after json_object_set_nocheck failed");
+
+    if (json_object_set_new_nocheck(object, "bax", json_integer(123)))
+        fail("json_object_set_new_nocheck failed");
+    if (json_integer_value(json_object_get(object, "bax")) != 123)
+        fail("json_object_get after json_object_set_new_nocheck failed");
+
+    /* invalid UTF-8 in key */
+    if (json_object_set_new_nocheck(object, "asdf\xfe", json_integer(321)))
+        fail("json_object_set_new_nocheck failed for invalid UTF-8");
+    if (json_integer_value(json_object_get(object, "asdf\xfe")) != 321)
+        fail("json_object_get after json_object_set_new_nocheck failed");
+
+    json_decref(string);
+    json_decref(object);
+}
+
+static void test_iterators() {
+    json_t *object, *foo, *bar, *baz;
+    void *iter;
+
+    if (json_object_iter(NULL))
+        fail("able to iterate over NULL");
+
+    if (json_object_iter_next(NULL, NULL))
+        fail("able to increment an iterator on a NULL object");
+
+    object = json_object();
+    foo = json_string("foo");
+    bar = json_string("bar");
+    baz = json_string("baz");
+    if (!object || !foo || !bar || !baz)
+        fail("unable to create values");
+
+    if (json_object_iter_next(object, NULL))
+        fail("able to increment a NULL iterator");
+
+    if (json_object_set(object, "a", foo) || json_object_set(object, "b", bar) ||
+        json_object_set(object, "c", baz))
+        fail("unable to populate object");
+
+    iter = json_object_iter(object);
+    if (!iter)
+        fail("unable to get iterator");
+    if (strcmp(json_object_iter_key(iter), "a") != 0)
+        fail("iterating doesn't yield keys in order");
+    if (json_object_iter_value(iter) != foo)
+        fail("iterating doesn't yield values in order");
+
+    iter = json_object_iter_next(object, iter);
+    if (!iter)
+        fail("unable to increment iterator");
+    if (strcmp(json_object_iter_key(iter), "b") != 0)
+        fail("iterating doesn't yield keys in order");
+    if (json_object_iter_value(iter) != bar)
+        fail("iterating doesn't yield values in order");
+
+    iter = json_object_iter_next(object, iter);
+    if (!iter)
+        fail("unable to increment iterator");
+    if (strcmp(json_object_iter_key(iter), "c") != 0)
+        fail("iterating doesn't yield keys in order");
+    if (json_object_iter_value(iter) != baz)
+        fail("iterating doesn't yield values in order");
+
+    if (json_object_iter_next(object, iter) != NULL)
+        fail("able to iterate over the end");
+
+    if (json_object_iter_at(object, "foo"))
+        fail("json_object_iter_at() succeeds for non-existent key");
+
+    iter = json_object_iter_at(object, "b");
+    if (!iter)
+        fail("json_object_iter_at() fails for an existing key");
+
+    if (strcmp(json_object_iter_key(iter), "b"))
+        fail("iterating failed: wrong key");
+    if (json_object_iter_value(iter) != bar)
+        fail("iterating failed: wrong value");
+
+    if (json_object_iter_set(object, iter, baz))
+        fail("unable to set value at iterator");
+
+    if (strcmp(json_object_iter_key(iter), "b"))
+        fail("json_object_iter_key() fails after json_object_iter_set()");
+    if (json_object_iter_value(iter) != baz)
+        fail("json_object_iter_value() fails after json_object_iter_set()");
+    if (json_object_get(object, "b") != baz)
+        fail("json_object_get() fails after json_object_iter_set()");
+
+    json_decref(object);
+    json_decref(foo);
+    json_decref(bar);
+    json_decref(baz);
+}
+
+static void test_misc() {
+    json_t *object, *string, *other_string, *value;
+
+    object = json_object();
+    string = json_string("test");
+    other_string = json_string("other");
+
+    if (!object)
+        fail("unable to create object");
+    if (!string || !other_string)
+        fail("unable to create string");
+
+    if (json_object_get(object, "a"))
+        fail("value for nonexisting key");
+
+    if (json_object_set(object, "a", string))
+        fail("unable to set value");
+
+    if (!json_object_set(object, NULL, string))
+        fail("able to set NULL key");
+
+    if (json_object_del(object, "a"))
+        fail("unable to del the only key");
+
+    if (json_object_set(object, "a", string))
+        fail("unable to set value");
+
+    if (!json_object_set(object, "a", NULL))
+        fail("able to set NULL value");
+
+    /* invalid UTF-8 in key */
+    if (!json_object_set(object, "a\xefz", string))
+        fail("able to set invalid unicode key");
+
+    value = json_object_get(object, "a");
+    if (!value)
+        fail("no value for existing key");
+    if (value != string)
+        fail("got different value than what was added");
+
+    /* "a", "lp" and "px" collide in a five-bucket hashtable */
+    if (json_object_set(object, "b", string) || json_object_set(object, "lp", string) ||
+        json_object_set(object, "px", string))
+        fail("unable to set value");
+
+    value = json_object_get(object, "a");
+    if (!value)
+        fail("no value for existing key");
+    if (value != string)
+        fail("got different value than what was added");
+
+    if (json_object_set(object, "a", other_string))
+        fail("unable to replace an existing key");
+
+    value = json_object_get(object, "a");
+    if (!value)
+        fail("no value for existing key");
+    if (value != other_string)
+        fail("got different value than what was set");
+
+    if (!json_object_del(object, "nonexisting"))
+        fail("able to delete a nonexisting key");
+
+    if (json_object_del(object, "px"))
+        fail("unable to delete an existing key");
+
+    if (json_object_del(object, "a"))
+        fail("unable to delete an existing key");
+
+    if (json_object_del(object, "lp"))
+        fail("unable to delete an existing key");
+
+    /* add many keys to initiate rehashing */
+
+    if (json_object_set(object, "a", string))
+        fail("unable to set value");
+
+    if (json_object_set(object, "lp", string))
+        fail("unable to set value");
+
+    if (json_object_set(object, "px", string))
+        fail("unable to set value");
+
+    if (json_object_set(object, "c", string))
+        fail("unable to set value");
+
+    if (json_object_set(object, "d", string))
+        fail("unable to set value");
+
+    if (json_object_set(object, "e", string))
+        fail("unable to set value");
+
+    if (json_object_set_new(object, "foo", json_integer(123)))
+        fail("unable to set new value");
+
+    value = json_object_get(object, "foo");
+    if (!json_is_integer(value) || json_integer_value(value) != 123)
+        fail("json_object_set_new works incorrectly");
+
+    if (!json_object_set_new(object, NULL, json_integer(432)))
+        fail("able to set_new NULL key");
+
+    if (!json_object_set_new(object, "foo", NULL))
+        fail("able to set_new NULL value");
+
+    json_decref(string);
+    json_decref(other_string);
+    json_decref(object);
+}
+
+static void test_preserve_order() {
+    json_t *object;
+    char *result;
+
+    const char *expected = "{\"foobar\": 1, \"bazquux\": 6, \"lorem ipsum\": "
+                           "3, \"sit amet\": 5, \"helicopter\": 7}";
+
+    object = json_object();
+
+    json_object_set_new(object, "foobar", json_integer(1));
+    json_object_set_new(object, "bazquux", json_integer(2));
+    json_object_set_new(object, "lorem ipsum", json_integer(3));
+    json_object_set_new(object, "dolor", json_integer(4));
+    json_object_set_new(object, "sit amet", json_integer(5));
+
+    /* changing a value should preserve the order */
+    json_object_set_new(object, "bazquux", json_integer(6));
+
+    /* deletion shouldn't change the order of others */
+    json_object_del(object, "dolor");
+
+    /* add a new item just to make sure */
+    json_object_set_new(object, "helicopter", json_integer(7));
+
+    result = json_dumps(object, JSON_PRESERVE_ORDER);
+
+    if (strcmp(expected, result) != 0) {
+        fprintf(stderr, "%s != %s", expected, result);
+        fail("JSON_PRESERVE_ORDER doesn't work");
+    }
+
+    free(result);
+    json_decref(object);
+}
+
+static void test_object_foreach() {
+    const char *key;
+    json_t *object1, *object2, *value;
+
+    object1 = json_pack("{sisisi}", "foo", 1, "bar", 2, "baz", 3);
+    object2 = json_object();
+
+    json_object_foreach(object1, key, value) json_object_set(object2, key, value);
+
+    if (!json_equal(object1, object2))
+        fail("json_object_foreach failed to iterate all key-value pairs");
+
+    json_decref(object1);
+    json_decref(object2);
+}
+
+static void test_object_foreach_safe() {
+    const char *key;
+    void *tmp;
+    json_t *object, *value;
+
+    object = json_pack("{sisisi}", "foo", 1, "bar", 2, "baz", 3);
+
+    json_object_foreach_safe(object, tmp, key, value) { json_object_del(object, key); }
+
+    if (json_object_size(object) != 0)
+        fail("json_object_foreach_safe failed to iterate all key-value pairs");
+
+    json_decref(object);
+}
+
+static void test_bad_args(void) {
+    json_t *obj = json_object();
+    json_t *num = json_integer(1);
+    void *iter;
+
+    if (!obj || !num)
+        fail("failed to allocate test objects");
+
+    if (json_object_set(obj, "testkey", json_null()))
+        fail("failed to set testkey on object");
+
+    iter = json_object_iter(obj);
+    if (!iter)
+        fail("failed to retrieve test iterator");
+
+    if (json_object_size(NULL) != 0)
+        fail("json_object_size with non-object argument returned non-zero");
+    if (json_object_size(num) != 0)
+        fail("json_object_size with non-object argument returned non-zero");
+
+    if (json_object_get(NULL, "test") != NULL)
+        fail("json_object_get with non-object argument returned non-NULL");
+    if (json_object_get(num, "test") != NULL)
+        fail("json_object_get with non-object argument returned non-NULL");
+    if (json_object_get(obj, NULL) != NULL)
+        fail("json_object_get with NULL key returned non-NULL");
+
+    if (!json_object_set_new_nocheck(NULL, "test", json_null()))
+        fail("json_object_set_new_nocheck with non-object argument did not "
+             "return error");
+    if (!json_object_set_new_nocheck(num, "test", json_null()))
+        fail("json_object_set_new_nocheck with non-object argument did not "
+             "return error");
+    if (!json_object_set_new_nocheck(obj, "test", json_incref(obj)))
+        fail("json_object_set_new_nocheck with object == value did not return "
+             "error");
+    if (!json_object_set_new_nocheck(obj, NULL, json_object()))
+        fail("json_object_set_new_nocheck with NULL key did not return error");
+
+    if (!json_object_del(NULL, "test"))
+        fail("json_object_del with non-object argument did not return error");
+    if (!json_object_del(num, "test"))
+        fail("json_object_del with non-object argument did not return error");
+    if (!json_object_del(obj, NULL))
+        fail("json_object_del with NULL key did not return error");
+
+    if (!json_object_clear(NULL))
+        fail("json_object_clear with non-object argument did not return error");
+    if (!json_object_clear(num))
+        fail("json_object_clear with non-object argument did not return error");
+
+    if (!json_object_update(NULL, obj))
+        fail("json_object_update with non-object first argument did not return "
+             "error");
+    if (!json_object_update(num, obj))
+        fail("json_object_update with non-object first argument did not return "
+             "error");
+    if (!json_object_update(obj, NULL))
+        fail("json_object_update with non-object second argument did not "
+             "return error");
+    if (!json_object_update(obj, num))
+        fail("json_object_update with non-object second argument did not "
+             "return error");
+
+    if (!json_object_update_existing(NULL, obj))
+        fail("json_object_update_existing with non-object first argument did "
+             "not return error");
+    if (!json_object_update_existing(num, obj))
+        fail("json_object_update_existing with non-object first argument did "
+             "not return error");
+    if (!json_object_update_existing(obj, NULL))
+        fail("json_object_update_existing with non-object second argument did "
+             "not return error");
+    if (!json_object_update_existing(obj, num))
+        fail("json_object_update_existing with non-object second argument did "
+             "not return error");
+
+    if (!json_object_update_missing(NULL, obj))
+        fail("json_object_update_missing with non-object first argument did "
+             "not return error");
+    if (!json_object_update_missing(num, obj))
+        fail("json_object_update_missing with non-object first argument did "
+             "not return error");
+    if (!json_object_update_missing(obj, NULL))
+        fail("json_object_update_missing with non-object second argument did "
+             "not return error");
+    if (!json_object_update_missing(obj, num))
+        fail("json_object_update_missing with non-object second argument did "
+             "not return error");
+
+    if (json_object_iter(NULL) != NULL)
+        fail("json_object_iter with non-object argument returned non-NULL");
+    if (json_object_iter(num) != NULL)
+        fail("json_object_iter with non-object argument returned non-NULL");
+
+    if (json_object_iter_at(NULL, "test") != NULL)
+        fail("json_object_iter_at with non-object argument returned non-NULL");
+    if (json_object_iter_at(num, "test") != NULL)
+        fail("json_object_iter_at with non-object argument returned non-NULL");
+    if (json_object_iter_at(obj, NULL) != NULL)
+        fail("json_object_iter_at with NULL iter returned non-NULL");
+
+    if (json_object_iter_next(obj, NULL) != NULL)
+        fail("json_object_iter_next with NULL iter returned non-NULL");
+    if (json_object_iter_next(num, iter) != NULL)
+        fail("json_object_iter_next with non-object argument returned non-NULL");
+
+    if (json_object_iter_key(NULL) != NULL)
+        fail("json_object_iter_key with NULL iter returned non-NULL");
+
+    if (json_object_key_to_iter(NULL) != NULL)
+        fail("json_object_key_to_iter with NULL iter returned non-NULL");
+
+    if (json_object_iter_value(NULL) != NULL)
+        fail("json_object_iter_value with NULL iter returned non-NULL");
+
+    if (!json_object_iter_set_new(NULL, iter, json_incref(num)))
+        fail("json_object_iter_set_new with non-object argument did not return "
+             "error");
+    if (!json_object_iter_set_new(num, iter, json_incref(num)))
+        fail("json_object_iter_set_new with non-object argument did not return "
+             "error");
+    if (!json_object_iter_set_new(obj, NULL, json_incref(num)))
+        fail("json_object_iter_set_new with NULL iter did not return error");
+    if (!json_object_iter_set_new(obj, iter, NULL))
+        fail("json_object_iter_set_new with NULL value did not return error");
+
+    if (obj->refcount != 1)
+        fail("unexpected reference count for obj");
+
+    if (num->refcount != 1)
+        fail("unexpected reference count for num");
+
+    json_decref(obj);
+    json_decref(num);
+}
+
+static void run_tests() {
+    test_misc();
+    test_clear();
+    test_update();
+    test_set_many_keys();
+    test_conditional_updates();
+    test_recursive_updates();
+    test_circular();
+    test_set_nocheck();
+    test_iterators();
+    test_preserve_order();
+    test_object_foreach();
+    test_object_foreach_safe();
+    test_bad_args();
+}

+ 547 - 0
jansson.mod/jansson/test/suites/api/test_pack.c

@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ * Copyright (c) 2010-2012 Graeme Smecher <[email protected]>
+ *
+ * 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 <jansson_private_config.h>
+#endif
+
+#include <jansson_config.h>
+
+#include "util.h"
+#include <jansson.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef INFINITY
+// This test triggers "warning C4756: overflow in constant arithmetic"
+// in Visual Studio. This warning is triggered here by design, so disable it.
+// (This can only be done on function level so we keep these tests separate)
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4756)
+#endif
+static void test_inifity() {
+    json_error_t error;
+
+    if (json_pack_ex(&error, 0, "f", INFINITY))
+        fail("json_pack infinity incorrectly succeeded");
+    check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1,
+                1, 1);
+
+    if (json_pack_ex(&error, 0, "[f]", INFINITY))
+        fail("json_pack infinity array element incorrectly succeeded");
+    check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1,
+                2, 2);
+
+    if (json_pack_ex(&error, 0, "{s:f}", "key", INFINITY))
+        fail("json_pack infinity object value incorrectly succeeded");
+    check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1,
+                4, 4);
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+}
+#endif // INFINITY
+
+static void run_tests() {
+    json_t *value;
+    int i;
+    char buffer[4] = {'t', 'e', 's', 't'};
+    json_error_t error;
+
+    /*
+     * Simple, valid json_pack cases
+     */
+    /* true */
+    value = json_pack("b", 1);
+    if (!json_is_true(value))
+        fail("json_pack boolean failed");
+    if (value->refcount != (size_t)-1)
+        fail("json_pack boolean refcount failed");
+    json_decref(value);
+
+    /* false */
+    value = json_pack("b", 0);
+    if (!json_is_false(value))
+        fail("json_pack boolean failed");
+    if (value->refcount != (size_t)-1)
+        fail("json_pack boolean refcount failed");
+    json_decref(value);
+
+    /* null */
+    value = json_pack("n");
+    if (!json_is_null(value))
+        fail("json_pack null failed");
+    if (value->refcount != (size_t)-1)
+        fail("json_pack null refcount failed");
+    json_decref(value);
+
+    /* integer */
+    value = json_pack("i", 1);
+    if (!json_is_integer(value) || json_integer_value(value) != 1)
+        fail("json_pack integer failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack integer refcount failed");
+    json_decref(value);
+
+    /* integer from json_int_t */
+    value = json_pack("I", (json_int_t)555555);
+    if (!json_is_integer(value) || json_integer_value(value) != 555555)
+        fail("json_pack json_int_t failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack integer refcount failed");
+    json_decref(value);
+
+    /* real */
+    value = json_pack("f", 1.0);
+    if (!json_is_real(value) || json_real_value(value) != 1.0)
+        fail("json_pack real failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack real refcount failed");
+    json_decref(value);
+
+    /* string */
+    value = json_pack("s", "test");
+    if (!json_is_string(value) || strcmp("test", json_string_value(value)))
+        fail("json_pack string failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack string refcount failed");
+    json_decref(value);
+
+    /* nullable string (defined case) */
+    value = json_pack("s?", "test");
+    if (!json_is_string(value) || strcmp("test", json_string_value(value)))
+        fail("json_pack nullable string (defined case) failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack nullable string (defined case) refcount failed");
+    json_decref(value);
+
+    /* nullable string (NULL case) */
+    value = json_pack("s?", NULL);
+    if (!json_is_null(value))
+        fail("json_pack nullable string (NULL case) failed");
+    if (value->refcount != (size_t)-1)
+        fail("json_pack nullable string (NULL case) refcount failed");
+    json_decref(value);
+
+    /* nullable string concatenation */
+    if (json_pack_ex(&error, 0, "s?+", "test", "ing"))
+        fail("json_pack failed to catch invalid format 's?+'");
+    check_error(json_error_invalid_format, "Cannot use '+' on optional strings",
+                "<format>", 1, 2, 2);
+
+    /* nullable string with integer length */
+    if (json_pack_ex(&error, 0, "s?#", "test", 4))
+        fail("json_pack failed to catch invalid format 's?#'");
+    check_error(json_error_invalid_format, "Cannot use '#' on optional strings",
+                "<format>", 1, 2, 2);
+
+    /* string and length (int) */
+    value = json_pack("s#", "test asdf", 4);
+    if (!json_is_string(value) || strcmp("test", json_string_value(value)))
+        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 (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 */
+    if (json_pack("s+", "test", NULL))
+        fail("json_pack string concatenation succeeded with NULL string");
+
+    value = json_pack("s++", "te", "st", "ing");
+    if (!json_is_string(value) || strcmp("testing", json_string_value(value)))
+        fail("json_pack string concatenation failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack string concatenation refcount failed");
+    json_decref(value);
+
+    /* 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 (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 (size_t) refcount "
+             "failed");
+    json_decref(value);
+
+    /* empty object */
+    value = json_pack("{}", 1.0);
+    if (!json_is_object(value) || json_object_size(value) != 0)
+        fail("json_pack empty object failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack empty object refcount failed");
+    json_decref(value);
+
+    /* empty list */
+    value = json_pack("[]", 1.0);
+    if (!json_is_array(value) || json_array_size(value) != 0)
+        fail("json_pack empty list failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack empty list failed");
+    json_decref(value);
+
+    /* non-incref'd object */
+    value = json_pack("o", json_integer(1));
+    if (!json_is_integer(value) || json_integer_value(value) != 1)
+        fail("json_pack object failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack integer refcount failed");
+    json_decref(value);
+
+    /* non-incref'd nullable object (defined case) */
+    value = json_pack("o?", json_integer(1));
+    if (!json_is_integer(value) || json_integer_value(value) != 1)
+        fail("json_pack nullable object (defined case) failed");
+    if (value->refcount != (size_t)1)
+        fail("json_pack nullable object (defined case) refcount failed");
+    json_decref(value);
+
+    /* non-incref'd nullable object (NULL case) */
+    value = json_pack("o?", NULL);
+    if (!json_is_null(value))
+        fail("json_pack nullable object (NULL case) failed");
+    if (value->refcount != (size_t)-1)
+        fail("json_pack nullable object (NULL case) refcount failed");
+    json_decref(value);
+
+    /* incref'd object */
+    value = json_pack("O", json_integer(1));
+    if (!json_is_integer(value) || json_integer_value(value) != 1)
+        fail("json_pack object failed");
+    if (value->refcount != (size_t)2)
+        fail("json_pack integer refcount failed");
+    json_decref(value);
+    json_decref(value);
+
+    /* incref'd nullable object (defined case) */
+    value = json_pack("O?", json_integer(1));
+    if (!json_is_integer(value) || json_integer_value(value) != 1)
+        fail("json_pack incref'd nullable object (defined case) failed");
+    if (value->refcount != (size_t)2)
+        fail("json_pack incref'd nullable object (defined case) refcount "
+             "failed");
+    json_decref(value);
+    json_decref(value);
+
+    /* incref'd nullable object (NULL case) */
+    value = json_pack("O?", NULL);
+    if (!json_is_null(value))
+        fail("json_pack incref'd nullable object (NULL case) failed");
+    if (value->refcount != (size_t)-1)
+        fail("json_pack incref'd nullable object (NULL case) refcount failed");
+
+    /* simple object */
+    value = json_pack("{s:[]}", "foo");
+    if (!json_is_object(value) || json_object_size(value) != 1)
+        fail("json_pack array failed");
+    if (!json_is_array(json_object_get(value, "foo")))
+        fail("json_pack array failed");
+    if (json_object_get(value, "foo")->refcount != (size_t)1)
+        fail("json_pack object refcount failed");
+    json_decref(value);
+
+    /* object with complex key */
+    value = json_pack("{s+#+: []}", "foo", "barbar", 3, "baz");
+    if (!json_is_object(value) || json_object_size(value) != 1)
+        fail("json_pack array failed");
+    if (!json_is_array(json_object_get(value, "foobarbaz")))
+        fail("json_pack array failed");
+    if (json_object_get(value, "foobarbaz")->refcount != (size_t)1)
+        fail("json_pack object refcount failed");
+    json_decref(value);
+
+    /* object with optional members */
+    value = json_pack("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
+    if (value)
+        fail("json_pack object optional incorrectly succeeded");
+
+    value = json_pack("{s:**}", "a", NULL);
+    if (value)
+        fail("json_pack object optional invalid incorrectly succeeded");
+
+    if (json_pack_ex(&error, 0, "{s:i*}", "a", 1))
+        fail("json_pack object optional invalid incorrectly succeeded");
+    check_error(json_error_invalid_format, "Expected format 's', got '*'", "<format>", 1,
+                5, 5);
+
+    value = json_pack("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
+    if (!json_is_object(value) || json_object_size(value) != 0)
+        fail("json_pack object optional failed");
+    json_decref(value);
+
+    value = json_pack("{s:s*}", "key", "\xff\xff");
+    if (value)
+        fail("json_pack object optional with invalid UTF-8 incorrectly "
+             "succeeded");
+
+    if (json_pack_ex(&error, 0, "{s: s*#}", "key", "test", 1))
+        fail("json_pack failed to catch invalid format 's*#'");
+    check_error(json_error_invalid_format, "Cannot use '#' on optional strings",
+                "<format>", 1, 6, 6);
+
+    if (json_pack_ex(&error, 0, "{s: s*+}", "key", "test", "ing"))
+        fail("json_pack failed to catch invalid format 's*+'");
+    check_error(json_error_invalid_format, "Cannot use '+' on optional strings",
+                "<format>", 1, 6, 6);
+
+    /* simple array */
+    value = json_pack("[i,i,i]", 0, 1, 2);
+    if (!json_is_array(value) || json_array_size(value) != 3)
+        fail("json_pack object failed");
+    for (i = 0; i < 3; i++) {
+        if (!json_is_integer(json_array_get(value, i)) ||
+            json_integer_value(json_array_get(value, i)) != i)
+
+            fail("json_pack integer array failed");
+    }
+    json_decref(value);
+
+    /* simple array with optional members */
+    value = json_pack("[s,o,O]", NULL, NULL, NULL);
+    if (value)
+        fail("json_pack array optional incorrectly succeeded");
+
+    if (json_pack_ex(&error, 0, "[i*]", 1))
+        fail("json_pack array optional invalid incorrectly succeeded");
+    check_error(json_error_invalid_format, "Unexpected format character '*'", "<format>",
+                1, 3, 3);
+
+    value = json_pack("[**]", NULL);
+    if (value)
+        fail("json_pack array optional invalid incorrectly succeeded");
+    value = json_pack("[s*,o*,O*]", NULL, NULL, NULL);
+    if (!json_is_array(value) || json_array_size(value) != 0)
+        fail("json_pack array optional failed");
+    json_decref(value);
+
+#ifdef NAN
+    /* Invalid float values */
+    if (json_pack_ex(&error, 0, "f", NAN))
+        fail("json_pack NAN incorrectly succeeded");
+    check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1,
+                1, 1);
+
+    if (json_pack_ex(&error, 0, "[f]", NAN))
+        fail("json_pack NAN array element incorrectly succeeded");
+    check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1,
+                2, 2);
+
+    if (json_pack_ex(&error, 0, "{s:f}", "key", NAN))
+        fail("json_pack NAN object value incorrectly succeeded");
+    check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1,
+                4, 4);
+#endif
+
+#ifdef INFINITY
+    test_inifity();
+#endif
+
+    /* Whitespace; regular string */
+    value = json_pack(" s\t ", "test");
+    if (!json_is_string(value) || strcmp("test", json_string_value(value)))
+        fail("json_pack string (with whitespace) failed");
+    json_decref(value);
+
+    /* Whitespace; empty array */
+    value = json_pack("[ ]");
+    if (!json_is_array(value) || json_array_size(value) != 0)
+        fail("json_pack empty array (with whitespace) failed");
+    json_decref(value);
+
+    /* Whitespace; array */
+    value = json_pack("[ i , i,  i ] ", 1, 2, 3);
+    if (!json_is_array(value) || json_array_size(value) != 3)
+        fail("json_pack array (with whitespace) failed");
+    json_decref(value);
+
+    /*
+     * Invalid cases
+     */
+
+    /* newline in format string */
+    if (json_pack_ex(&error, 0, "{\n\n1"))
+        fail("json_pack failed to catch invalid format '1'");
+    check_error(json_error_invalid_format, "Expected format 's', got '1'", "<format>", 3,
+                1, 4);
+
+    /* mismatched open/close array/object */
+    if (json_pack_ex(&error, 0, "[}"))
+        fail("json_pack failed to catch mismatched '}'");
+    check_error(json_error_invalid_format, "Unexpected format character '}'", "<format>",
+                1, 2, 2);
+
+    if (json_pack_ex(&error, 0, "{]"))
+        fail("json_pack failed to catch mismatched ']'");
+    check_error(json_error_invalid_format, "Expected format 's', got ']'", "<format>", 1,
+                2, 2);
+
+    /* missing close array */
+    if (json_pack_ex(&error, 0, "["))
+        fail("json_pack failed to catch missing ']'");
+    check_error(json_error_invalid_format, "Unexpected end of format string", "<format>",
+                1, 2, 2);
+
+    /* missing close object */
+    if (json_pack_ex(&error, 0, "{"))
+        fail("json_pack failed to catch missing '}'");
+    check_error(json_error_invalid_format, "Unexpected end of format string", "<format>",
+                1, 2, 2);
+
+    /* garbage after format string */
+    if (json_pack_ex(&error, 0, "[i]a", 42))
+        fail("json_pack failed to catch garbage after format string");
+    check_error(json_error_invalid_format, "Garbage after format string", "<format>", 1,
+                4, 4);
+
+    if (json_pack_ex(&error, 0, "ia", 42))
+        fail("json_pack failed to catch garbage after format string");
+    check_error(json_error_invalid_format, "Garbage after format string", "<format>", 1,
+                2, 2);
+
+    /* NULL string */
+    if (json_pack_ex(&error, 0, "s", NULL))
+        fail("json_pack failed to catch null argument string");
+    check_error(json_error_null_value, "NULL string", "<args>", 1, 1, 1);
+
+    /* + on its own */
+    if (json_pack_ex(&error, 0, "+", NULL))
+        fail("json_pack failed to a lone +");
+    check_error(json_error_invalid_format, "Unexpected format character '+'", "<format>",
+                1, 1, 1);
+
+    /* Empty format */
+    if (json_pack_ex(&error, 0, ""))
+        fail("json_pack failed to catch empty format string");
+    check_error(json_error_invalid_argument, "NULL or empty format string", "<format>",
+                -1, -1, 0);
+
+    /* NULL format */
+    if (json_pack_ex(&error, 0, NULL))
+        fail("json_pack failed to catch NULL format string");
+    check_error(json_error_invalid_argument, "NULL or empty format string", "<format>",
+                -1, -1, 0);
+
+    /* NULL key */
+    if (json_pack_ex(&error, 0, "{s:i}", NULL, 1))
+        fail("json_pack failed to catch NULL key");
+    check_error(json_error_null_value, "NULL object key", "<args>", 1, 2, 2);
+
+    /* NULL value followed by object still steals the object's ref */
+    value = json_incref(json_object());
+    if (json_pack_ex(&error, 0, "{s:s,s:o}", "badnull", NULL, "dontleak", value))
+        fail("json_pack failed to catch NULL value");
+    check_error(json_error_null_value, "NULL string", "<args>", 1, 4, 4);
+    if (value->refcount != (size_t)1)
+        fail("json_pack failed to steal reference after error.");
+    json_decref(value);
+
+    /* More complicated checks for row/columns */
+    if (json_pack_ex(&error, 0, "{ {}: s }", "foo"))
+        fail("json_pack failed to catch object as key");
+    check_error(json_error_invalid_format, "Expected format 's', got '{'", "<format>", 1,
+                3, 3);
+
+    /* Complex object */
+    if (json_pack_ex(&error, 0, "{ s: {},  s:[ii{} }", "foo", "bar", 12, 13))
+        fail("json_pack failed to catch missing ]");
+    check_error(json_error_invalid_format, "Unexpected format character '}'", "<format>",
+                1, 19, 19);
+
+    /* Complex array */
+    if (json_pack_ex(&error, 0, "[[[[[   [[[[[  [[[[ }]]]] ]]]] ]]]]]"))
+        fail("json_pack failed to catch extra }");
+    check_error(json_error_invalid_format, "Unexpected format character '}'", "<format>",
+                1, 21, 21);
+
+    /* Invalid UTF-8 in object key */
+    if (json_pack_ex(&error, 0, "{s:i}", "\xff\xff", 42))
+        fail("json_pack failed to catch invalid UTF-8 in an object key");
+    check_error(json_error_invalid_utf8, "Invalid UTF-8 object key", "<args>", 1, 2, 2);
+
+    /* Invalid UTF-8 in a string */
+    if (json_pack_ex(&error, 0, "{s:s}", "foo", "\xff\xff"))
+        fail("json_pack failed to catch invalid UTF-8 in a string");
+    check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "<args>", 1, 4, 4);
+
+    /* Invalid UTF-8 in an optional '?' string */
+    if (json_pack_ex(&error, 0, "{s:s?}", "foo", "\xff\xff"))
+        fail("json_pack failed to catch invalid UTF-8 in an optional '?' "
+             "string");
+    check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "<args>", 1, 5, 5);
+
+    /* Invalid UTF-8 in an optional '*' string */
+    if (json_pack_ex(&error, 0, "{s:s*}", "foo", "\xff\xff"))
+        fail("json_pack failed to catch invalid UTF-8 in an optional '*' "
+             "string");
+    check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "<args>", 1, 5, 5);
+
+    /* Invalid UTF-8 in a concatenated key */
+    if (json_pack_ex(&error, 0, "{s+:i}", "\xff\xff", "concat", 42))
+        fail("json_pack failed to catch invalid UTF-8 in an object key");
+    check_error(json_error_invalid_utf8, "Invalid UTF-8 object key", "<args>", 1, 3, 3);
+
+    if (json_pack_ex(&error, 0, "{s:o}", "foo", NULL))
+        fail("json_pack failed to catch nullable object");
+    check_error(json_error_null_value, "NULL object", "<args>", 1, 4, 4);
+
+    if (json_pack_ex(&error, 0, "{s:O}", "foo", NULL))
+        fail("json_pack failed to catch nullable incref object");
+    check_error(json_error_null_value, "NULL object", "<args>", 1, 4, 4);
+
+    if (json_pack_ex(&error, 0, "{s+:o}", "foo", "bar", NULL))
+        fail("json_pack failed to catch non-nullable object value");
+    check_error(json_error_null_value, "NULL object", "<args>", 1, 5, 5);
+
+    if (json_pack_ex(&error, 0, "[1s", "Hi"))
+        fail("json_pack failed to catch invalid format");
+    check_error(json_error_invalid_format, "Unexpected format character '1'", "<format>",
+                1, 2, 2);
+
+    if (json_pack_ex(&error, 0, "[1s+", "Hi", "ya"))
+        fail("json_pack failed to catch invalid format");
+    check_error(json_error_invalid_format, "Unexpected format character '1'", "<format>",
+                1, 2, 2);
+
+    if (json_pack_ex(&error, 0, "[so]", NULL, json_object()))
+        fail("json_pack failed to catch NULL value");
+    check_error(json_error_null_value, "NULL string", "<args>", 1, 2, 2);
+}

+ 287 - 0
jansson.mod/jansson/test/suites/api/test_simple.c

@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void test_bad_args(void) {
+    json_t *num = json_integer(1);
+    json_t *txt = json_string("test");
+
+    if (!num || !txt)
+        fail("failed to allocate test objects");
+
+    if (json_string_nocheck(NULL) != NULL)
+        fail("json_string_nocheck with NULL argument did not return NULL");
+    if (json_stringn_nocheck(NULL, 0) != NULL)
+        fail("json_stringn_nocheck with NULL argument did not return NULL");
+    if (json_string(NULL) != NULL)
+        fail("json_string with NULL argument did not return NULL");
+    if (json_stringn(NULL, 0) != NULL)
+        fail("json_stringn with NULL argument did not return NULL");
+
+    if (json_string_length(NULL) != 0)
+        fail("json_string_length with non-string argument did not return 0");
+    if (json_string_length(num) != 0)
+        fail("json_string_length with non-string argument did not return 0");
+
+    if (json_string_value(NULL) != NULL)
+        fail("json_string_value with non-string argument did not return NULL");
+    if (json_string_value(num) != NULL)
+        fail("json_string_value with non-string argument did not return NULL");
+
+    if (!json_string_setn_nocheck(NULL, "", 0))
+        fail("json_string_setn with non-string argument did not return error");
+    if (!json_string_setn_nocheck(num, "", 0))
+        fail("json_string_setn with non-string argument did not return error");
+    if (!json_string_setn_nocheck(txt, NULL, 0))
+        fail("json_string_setn_nocheck with NULL value did not return error");
+
+    if (!json_string_set_nocheck(txt, NULL))
+        fail("json_string_set_nocheck with NULL value did not return error");
+    if (!json_string_set(txt, NULL))
+        fail("json_string_set with NULL value did not return error");
+    if (!json_string_setn(txt, NULL, 0))
+        fail("json_string_setn with NULL value did not return error");
+
+    if (num->refcount != 1)
+        fail("unexpected reference count for num");
+    if (txt->refcount != 1)
+        fail("unexpected reference count for txt");
+
+    json_decref(num);
+    json_decref(txt);
+}
+
+/* Call the simple functions not covered by other tests of the public API */
+static void run_tests() {
+    json_t *value;
+
+    value = json_boolean(1);
+    if (!json_is_true(value))
+        fail("json_boolean(1) failed");
+    json_decref(value);
+
+    value = json_boolean(-123);
+    if (!json_is_true(value))
+        fail("json_boolean(-123) failed");
+    json_decref(value);
+
+    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);
+
+    value = json_integer(1);
+    if (json_typeof(value) != JSON_INTEGER)
+        fail("json_typeof failed");
+
+    if (json_is_object(value))
+        fail("json_is_object failed");
+
+    if (json_is_array(value))
+        fail("json_is_array failed");
+
+    if (json_is_string(value))
+        fail("json_is_string failed");
+
+    if (!json_is_integer(value))
+        fail("json_is_integer failed");
+
+    if (json_is_real(value))
+        fail("json_is_real failed");
+
+    if (!json_is_number(value))
+        fail("json_is_number failed");
+
+    if (json_is_true(value))
+        fail("json_is_true failed");
+
+    if (json_is_false(value))
+        fail("json_is_false failed");
+
+    if (json_is_boolean(value))
+        fail("json_is_boolean failed");
+
+    if (json_is_null(value))
+        fail("json_is_null failed");
+
+    json_decref(value);
+
+    value = json_string("foo");
+    if (!value)
+        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, "barr"))
+        fail("json_string_set failed");
+    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);
+
+    value = json_string(NULL);
+    if (value)
+        fail("json_string(NULL) failed");
+
+    /* invalid UTF-8  */
+    value = json_string("a\xefz");
+    if (value)
+        fail("json_string(<invalid utf-8>) failed");
+
+    value = json_string_nocheck("foo");
+    if (!value)
+        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, "barr"))
+        fail("json_string_set_nocheck failed");
+    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);
+
+    /* invalid UTF-8 */
+    value = json_string_nocheck("qu\xff");
+    if (!value)
+        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);
+
+    value = json_integer(123);
+    if (!value)
+        fail("json_integer failed");
+    if (json_integer_value(value) != 123)
+        fail("invalid integer value");
+    if (json_number_value(value) != 123.0)
+        fail("invalid number value");
+
+    if (json_integer_set(value, 321))
+        fail("json_integer_set failed");
+    if (json_integer_value(value) != 321)
+        fail("invalid integer value");
+    if (json_number_value(value) != 321.0)
+        fail("invalid number value");
+
+    json_decref(value);
+
+    value = json_real(123.123);
+    if (!value)
+        fail("json_real failed");
+    if (json_real_value(value) != 123.123)
+        fail("invalid integer value");
+    if (json_number_value(value) != 123.123)
+        fail("invalid number value");
+
+    if (json_real_set(value, 321.321))
+        fail("json_real_set failed");
+    if (json_real_value(value) != 321.321)
+        fail("invalid real value");
+    if (json_number_value(value) != 321.321)
+        fail("invalid number value");
+
+    json_decref(value);
+
+    value = json_true();
+    if (!value)
+        fail("json_true failed");
+    json_decref(value);
+
+    value = json_false();
+    if (!value)
+        fail("json_false failed");
+    json_decref(value);
+
+    value = json_null();
+    if (!value)
+        fail("json_null failed");
+    json_decref(value);
+
+    /* Test reference counting on singletons (true, false, null) */
+    value = json_true();
+    if (value->refcount != (size_t)-1)
+        fail("refcounting true works incorrectly");
+    json_decref(value);
+    if (value->refcount != (size_t)-1)
+        fail("refcounting true works incorrectly");
+    json_incref(value);
+    if (value->refcount != (size_t)-1)
+        fail("refcounting true works incorrectly");
+
+    value = json_false();
+    if (value->refcount != (size_t)-1)
+        fail("refcounting false works incorrectly");
+    json_decref(value);
+    if (value->refcount != (size_t)-1)
+        fail("refcounting false works incorrectly");
+    json_incref(value);
+    if (value->refcount != (size_t)-1)
+        fail("refcounting false works incorrectly");
+
+    value = json_null();
+    if (value->refcount != (size_t)-1)
+        fail("refcounting null works incorrectly");
+    json_decref(value);
+    if (value->refcount != (size_t)-1)
+        fail("refcounting null works incorrectly");
+    json_incref(value);
+    if (value->refcount != (size_t)-1)
+        fail("refcounting null works incorrectly");
+
+#ifdef json_auto_t
+    value = json_string("foo");
+    {
+        json_auto_t *test = json_incref(value);
+        /* Use test so GCC doesn't complain it is unused. */
+        if (!json_is_string(test))
+            fail("value type check failed");
+    }
+    if (value->refcount != 1)
+        fail("automatic decrement failed");
+    json_decref(value);
+#endif
+
+    test_bad_args();
+}

+ 29 - 0
jansson.mod/jansson/test/suites/api/test_sprintf.c

@@ -0,0 +1,29 @@
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void test_sprintf() {
+    json_t *s = json_sprintf("foo bar %d", 42);
+    if (!s)
+        fail("json_sprintf returned NULL");
+    if (!json_is_string(s))
+        fail("json_sprintf didn't return a JSON string");
+    if (strcmp(json_string_value(s), "foo bar 42"))
+        fail("json_sprintf generated an unexpected string");
+
+    json_decref(s);
+
+    s = json_sprintf("%s", "");
+    if (!s)
+        fail("json_sprintf returned NULL");
+    if (!json_is_string(s))
+        fail("json_sprintf didn't return a JSON string");
+    if (json_string_length(s) != 0)
+        fail("string is not empty");
+    json_decref(s);
+
+    if (json_sprintf("%s", "\xff\xff"))
+        fail("json_sprintf unexpected success with invalid UTF");
+}
+
+static void run_tests() { test_sprintf(); }

+ 431 - 0
jansson.mod/jansson/test/suites/api/test_unpack.c

@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ * Copyright (c) 2010-2012 Graeme Smecher <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <stdio.h>
+#include <string.h>
+
+static void run_tests() {
+    json_t *j, *j2;
+    int i1, i2, i3;
+    json_int_t I1;
+    int rv;
+    size_t z;
+    double f;
+    char *s;
+
+    json_error_t error;
+
+    /*
+     * Simple, valid json_pack cases
+     */
+
+    /* true */
+    rv = json_unpack(json_true(), "b", &i1);
+    if (rv || !i1)
+        fail("json_unpack boolean failed");
+
+    /* false */
+    rv = json_unpack(json_false(), "b", &i1);
+    if (rv || i1)
+        fail("json_unpack boolean failed");
+
+    /* null */
+    if (json_unpack(json_null(), "n"))
+        fail("json_unpack null failed");
+
+    /* integer */
+    j = json_integer(42);
+    rv = json_unpack(j, "i", &i1);
+    if (rv || i1 != 42)
+        fail("json_unpack integer failed");
+    json_decref(j);
+
+    /* json_int_t */
+    j = json_integer(5555555);
+    rv = json_unpack(j, "I", &I1);
+    if (rv || I1 != 5555555)
+        fail("json_unpack json_int_t failed");
+    json_decref(j);
+
+    /* real */
+    j = json_real(1.7);
+    rv = json_unpack(j, "f", &f);
+    if (rv || f != 1.7)
+        fail("json_unpack real failed");
+    json_decref(j);
+
+    /* number */
+    j = json_integer(12345);
+    rv = json_unpack(j, "F", &f);
+    if (rv || f != 12345.0)
+        fail("json_unpack (real or) integer failed");
+    json_decref(j);
+
+    j = json_real(1.7);
+    rv = json_unpack(j, "F", &f);
+    if (rv || f != 1.7)
+        fail("json_unpack real (or integer) failed");
+    json_decref(j);
+
+    /* string */
+    j = json_string("foo");
+    rv = json_unpack(j, "s", &s);
+    if (rv || strcmp(s, "foo"))
+        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, "{}"))
+        fail("json_unpack empty object failed");
+    json_decref(j);
+
+    /* empty list */
+    j = json_array();
+    if (json_unpack(j, "[]"))
+        fail("json_unpack empty list failed");
+    json_decref(j);
+
+    /* non-incref'd object */
+    j = json_object();
+    rv = json_unpack(j, "o", &j2);
+    if (rv || j2 != j || j->refcount != 1)
+        fail("json_unpack object failed");
+    json_decref(j);
+
+    /* incref'd object */
+    j = json_object();
+    rv = json_unpack(j, "O", &j2);
+    if (rv || j2 != j || j->refcount != 2)
+        fail("json_unpack object failed");
+    json_decref(j);
+    json_decref(j);
+
+    /* simple object */
+    j = json_pack("{s:i}", "foo", 42);
+    rv = json_unpack(j, "{s:i}", "foo", &i1);
+    if (rv || i1 != 42)
+        fail("json_unpack simple object failed");
+    json_decref(j);
+
+    /* simple array */
+    j = json_pack("[iii]", 1, 2, 3);
+    rv = json_unpack(j, "[i,i,i]", &i1, &i2, &i3);
+    if (rv || i1 != 1 || i2 != 2 || i3 != 3)
+        fail("json_unpack simple array failed");
+    json_decref(j);
+
+    /* object with many items & strict checking */
+    j = json_pack("{s:i, s:i, s:i}", "a", 1, "b", 2, "c", 3);
+    rv = json_unpack(j, "{s:i, s:i, s:i}", "a", &i1, "b", &i2, "c", &i3);
+    if (rv || i1 != 1 || i2 != 2 || i3 != 3)
+        fail("json_unpack object with many items failed");
+    json_decref(j);
+
+    /*
+     * Invalid cases
+     */
+
+    j = json_integer(42);
+    if (!json_unpack_ex(j, &error, 0, "z"))
+        fail("json_unpack succeeded with invalid format character");
+    check_error(json_error_invalid_format, "Unexpected format character 'z'", "<format>",
+                1, 1, 1);
+
+    if (!json_unpack_ex(NULL, &error, 0, "[i]"))
+        fail("json_unpack succeeded with NULL root");
+    check_error(json_error_null_value, "NULL root value", "<root>", -1, -1, 0);
+    json_decref(j);
+
+    /* mismatched open/close array/object */
+    j = json_pack("[]");
+    if (!json_unpack_ex(j, &error, 0, "[}"))
+        fail("json_unpack failed to catch mismatched ']'");
+    check_error(json_error_invalid_format, "Unexpected format character '}'", "<format>",
+                1, 2, 2);
+    json_decref(j);
+
+    j = json_pack("{}");
+    if (!json_unpack_ex(j, &error, 0, "{]"))
+        fail("json_unpack failed to catch mismatched '}'");
+    check_error(json_error_invalid_format, "Expected format 's', got ']'", "<format>", 1,
+                2, 2);
+    json_decref(j);
+
+    /* missing close array */
+    j = json_pack("[]");
+    if (!json_unpack_ex(j, &error, 0, "["))
+        fail("json_unpack failed to catch missing ']'");
+    check_error(json_error_invalid_format, "Unexpected end of format string", "<format>",
+                1, 2, 2);
+    json_decref(j);
+
+    /* missing close object */
+    j = json_pack("{}");
+    if (!json_unpack_ex(j, &error, 0, "{"))
+        fail("json_unpack failed to catch missing '}'");
+    check_error(json_error_invalid_format, "Unexpected end of format string", "<format>",
+                1, 2, 2);
+    json_decref(j);
+
+    /* garbage after format string */
+    j = json_pack("[i]", 42);
+    if (!json_unpack_ex(j, &error, 0, "[i]a", &i1))
+        fail("json_unpack failed to catch garbage after format string");
+    check_error(json_error_invalid_format, "Garbage after format string", "<format>", 1,
+                4, 4);
+    json_decref(j);
+
+    j = json_integer(12345);
+    if (!json_unpack_ex(j, &error, 0, "ia", &i1))
+        fail("json_unpack failed to catch garbage after format string");
+    check_error(json_error_invalid_format, "Garbage after format string", "<format>", 1,
+                2, 2);
+    json_decref(j);
+
+    /* NULL format string */
+    j = json_pack("[]");
+    if (!json_unpack_ex(j, &error, 0, NULL))
+        fail("json_unpack failed to catch null format string");
+    check_error(json_error_invalid_argument, "NULL or empty format string", "<format>",
+                -1, -1, 0);
+    json_decref(j);
+
+    /* NULL string pointer */
+    j = json_string("foobie");
+    if (!json_unpack_ex(j, &error, 0, "s", NULL))
+        fail("json_unpack failed to catch null string pointer");
+    check_error(json_error_null_value, "NULL string argument", "<args>", 1, 1, 1);
+    json_decref(j);
+
+    /* invalid types */
+    j = json_integer(42);
+    j2 = json_string("foo");
+    if (!json_unpack_ex(j, &error, 0, "s"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected string, got integer", "<validation>", 1,
+                1, 1);
+
+    if (!json_unpack_ex(j, &error, 0, "n"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected null, got integer", "<validation>", 1, 1,
+                1);
+
+    if (!json_unpack_ex(j, &error, 0, "b"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected true or false, got integer",
+                "<validation>", 1, 1, 1);
+
+    if (!json_unpack_ex(j2, &error, 0, "i"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected integer, got string", "<validation>", 1,
+                1, 1);
+
+    if (!json_unpack_ex(j2, &error, 0, "I"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected integer, got string", "<validation>", 1,
+                1, 1);
+
+    if (!json_unpack_ex(j, &error, 0, "f"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected real, got integer", "<validation>", 1, 1,
+                1);
+
+    if (!json_unpack_ex(j2, &error, 0, "F"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected real or integer, got string",
+                "<validation>", 1, 1, 1);
+
+    if (!json_unpack_ex(j, &error, 0, "[i]"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected array, got integer", "<validation>", 1,
+                1, 1);
+
+    if (!json_unpack_ex(j, &error, 0, "{si}", "foo"))
+        fail("json_unpack failed to catch invalid type");
+    check_error(json_error_wrong_type, "Expected object, got integer", "<validation>", 1,
+                1, 1);
+
+    json_decref(j);
+    json_decref(j2);
+
+    /* Array index out of range */
+    j = json_pack("[i]", 1);
+    if (!json_unpack_ex(j, &error, 0, "[ii]", &i1, &i2))
+        fail("json_unpack failed to catch index out of array bounds");
+    check_error(json_error_index_out_of_range, "Array index 1 out of range",
+                "<validation>", 1, 3, 3);
+    json_decref(j);
+
+    /* NULL object key */
+    j = json_pack("{si}", "foo", 42);
+    if (!json_unpack_ex(j, &error, 0, "{si}", NULL, &i1))
+        fail("json_unpack failed to catch null string pointer");
+    check_error(json_error_null_value, "NULL object key", "<args>", 1, 2, 2);
+    json_decref(j);
+
+    /* Object key not found */
+    j = json_pack("{si}", "foo", 42);
+    if (!json_unpack_ex(j, &error, 0, "{si}", "baz", &i1))
+        fail("json_unpack failed to catch null string pointer");
+    check_error(json_error_item_not_found, "Object item not found: baz", "<validation>",
+                1, 3, 3);
+    json_decref(j);
+
+    /*
+     * Strict validation
+     */
+
+    j = json_pack("[iii]", 1, 2, 3);
+    rv = json_unpack(j, "[iii!]", &i1, &i2, &i3);
+    if (rv || i1 != 1 || i2 != 2 || i3 != 3)
+        fail("json_unpack array with strict validation failed");
+    json_decref(j);
+
+    j = json_pack("[iii]", 1, 2, 3);
+    if (!json_unpack_ex(j, &error, 0, "[ii!]", &i1, &i2))
+        fail("json_unpack array with strict validation failed");
+    check_error(json_error_end_of_input_expected, "1 array item(s) left unpacked",
+                "<validation>", 1, 5, 5);
+    json_decref(j);
+
+    /* Like above, but with JSON_STRICT instead of '!' format */
+    j = json_pack("[iii]", 1, 2, 3);
+    if (!json_unpack_ex(j, &error, JSON_STRICT, "[ii]", &i1, &i2))
+        fail("json_unpack array with strict validation failed");
+    check_error(json_error_end_of_input_expected, "1 array item(s) left unpacked",
+                "<validation>", 1, 4, 4);
+    json_decref(j);
+
+    j = json_pack("{s:s, s:i}", "foo", "bar", "baz", 42);
+    rv = json_unpack(j, "{sssi!}", "foo", &s, "baz", &i1);
+    if (rv || strcmp(s, "bar") != 0 || i1 != 42)
+        fail("json_unpack object with strict validation failed");
+    json_decref(j);
+
+    /* Unpack the same item twice */
+    j = json_pack("{s:s, s:i, s:b}", "foo", "bar", "baz", 42, "quux", 1);
+    if (!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s))
+        fail("json_unpack object with strict validation failed");
+    {
+        const char *possible_errors[] = {"2 object item(s) left unpacked: baz, quux",
+                                         "2 object item(s) left unpacked: quux, baz"};
+        check_errors(json_error_end_of_input_expected, possible_errors, 2, "<validation>",
+                     1, 10, 10);
+    }
+    json_decref(j);
+
+    j = json_pack("[i,{s:i,s:n},[i,i]]", 1, "foo", 2, "bar", 3, 4);
+    if (json_unpack_ex(j, NULL, JSON_STRICT | JSON_VALIDATE_ONLY, "[i{sisn}[ii]]", "foo",
+                       "bar"))
+        fail("json_unpack complex value with strict validation failed");
+    json_decref(j);
+
+    /* ! and * must be last */
+    j = json_pack("[ii]", 1, 2);
+    if (!json_unpack_ex(j, &error, 0, "[i!i]", &i1, &i2))
+        fail("json_unpack failed to catch ! in the middle of an array");
+    check_error(json_error_invalid_format, "Expected ']' after '!', got 'i'", "<format>",
+                1, 4, 4);
+
+    if (!json_unpack_ex(j, &error, 0, "[i*i]", &i1, &i2))
+        fail("json_unpack failed to catch * in the middle of an array");
+    check_error(json_error_invalid_format, "Expected ']' after '*', got 'i'", "<format>",
+                1, 4, 4);
+    json_decref(j);
+
+    j = json_pack("{sssi}", "foo", "bar", "baz", 42);
+    if (!json_unpack_ex(j, &error, 0, "{ss!si}", "foo", &s, "baz", &i1))
+        fail("json_unpack failed to catch ! in the middle of an object");
+    check_error(json_error_invalid_format, "Expected '}' after '!', got 's'", "<format>",
+                1, 5, 5);
+
+    if (!json_unpack_ex(j, &error, 0, "{ss*si}", "foo", &s, "baz", &i1))
+        fail("json_unpack failed to catch ! in the middle of an object");
+    check_error(json_error_invalid_format, "Expected '}' after '*', got 's'", "<format>",
+                1, 5, 5);
+    json_decref(j);
+
+    /* Error in nested object */
+    j = json_pack("{s{snsn}}", "foo", "bar", "baz");
+    if (!json_unpack_ex(j, &error, 0, "{s{sn!}}", "foo", "bar"))
+        fail("json_unpack nested object with strict validation failed");
+    check_error(json_error_end_of_input_expected, "1 object item(s) left unpacked: baz",
+                "<validation>", 1, 7, 7);
+    json_decref(j);
+
+    /* Error in nested array */
+    j = json_pack("[[ii]]", 1, 2);
+    if (!json_unpack_ex(j, &error, 0, "[[i!]]", &i1))
+        fail("json_unpack nested array with strict validation failed");
+    check_error(json_error_end_of_input_expected, "1 array item(s) left unpacked",
+                "<validation>", 1, 5, 5);
+    json_decref(j);
+
+    /* Optional values */
+    j = json_object();
+    i1 = 0;
+    if (json_unpack(j, "{s?i}", "foo", &i1))
+        fail("json_unpack failed for optional key");
+    if (i1 != 0)
+        fail("json_unpack unpacked an optional key");
+    json_decref(j);
+
+    i1 = 0;
+    j = json_pack("{si}", "foo", 42);
+    if (json_unpack(j, "{s?i}", "foo", &i1))
+        fail("json_unpack failed for an optional value");
+    if (i1 != 42)
+        fail("json_unpack failed to unpack an optional value");
+    json_decref(j);
+
+    j = json_object();
+    i1 = i2 = i3 = 0;
+    if (json_unpack(j, "{s?[ii]s?{s{si}}}", "foo", &i1, &i2, "bar", "baz", "quux", &i3))
+        fail("json_unpack failed for complex optional values");
+    if (i1 != 0 || i2 != 0 || i3 != 0)
+        fail("json_unpack unexpectedly unpacked something");
+    json_decref(j);
+
+    j = json_pack("{s{si}}", "foo", "bar", 42);
+    if (json_unpack(j, "{s?{s?i}}", "foo", "bar", &i1))
+        fail("json_unpack failed for complex optional values");
+    if (i1 != 42)
+        fail("json_unpack failed to unpack");
+    json_decref(j);
+
+    /* Combine ? and ! */
+    j = json_pack("{si}", "foo", 42);
+    i1 = i2 = 0;
+    if (json_unpack(j, "{sis?i!}", "foo", &i1, "bar", &i2))
+        fail("json_unpack failed for optional values with strict mode");
+    if (i1 != 42)
+        fail("json_unpack failed to unpack");
+    if (i2 != 0)
+        fail("json_unpack failed to unpack");
+    json_decref(j);
+
+    /* But don't compensate a missing key with an optional one. */
+    j = json_pack("{sisi}", "foo", 42, "baz", 43);
+    i1 = i2 = i3 = 0;
+    if (!json_unpack_ex(j, &error, 0, "{sis?i!}", "foo", &i1, "bar", &i2))
+        fail("json_unpack failed for optional values with strict mode and "
+             "compensation");
+    check_error(json_error_end_of_input_expected, "1 object item(s) left unpacked: baz",
+                "<validation>", 1, 8, 8);
+    json_decref(j);
+}

+ 61 - 0
jansson.mod/jansson/test/suites/api/test_version.c

@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019 Sean Bright <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include "util.h"
+#include <jansson.h>
+#include <string.h>
+
+static void test_version_str(void) {
+    if (strcmp(jansson_version_str(), JANSSON_VERSION)) {
+        fail("jansson_version_str returned invalid version string");
+    }
+}
+
+static void test_version_cmp() {
+    if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION,
+                            JANSSON_MICRO_VERSION)) {
+        fail("jansson_version_cmp equality check failed");
+    }
+
+    if (jansson_version_cmp(JANSSON_MAJOR_VERSION - 1, 0, 0) <= 0) {
+        fail("jansson_version_cmp less than check failed");
+    }
+
+    if (JANSSON_MINOR_VERSION) {
+        if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION - 1,
+                                JANSSON_MICRO_VERSION) <= 0) {
+            fail("jansson_version_cmp less than check failed");
+        }
+    }
+
+    if (JANSSON_MICRO_VERSION) {
+        if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION,
+                                JANSSON_MICRO_VERSION - 1) <= 0) {
+            fail("jansson_version_cmp less than check failed");
+        }
+    }
+
+    if (jansson_version_cmp(JANSSON_MAJOR_VERSION + 1, JANSSON_MINOR_VERSION,
+                            JANSSON_MICRO_VERSION) >= 0) {
+        fail("jansson_version_cmp greater than check failed");
+    }
+
+    if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION + 1,
+                            JANSSON_MICRO_VERSION) >= 0) {
+        fail("jansson_version_cmp greater than check failed");
+    }
+
+    if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION,
+                            JANSSON_MICRO_VERSION + 1) >= 0) {
+        fail("jansson_version_cmp greater than check failed");
+    }
+}
+
+static void run_tests() {
+    test_version_str();
+    test_version_cmp();
+}

+ 93 - 0
jansson.mod/jansson/test/suites/api/util.h

@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2009-2016 Petri Lehtinen <[email protected]>
+ *
+ * Jansson is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#ifdef HAVE_CONFIG_H
+#include <jansson_private_config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#include <jansson.h>
+
+#define failhdr fprintf(stderr, "%s:%d: ", __FILE__, __LINE__)
+
+#define fail(msg)                                                                        \
+    do {                                                                                 \
+        failhdr;                                                                         \
+        fprintf(stderr, "%s\n", msg);                                                    \
+        exit(1);                                                                         \
+    } while (0)
+
+/* Assumes json_error_t error */
+#define check_errors(code_, texts_, num_, source_, line_, column_, position_)            \
+    do {                                                                                 \
+        int i_, found_ = 0;                                                              \
+        if (json_error_code(&error) != code_) {                                          \
+            failhdr;                                                                     \
+            fprintf(stderr, "code: %d != %d\n", json_error_code(&error), code_);         \
+            exit(1);                                                                     \
+        }                                                                                \
+        for (i_ = 0; i_ < num_; i_++) {                                                  \
+            if (strcmp(error.text, texts_[i_]) == 0) {                                   \
+                found_ = 1;                                                              \
+                break;                                                                   \
+            }                                                                            \
+        }                                                                                \
+        if (!found_) {                                                                   \
+            failhdr;                                                                     \
+            if (num_ == 1) {                                                             \
+                fprintf(stderr, "text: \"%s\" != \"%s\"\n", error.text, texts_[0]);      \
+            } else {                                                                     \
+                fprintf(stderr, "text: \"%s\" does not match\n", error.text);            \
+            }                                                                            \
+            exit(1);                                                                     \
+        }                                                                                \
+        if (strcmp(error.source, source_) != 0) {                                        \
+            failhdr;                                                                     \
+                                                                                         \
+            fprintf(stderr, "source: \"%s\" != \"%s\"\n", error.source, source_);        \
+            exit(1);                                                                     \
+        }                                                                                \
+        if (error.line != line_) {                                                       \
+            failhdr;                                                                     \
+            fprintf(stderr, "line: %d != %d\n", error.line, line_);                      \
+            exit(1);                                                                     \
+        }                                                                                \
+        if (error.column != column_) {                                                   \
+            failhdr;                                                                     \
+            fprintf(stderr, "column: %d != %d\n", error.column, column_);                \
+            exit(1);                                                                     \
+        }                                                                                \
+        if (error.position != position_) {                                               \
+            failhdr;                                                                     \
+            fprintf(stderr, "position: %d != %d\n", error.position, position_);          \
+            exit(1);                                                                     \
+        }                                                                                \
+    } while (0)
+
+/* Assumes json_error_t error */
+#define check_error(code_, text_, source_, line_, column_, position_)                    \
+    check_errors(code_, &text_, 1, source_, line_, column_, position_)
+
+static void run_tests();
+
+int main() {
+#ifdef HAVE_SETLOCALE
+    setlocale(LC_ALL, "");
+#endif
+    run_tests();
+    return 0;
+}
+
+#endif

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/array/input

@@ -0,0 +1 @@
+[1, 2]

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/array/output

@@ -0,0 +1 @@
+[1, 2]

+ 2 - 0
jansson.mod/jansson/test/suites/encoding-flags/compact-array/env

@@ -0,0 +1,2 @@
+JSON_COMPACT=1
+export JSON_COMPACT

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/compact-array/input

@@ -0,0 +1 @@
+[1, 2]

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/compact-array/output

@@ -0,0 +1 @@
+[1,2]

+ 3 - 0
jansson.mod/jansson/test/suites/encoding-flags/compact-object/env

@@ -0,0 +1,3 @@
+JSON_COMPACT=1
+HASHSEED=1
+export JSON_COMPACT HASHSEED

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/compact-object/input

@@ -0,0 +1 @@
+{"a": 1, "b": 2}

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/compact-object/output

@@ -0,0 +1 @@
+{"a":1,"b":2}

+ 2 - 0
jansson.mod/jansson/test/suites/encoding-flags/ensure-ascii/env

@@ -0,0 +1,2 @@
+JSON_ENSURE_ASCII=1
+export JSON_ENSURE_ASCII

+ 8 - 0
jansson.mod/jansson/test/suites/encoding-flags/ensure-ascii/input

@@ -0,0 +1,8 @@
+[
+    "foo",
+    "å ä ö",
+    "foo åä",
+    "åä foo",
+    "å foo ä",
+    "clef g: 𝄞"
+]

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/ensure-ascii/output

@@ -0,0 +1 @@
+["foo", "\u00E5 \u00E4 \u00F6", "foo \u00E5\u00E4", "\u00E5\u00E4 foo", "\u00E5 foo \u00E4", "clef g: \uD834\uDD1E"]

+ 2 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-array/env

@@ -0,0 +1,2 @@
+JSON_INDENT=4
+export JSON_INDENT

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-array/input

@@ -0,0 +1 @@
+[1, 2]

+ 4 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-array/output

@@ -0,0 +1,4 @@
+[
+    1,
+    2
+]

+ 3 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-compact-array/env

@@ -0,0 +1,3 @@
+JSON_INDENT=4
+JSON_COMPACT=1
+export JSON_INDENT JSON_COMPACT

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-compact-array/input

@@ -0,0 +1 @@
+[1, 2]

+ 4 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-compact-array/output

@@ -0,0 +1,4 @@
+[
+    1,
+    2
+]

+ 4 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-compact-object/env

@@ -0,0 +1,4 @@
+JSON_INDENT=4
+JSON_COMPACT=1
+HASHSEED=1
+export JSON_INDENT JSON_COMPACT HASHSEED

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-compact-object/input

@@ -0,0 +1 @@
+{"a": 1, "b": 2}

+ 4 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-compact-object/output

@@ -0,0 +1,4 @@
+{
+    "a":1,
+    "b":2
+}

+ 3 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-object/env

@@ -0,0 +1,3 @@
+JSON_INDENT=4
+HASHSEED=1
+export JSON_INDENT HASHSEED

+ 1 - 0
jansson.mod/jansson/test/suites/encoding-flags/indent-object/input

@@ -0,0 +1 @@
+{"a": 1, "b": 2}

Неке датотеке нису приказане због велике количине промена