├── .clang-format ├── .github ├── dependabot.yml └── workflows │ ├── fuzz.yml │ └── tests.yml ├── .gitignore ├── Android.mk ├── CHANGES ├── CMakeLists.txt ├── CONTRIBUTING.md ├── CleanSpec.mk ├── LICENSE ├── Makefile.am ├── README.rst ├── SECURITY.md ├── android └── jansson_config.h ├── appveyor.yml ├── cmake ├── CheckFunctionKeywords.cmake ├── CodeCoverage.cmake ├── FindSphinx.cmake ├── janssonConfig.cmake.in ├── jansson_config.h.cmake └── jansson_private_config.h.cmake ├── configure.ac ├── doc ├── .gitignore ├── .readthedocs.yaml ├── Makefile.am ├── README ├── apiref.rst ├── changes.rst ├── conf.py ├── conformance.rst ├── ext │ └── refcounting.py ├── gettingstarted.rst ├── github_commits.c ├── index.rst ├── threadsafety.rst ├── tutorial.rst └── upgrading.rst ├── examples ├── README.rst └── simple_parse.c ├── jansson.pc.in ├── release.sh ├── scripts ├── clang-format └── clang-format-check ├── src ├── Makefile.am ├── dtoa.c ├── dump.c ├── error.c ├── hashtable.c ├── hashtable.h ├── hashtable_seed.c ├── jansson.def ├── jansson.h ├── jansson_config.h.in ├── jansson_private.h ├── load.c ├── lookup3.h ├── memory.c ├── pack_unpack.c ├── strbuffer.c ├── strbuffer.h ├── strconv.c ├── utf.c ├── utf.h ├── value.c └── version.c └── test ├── .gitignore ├── Makefile.am ├── bin ├── Makefile.am └── json_process.c ├── ossfuzz ├── .gitignore ├── Makefile.am ├── json_load_dump_fuzzer.cc ├── ossfuzz.sh ├── standaloneengine.cc └── testinput.h ├── run-suites ├── scripts ├── run-tests.sh └── valgrind.sh └── suites ├── .gitattributes ├── Makefile.am ├── api ├── Makefile.am ├── check-exports ├── run ├── test_array.c ├── test_chaos.c ├── test_copy.c ├── test_dump.c ├── test_dump_callback.c ├── test_equal.c ├── test_fixed_size.c ├── test_load.c ├── test_load_callback.c ├── test_loadb.c ├── test_memory_funcs.c ├── test_number.c ├── test_object.c ├── test_pack.c ├── test_simple.c ├── test_sprintf.c ├── test_unpack.c ├── test_version.c └── util.h ├── encoding-flags ├── array │ ├── input │ └── output ├── compact-array │ ├── env │ ├── input │ └── output ├── compact-object │ ├── env │ ├── input │ └── output ├── ensure-ascii │ ├── env │ ├── input │ └── output ├── indent-array │ ├── env │ ├── input │ └── output ├── indent-compact-array │ ├── env │ ├── input │ └── output ├── indent-compact-object │ ├── env │ ├── input │ └── output ├── indent-object │ ├── env │ ├── input │ └── output ├── object │ ├── env │ ├── input │ └── output ├── preserve-order │ ├── env │ ├── input │ └── output ├── real-precision │ ├── env │ ├── input │ └── output ├── run └── sort-keys │ ├── env │ ├── input │ └── output ├── invalid-unicode ├── encoded-surrogate-half │ ├── error │ └── input ├── invalid-utf-8-after-backslash │ ├── error │ └── input ├── invalid-utf-8-in-array │ ├── error │ └── input ├── invalid-utf-8-in-bigger-int │ ├── error │ └── input ├── invalid-utf-8-in-escape │ ├── error │ └── input ├── invalid-utf-8-in-exponent │ ├── error │ └── input ├── invalid-utf-8-in-identifier │ ├── error │ └── input ├── invalid-utf-8-in-int │ ├── error │ └── input ├── invalid-utf-8-in-real-after-e │ ├── error │ └── input ├── invalid-utf-8-in-string │ ├── error │ └── input ├── lone-invalid-utf-8 │ ├── error │ └── input ├── lone-utf-8-continuation-byte │ ├── error │ └── input ├── not-in-unicode-range │ ├── error │ └── input ├── overlong-3-byte-encoding │ ├── error │ └── input ├── overlong-4-byte-encoding │ ├── error │ └── input ├── overlong-ascii-encoding │ ├── error │ └── input ├── restricted-utf-8 │ ├── error │ └── input ├── run └── truncated-utf-8 │ ├── error │ └── input ├── invalid ├── apostrophe │ ├── error │ └── input ├── ascii-unicode-identifier │ ├── error │ └── input ├── brace-comma │ ├── error │ └── input ├── bracket-comma │ ├── error │ └── input ├── bracket-one-comma │ ├── error.normal │ ├── error.strip │ └── input ├── empty │ ├── error │ └── input ├── extra-comma-in-array │ ├── error │ └── input ├── extra-comma-in-multiline-array │ ├── error │ └── input ├── garbage-after-newline │ ├── error │ └── input ├── garbage-at-the-end │ ├── error │ └── input ├── integer-starting-with-zero │ ├── error │ └── input ├── invalid-escape │ ├── error │ └── input ├── invalid-identifier │ ├── error │ └── input ├── invalid-negative-integer │ ├── error │ └── input ├── invalid-negative-real │ ├── error │ └── input ├── invalid-second-surrogate │ ├── error │ └── input ├── invalid-unicode-escape │ ├── error │ └── input ├── lone-open-brace │ ├── error.normal │ ├── error.strip │ └── input ├── lone-open-bracket │ ├── error.normal │ ├── error.strip │ └── input ├── lone-second-surrogate │ ├── error │ └── input ├── minus-sign-without-number │ ├── error │ └── input ├── negative-integer-starting-with-zero │ ├── error │ └── input ├── null-byte-in-object-key │ ├── error │ └── input ├── null-byte-in-string │ ├── error │ ├── input │ └── nostrip ├── null-byte-outside-string │ ├── error │ ├── input │ └── nostrip ├── null-escape-in-string │ ├── error │ └── input ├── null │ ├── error │ └── input ├── object-apostrophes │ ├── error │ └── input ├── object-garbage-at-end │ ├── error │ └── input ├── object-in-unterminated-array │ ├── error.normal │ ├── error.strip │ └── input ├── object-no-colon │ ├── error.normal │ ├── error.strip │ └── input ├── object-no-value │ ├── error.normal │ ├── error.strip │ └── input ├── object-unterminated-value │ ├── error.normal │ ├── error.strip │ └── input ├── real-garbage-after-e │ ├── error │ └── input ├── real-negative-overflow │ ├── error │ └── input ├── real-positive-overflow │ ├── error │ └── input ├── real-truncated-at-e │ ├── error │ └── input ├── real-truncated-at-point │ ├── error │ └── input ├── recursion-depth │ ├── error │ └── input ├── run ├── tab-character-in-string │ ├── error │ └── input ├── too-big-negative-integer │ ├── error │ └── input ├── too-big-positive-integer │ ├── error │ └── input ├── truncated-unicode-surrogate │ ├── error │ └── input ├── unicode-identifier │ ├── error │ └── input ├── unterminated-array-and-object │ ├── error.normal │ ├── error.strip │ └── input ├── unterminated-array │ ├── error.normal │ ├── error.strip │ └── input ├── unterminated-empty-key │ ├── error.normal │ ├── error.strip │ └── input ├── unterminated-key │ ├── error.normal │ ├── error.strip │ └── input ├── unterminated-object-and-array │ ├── error │ └── input └── unterminated-string │ ├── error.normal │ ├── error.strip │ └── input └── valid ├── complex-array ├── env ├── input └── output ├── empty-array ├── input └── output ├── empty-object-in-array ├── input └── output ├── empty-object ├── input └── output ├── empty-string ├── input └── output ├── escaped-utf-control-char ├── input └── output ├── false ├── input └── output ├── negative-int ├── input └── output ├── negative-one ├── input └── output ├── negative-zero ├── input └── output ├── null ├── input └── output ├── one-byte-utf-8 ├── input └── output ├── real-capital-e-negative-exponent ├── input └── output ├── real-capital-e-positive-exponent ├── input └── output ├── real-capital-e ├── input └── output ├── real-exponent-no-dtoa ├── input ├── output └── skip_if_dtoa ├── real-exponent ├── input ├── output └── skip_unless_dtoa ├── real-fraction-exponent ├── input └── output ├── real-negative-exponent ├── input └── output ├── real-positive-exponent ├── input └── output ├── real-subnormal-number ├── input └── output ├── real-underflow ├── input └── output ├── run ├── short-string ├── input └── output ├── simple-ascii-string ├── input └── output ├── simple-int-0 ├── input └── output ├── simple-int-1 ├── input └── output ├── simple-int-123 ├── input └── output ├── simple-object ├── input └── output ├── simple-real ├── input └── output ├── string-escapes ├── input └── output ├── three-byte-utf-8 ├── input └── output ├── true ├── input └── output ├── two-byte-utf-8 ├── input └── output ├── utf-8-string ├── input └── output └── utf-surrogate-four-byte-encoding ├── input └── output /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | AlignConsecutiveMacros: true 3 | ColumnLimit: 90 4 | IndentCaseLabels: true 5 | IndentWidth: 4 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "monthly" 12 | groups: 13 | github-actions: 14 | patterns: 15 | - "*" 16 | -------------------------------------------------------------------------------- /.github/workflows/fuzz.yml: -------------------------------------------------------------------------------- 1 | name: oss-fuzz 2 | 3 | on: 4 | pull_request: 5 | branches: [ master ] 6 | paths: 7 | - '**.c' 8 | - '**.h' 9 | 10 | jobs: 11 | fuzz: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Build Fuzzers 15 | id: build 16 | uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master 17 | with: 18 | oss-fuzz-project-name: 'jansson' 19 | dry-run: false 20 | - name: Run Fuzzers 21 | uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master 22 | with: 23 | oss-fuzz-project-name: 'jansson' 24 | fuzz-seconds: 600 25 | dry-run: false 26 | - name: Upload Crash 27 | uses: actions/upload-artifact@v4 28 | if: failure() && steps.build.outcome == 'success' 29 | with: 30 | name: artifacts 31 | path: ./out/artifacts 32 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | lint: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - run: ./scripts/clang-format-check 15 | 16 | autotools: 17 | strategy: 18 | matrix: 19 | os: ["ubuntu-latest", "macos-latest"] 20 | cc: ["gcc", "clang"] 21 | dtoa: ["yes", "no"] 22 | 23 | runs-on: ${{ matrix.os }} 24 | 25 | steps: 26 | - if: ${{runner.os == 'macOS'}} 27 | run: brew install autoconf automake libtool 28 | - uses: actions/checkout@v4 29 | - run: autoreconf -fi 30 | - env: 31 | CC: ${{ matrix.cc }} 32 | CFLAGS: -Werror 33 | run: ./configure --enable-dtoa=${{ matrix.dtoa }} 34 | - run: make check 35 | 36 | cmake: 37 | strategy: 38 | matrix: 39 | os: ["ubuntu-latest", "macos-latest", "windows-latest"] 40 | cc: ["gcc", "clang"] 41 | exclude: 42 | - os: windows-latest 43 | cc: gcc 44 | - os: windows-latest 45 | cc: clang 46 | include: 47 | - os: windows-latest 48 | cc: 'msvc' # Doesn't really matter, MSVC is always used on Windows 49 | 50 | runs-on: ${{matrix.os}} 51 | 52 | steps: 53 | - uses: actions/checkout@v4 54 | - env: 55 | CC: ${{matrix.cc}} 56 | run: cmake . 57 | - run: cmake --build . 58 | - run: ctest --output-on-failure 59 | 60 | valgrind: 61 | runs-on: ubuntu-latest 62 | steps: 63 | - uses: actions/checkout@v4 64 | - run: sudo apt update && sudo apt install valgrind 65 | - run: cmake -DJANSSON_TEST_WITH_VALGRIND=ON . 66 | - run: cmake --build . 67 | - run: ctest --output-on-failure 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | *.a 4 | .libs 5 | .deps 6 | Makefile 7 | Makefile.in 8 | aclocal.m4 9 | autom4te.cache 10 | config.guess 11 | config.h 12 | config.h.in 13 | config.log 14 | config.status 15 | config.sub 16 | configure 17 | depcomp 18 | install-sh 19 | libtool 20 | ltmain.sh 21 | missing 22 | compile 23 | test-driver 24 | *.lo 25 | *.la 26 | stamp-h1 27 | *.pyc 28 | *.pc 29 | /src/jansson_config.h 30 | /jansson_private_config.h.in 31 | /jansson_private_config.h 32 | /build 33 | *.exe 34 | .idea 35 | cmake-build-debug/ 36 | *.log 37 | *.trs -------------------------------------------------------------------------------- /Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir) 2 | include $(CLEAR_VARS) 3 | 4 | LOCAL_ARM_MODE := arm 5 | 6 | LOCAL_SRC_FILES := \ 7 | src/dump.c \ 8 | src/error.c \ 9 | src/hashtable.c \ 10 | src/hashtable_seed.c \ 11 | src/load.c \ 12 | src/memory.c \ 13 | src/pack_unpack.c \ 14 | src/strbuffer.c \ 15 | src/strconv.c \ 16 | src/utf.c \ 17 | src/value.c 18 | 19 | LOCAL_C_INCLUDES += \ 20 | $(LOCAL_PATH) \ 21 | $(LOCAL_PATH)/android \ 22 | $(LOCAL_PATH)/src 23 | 24 | LOCAL_MODULE_TAGS := optional 25 | LOCAL_SHARED_LIBRARIES := libc 26 | LOCAL_CFLAGS += -O3 -DHAVE_STDINT_H=1 27 | 28 | LOCAL_MODULE:= libjansson 29 | 30 | include $(BUILD_SHARED_LIBRARY) 31 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Hi, and thanks for contributing! 2 | 3 | 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. 4 | -------------------------------------------------------------------------------- /CleanSpec.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007 The Android Open Source Project 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | # If you don't need to do a full clean build but would like to touch 17 | # a file or delete some intermediate files, add a clean step to the end 18 | # of the list. These steps will only be run once, if they haven't been 19 | # run before. 20 | # 21 | # E.g.: 22 | # $(call add-clean-step, touch -c external/sqlite/sqlite3.h) 23 | # $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) 24 | # 25 | # Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with 26 | # files that are missing or have been moved. 27 | # 28 | # Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. 29 | # Use $(OUT_DIR) to refer to the "out" directory. 30 | # 31 | # If you need to re-do something that's already mentioned, just copy 32 | # the command and add it to the bottom of the list. E.g., if a change 33 | # that you made last week required touching a file and a change you 34 | # made today requires touching the same file, just copy the old 35 | # touch step and add it to the end of the list. 36 | # 37 | # ************************************************ 38 | # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST 39 | # ************************************************ 40 | 41 | # For example: 42 | #$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) 43 | #$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) 44 | #$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) 45 | #$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) 46 | 47 | # ************************************************ 48 | # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST 49 | # ************************************************ 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | This project is licensed under the MIT license, except where otherwise noted. 4 | The full text of the MIT license is included below. 5 | 6 | ## MIT License 7 | 8 | Copyright (c) 2009-2024 Petri Lehtinen 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | 28 | ## Exceptions 29 | 30 | ### `src/dtoa.c` 31 | 32 | Copyright (c) 1991, 2000, 2001 by Lucent Technologies. 33 | 34 | Permission to use, copy, modify, and distribute this software for any 35 | purpose without fee is hereby granted, provided that this entire notice 36 | is included in all copies of any software which is or includes a copy 37 | or modification of this software and in all copies of the supporting 38 | documentation for such software. 39 | 40 | THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED 41 | WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY 42 | REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY 43 | OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 44 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = CHANGES LICENSE README.rst CMakeLists.txt cmake android examples scripts 2 | SUBDIRS = doc src test 3 | 4 | # "make distcheck" builds the dvi target, so use it to check that the 5 | # documentation is built correctly. 6 | dvi: 7 | $(MAKE) SPHINXOPTS_EXTRA=-W html 8 | 9 | pkgconfigdir = $(libdir)/pkgconfig 10 | pkgconfig_DATA = jansson.pc 11 | 12 | TESTS = scripts/clang-format-check 13 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Jansson README 2 | ============== 3 | 4 | .. |tests| image:: https://github.com/akheron/jansson/workflows/tests/badge.svg 5 | .. |appveyor| image:: https://ci.appveyor.com/api/projects/status/lmhkkc4q8cwc65ko 6 | 7 | |tests| |appveyor| 8 | 9 | Jansson_ is a C library for encoding, decoding and manipulating JSON 10 | data. Its main features and design principles are: 11 | 12 | - Simple and intuitive API and data model 13 | 14 | - `Comprehensive documentation`_ 15 | 16 | - No dependencies on other libraries 17 | 18 | - Full Unicode support (UTF-8) 19 | 20 | - Extensive test suite 21 | 22 | Jansson is licensed under the `MIT license`_; see LICENSE in the 23 | source distribution for details. 24 | 25 | Compilation and Installation 26 | ---------------------------- 27 | 28 | If you obtained a ``jansson-X.Y.tar.*`` tarball from GitHub Releases, just use 29 | the standard autotools commands:: 30 | 31 | $ ./configure 32 | $ make 33 | $ make install 34 | 35 | To run the test suite, invoke:: 36 | 37 | $ make check 38 | 39 | If the source has been checked out from a Git repository, the ``configure`` 40 | script has to be generated first. The easiest way is to use autoreconf:: 41 | 42 | $ autoreconf -i 43 | 44 | 45 | Documentation 46 | ------------- 47 | 48 | Documentation is available at http://jansson.readthedocs.io/en/latest/. 49 | 50 | The documentation source is in the ``doc/`` subdirectory. To generate 51 | HTML documentation, invoke:: 52 | 53 | $ make html 54 | 55 | Then, point your browser to ``doc/_build/html/index.html``. Sphinx_ 56 | 1.0 or newer is required to generate the documentation. 57 | 58 | 59 | Community 60 | --------- 61 | 62 | * `Documentation `_ 63 | * `Issue tracker `_ 64 | * `Mailing list `_ 65 | * `Wiki `_ contains some development documentation 66 | 67 | .. _Jansson: http://www.digip.org/jansson/ 68 | .. _`Comprehensive documentation`: http://jansson.readthedocs.io/en/latest/ 69 | .. _`MIT license`: http://www.opensource.org/licenses/mit-license.php 70 | .. _Sphinx: http://sphinx.pocoo.org/ 71 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Latest released version. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | Send an email to petri@digip.org. 10 | -------------------------------------------------------------------------------- /android/jansson_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | * 7 | * 8 | * This file specifies a part of the site-specific configuration for 9 | * Jansson, namely those things that affect the public API in 10 | * jansson.h. 11 | * 12 | * The configure script copies this file to jansson_config.h and 13 | * replaces @var@ substitutions by values that fit your system. If you 14 | * cannot run the configure script, you can do the value substitution 15 | * by hand. 16 | */ 17 | 18 | #ifndef JANSSON_CONFIG_H 19 | #define JANSSON_CONFIG_H 20 | 21 | /* If your compiler supports the inline keyword in C, JSON_INLINE is 22 | defined to `inline', otherwise empty. In C++, the inline is always 23 | supported. */ 24 | #ifdef __cplusplus 25 | #define JSON_INLINE inline 26 | #else 27 | #define JSON_INLINE inline 28 | #endif 29 | 30 | /* If your compiler supports the `long long` type and the strtoll() 31 | library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, 32 | otherwise to 0. */ 33 | #define JSON_INTEGER_IS_LONG_LONG 1 34 | 35 | /* Maximum recursion depth for parsing JSON input. 36 | This limits the depth of e.g. array-within-array constructions. */ 37 | #define JSON_PARSER_MAX_DEPTH 2048 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - VS: Visual Studio 9 2008 4 | - VS: Visual Studio 10 2010 5 | - VS: Visual Studio 11 2012 6 | - VS: Visual Studio 12 2013 7 | - VS: Visual Studio 14 2015 8 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 9 | VS: Visual Studio 15 2017 10 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 11 | VS: Visual Studio 16 2019 12 | 13 | build_script: 14 | - md build 15 | - cd build 16 | - cmake -G "%VS%" .. 17 | - cmake --build . --config Release 18 | - ctest --output-on-failure 19 | -------------------------------------------------------------------------------- /cmake/CheckFunctionKeywords.cmake: -------------------------------------------------------------------------------- 1 | include(CheckCSourceCompiles) 2 | 3 | macro(check_function_keywords _wordlist) 4 | set(${_result} "") 5 | foreach(flag ${_wordlist}) 6 | string(REGEX REPLACE "[-+/ ()]" "_" flagname "${flag}") 7 | string(TOUPPER "${flagname}" flagname) 8 | set(have_flag "HAVE_${flagname}") 9 | check_c_source_compiles("${flag} void func(); void func() { } int main() { func(); return 0; }" ${have_flag}) 10 | if(${have_flag} AND NOT ${_result}) 11 | set(${_result} "${flag}") 12 | # break() 13 | endif(${have_flag} AND NOT ${_result}) 14 | endforeach(flag) 15 | endmacro(check_function_keywords) 16 | -------------------------------------------------------------------------------- /cmake/CodeCoverage.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Boost Software License - Version 1.0 - August 17th, 2003 3 | # 4 | # Permission is hereby granted, free of charge, to any person or organization 5 | # obtaining a copy of the software and accompanying documentation covered by 6 | # this license (the "Software") to use, reproduce, display, distribute, 7 | # execute, and transmit the Software, and to prepare derivative works of the 8 | # Software, and to permit third-parties to whom the Software is furnished to 9 | # do so, all subject to the following: 10 | # 11 | # The copyright notices in the Software and this entire statement, including 12 | # the above license grant, this restriction and the following disclaimer, 13 | # must be included in all copies of the Software, in whole or in part, and 14 | # all derivative works of the Software, unless such copies or derivative 15 | # works are solely in the form of machine-executable object code generated by 16 | # a source language processor. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 21 | # SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 22 | # FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 23 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | # DEALINGS IN THE SOFTWARE. 25 | # 26 | # 2012-01-31, Lars Bilke 27 | # - Enable Code Coverage 28 | # 29 | # 2013-09-17, Joakim Söderberg 30 | # - Added support for Clang. 31 | # - Some additional usage instructions. 32 | # 33 | # USAGE: 34 | # 1. Copy this file into your cmake modules path. 35 | # 36 | # 2. Add the following line to your CMakeLists.txt: 37 | # INCLUDE(CodeCoverage) 38 | # 39 | # 3. Set compiler flags to turn off optimization and enable coverage: 40 | # SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") 41 | # SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") 42 | # 43 | # 3. Use the function SETUP_TARGET_FOR_COVERAGE to create a custom make target 44 | # which runs your test executable and produces a lcov code coverage report: 45 | # Example: 46 | # SETUP_TARGET_FOR_COVERAGE( 47 | # my_coverage_target # Name for custom target. 48 | # test_driver # Name of the test driver executable that runs the tests. 49 | # # NOTE! This should always have a ZERO as exit code 50 | # # otherwise the coverage generation will not complete. 51 | # coverage # Name of output directory. 52 | # ) 53 | # 54 | # 4. Build a Debug build: 55 | # cmake -DCMAKE_BUILD_TYPE=Debug .. 56 | # make 57 | # make my_coverage_target 58 | # 59 | # 60 | 61 | # Check prereqs 62 | FIND_PROGRAM( GCOV_PATH gcov ) 63 | FIND_PROGRAM( LCOV_PATH lcov ) 64 | FIND_PROGRAM( GENHTML_PATH genhtml ) 65 | FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests) 66 | 67 | IF(NOT GCOV_PATH) 68 | MESSAGE(FATAL_ERROR "gcov not found! Aborting...") 69 | ENDIF() # NOT GCOV_PATH 70 | 71 | IF(NOT (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUCC)) 72 | # Clang version 3.0.0 and greater now supports gcov as well. 73 | MESSAGE(WARNING "Compiler is not GNU gcc! Clang Version 3.0.0 and greater supports gcov as well, but older versions don't.") 74 | 75 | IF(NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")) 76 | MESSAGE(FATAL_ERROR "Compiler is not GNU gcc or Clang! Aborting...") 77 | ENDIF() 78 | ENDIF() # NOT CMAKE_COMPILER_IS_GNUCXX 79 | 80 | IF ( NOT CMAKE_BUILD_TYPE STREQUAL "Debug" ) 81 | MESSAGE( WARNING "Code coverage results with an optimized (non-Debug) build may be misleading" ) 82 | ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug" 83 | 84 | 85 | # Param _targetname The name of new the custom make target 86 | # Param _outputname lcov output is generated as _outputname.info 87 | # HTML report is generated in _outputname/index.html 88 | # Param _testrunner The name of the target which runs the tests. 89 | # MUST return ZERO always, even on errors. 90 | # If not, no coverage report will be created! 91 | # Optional fourth parameter is passed as arguments to _testrunner 92 | # Pass them in list form, e.g.: "-j;2" for -j 2 93 | FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _outputname _testrunner) 94 | 95 | IF(NOT LCOV_PATH) 96 | MESSAGE(FATAL_ERROR "lcov not found! Aborting...") 97 | ENDIF() # NOT LCOV_PATH 98 | 99 | IF(NOT GENHTML_PATH) 100 | MESSAGE(FATAL_ERROR "genhtml not found! Aborting...") 101 | ENDIF() # NOT GENHTML_PATH 102 | 103 | # Setup target 104 | ADD_CUSTOM_TARGET(${_targetname} 105 | 106 | # Cleanup lcov 107 | ${LCOV_PATH} --directory . --zerocounters 108 | 109 | # Run tests 110 | COMMAND ${_testrunner} ${ARGV3} 111 | 112 | # Capturing lcov counters and generating report 113 | COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info --rc lcov_branch_coverage=1 114 | COMMAND ${LCOV_PATH} --remove ${_outputname}.info '*/build/include/*' '*/test/*' '/usr/include/*' --output-file ${_outputname}.info --rc lcov_branch_coverage=1 115 | # COMMAND ${GENHTML_PATH} --branch-coverage -o ${_outputname} ${_outputname}.info.cleaned 116 | # COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned 117 | 118 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 119 | COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." 120 | ) 121 | 122 | # Show info where to find the report 123 | ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD 124 | COMMAND ; 125 | COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report." 126 | ) 127 | 128 | ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE 129 | 130 | # Param _targetname The name of new the custom make target 131 | # Param _testrunner The name of the target which runs the tests 132 | # Param _outputname cobertura output is generated as _outputname.xml 133 | # Optional fourth parameter is passed as arguments to _testrunner 134 | # Pass them in list form, e.g.: "-j;2" for -j 2 135 | FUNCTION(SETUP_TARGET_FOR_COVERAGE_COBERTURA _targetname _testrunner _outputname) 136 | 137 | IF(NOT PYTHON_EXECUTABLE) 138 | MESSAGE(FATAL_ERROR "Python not found! Aborting...") 139 | ENDIF() # NOT PYTHON_EXECUTABLE 140 | 141 | IF(NOT GCOVR_PATH) 142 | MESSAGE(FATAL_ERROR "gcovr not found! Aborting...") 143 | ENDIF() # NOT GCOVR_PATH 144 | 145 | ADD_CUSTOM_TARGET(${_targetname} 146 | 147 | # Run tests 148 | ${_testrunner} ${ARGV3} 149 | 150 | # Running gcovr 151 | COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} -e '${CMAKE_SOURCE_DIR}/tests/' -o ${_outputname}.xml 152 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 153 | COMMENT "Running gcovr to produce Cobertura code coverage report." 154 | ) 155 | 156 | # Show info where to find the report 157 | ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD 158 | COMMAND ; 159 | COMMENT "Cobertura code coverage report saved in ${_outputname}.xml." 160 | ) 161 | 162 | ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE_COBERTURA 163 | 164 | -------------------------------------------------------------------------------- /cmake/janssonConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include("${CMAKE_CURRENT_LIST_DIR}/janssonTargets.cmake") 4 | check_required_components("@PROJECT_NAME@") 5 | -------------------------------------------------------------------------------- /cmake/jansson_config.h.cmake: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | * 7 | * 8 | * This file specifies a part of the site-specific configuration for 9 | * Jansson, namely those things that affect the public API in 10 | * jansson.h. 11 | * 12 | * The CMake system will generate the jansson_config.h file and 13 | * copy it to the build and install directories. 14 | */ 15 | 16 | #ifndef JANSSON_CONFIG_H 17 | #define JANSSON_CONFIG_H 18 | 19 | /* Define this so that we can disable scattered automake configuration in source files */ 20 | #ifndef JANSSON_USING_CMAKE 21 | #define JANSSON_USING_CMAKE 22 | #endif 23 | 24 | /* If your compiler supports the `long long` type and the strtoll() 25 | library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, 26 | otherwise to 0. */ 27 | #cmakedefine JSON_INTEGER_IS_LONG_LONG 1 28 | 29 | /* Bring in the cmake-detected defines */ 30 | #cmakedefine HAVE_STDINT_H 1 31 | #cmakedefine HAVE_INTTYPES_H 1 32 | #cmakedefine HAVE_SYS_TYPES_H 1 33 | 34 | /* Include our standard type header for the integer typedef */ 35 | 36 | #if defined(HAVE_STDINT_H) 37 | # include 38 | #elif defined(HAVE_INTTYPES_H) 39 | # include 40 | #elif defined(HAVE_SYS_TYPES_H) 41 | # include 42 | #endif 43 | 44 | 45 | /* If your compiler supports the inline keyword in C, JSON_INLINE is 46 | defined to `inline', otherwise empty. In C++, the inline is always 47 | supported. */ 48 | #ifdef __cplusplus 49 | #define JSON_INLINE inline 50 | #else 51 | #define JSON_INLINE @JSON_INLINE@ 52 | #endif 53 | 54 | 55 | #define json_int_t @JSON_INT_T@ 56 | #define json_strtoint @JSON_STRTOINT@ 57 | #define JSON_INTEGER_FORMAT @JSON_INTEGER_FORMAT@ 58 | 59 | 60 | /* If __atomic builtins are available they will be used to manage 61 | reference counts of json_t. */ 62 | #define JSON_HAVE_ATOMIC_BUILTINS @JSON_HAVE_ATOMIC_BUILTINS@ 63 | 64 | /* If __atomic builtins are not available we try using __sync builtins 65 | to manage reference counts of json_t. */ 66 | #define JSON_HAVE_SYNC_BUILTINS @JSON_HAVE_SYNC_BUILTINS@ 67 | 68 | /* Maximum recursion depth for parsing JSON input. 69 | This limits the depth of e.g. array-within-array constructions. */ 70 | #define JSON_PARSER_MAX_DEPTH 2048 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /cmake/jansson_private_config.h.cmake: -------------------------------------------------------------------------------- 1 | #cmakedefine HAVE_ENDIAN_H 1 2 | #cmakedefine HAVE_FCNTL_H 1 3 | #cmakedefine HAVE_SCHED_H 1 4 | #cmakedefine HAVE_UNISTD_H 1 5 | #cmakedefine HAVE_SYS_PARAM_H 1 6 | #cmakedefine HAVE_SYS_STAT_H 1 7 | #cmakedefine HAVE_SYS_TIME_H 1 8 | #cmakedefine HAVE_SYS_TYPES_H 1 9 | #cmakedefine HAVE_STDINT_H 1 10 | 11 | #cmakedefine HAVE_CLOSE 1 12 | #cmakedefine HAVE_GETPID 1 13 | #cmakedefine HAVE_GETTIMEOFDAY 1 14 | #cmakedefine HAVE_OPEN 1 15 | #cmakedefine HAVE_READ 1 16 | #cmakedefine HAVE_SCHED_YIELD 1 17 | 18 | #cmakedefine HAVE_SYNC_BUILTINS 1 19 | #cmakedefine HAVE_ATOMIC_BUILTINS 1 20 | 21 | #cmakedefine HAVE_LOCALE_H 1 22 | #cmakedefine HAVE_SETLOCALE 1 23 | 24 | #cmakedefine WORDS_BIGENDIAN 1 25 | 26 | #cmakedefine HAVE_INT32_T 1 27 | #ifndef HAVE_INT32_T 28 | # define int32_t @JSON_INT32@ 29 | #endif 30 | 31 | #cmakedefine HAVE_UINT32_T 1 32 | #ifndef HAVE_UINT32_T 33 | # define uint32_t @JSON_UINT32@ 34 | #endif 35 | 36 | #cmakedefine HAVE_UINT16_T 1 37 | #ifndef HAVE_UINT16_T 38 | # define uint16_t @JSON_UINT16@ 39 | #endif 40 | 41 | #cmakedefine HAVE_UINT8_T 1 42 | #ifndef HAVE_UINT8_T 43 | # define uint8_t @JSON_UINT8@ 44 | #endif 45 | 46 | #cmakedefine HAVE_SSIZE_T 1 47 | 48 | #ifndef HAVE_SSIZE_T 49 | # define ssize_t @JSON_SSIZE@ 50 | #endif 51 | 52 | #cmakedefine USE_URANDOM 1 53 | #cmakedefine USE_WINDOWS_CRYPTOAPI 1 54 | 55 | #cmakedefine USE_DTOA 1 56 | #if USE_DTOA 57 | # define DTOA_ENABLED 1 58 | #else 59 | # define DTOA_ENABLED 0 60 | #endif 61 | 62 | #define INITIAL_HASHTABLE_ORDER @JANSSON_INITIAL_HASHTABLE_ORDER@ 63 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.60]) 2 | AC_INIT([jansson], [2.14.1], [https://github.com/akheron/jansson/issues]) 3 | 4 | AC_CONFIG_AUX_DIR([.]) 5 | AM_INIT_AUTOMAKE([1.10 foreign]) 6 | 7 | AC_CONFIG_SRCDIR([src/value.c]) 8 | AC_CONFIG_HEADERS([jansson_private_config.h]) 9 | 10 | # Checks for programs. 11 | AC_PROG_CC 12 | AC_PROG_CXX 13 | AC_PROG_LIBTOOL 14 | AM_CONDITIONAL([GCC], [test x$GCC = xyes]) 15 | 16 | # Checks for libraries. 17 | 18 | # Checks for header files. 19 | AC_CHECK_HEADERS([endian.h fcntl.h locale.h sched.h unistd.h sys/param.h sys/stat.h sys/time.h sys/types.h]) 20 | 21 | # Checks for typedefs, structures, and compiler characteristics. 22 | AC_TYPE_INT32_T 23 | AC_TYPE_UINT32_T 24 | AC_TYPE_UINT16_T 25 | AC_TYPE_UINT8_T 26 | AC_TYPE_LONG_LONG_INT 27 | 28 | AC_C_BIGENDIAN 29 | 30 | AC_C_INLINE 31 | case $ac_cv_c_inline in 32 | yes) json_inline=inline;; 33 | no) json_inline=;; 34 | *) json_inline=$ac_cv_c_inline;; 35 | esac 36 | AC_SUBST([json_inline]) 37 | 38 | # Checks for library functions. 39 | AC_CHECK_FUNCS([close getpid gettimeofday open read setlocale sched_yield strtoll]) 40 | 41 | AC_MSG_CHECKING([for gcc __sync builtins]) 42 | have_sync_builtins=no 43 | AC_TRY_LINK( 44 | [], [unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1); __sync_add_and_fetch(&val, 1); __sync_sub_and_fetch(&val, 1);], 45 | [have_sync_builtins=yes], 46 | ) 47 | if test "x$have_sync_builtins" = "xyes"; then 48 | AC_DEFINE([HAVE_SYNC_BUILTINS], [1], 49 | [Define to 1 if gcc's __sync builtins are available]) 50 | json_have_sync_builtins=1 51 | else 52 | json_have_sync_builtins=0 53 | fi 54 | AC_SUBST([json_have_sync_builtins]) 55 | AC_MSG_RESULT([$have_sync_builtins]) 56 | 57 | AC_MSG_CHECKING([for gcc __atomic builtins]) 58 | have_atomic_builtins=no 59 | AC_TRY_LINK( 60 | [], [char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_RELEASE); __atomic_load_n(&v, __ATOMIC_ACQUIRE); __atomic_add_fetch(&v, 1, __ATOMIC_ACQUIRE); __atomic_sub_fetch(&v, 1, __ATOMIC_RELEASE);], 61 | [have_atomic_builtins=yes], 62 | ) 63 | if test "x$have_atomic_builtins" = "xyes"; then 64 | AC_DEFINE([HAVE_ATOMIC_BUILTINS], [1], 65 | [Define to 1 if gcc's __atomic builtins are available]) 66 | json_have_atomic_builtins=1 67 | else 68 | json_have_atomic_builtins=0 69 | fi 70 | AC_SUBST([json_have_atomic_builtins]) 71 | AC_MSG_RESULT([$have_atomic_builtins]) 72 | 73 | case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in 74 | yesyes) json_have_long_long=1;; 75 | *) json_have_long_long=0;; 76 | esac 77 | AC_SUBST([json_have_long_long]) 78 | 79 | # Features 80 | AC_ARG_ENABLE([urandom], 81 | [AS_HELP_STRING([--disable-urandom], 82 | [Don't use /dev/urandom to seed the hash function])], 83 | [use_urandom=$enableval], [use_urandom=yes]) 84 | 85 | if test "x$use_urandom" = xyes; then 86 | AC_DEFINE([USE_URANDOM], [1], 87 | [Define to 1 if /dev/urandom should be used for seeding the hash function]) 88 | fi 89 | 90 | AC_ARG_ENABLE([windows-cryptoapi], 91 | [AS_HELP_STRING([--disable-windows-cryptoapi], 92 | [Don't use CryptGenRandom to seed the hash function])], 93 | [use_windows_cryptoapi=$enableval], [use_windows_cryptoapi=yes]) 94 | 95 | if test "x$use_windows_cryptoapi" = xyes; then 96 | AC_DEFINE([USE_WINDOWS_CRYPTOAPI], [1], 97 | [Define to 1 if CryptGenRandom should be used for seeding the hash function]) 98 | fi 99 | 100 | AC_ARG_ENABLE([initial-hashtable-order], 101 | [AS_HELP_STRING([--enable-initial-hashtable-order=VAL], 102 | [Number of buckets new object hashtables contain is 2 raised to this power. The default is 3, so empty hashtables contain 2^3 = 8 buckets.])], 103 | [initial_hashtable_order=$enableval], [initial_hashtable_order=3]) 104 | AC_DEFINE_UNQUOTED([INITIAL_HASHTABLE_ORDER], [$initial_hashtable_order], 105 | [Number of buckets new object hashtables contain is 2 raised to this power. E.g. 3 -> 2^3 = 8.]) 106 | 107 | AC_ARG_ENABLE([Bsymbolic], 108 | [AS_HELP_STRING([--disable-Bsymbolic], 109 | [Avoid linking with -Bsymbolic-function])], 110 | [], [with_Bsymbolic=check]) 111 | 112 | if test "x$with_Bsymbolic" != "xno" ; then 113 | AC_MSG_CHECKING([for -Bsymbolic-functions linker flag]) 114 | saved_LDFLAGS="${LDFLAGS}" 115 | LDFLAGS=-Wl,-Bsymbolic-functions 116 | AC_TRY_LINK( 117 | [], [int main (void) { return 0; }], 118 | [AC_MSG_RESULT([yes]) 119 | have_Bsymbolic=yes], 120 | [AC_MSG_RESULT([no]) 121 | have_Bsymbolic=no] 122 | ) 123 | LDFLAGS="${saved_LDFLAGS}" 124 | 125 | if test "x$with_Bsymbolic" = "xcheck" ; then 126 | with_Bsymbolic=$have_Bsymbolic; 127 | fi 128 | if test "x$with_Bsymbolic:x$have_Bsymbolic" = "xyes:xno" ; then 129 | AC_MSG_ERROR([linker support is required for -Bsymbolic]) 130 | fi 131 | fi 132 | 133 | AS_IF([test "x$with_Bsymbolic" = "xyes"], [JSON_BSYMBOLIC_LDFLAGS=-Wl[,]-Bsymbolic-functions]) 134 | AC_SUBST(JSON_BSYMBOLIC_LDFLAGS) 135 | 136 | # Enable symbol versioning on GNU libc 137 | JSON_SYMVER_LDFLAGS= 138 | AC_CHECK_DECL([__GLIBC__], [JSON_SYMVER_LDFLAGS=-Wl,--default-symver]) 139 | AC_SUBST([JSON_SYMVER_LDFLAGS]) 140 | 141 | AC_ARG_ENABLE([dtoa], 142 | [AS_HELP_STRING([--enable-dtoa], [Use dtoa for optimal floating point to string conversion])], 143 | [case "$enableval" in 144 | yes) dtoa=yes ;; 145 | no) dtoa=no ;; 146 | *) AC_MSG_ERROR([bad value ${enableval} for --enable-dtoa]) ;; 147 | esac], [dtoa=yes]) 148 | if test "$dtoa" = "yes"; then 149 | AC_DEFINE([DTOA_ENABLED], [1], 150 | [Define to 1 to use dtoa to convert floating points to strings]) 151 | fi 152 | AM_CONDITIONAL([DTOA_ENABLED], [test "$dtoa" = "yes"]) 153 | 154 | AC_ARG_ENABLE([ossfuzzers], 155 | [AS_HELP_STRING([--enable-ossfuzzers], 156 | [Whether to generate the fuzzers for OSS-Fuzz])], 157 | [have_ossfuzzers=yes], [have_ossfuzzers=no]) 158 | AM_CONDITIONAL([USE_OSSFUZZERS], [test "x$have_ossfuzzers" = "xyes"]) 159 | 160 | 161 | AC_SUBST([LIB_FUZZING_ENGINE]) 162 | AM_CONDITIONAL([USE_OSSFUZZ_FLAG], [test "x$LIB_FUZZING_ENGINE" = "x-fsanitize=fuzzer"]) 163 | AM_CONDITIONAL([USE_OSSFUZZ_STATIC], [test -f "$LIB_FUZZING_ENGINE"]) 164 | 165 | 166 | if test x$GCC = xyes; then 167 | AC_MSG_CHECKING(for -Wno-format-truncation) 168 | wnoformat_truncation="-Wno-format-truncation" 169 | AS_IF([${CC} -Wno-format-truncation -Werror -S -o /dev/null -xc /dev/null > /dev/null 2>&1], 170 | [AC_MSG_RESULT(yes)], 171 | [AC_MSG_RESULT(no) 172 | wnoformat_truncation=""]) 173 | 174 | AM_CFLAGS="-Wall -Wextra -Wdeclaration-after-statement -Wshadow ${wnoformat_truncation}" 175 | fi 176 | AC_SUBST([AM_CFLAGS]) 177 | 178 | AC_CONFIG_FILES([ 179 | jansson.pc 180 | Makefile 181 | doc/Makefile 182 | src/Makefile 183 | src/jansson_config.h 184 | test/Makefile 185 | test/bin/Makefile 186 | test/ossfuzz/Makefile 187 | test/suites/Makefile 188 | test/suites/api/Makefile 189 | ]) 190 | AC_OUTPUT 191 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | -------------------------------------------------------------------------------- /doc/.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-22.04 5 | tools: 6 | python: "3.12" 7 | 8 | sphinx: 9 | configuration: doc/conf.py 10 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = conf.py apiref.rst changes.rst conformance.rst \ 2 | gettingstarted.rst github_commits.c index.rst threadsafety.rst \ 3 | tutorial.rst upgrading.rst ext/refcounting.py 4 | 5 | SPHINXBUILD = sphinx-build 6 | SPHINXOPTS = -d _build/doctrees $(SPHINXOPTS_EXTRA) 7 | 8 | html-local: 9 | $(SPHINXBUILD) -b html $(SPHINXOPTS) $(srcdir) _build/html 10 | 11 | install-html-local: html 12 | mkdir -p $(DESTDIR)$(htmldir) 13 | cp -r _build/html $(DESTDIR)$(htmldir) 14 | 15 | uninstall-local: 16 | rm -rf $(DESTDIR)$(htmldir) 17 | 18 | clean-local: 19 | rm -rf _build 20 | rm -f ext/refcounting.pyc 21 | -------------------------------------------------------------------------------- /doc/README: -------------------------------------------------------------------------------- 1 | To build the documentation, invoke 2 | 3 | make html 4 | 5 | Then point your browser to _build/html/index.html. 6 | -------------------------------------------------------------------------------- /doc/changes.rst: -------------------------------------------------------------------------------- 1 | ****************** 2 | Changes in Jansson 3 | ****************** 4 | 5 | .. include:: ../CHANGES 6 | -------------------------------------------------------------------------------- /doc/conformance.rst: -------------------------------------------------------------------------------- 1 | .. _rfc-conformance: 2 | 3 | *************** 4 | RFC Conformance 5 | *************** 6 | 7 | JSON is specified in :rfc:`4627`, *"The application/json Media Type 8 | for JavaScript Object Notation (JSON)"*. 9 | 10 | Character Encoding 11 | ================== 12 | 13 | Jansson only supports UTF-8 encoded JSON texts. It does not support or 14 | auto-detect any of the other encodings mentioned in the RFC, namely 15 | UTF-16LE, UTF-16BE, UTF-32LE or UTF-32BE. Pure ASCII is supported, as 16 | it's a subset of UTF-8. 17 | 18 | Strings 19 | ======= 20 | 21 | JSON strings are mapped to C-style null-terminated character arrays, 22 | and UTF-8 encoding is used internally. 23 | 24 | All Unicode codepoints U+0000 through U+10FFFF are allowed in string 25 | values. However, U+0000 is allowed in object keys only for length-aware functions. 26 | 27 | Unicode normalization or any other transformation is never performed 28 | on any strings (string values or object keys). When checking for 29 | equivalence of strings or object keys, the comparison is performed 30 | byte by byte between the original UTF-8 representations of the 31 | strings. 32 | 33 | Numbers 34 | ======= 35 | 36 | .. _real-vs-integer: 37 | 38 | Real vs. Integer 39 | ---------------- 40 | 41 | JSON makes no distinction between real and integer numbers; Jansson 42 | does. Real numbers are mapped to the ``double`` type and integers to 43 | the ``json_int_t`` type, which is a typedef of ``long long`` or 44 | ``long``, depending on whether ``long long`` is supported by your 45 | compiler or not. 46 | 47 | A JSON number is considered to be a real number if its lexical 48 | representation includes one of ``e``, ``E``, or ``.``; regardless if 49 | its actual numeric value is a true integer (e.g., all of ``1E6``, 50 | ``3.0``, ``400E-2``, and ``3.14E3`` are mathematical integers, but 51 | will be treated as real values). With the ``JSON_DECODE_INT_AS_REAL`` 52 | decoder flag set all numbers are interpreted as real. 53 | 54 | All other JSON numbers are considered integers. 55 | 56 | When encoding to JSON, real values are always represented 57 | with a fractional part; e.g., the ``double`` value 3.0 will be 58 | represented in JSON as ``3.0``, not ``3``. 59 | 60 | Overflow, Underflow & Precision 61 | ------------------------------- 62 | 63 | Real numbers whose absolute values are too small to be represented in 64 | a C ``double`` will be silently estimated with 0.0. Thus, depending on 65 | platform, JSON numbers very close to zero such as 1E-999 may result in 66 | 0.0. 67 | 68 | Real numbers whose absolute values are too large to be represented in 69 | a C ``double`` will result in an overflow error (a JSON decoding 70 | error). Thus, depending on platform, JSON numbers like 1E+999 or 71 | -1E+999 may result in a parsing error. 72 | 73 | Likewise, integer numbers whose absolute values are too large to be 74 | represented in the ``json_int_t`` type (see above) will result in an 75 | overflow error (a JSON decoding error). Thus, depending on platform, 76 | JSON numbers like 1000000000000000 may result in parsing error. 77 | 78 | Parsing JSON real numbers may result in a loss of precision. As long 79 | as overflow does not occur (i.e. a total loss of precision), the 80 | rounded approximate value is silently used. Thus the JSON number 81 | 1.000000000000000005 may, depending on platform, result in the 82 | ``double`` value 1.0. 83 | 84 | Signed zeros 85 | ------------ 86 | 87 | JSON makes no statement about what a number means; however Javascript 88 | (ECMAscript) does state that +0.0 and -0.0 must be treated as being 89 | distinct values, i.e. -0.0 |not-equal| 0.0. Jansson relies on the 90 | underlying floating point library in the C environment in which it is 91 | compiled. Therefore it is platform-dependent whether 0.0 and -0.0 will 92 | be distinct values. Most platforms that use the IEEE 754 93 | floating-point standard will support signed zeros. 94 | 95 | Note that this only applies to floating-point; neither JSON, C, or 96 | IEEE support the concept of signed integer zeros. 97 | 98 | .. |not-equal| unicode:: U+2260 99 | 100 | Types 101 | ----- 102 | 103 | No support is provided in Jansson for any C numeric types other than 104 | ``json_int_t`` and ``double``. This excludes things such as unsigned 105 | types, ``long double``, etc. Obviously, shorter types like ``short``, 106 | ``int``, ``long`` (if ``json_int_t`` is ``long long``) and ``float`` 107 | are implicitly handled via the ordinary C type coercion rules (subject 108 | to overflow semantics). Also, no support or hooks are provided for any 109 | supplemental "bignum" type add-on packages. 110 | 111 | Depth of nested values 112 | ====================== 113 | 114 | To avoid stack exhaustion, Jansson currently limits the nesting depth 115 | for arrays and objects to a certain value (default: 2048), defined as 116 | a macro ``JSON_PARSER_MAX_DEPTH`` within ``jansson_config.h``. 117 | 118 | The limit is allowed to be set by the RFC; there is no recommended value 119 | or required minimum depth to be supported. 120 | -------------------------------------------------------------------------------- /doc/ext/refcounting.py: -------------------------------------------------------------------------------- 1 | """ 2 | refcounting 3 | ~~~~~~~~~~~ 4 | 5 | Reference count annotations for C API functions. Has the same 6 | result as the sphinx.ext.refcounting extension but works for all 7 | functions regardless of the signature, and the reference counting 8 | information is written inline with the documentation instead of a 9 | separate file. 10 | 11 | Adds a new directive "refcounting". The directive has no content 12 | and one required positional parameter:: "new" or "borrow". 13 | 14 | Example: 15 | 16 | .. cfunction:: json_t *json_object(void) 17 | 18 | .. refcounting:: new 19 | 20 | 21 | 22 | :copyright: Copyright (c) 2009-2016 Petri Lehtinen 23 | :license: MIT, see LICENSE for details. 24 | """ 25 | 26 | from docutils import nodes 27 | from docutils.parsers.rst import Directive 28 | 29 | 30 | def visit(self, node): 31 | self.visit_emphasis(node) 32 | 33 | def depart(self, node): 34 | self.depart_emphasis(node) 35 | 36 | def html_visit(self, node): 37 | self.body.append(self.starttag(node, 'em', '', CLASS='refcount')) 38 | 39 | def html_depart(self, node): 40 | self.body.append('') 41 | 42 | 43 | class refcounting(nodes.emphasis): 44 | pass 45 | 46 | class refcounting_directive(Directive): 47 | has_content = False 48 | required_arguments = 1 49 | optional_arguments = 0 50 | final_argument_whitespace = False 51 | 52 | def run(self): 53 | if self.arguments[0] == 'borrow': 54 | text = 'Return value: Borrowed reference.' 55 | elif self.arguments[0] == 'new': 56 | text = 'Return value: New reference.' 57 | else: 58 | raise Error('Valid arguments: new, borrow') 59 | 60 | return [refcounting(text, text)] 61 | 62 | 63 | def setup(app): 64 | app.add_node(refcounting, 65 | html=(html_visit, html_depart), 66 | latex=(visit, depart), 67 | text=(visit, depart), 68 | man=(visit, depart)) 69 | app.add_directive('refcounting', refcounting_directive) 70 | -------------------------------------------------------------------------------- /doc/github_commits.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #define BUFFER_SIZE (256 * 1024) /* 256 KB */ 15 | 16 | #define URL_FORMAT "https://api.github.com/repos/%s/%s/commits" 17 | #define URL_SIZE 256 18 | 19 | /* Return the offset of the first newline in text or the length of 20 | text if there's no newline */ 21 | static int newline_offset(const char *text) { 22 | const char *newline = strchr(text, '\n'); 23 | if (!newline) 24 | return strlen(text); 25 | else 26 | return (int)(newline - text); 27 | } 28 | 29 | struct write_result { 30 | char *data; 31 | int pos; 32 | }; 33 | 34 | static size_t write_response(void *ptr, size_t size, size_t nmemb, void *stream) { 35 | struct write_result *result = (struct write_result *)stream; 36 | 37 | if (result->pos + size * nmemb >= BUFFER_SIZE - 1) { 38 | fprintf(stderr, "error: too small buffer\n"); 39 | return 0; 40 | } 41 | 42 | memcpy(result->data + result->pos, ptr, size * nmemb); 43 | result->pos += size * nmemb; 44 | 45 | return size * nmemb; 46 | } 47 | 48 | static char *request(const char *url) { 49 | CURL *curl = NULL; 50 | CURLcode status; 51 | struct curl_slist *headers = NULL; 52 | char *data = NULL; 53 | long code; 54 | 55 | curl_global_init(CURL_GLOBAL_ALL); 56 | curl = curl_easy_init(); 57 | if (!curl) 58 | goto error; 59 | 60 | data = malloc(BUFFER_SIZE); 61 | if (!data) 62 | goto error; 63 | 64 | struct write_result write_result = {.data = data, .pos = 0}; 65 | 66 | curl_easy_setopt(curl, CURLOPT_URL, url); 67 | 68 | /* GitHub commits API v3 requires a User-Agent header */ 69 | headers = curl_slist_append(headers, "User-Agent: Jansson-Tutorial"); 70 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 71 | 72 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_response); 73 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_result); 74 | 75 | status = curl_easy_perform(curl); 76 | if (status != 0) { 77 | fprintf(stderr, "error: unable to request data from %s:\n", url); 78 | fprintf(stderr, "%s\n", curl_easy_strerror(status)); 79 | goto error; 80 | } 81 | 82 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); 83 | if (code != 200) { 84 | fprintf(stderr, "error: server responded with code %ld\n", code); 85 | goto error; 86 | } 87 | 88 | curl_easy_cleanup(curl); 89 | curl_slist_free_all(headers); 90 | curl_global_cleanup(); 91 | 92 | /* zero-terminate the result */ 93 | data[write_result.pos] = '\0'; 94 | 95 | return data; 96 | 97 | error: 98 | if (data) 99 | free(data); 100 | if (curl) 101 | curl_easy_cleanup(curl); 102 | if (headers) 103 | curl_slist_free_all(headers); 104 | curl_global_cleanup(); 105 | return NULL; 106 | } 107 | 108 | int main(int argc, char *argv[]) { 109 | size_t i; 110 | char *text; 111 | char url[URL_SIZE]; 112 | 113 | json_t *root; 114 | json_error_t error; 115 | 116 | if (argc != 3) { 117 | fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]); 118 | fprintf(stderr, "List commits at USER's REPOSITORY.\n\n"); 119 | return 2; 120 | } 121 | 122 | snprintf(url, URL_SIZE, URL_FORMAT, argv[1], argv[2]); 123 | 124 | text = request(url); 125 | if (!text) 126 | return 1; 127 | 128 | root = json_loads(text, 0, &error); 129 | free(text); 130 | 131 | if (!root) { 132 | fprintf(stderr, "error: on line %d: %s\n", error.line, error.text); 133 | return 1; 134 | } 135 | 136 | if (!json_is_array(root)) { 137 | fprintf(stderr, "error: root is not an array\n"); 138 | json_decref(root); 139 | return 1; 140 | } 141 | 142 | for (i = 0; i < json_array_size(root); i++) { 143 | json_t *data, *sha, *commit, *message; 144 | const char *message_text; 145 | 146 | data = json_array_get(root, i); 147 | if (!json_is_object(data)) { 148 | fprintf(stderr, "error: commit data %d is not an object\n", (int)(i + 1)); 149 | json_decref(root); 150 | return 1; 151 | } 152 | 153 | sha = json_object_get(data, "sha"); 154 | if (!json_is_string(sha)) { 155 | fprintf(stderr, "error: commit %d: sha is not a string\n", (int)(i + 1)); 156 | json_decref(root); 157 | return 1; 158 | } 159 | 160 | commit = json_object_get(data, "commit"); 161 | if (!json_is_object(commit)) { 162 | fprintf(stderr, "error: commit %d: commit is not an object\n", (int)(i + 1)); 163 | json_decref(root); 164 | return 1; 165 | } 166 | 167 | message = json_object_get(commit, "message"); 168 | if (!json_is_string(message)) { 169 | fprintf(stderr, "error: commit %d: message is not a string\n", (int)(i + 1)); 170 | json_decref(root); 171 | return 1; 172 | } 173 | 174 | message_text = json_string_value(message); 175 | printf("%.8s %.*s\n", json_string_value(sha), newline_offset(message_text), 176 | message_text); 177 | } 178 | 179 | json_decref(root); 180 | return 0; 181 | } 182 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | Jansson Documentation 2 | ===================== 3 | 4 | This is the documentation for Jansson_ |release|, last updated |today|. 5 | 6 | Introduction 7 | ------------ 8 | 9 | Jansson_ is a C library for encoding, decoding and manipulating JSON 10 | data. Its main features and design principles are: 11 | 12 | - Simple and intuitive API and data model 13 | 14 | - Comprehensive documentation 15 | 16 | - No dependencies on other libraries 17 | 18 | - Full Unicode support (UTF-8) 19 | 20 | - Extensive test suite 21 | 22 | Jansson is licensed under the `MIT license`_; see LICENSE in the 23 | source distribution for details. 24 | 25 | Jansson is used in production and its API is stable. It works on 26 | numerous platforms, including numerous Unix like systems and Windows. 27 | It's suitable for use on any system, including desktop, server, and 28 | small embedded systems. 29 | 30 | 31 | .. _`MIT license`: http://www.opensource.org/licenses/mit-license.php 32 | .. _Jansson: http://www.digip.org/jansson/ 33 | 34 | Contents 35 | -------- 36 | 37 | .. toctree:: 38 | :maxdepth: 2 39 | 40 | gettingstarted 41 | upgrading 42 | tutorial 43 | conformance 44 | threadsafety 45 | apiref 46 | changes 47 | 48 | 49 | Indices and Tables 50 | ================== 51 | 52 | * :ref:`genindex` 53 | * :ref:`search` 54 | -------------------------------------------------------------------------------- /doc/threadsafety.rst: -------------------------------------------------------------------------------- 1 | .. _thread-safety: 2 | 3 | ************* 4 | Thread safety 5 | ************* 6 | 7 | Jansson as a library is thread safe and has no mutable global state. 8 | The only exceptions are the hash function seed and memory allocation 9 | functions, see below. 10 | 11 | There's no locking performed inside Jansson's code. **Read-only** 12 | access to JSON values shared by multiple threads is safe, but 13 | **mutating** a JSON value that's shared by multiple threads is not. A 14 | multithreaded program must perform its own locking if JSON values 15 | shared by multiple threads are mutated. 16 | 17 | However, **reference count manipulation** (:func:`json_incref()`, 18 | :func:`json_decref()`) is usually thread-safe, and can be performed on 19 | JSON values that are shared among threads. The thread-safety of 20 | reference counting can be checked with the 21 | ``JANSSON_THREAD_SAFE_REFCOUNT`` preprocessor constant. Thread-safe 22 | reference count manipulation is achieved using compiler built-in 23 | atomic functions, which are available in most modern compilers. 24 | 25 | If compiler support is not available (``JANSSON_THREAD_SAFE_REFCOUNT`` 26 | is not defined), it may be very difficult to ensure thread safety of 27 | reference counting. It's possible to have a reference to a value 28 | that's also stored inside an array or object in another thread. 29 | Modifying the container (adding or removing values) may trigger 30 | concurrent access to such values, as containers manage the reference 31 | count of their contained values. 32 | 33 | 34 | Hash function seed 35 | ================== 36 | 37 | To prevent an attacker from intentionally causing large JSON objects 38 | with specially crafted keys to perform very slow, the hash function 39 | used by Jansson is randomized using a seed value. The seed is 40 | automatically generated on the first explicit or implicit call to 41 | :func:`json_object()`, if :func:`json_object_seed()` has not been 42 | called beforehand. 43 | 44 | The seed is generated by using operating system's entropy sources if 45 | they are available (``/dev/urandom``, ``CryptGenRandom()``). The 46 | initialization is done in as thread safe manner as possible, by using 47 | architecture specific lockless operations if provided by the platform 48 | or the compiler. 49 | 50 | If you're using threads, it's recommended to autoseed the hashtable 51 | explicitly before spawning any threads by calling 52 | ``json_object_seed(0)`` , especially if you're unsure whether the 53 | initialization is thread safe on your platform. 54 | 55 | 56 | Memory allocation functions 57 | =========================== 58 | 59 | Memory allocation functions should be set at most once, and only on 60 | program startup. See :ref:`apiref-custom-memory-allocation`. 61 | 62 | 63 | Locale 64 | ====== 65 | 66 | Jansson works fine under any locale. 67 | 68 | However, if the host program is multithreaded and uses ``setlocale()`` 69 | to switch the locale in one thread while Jansson is currently encoding 70 | or decoding JSON data in another thread, the result may be wrong or 71 | the program may even crash. 72 | 73 | Jansson uses locale specific functions for certain string conversions 74 | in the encoder and decoder, and then converts the locale specific 75 | values to/from the JSON representation. This fails if the locale 76 | changes between the string conversion and the locale-to-JSON 77 | conversion. This can only happen in multithreaded programs that use 78 | ``setlocale()``, because ``setlocale()`` switches the locale for all 79 | running threads, not only the thread that calls ``setlocale()``. 80 | 81 | If your program uses ``setlocale()`` as described above, consider 82 | using the thread-safe ``uselocale()`` instead. 83 | -------------------------------------------------------------------------------- /doc/upgrading.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: c 2 | 3 | ****************** 4 | Upgrading from 1.x 5 | ****************** 6 | 7 | This chapter lists the backwards incompatible changes introduced in 8 | Jansson 2.0, and the steps that are needed for upgrading your code. 9 | 10 | **The incompatibilities are not dramatic.** The biggest change is that 11 | all decoding functions now require and extra parameter. Most programs 12 | can be modified to work with 2.0 by adding a ``0`` as the second 13 | parameter to all calls of :func:`json_loads()`, :func:`json_loadf()` 14 | and :func:`json_load_file()`. 15 | 16 | 17 | Compatibility 18 | ============= 19 | 20 | Jansson 2.0 is backwards incompatible with the Jansson 1.x releases. 21 | It is ABI incompatible, i.e. all programs dynamically linking to the 22 | Jansson library need to be recompiled. It's also API incompatible, 23 | i.e. the source code of programs using Jansson 1.x may need 24 | modifications to make them compile against Jansson 2.0. 25 | 26 | All the 2.x releases are guaranteed to be backwards compatible for 27 | both ABI and API, so no recompilation or source changes are needed 28 | when upgrading from 2.x to 2.y. 29 | 30 | 31 | List of Incompatible Changes 32 | ============================ 33 | 34 | **Decoding flags** 35 | For future needs, a ``flags`` parameter was added as the second 36 | parameter to all decoding functions, i.e. :func:`json_loads()`, 37 | :func:`json_loadf()` and :func:`json_load_file()`. All calls to 38 | these functions need to be changed by adding a ``0`` as the second 39 | argument. For example:: 40 | 41 | /* old code */ 42 | json_loads(input, &error); 43 | 44 | /* new code */ 45 | json_loads(input, 0, &error); 46 | 47 | 48 | **Underlying type of JSON integers** 49 | The underlying C type of JSON integers has been changed from 50 | ``int`` to the widest available signed integer type, i.e. 51 | ``long long`` or ``long``, depending on whether 52 | ``long long`` is supported on your system or not. This makes 53 | the whole 64-bit integer range available on most modern systems. 54 | 55 | ``jansson.h`` has a typedef :type:`json_int_t` to the underlying 56 | integer type. ``int`` should still be used in most cases when 57 | dealing with smallish JSON integers, as the compiler handles 58 | implicit type coercion. Only when the full 64-bit range is needed, 59 | :type:`json_int_t` should be explicitly used. 60 | 61 | 62 | **Maximum encoder indentation depth** 63 | The maximum argument of the ``JSON_INDENT()`` macro has been 64 | changed from 255 to 31, to free up bits from the ``flags`` 65 | parameter of :func:`json_dumps()`, :func:`json_dumpf()` and 66 | :func:`json_dump_file()`. If your code uses a bigger indentation 67 | than 31, it needs to be changed. 68 | 69 | 70 | **Unsigned integers in API functions** 71 | Version 2.0 unifies unsigned integer usage in the API. All uses of 72 | ``unsigned int`` and ``unsigned long`` have been replaced 73 | with ``size_t``. This includes flags, container sizes, etc. 74 | This should not require source code changes, as both 75 | ``unsigned int`` and ``unsigned long`` are usually 76 | compatible with ``size_t``. 77 | -------------------------------------------------------------------------------- /examples/README.rst: -------------------------------------------------------------------------------- 1 | Jansson examples 2 | ================ 3 | 4 | This directory contains simple example programs that use Jansson. 5 | -------------------------------------------------------------------------------- /examples/simple_parse.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple example of parsing and printing JSON using jansson. 3 | * 4 | * SYNOPSIS: 5 | * $ examples/simple_parse 6 | * Type some JSON > [true, false, null, 1, 0.0, -0.0, "", {"name": "barney"}] 7 | * JSON Array of 8 elements: 8 | * JSON True 9 | * JSON False 10 | * JSON Null 11 | * JSON Integer: "1" 12 | * JSON Real: 0.000000 13 | * JSON Real: -0.000000 14 | * JSON String: "" 15 | * JSON Object of 1 pair: 16 | * JSON Key: "name" 17 | * JSON String: "barney" 18 | * 19 | * Copyright (c) 2014 Robert Poor 20 | * 21 | * Jansson is free software; you can redistribute it and/or modify 22 | * it under the terms of the MIT license. See LICENSE for details. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | /* forward refs */ 30 | void print_json(json_t *root); 31 | void print_json_aux(json_t *element, int indent); 32 | void print_json_indent(int indent); 33 | const char *json_plural(size_t count); 34 | void print_json_object(json_t *element, int indent); 35 | void print_json_array(json_t *element, int indent); 36 | void print_json_string(json_t *element, int indent); 37 | void print_json_integer(json_t *element, int indent); 38 | void print_json_real(json_t *element, int indent); 39 | void print_json_true(json_t *element, int indent); 40 | void print_json_false(json_t *element, int indent); 41 | void print_json_null(json_t *element, int indent); 42 | 43 | void print_json(json_t *root) { print_json_aux(root, 0); } 44 | 45 | void print_json_aux(json_t *element, int indent) { 46 | switch (json_typeof(element)) { 47 | case JSON_OBJECT: 48 | print_json_object(element, indent); 49 | break; 50 | case JSON_ARRAY: 51 | print_json_array(element, indent); 52 | break; 53 | case JSON_STRING: 54 | print_json_string(element, indent); 55 | break; 56 | case JSON_INTEGER: 57 | print_json_integer(element, indent); 58 | break; 59 | case JSON_REAL: 60 | print_json_real(element, indent); 61 | break; 62 | case JSON_TRUE: 63 | print_json_true(element, indent); 64 | break; 65 | case JSON_FALSE: 66 | print_json_false(element, indent); 67 | break; 68 | case JSON_NULL: 69 | print_json_null(element, indent); 70 | break; 71 | default: 72 | fprintf(stderr, "unrecognized JSON type %d\n", json_typeof(element)); 73 | } 74 | } 75 | 76 | void print_json_indent(int indent) { 77 | int i; 78 | for (i = 0; i < indent; i++) { 79 | putchar(' '); 80 | } 81 | } 82 | 83 | const char *json_plural(size_t count) { return count == 1 ? "" : "s"; } 84 | 85 | void print_json_object(json_t *element, int indent) { 86 | size_t size; 87 | const char *key; 88 | json_t *value; 89 | 90 | print_json_indent(indent); 91 | size = json_object_size(element); 92 | 93 | printf("JSON Object of %lld pair%s:\n", (long long)size, json_plural(size)); 94 | json_object_foreach(element, key, value) { 95 | print_json_indent(indent + 2); 96 | printf("JSON Key: \"%s\"\n", key); 97 | print_json_aux(value, indent + 2); 98 | } 99 | } 100 | 101 | void print_json_array(json_t *element, int indent) { 102 | size_t i; 103 | size_t size = json_array_size(element); 104 | print_json_indent(indent); 105 | 106 | printf("JSON Array of %lld element%s:\n", (long long)size, json_plural(size)); 107 | for (i = 0; i < size; i++) { 108 | print_json_aux(json_array_get(element, i), indent + 2); 109 | } 110 | } 111 | 112 | void print_json_string(json_t *element, int indent) { 113 | print_json_indent(indent); 114 | printf("JSON String: \"%s\"\n", json_string_value(element)); 115 | } 116 | 117 | void print_json_integer(json_t *element, int indent) { 118 | print_json_indent(indent); 119 | printf("JSON Integer: \"%" JSON_INTEGER_FORMAT "\"\n", json_integer_value(element)); 120 | } 121 | 122 | void print_json_real(json_t *element, int indent) { 123 | print_json_indent(indent); 124 | printf("JSON Real: %f\n", json_real_value(element)); 125 | } 126 | 127 | void print_json_true(json_t *element, int indent) { 128 | (void)element; 129 | print_json_indent(indent); 130 | printf("JSON True\n"); 131 | } 132 | 133 | void print_json_false(json_t *element, int indent) { 134 | (void)element; 135 | print_json_indent(indent); 136 | printf("JSON False\n"); 137 | } 138 | 139 | void print_json_null(json_t *element, int indent) { 140 | (void)element; 141 | print_json_indent(indent); 142 | printf("JSON Null\n"); 143 | } 144 | 145 | /* 146 | * Parse text into a JSON object. If text is valid JSON, returns a 147 | * json_t structure, otherwise prints and error and returns null. 148 | */ 149 | json_t *load_json(const char *text) { 150 | json_t *root; 151 | json_error_t error; 152 | 153 | root = json_loads(text, 0, &error); 154 | 155 | if (root) { 156 | return root; 157 | } else { 158 | fprintf(stderr, "json error on line %d: %s\n", error.line, error.text); 159 | return (json_t *)0; 160 | } 161 | } 162 | 163 | /* 164 | * Print a prompt and return (by reference) a null-terminated line of 165 | * text. Returns NULL on eof or some error. 166 | */ 167 | char *read_line(char *line, int max_chars) { 168 | printf("Type some JSON > "); 169 | fflush(stdout); 170 | return fgets(line, max_chars, stdin); 171 | } 172 | 173 | /* ================================================================ 174 | * main 175 | */ 176 | 177 | #define MAX_CHARS 4096 178 | 179 | int main(int argc, char *argv[]) { 180 | char line[MAX_CHARS]; 181 | 182 | if (argc != 1) { 183 | fprintf(stderr, "Usage: %s\n", argv[0]); 184 | exit(-1); 185 | } 186 | 187 | while (read_line(line, MAX_CHARS) != (char *)NULL) { 188 | 189 | /* parse text into JSON structure */ 190 | json_t *root = load_json(line); 191 | 192 | if (root) { 193 | /* print and release the JSON structure */ 194 | print_json(root); 195 | json_decref(root); 196 | } 197 | } 198 | 199 | return 0; 200 | } 201 | -------------------------------------------------------------------------------- /jansson.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: Jansson 7 | Description: Library for encoding, decoding and manipulating JSON data 8 | Version: @VERSION@ 9 | Libs: -L${libdir} -ljansson 10 | Cflags: -I${includedir} 11 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Use this script to easily make releases of Jansson. It configures 4 | # the source tree, and builds and signs all tarballs. 5 | 6 | die() { 7 | echo $1 >&2 8 | exit 1 9 | } 10 | 11 | confirm() { 12 | local answer 13 | read -p "$1 [yN]: " answer 14 | [ "$answer" = "Y" -o "$answer" = "y" ] || exit 0 15 | } 16 | 17 | set -e 18 | [ -f configure.ac ] || die "Must be run at project root directory" 19 | 20 | # Determine version 21 | v=$(grep AC_INIT configure.ac | sed -r 's/.*, \[(.+?)\],.*/\1/') 22 | [ -n "$v" ] || die "Unable to determine version" 23 | confirm "Version is $v, proceed?" 24 | 25 | # Sanity checks 26 | vi=$(grep version-info src/Makefile.am | sed 's/^[ \t]*//g' | cut -d" " -f2) 27 | confirm "Libtool version-info is $vi, proceed?" 28 | 29 | r=$(grep 'Released ' CHANGES | head -n 1) 30 | confirm "Last CHANGES entry says \"$r\", proceed??" 31 | 32 | dv=$(grep ^version doc/conf.py | sed -r "s/.*'(.*)'.*/\1/") 33 | if [ "$dv" != "$v" ]; then 34 | die "Documentation version ($dv) doesn't match library version" 35 | fi 36 | 37 | [ -f Makefile ] && make distclean || true 38 | rm -f jansson-$v.tar.* 39 | rm -rf jansson-$v-doc 40 | rm -f jansson-$v-doc.tar.* 41 | 42 | autoreconf -fi 43 | ./configure 44 | 45 | # Run tests and make gz source tarball 46 | : ${VALGRIND:=1} 47 | export VALGRIND 48 | make distcheck 49 | 50 | # Make bzip2 source tarball 51 | make dist-bzip2 52 | 53 | # Sign source tarballs 54 | for s in gz bz2; do 55 | gpg --detach-sign --armor jansson-$v.tar.$s 56 | done 57 | 58 | # Build documentation 59 | make html 60 | mv doc/_build/html jansson-$v-doc 61 | 62 | # Make and sign documentation tarballs 63 | for s in gz bz2; do 64 | [ $s = gz ] && compress=gzip 65 | [ $s = bz2 ] && compress=bzip2 66 | tar cf - jansson-$v-doc | $compress -9 -c > jansson-$v-doc.tar.$s 67 | gpg --detach-sign --armor jansson-$v-doc.tar.$s 68 | done 69 | 70 | echo "All done" 71 | -------------------------------------------------------------------------------- /scripts/clang-format: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git ls-files | grep '\.[ch]$' | xargs clang-format -i 4 | -------------------------------------------------------------------------------- /scripts/clang-format-check: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CLANG_FORMAT=${CLANG_FORMAT:-clang-format} 4 | CLANG_FORMAT_VERSION=${CLANG_FORMAT_VERSION:-} 5 | 6 | if ! type $CLANG_FORMAT >/dev/null || \ 7 | ! $CLANG_FORMAT --version | grep -q "version ${CLANG_FORMAT_VERSION}"; then 8 | # If running tests, mark this test as skipped. 9 | exit 77 10 | fi 11 | 12 | errors=0 13 | paths=$(git ls-files | grep '\.[ch]$') 14 | for path in $paths; do 15 | echo "Checking $path" 16 | $CLANG_FORMAT $path > $path.formatted 17 | in=$(cat $path) 18 | out=$(cat $path.formatted) 19 | 20 | if [ "$in" != "$out" ]; then 21 | diff -u $path $path.formatted 22 | errors=1 23 | fi 24 | rm $path.formatted 25 | done 26 | 27 | if [ $errors -ne 0 ]; then 28 | echo "Formatting errors detected, run ./scripts/clang-format to fix!" 29 | exit 1 30 | fi 31 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = jansson.def dtoa.c 2 | 3 | include_HEADERS = jansson.h 4 | nodist_include_HEADERS = jansson_config.h 5 | 6 | lib_LTLIBRARIES = libjansson.la 7 | libjansson_la_SOURCES = \ 8 | dump.c \ 9 | error.c \ 10 | hashtable.c \ 11 | hashtable.h \ 12 | hashtable_seed.c \ 13 | jansson_private.h \ 14 | load.c \ 15 | lookup3.h \ 16 | memory.c \ 17 | pack_unpack.c \ 18 | strbuffer.c \ 19 | strbuffer.h \ 20 | strconv.c \ 21 | utf.c \ 22 | utf.h \ 23 | value.c \ 24 | version.c 25 | 26 | if DTOA_ENABLED 27 | libjansson_la_SOURCES += dtoa.c 28 | endif 29 | 30 | libjansson_la_LDFLAGS = \ 31 | -no-undefined \ 32 | -export-symbols-regex '^json_|^jansson_' \ 33 | -version-info 18:1:14 \ 34 | @JSON_SYMVER_LDFLAGS@ \ 35 | @JSON_BSYMBOLIC_LDFLAGS@ 36 | -------------------------------------------------------------------------------- /src/error.c: -------------------------------------------------------------------------------- 1 | #include "jansson_private.h" 2 | #include 3 | 4 | void jsonp_error_init(json_error_t *error, const char *source) { 5 | if (error) { 6 | error->text[0] = '\0'; 7 | error->line = -1; 8 | error->column = -1; 9 | error->position = 0; 10 | if (source) 11 | jsonp_error_set_source(error, source); 12 | else 13 | error->source[0] = '\0'; 14 | } 15 | } 16 | 17 | void jsonp_error_set_source(json_error_t *error, const char *source) { 18 | size_t length; 19 | 20 | if (!error || !source) 21 | return; 22 | 23 | length = strlen(source); 24 | if (length < JSON_ERROR_SOURCE_LENGTH) 25 | strncpy(error->source, source, length + 1); 26 | else { 27 | size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4; 28 | memcpy(error->source, "...", 3); 29 | strncpy(error->source + 3, source + extra, length - extra + 1); 30 | } 31 | } 32 | 33 | void jsonp_error_set(json_error_t *error, int line, int column, size_t position, 34 | enum json_error_code code, const char *msg, ...) { 35 | va_list ap; 36 | 37 | va_start(ap, msg); 38 | jsonp_error_vset(error, line, column, position, code, msg, ap); 39 | va_end(ap); 40 | } 41 | 42 | void jsonp_error_vset(json_error_t *error, int line, int column, size_t position, 43 | enum json_error_code code, const char *msg, va_list ap) { 44 | if (!error) 45 | return; 46 | 47 | if (error->text[0] != '\0') { 48 | /* error already set */ 49 | return; 50 | } 51 | 52 | error->line = line; 53 | error->column = column; 54 | error->position = (int)position; 55 | 56 | vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH - 1, msg, ap); 57 | error->text[JSON_ERROR_TEXT_LENGTH - 2] = '\0'; 58 | error->text[JSON_ERROR_TEXT_LENGTH - 1] = code; 59 | } 60 | -------------------------------------------------------------------------------- /src/hashtable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2016 Petri Lehtinen 3 | * 4 | * This library is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #ifndef HASHTABLE_H 9 | #define HASHTABLE_H 10 | 11 | #include "jansson.h" 12 | #include 13 | 14 | struct hashtable_list { 15 | struct hashtable_list *prev; 16 | struct hashtable_list *next; 17 | }; 18 | 19 | /* "pair" may be a bit confusing a name, but think of it as a 20 | key-value pair. In this case, it just encodes some extra data, 21 | too */ 22 | struct hashtable_pair { 23 | struct hashtable_list list; 24 | struct hashtable_list ordered_list; 25 | size_t hash; 26 | json_t *value; 27 | size_t key_len; 28 | char key[1]; 29 | }; 30 | 31 | struct hashtable_bucket { 32 | struct hashtable_list *first; 33 | struct hashtable_list *last; 34 | }; 35 | 36 | typedef struct hashtable { 37 | size_t size; 38 | struct hashtable_bucket *buckets; 39 | size_t order; /* hashtable has pow(2, order) buckets */ 40 | struct hashtable_list list; 41 | struct hashtable_list ordered_list; 42 | } hashtable_t; 43 | 44 | #define hashtable_key_to_iter(key_) \ 45 | (&(container_of(key_, struct hashtable_pair, key)->ordered_list)) 46 | 47 | /** 48 | * hashtable_init - Initialize a hashtable object 49 | * 50 | * @hashtable: The (statically allocated) hashtable object 51 | * 52 | * Initializes a statically allocated hashtable object. The object 53 | * should be cleared with hashtable_close when it's no longer used. 54 | * 55 | * Returns 0 on success, -1 on error (out of memory). 56 | */ 57 | int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS((warn_unused_result)); 58 | 59 | /** 60 | * hashtable_close - Release all resources used by a hashtable object 61 | * 62 | * @hashtable: The hashtable 63 | * 64 | * Destroys a statically allocated hashtable object. 65 | */ 66 | void hashtable_close(hashtable_t *hashtable); 67 | 68 | /** 69 | * hashtable_set - Add/modify value in hashtable 70 | * 71 | * @hashtable: The hashtable object 72 | * @key: The key 73 | * @key: The length of key 74 | * @serial: For addition order of keys 75 | * @value: The value 76 | * 77 | * If a value with the given key already exists, its value is replaced 78 | * with the new value. Value is "stealed" in the sense that hashtable 79 | * doesn't increment its refcount but decreases the refcount when the 80 | * value is no longer needed. 81 | * 82 | * Returns 0 on success, -1 on failure (out of memory). 83 | */ 84 | int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len, json_t *value); 85 | 86 | /** 87 | * hashtable_get - Get a value associated with a key 88 | * 89 | * @hashtable: The hashtable object 90 | * @key: The key 91 | * @key: The length of key 92 | * 93 | * Returns value if it is found, or NULL otherwise. 94 | */ 95 | void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len); 96 | 97 | /** 98 | * hashtable_del - Remove a value from the hashtable 99 | * 100 | * @hashtable: The hashtable object 101 | * @key: The key 102 | * @key: The length of key 103 | * 104 | * Returns 0 on success, or -1 if the key was not found. 105 | */ 106 | int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len); 107 | 108 | /** 109 | * hashtable_clear - Clear hashtable 110 | * 111 | * @hashtable: The hashtable object 112 | * 113 | * Removes all items from the hashtable. 114 | */ 115 | void hashtable_clear(hashtable_t *hashtable); 116 | 117 | /** 118 | * hashtable_iter - Iterate over hashtable 119 | * 120 | * @hashtable: The hashtable object 121 | * 122 | * Returns an opaque iterator to the first element in the hashtable. 123 | * The iterator should be passed to hashtable_iter_* functions. 124 | * The hashtable items are not iterated over in any particular order. 125 | * 126 | * There's no need to free the iterator in any way. The iterator is 127 | * valid as long as the item that is referenced by the iterator is not 128 | * deleted. Other values may be added or deleted. In particular, 129 | * hashtable_iter_next() may be called on an iterator, and after that 130 | * the key/value pair pointed by the old iterator may be deleted. 131 | */ 132 | void *hashtable_iter(hashtable_t *hashtable); 133 | 134 | /** 135 | * hashtable_iter_at - Return an iterator at a specific key 136 | * 137 | * @hashtable: The hashtable object 138 | * @key: The key that the iterator should point to 139 | * @key: The length of key 140 | * 141 | * Like hashtable_iter() but returns an iterator pointing to a 142 | * specific key. 143 | */ 144 | void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len); 145 | 146 | /** 147 | * hashtable_iter_next - Advance an iterator 148 | * 149 | * @hashtable: The hashtable object 150 | * @iter: The iterator 151 | * 152 | * Returns a new iterator pointing to the next element in the 153 | * hashtable or NULL if the whole hastable has been iterated over. 154 | */ 155 | void *hashtable_iter_next(hashtable_t *hashtable, void *iter); 156 | 157 | /** 158 | * hashtable_iter_key - Retrieve the key pointed by an iterator 159 | * 160 | * @iter: The iterator 161 | */ 162 | void *hashtable_iter_key(void *iter); 163 | 164 | /** 165 | * hashtable_iter_key_len - Retrieve the key length pointed by an iterator 166 | * 167 | * @iter: The iterator 168 | */ 169 | size_t hashtable_iter_key_len(void *iter); 170 | 171 | /** 172 | * hashtable_iter_value - Retrieve the value pointed by an iterator 173 | * 174 | * @iter: The iterator 175 | */ 176 | void *hashtable_iter_value(void *iter); 177 | 178 | /** 179 | * hashtable_iter_set - Set the value pointed by an iterator 180 | * 181 | * @iter: The iterator 182 | * @value: The value to set 183 | */ 184 | void hashtable_iter_set(void *iter, json_t *value); 185 | 186 | #endif 187 | -------------------------------------------------------------------------------- /src/jansson.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | json_delete 3 | json_true 4 | json_false 5 | json_null 6 | json_sprintf 7 | json_vsprintf 8 | json_string 9 | json_stringn 10 | json_string_nocheck 11 | json_stringn_nocheck 12 | json_string_value 13 | json_string_length 14 | json_string_set 15 | json_string_setn 16 | json_string_set_nocheck 17 | json_string_setn_nocheck 18 | json_integer 19 | json_integer_value 20 | json_integer_set 21 | json_real 22 | json_real_value 23 | json_real_set 24 | json_number_value 25 | json_array 26 | json_array_size 27 | json_array_get 28 | json_array_set_new 29 | json_array_append_new 30 | json_array_insert_new 31 | json_array_remove 32 | json_array_clear 33 | json_array_extend 34 | json_object 35 | json_object_size 36 | json_object_get 37 | json_object_getn 38 | json_object_set_new 39 | json_object_setn_new 40 | json_object_set_new_nocheck 41 | json_object_setn_new_nocheck 42 | json_object_del 43 | json_object_deln 44 | json_object_clear 45 | json_object_update 46 | json_object_update_existing 47 | json_object_update_missing 48 | json_object_update_recursive 49 | json_object_iter 50 | json_object_iter_at 51 | json_object_iter_next 52 | json_object_iter_key 53 | json_object_iter_key_len 54 | json_object_iter_value 55 | json_object_iter_set_new 56 | json_object_key_to_iter 57 | json_object_seed 58 | json_dumps 59 | json_dumpb 60 | json_dumpf 61 | json_dumpfd 62 | json_dump_file 63 | json_dump_callback 64 | json_loads 65 | json_loadb 66 | json_loadf 67 | json_loadfd 68 | json_load_file 69 | json_load_callback 70 | json_equal 71 | json_copy 72 | json_deep_copy 73 | json_pack 74 | json_pack_ex 75 | json_vpack_ex 76 | json_unpack 77 | json_unpack_ex 78 | json_vunpack_ex 79 | json_set_alloc_funcs 80 | json_get_alloc_funcs 81 | jansson_version_str 82 | jansson_version_cmp 83 | 84 | -------------------------------------------------------------------------------- /src/jansson_config.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | * 7 | * 8 | * This file specifies a part of the site-specific configuration for 9 | * Jansson, namely those things that affect the public API in 10 | * jansson.h. 11 | * 12 | * The configure script copies this file to jansson_config.h and 13 | * replaces @var@ substitutions by values that fit your system. If you 14 | * cannot run the configure script, you can do the value substitution 15 | * by hand. 16 | */ 17 | 18 | #ifndef JANSSON_CONFIG_H 19 | #define JANSSON_CONFIG_H 20 | 21 | /* If your compiler supports the inline keyword in C, JSON_INLINE is 22 | defined to `inline', otherwise empty. In C++, the inline is always 23 | supported. */ 24 | #ifdef __cplusplus 25 | #define JSON_INLINE inline 26 | #else 27 | #define JSON_INLINE @json_inline@ 28 | #endif 29 | 30 | /* If your compiler supports the `long long` type and the strtoll() 31 | library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, 32 | otherwise to 0. */ 33 | #define JSON_INTEGER_IS_LONG_LONG @json_have_long_long@ 34 | 35 | /* If __atomic builtins are available they will be used to manage 36 | reference counts of json_t. */ 37 | #define JSON_HAVE_ATOMIC_BUILTINS @json_have_atomic_builtins@ 38 | 39 | /* If __atomic builtins are not available we try using __sync builtins 40 | to manage reference counts of json_t. */ 41 | #define JSON_HAVE_SYNC_BUILTINS @json_have_sync_builtins@ 42 | 43 | /* Maximum recursion depth for parsing JSON input. 44 | This limits the depth of e.g. array-within-array constructions. */ 45 | #define JSON_PARSER_MAX_DEPTH 2048 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/jansson_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #ifndef JANSSON_PRIVATE_H 9 | #define JANSSON_PRIVATE_H 10 | 11 | #include "hashtable.h" 12 | #include "jansson.h" 13 | #include "jansson_private_config.h" 14 | #include "strbuffer.h" 15 | #include 16 | 17 | #define container_of(ptr_, type_, member_) \ 18 | ((type_ *)((char *)ptr_ - offsetof(type_, member_))) 19 | 20 | /* On some platforms, max() may already be defined */ 21 | #ifndef max 22 | #define max(a, b) ((a) > (b) ? (a) : (b)) 23 | #endif 24 | 25 | /* va_copy is a C99 feature. In C89 implementations, it's sometimes 26 | available as __va_copy. If not, memcpy() should do the trick. */ 27 | #ifndef va_copy 28 | #ifdef __va_copy 29 | #define va_copy __va_copy 30 | #else 31 | #define va_copy(a, b) memcpy(&(a), &(b), sizeof(va_list)) 32 | #endif 33 | #endif 34 | 35 | typedef struct { 36 | json_t json; 37 | hashtable_t hashtable; 38 | } json_object_t; 39 | 40 | typedef struct { 41 | json_t json; 42 | size_t size; 43 | size_t entries; 44 | json_t **table; 45 | } json_array_t; 46 | 47 | typedef struct { 48 | json_t json; 49 | char *value; 50 | size_t length; 51 | } json_string_t; 52 | 53 | typedef struct { 54 | json_t json; 55 | double value; 56 | } json_real_t; 57 | 58 | typedef struct { 59 | json_t json; 60 | json_int_t value; 61 | } json_integer_t; 62 | 63 | #define json_to_object(json_) container_of(json_, json_object_t, json) 64 | #define json_to_array(json_) container_of(json_, json_array_t, json) 65 | #define json_to_string(json_) container_of(json_, json_string_t, json) 66 | #define json_to_real(json_) container_of(json_, json_real_t, json) 67 | #define json_to_integer(json_) container_of(json_, json_integer_t, json) 68 | 69 | /* Create a string by taking ownership of an existing buffer */ 70 | json_t *jsonp_stringn_nocheck_own(const char *value, size_t len); 71 | 72 | /* Error message formatting */ 73 | void jsonp_error_init(json_error_t *error, const char *source); 74 | void jsonp_error_set_source(json_error_t *error, const char *source); 75 | void jsonp_error_set(json_error_t *error, int line, int column, size_t position, 76 | enum json_error_code code, const char *msg, ...); 77 | void jsonp_error_vset(json_error_t *error, int line, int column, size_t position, 78 | enum json_error_code code, const char *msg, va_list ap); 79 | 80 | /* Locale independent string<->double conversions */ 81 | int jsonp_strtod(strbuffer_t *strbuffer, double *out); 82 | int jsonp_dtostr(char *buffer, size_t size, double value, int prec); 83 | 84 | /* Wrappers for custom memory functions */ 85 | void *jsonp_malloc(size_t size) JANSSON_ATTRS((warn_unused_result)); 86 | void jsonp_free(void *ptr); 87 | char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS((warn_unused_result)); 88 | char *jsonp_strdup(const char *str) JANSSON_ATTRS((warn_unused_result)); 89 | char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS((warn_unused_result)); 90 | 91 | /* Circular reference check*/ 92 | /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */ 93 | #define LOOP_KEY_LEN (2 + (sizeof(json_t *) * 2) + 1) 94 | int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size, 95 | size_t *key_len_out); 96 | 97 | /* Windows compatibility */ 98 | #if defined(_WIN32) || defined(WIN32) 99 | #if defined(_MSC_VER) /* MS compiller */ 100 | #if (_MSC_VER < 1900) && \ 101 | !defined(snprintf) /* snprintf not defined yet & not introduced */ 102 | #define snprintf _snprintf 103 | #endif 104 | #if (_MSC_VER < 1500) && \ 105 | !defined(vsnprintf) /* vsnprintf not defined yet & not introduced */ 106 | #define vsnprintf(b, c, f, a) _vsnprintf(b, c, f, a) 107 | #endif 108 | #else /* Other Windows compiller, old definition */ 109 | #define snprintf _snprintf 110 | #define vsnprintf _vsnprintf 111 | #endif 112 | #endif 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /src/memory.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2016 Petri Lehtinen 3 | * Copyright (c) 2011-2012 Basile Starynkevitch 4 | * 5 | * Jansson is free software; you can redistribute it and/or modify it 6 | * under the terms of the MIT license. See LICENSE for details. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #include "jansson.h" 13 | #include "jansson_private.h" 14 | 15 | /* C89 allows these to be macros */ 16 | #undef malloc 17 | #undef free 18 | 19 | /* memory function pointers */ 20 | static json_malloc_t do_malloc = malloc; 21 | static json_free_t do_free = free; 22 | 23 | void *jsonp_malloc(size_t size) { 24 | if (!size) 25 | return NULL; 26 | 27 | return (*do_malloc)(size); 28 | } 29 | 30 | void jsonp_free(void *ptr) { 31 | if (!ptr) 32 | return; 33 | 34 | (*do_free)(ptr); 35 | } 36 | 37 | char *jsonp_strdup(const char *str) { return jsonp_strndup(str, strlen(str)); } 38 | 39 | char *jsonp_strndup(const char *str, size_t len) { 40 | char *new_str; 41 | 42 | new_str = jsonp_malloc(len + 1); 43 | if (!new_str) 44 | return NULL; 45 | 46 | memcpy(new_str, str, len); 47 | new_str[len] = '\0'; 48 | return new_str; 49 | } 50 | 51 | void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) { 52 | do_malloc = malloc_fn; 53 | do_free = free_fn; 54 | } 55 | 56 | void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn) { 57 | if (malloc_fn) 58 | *malloc_fn = do_malloc; 59 | if (free_fn) 60 | *free_fn = do_free; 61 | } 62 | -------------------------------------------------------------------------------- /src/strbuffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #ifndef _GNU_SOURCE 9 | #define _GNU_SOURCE 10 | #endif 11 | 12 | #include "strbuffer.h" 13 | #include "jansson_private.h" 14 | #include 15 | #include 16 | 17 | #define STRBUFFER_MIN_SIZE 16 18 | #define STRBUFFER_FACTOR 2 19 | #define STRBUFFER_SIZE_MAX ((size_t)(-1)) 20 | 21 | int strbuffer_init(strbuffer_t *strbuff) { 22 | strbuff->size = STRBUFFER_MIN_SIZE; 23 | strbuff->length = 0; 24 | 25 | strbuff->value = jsonp_malloc(strbuff->size); 26 | if (!strbuff->value) 27 | return -1; 28 | 29 | /* initialize to empty */ 30 | strbuff->value[0] = '\0'; 31 | return 0; 32 | } 33 | 34 | void strbuffer_close(strbuffer_t *strbuff) { 35 | if (strbuff->value) 36 | jsonp_free(strbuff->value); 37 | 38 | strbuff->size = 0; 39 | strbuff->length = 0; 40 | strbuff->value = NULL; 41 | } 42 | 43 | void strbuffer_clear(strbuffer_t *strbuff) { 44 | strbuff->length = 0; 45 | strbuff->value[0] = '\0'; 46 | } 47 | 48 | const char *strbuffer_value(const strbuffer_t *strbuff) { return strbuff->value; } 49 | 50 | char *strbuffer_steal_value(strbuffer_t *strbuff) { 51 | char *result = strbuff->value; 52 | strbuff->value = NULL; 53 | return result; 54 | } 55 | 56 | int strbuffer_append_byte(strbuffer_t *strbuff, char byte) { 57 | return strbuffer_append_bytes(strbuff, &byte, 1); 58 | } 59 | 60 | int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size) { 61 | if (size >= strbuff->size - strbuff->length) { 62 | size_t new_size; 63 | char *new_value; 64 | 65 | /* avoid integer overflow */ 66 | if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR || 67 | size > STRBUFFER_SIZE_MAX - 1 || 68 | strbuff->length > STRBUFFER_SIZE_MAX - 1 - size) 69 | return -1; 70 | 71 | new_size = max(strbuff->size * STRBUFFER_FACTOR, strbuff->length + size + 1); 72 | 73 | new_value = jsonp_malloc(new_size); 74 | if (!new_value) 75 | return -1; 76 | 77 | memcpy(new_value, strbuff->value, strbuff->length); 78 | 79 | jsonp_free(strbuff->value); 80 | strbuff->value = new_value; 81 | strbuff->size = new_size; 82 | } 83 | 84 | memcpy(strbuff->value + strbuff->length, data, size); 85 | strbuff->length += size; 86 | strbuff->value[strbuff->length] = '\0'; 87 | 88 | return 0; 89 | } 90 | 91 | char strbuffer_pop(strbuffer_t *strbuff) { 92 | if (strbuff->length > 0) { 93 | char c = strbuff->value[--strbuff->length]; 94 | strbuff->value[strbuff->length] = '\0'; 95 | return c; 96 | } else 97 | return '\0'; 98 | } 99 | -------------------------------------------------------------------------------- /src/strbuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #ifndef STRBUFFER_H 9 | #define STRBUFFER_H 10 | 11 | #include "jansson.h" 12 | #include 13 | 14 | typedef struct { 15 | char *value; 16 | size_t length; /* bytes used */ 17 | size_t size; /* bytes allocated */ 18 | } strbuffer_t; 19 | 20 | int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS((warn_unused_result)); 21 | void strbuffer_close(strbuffer_t *strbuff); 22 | 23 | void strbuffer_clear(strbuffer_t *strbuff); 24 | 25 | const char *strbuffer_value(const strbuffer_t *strbuff); 26 | 27 | /* Steal the value and close the strbuffer */ 28 | char *strbuffer_steal_value(strbuffer_t *strbuff); 29 | 30 | int strbuffer_append_byte(strbuffer_t *strbuff, char byte); 31 | int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size); 32 | 33 | char strbuffer_pop(strbuffer_t *strbuff); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/strconv.c: -------------------------------------------------------------------------------- 1 | #include "jansson_private.h" 2 | #include "strbuffer.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* need jansson_private_config.h to get the correct snprintf */ 10 | #ifdef HAVE_CONFIG_H 11 | #include 12 | #endif 13 | 14 | /* 15 | - This code assumes that the decimal separator is exactly one 16 | character. 17 | 18 | - If setlocale() is called by another thread between the call to 19 | get_decimal_point() and the call to sprintf() or strtod(), the 20 | result may be wrong. setlocale() is not thread-safe and should 21 | not be used this way. Multi-threaded programs should use 22 | uselocale() instead. 23 | */ 24 | static char get_decimal_point() { 25 | char buf[3]; 26 | sprintf(buf, "%#.0f", 1.0); // "1." in the current locale 27 | return buf[1]; 28 | } 29 | 30 | static void to_locale(strbuffer_t *strbuffer) { 31 | char point; 32 | char *pos; 33 | 34 | point = get_decimal_point(); 35 | if (point == '.') { 36 | /* No conversion needed */ 37 | return; 38 | } 39 | 40 | pos = strchr(strbuffer->value, '.'); 41 | if (pos) 42 | *pos = point; 43 | } 44 | 45 | int jsonp_strtod(strbuffer_t *strbuffer, double *out) { 46 | double value; 47 | char *end; 48 | 49 | to_locale(strbuffer); 50 | 51 | errno = 0; 52 | value = strtod(strbuffer->value, &end); 53 | assert(end == strbuffer->value + strbuffer->length); 54 | 55 | if ((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) { 56 | /* Overflow */ 57 | return -1; 58 | } 59 | 60 | *out = value; 61 | return 0; 62 | } 63 | 64 | #if DTOA_ENABLED 65 | /* see dtoa.c */ 66 | char *dtoa_r(double dd, int mode, int ndigits, int *decpt, int *sign, char **rve, 67 | char *buf, size_t blen); 68 | 69 | int jsonp_dtostr(char *buffer, size_t size, double value, int precision) { 70 | /* adapted from `format_float_short()` in 71 | * https://github.com/python/cpython/blob/2cf18a44303b6d84faa8ecffaecc427b53ae121e/Python/pystrtod.c#L969 72 | */ 73 | char digits[25]; 74 | char *digits_end; 75 | int mode = precision == 0 ? 0 : 2; 76 | int decpt, sign, exp_len, exp = 0, use_exp = 0; 77 | int digits_len, vdigits_start, vdigits_end; 78 | char *p; 79 | 80 | if (dtoa_r(value, mode, precision, &decpt, &sign, &digits_end, digits, 25) == NULL) { 81 | // digits is too short => should not happen 82 | return -1; 83 | } 84 | 85 | digits_len = digits_end - digits; 86 | if (decpt <= -4 || decpt > 16) { 87 | use_exp = 1; 88 | exp = decpt - 1; 89 | decpt = 1; 90 | } 91 | 92 | vdigits_start = decpt <= 0 ? decpt - 1 : 0; 93 | vdigits_end = digits_len; 94 | if (!use_exp) { 95 | /* decpt + 1 to add ".0" if value is an integer */ 96 | vdigits_end = vdigits_end > decpt ? vdigits_end : decpt + 1; 97 | } else { 98 | vdigits_end = vdigits_end > decpt ? vdigits_end : decpt; 99 | } 100 | 101 | if ( 102 | /* sign, decimal point and trailing 0 byte */ 103 | (size_t)(3 + 104 | 105 | /* total digit count (including zero padding on both sides) */ 106 | (vdigits_end - vdigits_start) + 107 | 108 | /* exponent "e+100", max 3 numerical digits */ 109 | (use_exp ? 5 : 0)) > size) { 110 | /* buffer is too short */ 111 | return -1; 112 | } 113 | 114 | p = buffer; 115 | if (sign == 1) { 116 | *p++ = '-'; 117 | } 118 | 119 | /* note that exactly one of the three 'if' conditions is true, 120 | so we include exactly one decimal point */ 121 | /* Zero padding on left of digit string */ 122 | if (decpt <= 0) { 123 | memset(p, '0', decpt - vdigits_start); 124 | p += decpt - vdigits_start; 125 | *p++ = '.'; 126 | memset(p, '0', 0 - decpt); 127 | p += 0 - decpt; 128 | } else { 129 | memset(p, '0', 0 - vdigits_start); 130 | p += 0 - vdigits_start; 131 | } 132 | 133 | /* Digits, with included decimal point */ 134 | if (0 < decpt && decpt <= digits_len) { 135 | strncpy(p, digits, decpt - 0); 136 | p += decpt - 0; 137 | *p++ = '.'; 138 | strncpy(p, digits + decpt, digits_len - decpt); 139 | p += digits_len - decpt; 140 | } else { 141 | strncpy(p, digits, digits_len); 142 | p += digits_len; 143 | } 144 | 145 | /* And zeros on the right */ 146 | if (digits_len < decpt) { 147 | memset(p, '0', decpt - digits_len); 148 | p += decpt - digits_len; 149 | *p++ = '.'; 150 | memset(p, '0', vdigits_end - decpt); 151 | p += vdigits_end - decpt; 152 | } else { 153 | memset(p, '0', vdigits_end - digits_len); 154 | p += vdigits_end - digits_len; 155 | } 156 | 157 | if (p[-1] == '.') 158 | p--; 159 | 160 | if (use_exp) { 161 | *p++ = 'e'; 162 | exp_len = sprintf(p, "%d", exp); 163 | p += exp_len; 164 | } 165 | *p = '\0'; 166 | 167 | return (int)(p - buffer); 168 | } 169 | #else /* DTOA_ENABLED == 0 */ 170 | static void from_locale(char *buffer) { 171 | char point; 172 | char *pos; 173 | 174 | point = get_decimal_point(); 175 | if (point == '.') { 176 | /* No conversion needed */ 177 | return; 178 | } 179 | 180 | pos = strchr(buffer, point); 181 | if (pos) 182 | *pos = '.'; 183 | } 184 | 185 | int jsonp_dtostr(char *buffer, size_t size, double value, int precision) { 186 | int ret; 187 | char *start, *end; 188 | size_t length; 189 | 190 | if (precision == 0) 191 | precision = 17; 192 | 193 | ret = snprintf(buffer, size, "%.*g", precision, value); 194 | if (ret < 0) 195 | return -1; 196 | 197 | length = (size_t)ret; 198 | if (length >= size) 199 | return -1; 200 | 201 | from_locale(buffer); 202 | 203 | /* Make sure there's a dot or 'e' in the output. Otherwise 204 | a real is converted to an integer when decoding */ 205 | if (strchr(buffer, '.') == NULL && strchr(buffer, 'e') == NULL) { 206 | if (length + 3 >= size) { 207 | /* No space to append ".0" */ 208 | return -1; 209 | } 210 | buffer[length] = '.'; 211 | buffer[length + 1] = '0'; 212 | buffer[length + 2] = '\0'; 213 | length += 2; 214 | } 215 | 216 | /* Remove leading '+' from positive exponent. Also remove leading 217 | zeros from exponents (added by some printf() implementations) */ 218 | start = strchr(buffer, 'e'); 219 | if (start) { 220 | start++; 221 | end = start + 1; 222 | 223 | if (*start == '-') 224 | start++; 225 | 226 | while (*end == '0') 227 | end++; 228 | 229 | if (end != start) { 230 | memmove(start, end, length - (size_t)(end - buffer)); 231 | length -= (size_t)(end - start); 232 | } 233 | } 234 | 235 | return (int)length; 236 | } 237 | #endif 238 | -------------------------------------------------------------------------------- /src/utf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #include "utf.h" 9 | #include 10 | 11 | int utf8_encode(int32_t codepoint, char *buffer, size_t *size) { 12 | if (codepoint < 0) 13 | return -1; 14 | else if (codepoint < 0x80) { 15 | buffer[0] = (char)codepoint; 16 | *size = 1; 17 | } else if (codepoint < 0x800) { 18 | buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6); 19 | buffer[1] = 0x80 + ((codepoint & 0x03F)); 20 | *size = 2; 21 | } else if (codepoint < 0x10000) { 22 | buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12); 23 | buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6); 24 | buffer[2] = 0x80 + ((codepoint & 0x003F)); 25 | *size = 3; 26 | } else if (codepoint <= 0x10FFFF) { 27 | buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18); 28 | buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12); 29 | buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6); 30 | buffer[3] = 0x80 + ((codepoint & 0x00003F)); 31 | *size = 4; 32 | } else 33 | return -1; 34 | 35 | return 0; 36 | } 37 | 38 | size_t utf8_check_first(char byte) { 39 | unsigned char u = (unsigned char)byte; 40 | 41 | if (u < 0x80) 42 | return 1; 43 | 44 | if (0x80 <= u && u <= 0xBF) { 45 | /* second, third or fourth byte of a multi-byte 46 | sequence, i.e. a "continuation byte" */ 47 | return 0; 48 | } else if (u == 0xC0 || u == 0xC1) { 49 | /* overlong encoding of an ASCII byte */ 50 | return 0; 51 | } else if (0xC2 <= u && u <= 0xDF) { 52 | /* 2-byte sequence */ 53 | return 2; 54 | } 55 | 56 | else if (0xE0 <= u && u <= 0xEF) { 57 | /* 3-byte sequence */ 58 | return 3; 59 | } else if (0xF0 <= u && u <= 0xF4) { 60 | /* 4-byte sequence */ 61 | return 4; 62 | } else { /* u >= 0xF5 */ 63 | /* Restricted (start of 4-, 5- or 6-byte sequence) or invalid 64 | UTF-8 */ 65 | return 0; 66 | } 67 | } 68 | 69 | size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint) { 70 | size_t i; 71 | int32_t value = 0; 72 | unsigned char u = (unsigned char)buffer[0]; 73 | 74 | if (size == 2) { 75 | value = u & 0x1F; 76 | } else if (size == 3) { 77 | value = u & 0xF; 78 | } else if (size == 4) { 79 | value = u & 0x7; 80 | } else 81 | return 0; 82 | 83 | for (i = 1; i < size; i++) { 84 | u = (unsigned char)buffer[i]; 85 | 86 | if (u < 0x80 || u > 0xBF) { 87 | /* not a continuation byte */ 88 | return 0; 89 | } 90 | 91 | value = (value << 6) + (u & 0x3F); 92 | } 93 | 94 | if (value > 0x10FFFF) { 95 | /* not in Unicode range */ 96 | return 0; 97 | } 98 | 99 | else if (0xD800 <= value && value <= 0xDFFF) { 100 | /* invalid code point (UTF-16 surrogate halves) */ 101 | return 0; 102 | } 103 | 104 | else if ((size == 2 && value < 0x80) || (size == 3 && value < 0x800) || 105 | (size == 4 && value < 0x10000)) { 106 | /* overlong encoding */ 107 | return 0; 108 | } 109 | 110 | if (codepoint) 111 | *codepoint = value; 112 | 113 | return 1; 114 | } 115 | 116 | const char *utf8_iterate(const char *buffer, size_t bufsize, int32_t *codepoint) { 117 | size_t count; 118 | int32_t value; 119 | 120 | if (!bufsize) 121 | return buffer; 122 | 123 | count = utf8_check_first(buffer[0]); 124 | if (count <= 0) 125 | return NULL; 126 | 127 | if (count == 1) 128 | value = (unsigned char)buffer[0]; 129 | else { 130 | if (count > bufsize || !utf8_check_full(buffer, count, &value)) 131 | return NULL; 132 | } 133 | 134 | if (codepoint) 135 | *codepoint = value; 136 | 137 | return buffer + count; 138 | } 139 | 140 | int utf8_check_string(const char *string, size_t length) { 141 | size_t i; 142 | 143 | for (i = 0; i < length; i++) { 144 | size_t count = utf8_check_first(string[i]); 145 | if (count == 0) 146 | return 0; 147 | else if (count > 1) { 148 | if (count > length - i) 149 | return 0; 150 | 151 | if (!utf8_check_full(&string[i], count, NULL)) 152 | return 0; 153 | 154 | i += count - 1; 155 | } 156 | } 157 | 158 | return 1; 159 | } 160 | -------------------------------------------------------------------------------- /src/utf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #ifndef UTF_H 9 | #define UTF_H 10 | 11 | #ifdef HAVE_CONFIG_H 12 | #include 13 | #endif 14 | 15 | #include 16 | #ifdef HAVE_STDINT_H 17 | #include 18 | #endif 19 | 20 | int utf8_encode(int32_t codepoint, char *buffer, size_t *size); 21 | 22 | size_t utf8_check_first(char byte); 23 | size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint); 24 | const char *utf8_iterate(const char *buffer, size_t size, int32_t *codepoint); 25 | 26 | int utf8_check_string(const char *string, size_t length); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/version.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Sean Bright 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #ifndef _GNU_SOURCE 9 | #define _GNU_SOURCE 10 | #endif 11 | 12 | #include "jansson.h" 13 | 14 | const char *jansson_version_str(void) { return JANSSON_VERSION; } 15 | 16 | int jansson_version_cmp(int major, int minor, int micro) { 17 | int diff; 18 | 19 | if ((diff = JANSSON_MAJOR_VERSION - major)) { 20 | return diff; 21 | } 22 | 23 | if ((diff = JANSSON_MINOR_VERSION - minor)) { 24 | return diff; 25 | } 26 | 27 | return JANSSON_MICRO_VERSION - micro; 28 | } 29 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | bin/json_process 3 | suites/api/test_array 4 | suites/api/test_chaos 5 | suites/api/test_copy 6 | suites/api/test_cpp 7 | suites/api/test_dump 8 | suites/api/test_dump_callback 9 | suites/api/test_equal 10 | suites/api/test_fixed_size 11 | suites/api/test_load 12 | suites/api/test_load_callback 13 | suites/api/test_loadb 14 | suites/api/test_memory_funcs 15 | suites/api/test_number 16 | suites/api/test_object 17 | suites/api/test_pack 18 | suites/api/test_simple 19 | suites/api/test_sprintf 20 | suites/api/test_unpack 21 | suites/api/test_version 22 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = bin suites ossfuzz 2 | EXTRA_DIST = scripts run-suites 3 | 4 | TESTS = run-suites 5 | TESTS_ENVIRONMENT = \ 6 | top_srcdir=$(top_srcdir) \ 7 | top_builddir=$(top_builddir) 8 | 9 | clean-local: 10 | rm -rf logs 11 | -------------------------------------------------------------------------------- /test/bin/Makefile.am: -------------------------------------------------------------------------------- 1 | check_PROGRAMS = json_process 2 | 3 | AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src 4 | LDFLAGS = -static # for speed and Valgrind 5 | LDADD = $(top_builddir)/src/libjansson.la 6 | -------------------------------------------------------------------------------- /test/ossfuzz/.gitignore: -------------------------------------------------------------------------------- 1 | json_load_dump_fuzzer 2 | -------------------------------------------------------------------------------- /test/ossfuzz/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src 2 | LDADD = $(top_builddir)/src/libjansson.la 3 | 4 | if USE_OSSFUZZ_FLAG 5 | FUZZ_FLAG = $(LIB_FUZZING_ENGINE) 6 | else 7 | if USE_OSSFUZZ_STATIC 8 | LDADD += $(LIB_FUZZING_ENGINE) 9 | FUZZ_FLAG = 10 | else 11 | LDADD += libstandaloneengine.a 12 | FUZZ_FLAG = 13 | endif 14 | endif 15 | 16 | noinst_PROGRAMS = 17 | noinst_LIBRARIES = 18 | 19 | if USE_OSSFUZZERS 20 | noinst_PROGRAMS += \ 21 | json_load_dump_fuzzer 22 | 23 | noinst_LIBRARIES += \ 24 | libstandaloneengine.a 25 | endif 26 | 27 | json_load_dump_fuzzer_SOURCES = json_load_dump_fuzzer.cc testinput.h 28 | json_load_dump_fuzzer_CXXFLAGS = $(AM_CXXFLAGS) $(FUZZ_FLAG) 29 | json_load_dump_fuzzer_LDFLAGS = $(AM_LDFLAGS) -static 30 | 31 | libstandaloneengine_a_SOURCES = standaloneengine.cc 32 | libstandaloneengine_a_CXXFLAGS = $(AM_CXXFLAGS) 33 | -------------------------------------------------------------------------------- /test/ossfuzz/json_load_dump_fuzzer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "jansson.h" 7 | 8 | static int enable_diags; 9 | 10 | #define FUZZ_DEBUG(FMT, ...) \ 11 | if (enable_diags) \ 12 | { \ 13 | fprintf(stderr, FMT, ##__VA_ARGS__); \ 14 | fprintf(stderr, "\n"); \ 15 | } 16 | 17 | 18 | static int json_dump_counter(const char *buffer, size_t size, void *data) 19 | { 20 | uint64_t *counter = reinterpret_cast(data); 21 | *counter += size; 22 | return 0; 23 | } 24 | 25 | 26 | #define NUM_COMMAND_BYTES (sizeof(size_t) + sizeof(size_t) + 1) 27 | 28 | #define FUZZ_DUMP_CALLBACK 0x00 29 | #define FUZZ_DUMP_STRING 0x01 30 | 31 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 32 | { 33 | json_error_t error; 34 | unsigned char dump_mode; 35 | 36 | // Enable or disable diagnostics based on the FUZZ_VERBOSE environment flag. 37 | enable_diags = (getenv("FUZZ_VERBOSE") != NULL); 38 | 39 | FUZZ_DEBUG("Input data length: %zd", size); 40 | 41 | if (size < NUM_COMMAND_BYTES) 42 | { 43 | return 0; 44 | } 45 | 46 | // Use the first sizeof(size_t) bytes as load flags. 47 | size_t load_flags = *(const size_t*)data; 48 | data += sizeof(size_t); 49 | 50 | FUZZ_DEBUG("load_flags: 0x%zx\n" 51 | "& JSON_REJECT_DUPLICATES = 0x%zx\n" 52 | "& JSON_DECODE_ANY = 0x%zx\n" 53 | "& JSON_DISABLE_EOF_CHECK = 0x%zx\n" 54 | "& JSON_DECODE_INT_AS_REAL = 0x%zx\n" 55 | "& JSON_ALLOW_NUL = 0x%zx\n", 56 | load_flags, 57 | load_flags & JSON_REJECT_DUPLICATES, 58 | load_flags & JSON_DECODE_ANY, 59 | load_flags & JSON_DISABLE_EOF_CHECK, 60 | load_flags & JSON_DECODE_INT_AS_REAL, 61 | load_flags & JSON_ALLOW_NUL); 62 | 63 | // Use the next sizeof(size_t) bytes as dump flags. 64 | size_t dump_flags = *(const size_t*)data; 65 | data += sizeof(size_t); 66 | 67 | FUZZ_DEBUG("dump_flags: 0x%zx\n" 68 | "& JSON_MAX_INDENT = 0x%zx\n" 69 | "& JSON_COMPACT = 0x%zx\n" 70 | "& JSON_ENSURE_ASCII = 0x%zx\n" 71 | "& JSON_SORT_KEYS = 0x%zx\n" 72 | "& JSON_PRESERVE_ORDER = 0x%zx\n" 73 | "& JSON_ENCODE_ANY = 0x%zx\n" 74 | "& JSON_ESCAPE_SLASH = 0x%zx\n" 75 | "& JSON_REAL_PRECISION = 0x%zx\n" 76 | "& JSON_EMBED = 0x%zx\n", 77 | dump_flags, 78 | dump_flags & JSON_MAX_INDENT, 79 | dump_flags & JSON_COMPACT, 80 | dump_flags & JSON_ENSURE_ASCII, 81 | dump_flags & JSON_SORT_KEYS, 82 | dump_flags & JSON_PRESERVE_ORDER, 83 | dump_flags & JSON_ENCODE_ANY, 84 | dump_flags & JSON_ESCAPE_SLASH, 85 | ((dump_flags >> 11) & 0x1F) << 11, 86 | dump_flags & JSON_EMBED); 87 | 88 | // Use the next byte as the dump mode. 89 | dump_mode = data[0]; 90 | data++; 91 | 92 | FUZZ_DEBUG("dump_mode: 0x%x", (unsigned int)dump_mode); 93 | 94 | // Remove the command bytes from the size total. 95 | size -= NUM_COMMAND_BYTES; 96 | 97 | // Attempt to load the remainder of the data with the given load flags. 98 | const char* text = reinterpret_cast(data); 99 | json_t* jobj = json_loadb(text, size, load_flags, &error); 100 | 101 | if (jobj == NULL) 102 | { 103 | return 0; 104 | } 105 | 106 | if (dump_mode & FUZZ_DUMP_STRING) 107 | { 108 | // Dump as a string. Remove indents so that we don't run out of memory. 109 | char *out = json_dumps(jobj, dump_flags & ~JSON_MAX_INDENT); 110 | if (out != NULL) 111 | { 112 | free(out); 113 | } 114 | } 115 | else 116 | { 117 | // Default is callback mode. 118 | // 119 | // Attempt to dump the loaded json object with the given dump flags. 120 | uint64_t counter = 0; 121 | 122 | json_dump_callback(jobj, json_dump_counter, &counter, dump_flags); 123 | FUZZ_DEBUG("Counter function counted %" PRIu64 " bytes.", counter); 124 | } 125 | 126 | if (jobj) 127 | { 128 | json_decref(jobj); 129 | } 130 | 131 | return 0; 132 | } 133 | -------------------------------------------------------------------------------- /test/ossfuzz/ossfuzz.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | # This script is called by the oss-fuzz main project when compiling the fuzz 4 | # targets. This script is regression tested by travisoss.sh. 5 | 6 | # Save off the current folder as the build root. 7 | export BUILD_ROOT=$PWD 8 | 9 | echo "CC: $CC" 10 | echo "CXX: $CXX" 11 | echo "LIB_FUZZING_ENGINE: $LIB_FUZZING_ENGINE" 12 | echo "CFLAGS: $CFLAGS" 13 | echo "CXXFLAGS: $CXXFLAGS" 14 | echo "OUT: $OUT" 15 | 16 | export MAKEFLAGS+="-j$(nproc)" 17 | 18 | # Install dependencies 19 | apt-get -y install automake libtool 20 | 21 | # Compile the fuzzer. 22 | autoreconf -i 23 | ./configure --enable-ossfuzzers 24 | make 25 | 26 | # Copy the fuzzer to the output directory. 27 | cp -v test/ossfuzz/json_load_dump_fuzzer $OUT/ 28 | 29 | # Zip up all input files to use as a test corpus 30 | find test/suites -name "input" -print | zip $OUT/json_load_dump_fuzzer_seed_corpus.zip -@ 31 | -------------------------------------------------------------------------------- /test/ossfuzz/standaloneengine.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "testinput.h" 6 | 7 | /** 8 | * Main procedure for standalone fuzzing engine. 9 | * 10 | * Reads filenames from the argument array. For each filename, read the file 11 | * into memory and then call the fuzzing interface with the data. 12 | */ 13 | int main(int argc, char **argv) 14 | { 15 | int ii; 16 | for(ii = 1; ii < argc; ii++) 17 | { 18 | FILE *infile; 19 | printf("[%s] ", argv[ii]); 20 | 21 | /* Try and open the file. */ 22 | infile = fopen(argv[ii], "rb"); 23 | if(infile) 24 | { 25 | uint8_t *buffer = NULL; 26 | size_t buffer_len; 27 | 28 | printf("Opened.. "); 29 | 30 | /* Get the length of the file. */ 31 | fseek(infile, 0L, SEEK_END); 32 | buffer_len = ftell(infile); 33 | 34 | /* Reset the file indicator to the beginning of the file. */ 35 | fseek(infile, 0L, SEEK_SET); 36 | 37 | /* Allocate a buffer for the file contents. */ 38 | buffer = (uint8_t *)calloc(buffer_len, sizeof(uint8_t)); 39 | if(buffer) 40 | { 41 | /* Read all the text from the file into the buffer. */ 42 | fread(buffer, sizeof(uint8_t), buffer_len, infile); 43 | printf("Read %zu bytes, fuzzing.. ", buffer_len); 44 | 45 | /* Call the fuzzer with the data. */ 46 | LLVMFuzzerTestOneInput(buffer, buffer_len); 47 | 48 | printf("complete !!"); 49 | 50 | /* Free the buffer as it's no longer needed. */ 51 | free(buffer); 52 | buffer = NULL; 53 | } 54 | else 55 | { 56 | fprintf(stderr, 57 | "[%s] Failed to allocate %zu bytes \n", 58 | argv[ii], 59 | buffer_len); 60 | } 61 | 62 | /* Close the file as it's no longer needed. */ 63 | fclose(infile); 64 | infile = NULL; 65 | } 66 | else 67 | { 68 | /* Failed to open the file. Maybe wrong name or wrong permissions? */ 69 | fprintf(stderr, "[%s] Open failed. \n", argv[ii]); 70 | } 71 | 72 | printf("\n"); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /test/ossfuzz/testinput.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); 4 | -------------------------------------------------------------------------------- /test/run-suites: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | while [ -n "$1" ]; do 4 | suite=$1 5 | if [ -x $top_srcdir/test/suites/$suite/run ]; then 6 | SUITES="$SUITES $suite" 7 | else 8 | echo "No such suite: $suite" 9 | exit 1 10 | fi 11 | shift 12 | done 13 | 14 | if [ -z "$SUITES" ]; then 15 | suitedirs=$top_srcdir/test/suites/* 16 | for suitedir in $suitedirs; do 17 | if [ -d $suitedir ]; then 18 | SUITES="$SUITES `basename $suitedir`" 19 | fi 20 | done 21 | fi 22 | 23 | [ -z "$STOP" ] && STOP=0 24 | 25 | suites_srcdir=$top_srcdir/test/suites 26 | suites_builddir=suites 27 | scriptdir=$top_srcdir/test/scripts 28 | logdir=logs 29 | bindir=bin 30 | export suites_srcdir suites_builddir scriptdir logdir bindir 31 | 32 | passed=0 33 | failed=0 34 | for suite in $SUITES; do 35 | echo "Suite: $suite" 36 | if $suites_srcdir/$suite/run $suite; then 37 | passed=`expr $passed + 1` 38 | else 39 | failed=`expr $failed + 1` 40 | [ $STOP -eq 1 ] && break 41 | fi 42 | done 43 | 44 | if [ $failed -gt 0 ]; then 45 | echo "$failed of `expr $passed + $failed` test suites failed" 46 | exit 1 47 | else 48 | echo "$passed test suites passed" 49 | rm -rf $logdir 50 | fi 51 | -------------------------------------------------------------------------------- /test/scripts/run-tests.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2009-2016 Petri Lehtinen 2 | # 3 | # Jansson is free software; you can redistribute it and/or modify 4 | # it under the terms of the MIT license. See LICENSE for details. 5 | 6 | die() { 7 | echo "$1" >&2 8 | exit 1 9 | } 10 | 11 | [ -n "$1" ] || die "Usage: $0 suite-name" 12 | [ -n "$bindir" ] || die "Set bindir" 13 | [ -n "$logdir" ] || die "Set logdir" 14 | [ -n "$scriptdir" ] || die "Set scriptdir" 15 | [ -n "$suites_srcdir" ] || die "Set suites_srcdir" 16 | [ -n "$suites_builddir" ] || die "Set suites_builddir" 17 | 18 | json_process=$bindir/json_process 19 | 20 | suite_name=$1 21 | suite_srcdir=$suites_srcdir/$suite_name 22 | suite_builddir=$suites_builddir/$suite_name 23 | suite_log=$logdir/$suite_name 24 | 25 | [ -z "$VERBOSE" ] && VERBOSE=0 26 | [ -z "$STOP" ] && STOP=0 27 | 28 | . $scriptdir/valgrind.sh 29 | 30 | rm -rf $suite_log 31 | mkdir -p $suite_log 32 | 33 | for test_path in $suite_srcdir/*; do 34 | test_name=$(basename $test_path) 35 | test_builddir=$suite_builddir/$test_name 36 | test_log=$suite_log/$test_name 37 | 38 | [ "$test_name" = "run" ] && continue 39 | is_test || continue 40 | 41 | rm -rf $test_log 42 | mkdir -p $test_log 43 | if [ $VERBOSE -eq 1 ]; then 44 | printf '%s... ' "$test_name" 45 | fi 46 | 47 | run_test 48 | case $? in 49 | 0) 50 | # Success 51 | if [ $VERBOSE -eq 1 ]; then 52 | printf 'ok\n' 53 | else 54 | printf '.' 55 | fi 56 | rm -rf $test_log 57 | ;; 58 | 59 | 77) 60 | # Skip 61 | if [ $VERBOSE -eq 1 ]; then 62 | printf 'skipped\n' 63 | else 64 | printf 'S' 65 | fi 66 | rm -rf $test_log 67 | ;; 68 | 69 | *) 70 | # Failure 71 | if [ $VERBOSE -eq 1 ]; then 72 | printf 'FAILED\n' 73 | else 74 | printf 'F' 75 | fi 76 | 77 | [ $STOP -eq 1 ] && break 78 | ;; 79 | esac 80 | done 81 | 82 | if [ $VERBOSE -eq 0 ]; then 83 | printf '\n' 84 | fi 85 | 86 | if [ -n "$(ls -A $suite_log)" ]; then 87 | for test_log in $suite_log/*; do 88 | test_name=$(basename $test_log) 89 | test_path=$suite_srcdir/$test_name 90 | echo "=================================================================" 91 | echo "$suite_name/$test_name" 92 | echo "=================================================================" 93 | show_error 94 | echo 95 | done 96 | echo "=================================================================" 97 | exit 1 98 | else 99 | rm -rf $suite_log 100 | fi 101 | -------------------------------------------------------------------------------- /test/scripts/valgrind.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2009-2016 Petri Lehtinen 2 | # 3 | # Jansson is free software; you can redistribute it and/or modify 4 | # it under the terms of the MIT license. See LICENSE for details. 5 | 6 | [ -z "$VALGRIND" ] && VALGRIND=0 7 | 8 | VALGRIND_CMDLINE="valgrind --leak-check=full --show-reachable=yes --track-origins=yes -q" 9 | 10 | if [ $VALGRIND -eq 1 ]; then 11 | test_runner="$VALGRIND_CMDLINE" 12 | json_process="$VALGRIND_CMDLINE $json_process" 13 | else 14 | test_runner="" 15 | fi 16 | 17 | valgrind_check() { 18 | if [ $VALGRIND -eq 1 ]; then 19 | # Check for Valgrind error output. The valgrind option 20 | # --error-exitcode is not enough because Valgrind doesn't 21 | # think unfreed allocs are errors. 22 | if grep -E -q '^==[0-9]+== ' $1; then 23 | touch $test_log/valgrind_error 24 | return 1 25 | fi 26 | fi 27 | } 28 | 29 | valgrind_show_error() { 30 | if [ $VALGRIND -eq 1 -a -f $test_log/valgrind_error ]; then 31 | echo "valgrind detected an error" 32 | return 0 33 | fi 34 | return 1 35 | } 36 | -------------------------------------------------------------------------------- /test/suites/.gitattributes: -------------------------------------------------------------------------------- 1 | api/ text=auto 2 | * text eol=lf -------------------------------------------------------------------------------- /test/suites/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = api 2 | EXTRA_DIST = invalid invalid-unicode valid 3 | -------------------------------------------------------------------------------- /test/suites/api/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = run check-exports 2 | 3 | check_PROGRAMS = \ 4 | test_array \ 5 | test_chaos \ 6 | test_copy \ 7 | test_dump \ 8 | test_dump_callback \ 9 | test_equal \ 10 | test_fixed_size \ 11 | test_load \ 12 | test_load_callback \ 13 | test_loadb \ 14 | test_memory_funcs \ 15 | test_number \ 16 | test_object \ 17 | test_pack \ 18 | test_simple \ 19 | test_sprintf \ 20 | test_unpack \ 21 | test_version 22 | 23 | test_array_SOURCES = test_array.c util.h 24 | test_chaos_SOURCES = test_chaos.c util.h 25 | test_copy_SOURCES = test_copy.c util.h 26 | test_dump_SOURCES = test_dump.c util.h 27 | test_dump_callback_SOURCES = test_dump_callback.c util.h 28 | test_fixed_size_SOURCES = test_fixed_size.c util.h 29 | test_load_SOURCES = test_load.c util.h 30 | test_loadb_SOURCES = test_loadb.c util.h 31 | test_memory_funcs_SOURCES = test_memory_funcs.c util.h 32 | test_number_SOURCES = test_number.c util.h 33 | test_object_SOURCES = test_object.c util.h 34 | test_pack_SOURCES = test_pack.c util.h 35 | test_simple_SOURCES = test_simple.c util.h 36 | test_sprintf_SOURCES = test_sprintf.c util.h 37 | test_unpack_SOURCES = test_unpack.c util.h 38 | test_version_SOURCES = test_version.c util.h 39 | 40 | AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src 41 | LDFLAGS = -static # for speed and Valgrind 42 | LDADD = $(top_builddir)/src/libjansson.la 43 | -------------------------------------------------------------------------------- /test/suites/api/check-exports: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This test checks that libjansson.so exports the correct symbols. 4 | # 5 | 6 | SOFILE="../src/.libs/libjansson.so" 7 | 8 | # The list of symbols, which the shared object should export, is read 9 | # from the def file, which is used in Windows builds 10 | grep 'json_\|jansson_' $top_srcdir/src/jansson.def \ 11 | | sed -e 's/ //g' \ 12 | | sort \ 13 | >$test_log/exports 14 | 15 | nm -D $SOFILE >/dev/null >$test_log/symbols 2>/dev/null \ 16 | || exit 77 # Skip if "nm -D" doesn't seem to work 17 | 18 | grep ' [DT] ' $test_log/symbols | cut -d' ' -f3 | grep -v '^_' | sed 's/@@libjansson.*//' | sort >$test_log/output 19 | 20 | if ! cmp -s $test_log/exports $test_log/output; then 21 | diff -u $test_log/exports $test_log/output >&2 22 | exit 1 23 | fi 24 | -------------------------------------------------------------------------------- /test/suites/api/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2009-2016 Petri Lehtinen 4 | # 5 | # Jansson is free software; you can redistribute it and/or modify 6 | # it under the terms of the MIT license. See LICENSE for details. 7 | 8 | is_test() { 9 | case "$test_name" in 10 | *.c|check-exports) 11 | return 0 12 | ;; 13 | *) 14 | return 1 15 | ;; 16 | esac 17 | } 18 | 19 | run_test() { 20 | if [ "$test_name" = "check-exports" ]; then 21 | test_log=$test_log $test_path >$test_log/stdout 2>$test_log/stderr 22 | else 23 | $test_runner $suite_builddir/${test_name%.c} \ 24 | >$test_log/stdout \ 25 | 2>$test_log/stderr \ 26 | || return 1 27 | valgrind_check $test_log/stderr || return 1 28 | fi 29 | } 30 | 31 | show_error() { 32 | valgrind_show_error && return 33 | cat $test_log/stderr 34 | } 35 | 36 | . $top_srcdir/test/scripts/run-tests.sh 37 | -------------------------------------------------------------------------------- /test/suites/api/test_chaos.c: -------------------------------------------------------------------------------- 1 | #ifndef _GNU_SOURCE 2 | #define _GNU_SOURCE 3 | #endif 4 | 5 | #include "util.h" 6 | #include 7 | #include 8 | #include 9 | 10 | static int chaos_pos = 0; 11 | static int chaos_fail = 0; 12 | #define CHAOS_MAX_FAILURE 100 13 | 14 | void *chaos_malloc(size_t size) { 15 | if (chaos_pos == chaos_fail) 16 | return NULL; 17 | 18 | chaos_pos++; 19 | 20 | return malloc(size); 21 | } 22 | 23 | void chaos_free(void *obj) { free(obj); } 24 | 25 | /* Test all potential allocation failures. */ 26 | #define chaos_loop(condition, code, cleanup) \ 27 | { \ 28 | chaos_pos = chaos_fail = 0; \ 29 | while (condition) { \ 30 | if (chaos_fail > CHAOS_MAX_FAILURE) \ 31 | fail("too many chaos failures"); \ 32 | code chaos_pos = 0; \ 33 | chaos_fail++; \ 34 | } \ 35 | cleanup \ 36 | } 37 | 38 | #define chaos_loop_new_value(json, initcall) \ 39 | chaos_loop(!json, json = initcall;, json_decref(json); json = NULL;) 40 | 41 | int test_unpack() { 42 | int ret = -1; 43 | int v1; 44 | int v2; 45 | json_error_t error; 46 | json_t *root = json_pack("{s:i, s:i, s:i, s:i}", "n1", 1, "n2", 2, "n3", 3, "n4", 4); 47 | 48 | if (!root) 49 | return -1; 50 | 51 | if (!json_unpack_ex(root, &error, JSON_STRICT, "{s:i, s:i}", "n1", &v1, "n2", &v2)) 52 | fail("Unexpected success"); 53 | 54 | if (json_error_code(&error) != json_error_end_of_input_expected) { 55 | if (json_error_code(&error) != json_error_out_of_memory) 56 | fail("Unexpected error code"); 57 | 58 | goto out; 59 | } 60 | 61 | if (strcmp(error.text, "2 object item(s) left unpacked: n3, n4")) 62 | goto out; 63 | 64 | ret = 0; 65 | 66 | out: 67 | json_decref(root); 68 | return ret; 69 | } 70 | 71 | int dump_chaos_callback(const char *buffer, size_t size, void *data) { 72 | json_t *obj = json_object(); 73 | 74 | (void)buffer; 75 | (void)size; 76 | (void)data; 77 | 78 | if (!obj) 79 | return -1; 80 | 81 | json_decref(obj); 82 | 83 | return 0; 84 | } 85 | 86 | static void test_chaos() { 87 | json_malloc_t orig_malloc; 88 | json_free_t orig_free; 89 | json_t *json = NULL; 90 | json_t *obj = json_object(); 91 | json_t *arr1 = json_array(); 92 | json_t *arr2 = json_array(); 93 | json_t *txt = json_string("test"); 94 | json_t *intnum = json_integer(1); 95 | json_t *dblnum = json_real(0.5); 96 | char *dumptxt = NULL; 97 | json_t *dumpobj = json_pack("{s:[iiis], s:s}", "key1", 1, 2, 3, "txt", "key2", "v2"); 98 | int keyno; 99 | 100 | if (!obj || !arr1 || !arr2 || !txt || !intnum || !dblnum || !dumpobj) 101 | fail("failed to allocate basic objects"); 102 | 103 | json_get_alloc_funcs(&orig_malloc, &orig_free); 104 | json_set_alloc_funcs(chaos_malloc, chaos_free); 105 | 106 | chaos_loop_new_value(json, json_pack("{s:s}", "key", "value")); 107 | chaos_loop_new_value(json, json_pack("{s:[]}", "key")); 108 | chaos_loop_new_value(json, json_pack("[biIf]", 1, 1, (json_int_t)1, 1.0)); 109 | chaos_loop_new_value(json, json_pack("[s*,s*]", "v1", "v2")); 110 | chaos_loop_new_value(json, json_pack("o", json_incref(txt))); 111 | chaos_loop_new_value(json, json_pack("O", txt)); 112 | chaos_loop_new_value(json, json_pack("s++", "a", "long string to force realloc", 113 | "another long string to force yet another " 114 | "reallocation of the string because " 115 | "that's what we are testing.")); 116 | 117 | chaos_loop(test_unpack(), , ); 118 | 119 | chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL, JSON_INDENT(1)), 120 | , ); 121 | chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL, 122 | JSON_INDENT(1) | JSON_SORT_KEYS), 123 | , ); 124 | chaos_loop(!dumptxt, dumptxt = json_dumps(dumpobj, JSON_COMPACT);, free(dumptxt); 125 | dumptxt = NULL;); 126 | 127 | chaos_loop_new_value(json, json_copy(obj)); 128 | chaos_loop_new_value(json, json_deep_copy(obj)); 129 | 130 | chaos_loop_new_value(json, json_copy(arr1)); 131 | chaos_loop_new_value(json, json_deep_copy(arr1)); 132 | 133 | chaos_loop_new_value(json, json_copy(txt)); 134 | chaos_loop_new_value(json, json_copy(intnum)); 135 | chaos_loop_new_value(json, json_copy(dblnum)); 136 | 137 | #define JSON_LOAD_TXT "{\"n\":[1,2,3,4,5,6,7,8,9,10]}" 138 | chaos_loop_new_value(json, json_loads(JSON_LOAD_TXT, 0, NULL)); 139 | chaos_loop_new_value(json, json_loadb(JSON_LOAD_TXT, strlen(JSON_LOAD_TXT), 0, NULL)); 140 | 141 | chaos_loop_new_value(json, json_sprintf("%s", "string")); 142 | 143 | for (keyno = 0; keyno < 100; ++keyno) { 144 | #if !defined(_MSC_VER) || _MSC_VER >= 1900 145 | /* Skip this test on old Windows compilers. */ 146 | char testkey[10]; 147 | 148 | snprintf(testkey, sizeof(testkey), "test%d", keyno); 149 | chaos_loop(json_object_set_new_nocheck(obj, testkey, json_object()), , ); 150 | #endif 151 | chaos_loop(json_array_append_new(arr1, json_null()), , ); 152 | chaos_loop(json_array_insert_new(arr2, 0, json_null()), , ); 153 | } 154 | 155 | chaos_loop(json_array_extend(arr1, arr2), , ); 156 | chaos_loop(json_string_set_nocheck(txt, "test"), , ); 157 | 158 | json_set_alloc_funcs(orig_malloc, orig_free); 159 | json_decref(obj); 160 | json_decref(arr1); 161 | json_decref(arr2); 162 | json_decref(txt); 163 | json_decref(intnum); 164 | json_decref(dblnum); 165 | json_decref(dumpobj); 166 | } 167 | 168 | static void run_tests() { test_chaos(); } 169 | -------------------------------------------------------------------------------- /test/suites/api/test_dump_callback.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #include "util.h" 9 | #include 10 | #include 11 | #include 12 | 13 | struct my_sink { 14 | char *buf; 15 | size_t off; 16 | size_t cap; 17 | }; 18 | 19 | static int my_writer(const char *buffer, size_t len, void *data) { 20 | struct my_sink *s = data; 21 | if (len > s->cap - s->off) { 22 | return -1; 23 | } 24 | memcpy(s->buf + s->off, buffer, len); 25 | s->off += len; 26 | return 0; 27 | } 28 | 29 | static void run_tests() { 30 | struct my_sink s; 31 | json_t *json; 32 | const char str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]"; 33 | char *dumped_to_string; 34 | 35 | json = json_loads(str, 0, NULL); 36 | if (!json) { 37 | fail("json_loads failed"); 38 | } 39 | 40 | dumped_to_string = json_dumps(json, 0); 41 | if (!dumped_to_string) { 42 | json_decref(json); 43 | fail("json_dumps failed"); 44 | } 45 | 46 | s.off = 0; 47 | s.cap = strlen(dumped_to_string); 48 | s.buf = malloc(s.cap); 49 | if (!s.buf) { 50 | json_decref(json); 51 | free(dumped_to_string); 52 | fail("malloc failed"); 53 | } 54 | 55 | if (json_dump_callback(json, my_writer, &s, 0) == -1) { 56 | json_decref(json); 57 | free(dumped_to_string); 58 | free(s.buf); 59 | fail("json_dump_callback failed on an exact-length sink buffer"); 60 | } 61 | 62 | if (strncmp(dumped_to_string, s.buf, s.off) != 0) { 63 | json_decref(json); 64 | free(dumped_to_string); 65 | free(s.buf); 66 | fail("json_dump_callback and json_dumps did not produce identical " 67 | "output"); 68 | } 69 | 70 | s.off = 1; 71 | if (json_dump_callback(json, my_writer, &s, 0) != -1) { 72 | json_decref(json); 73 | free(dumped_to_string); 74 | free(s.buf); 75 | fail("json_dump_callback succeeded on a short buffer when it should " 76 | "have failed"); 77 | } 78 | 79 | json_decref(json); 80 | free(dumped_to_string); 81 | free(s.buf); 82 | } 83 | -------------------------------------------------------------------------------- /test/suites/api/test_equal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #include "util.h" 9 | #include 10 | 11 | static void test_equal_simple() { 12 | json_t *value1, *value2; 13 | 14 | if (json_equal(NULL, NULL)) 15 | fail("json_equal fails for two NULLs"); 16 | 17 | value1 = json_true(); 18 | if (json_equal(value1, NULL) || json_equal(NULL, value1)) 19 | fail("json_equal fails for NULL"); 20 | 21 | /* this covers true, false and null as they are singletons */ 22 | if (!json_equal(value1, value1)) 23 | fail("identical objects are not equal"); 24 | json_decref(value1); 25 | 26 | /* integer */ 27 | value1 = json_integer(1); 28 | value2 = json_integer(1); 29 | if (!value1 || !value2) 30 | fail("unable to create integers"); 31 | if (!json_equal(value1, value2)) 32 | fail("json_equal fails for two equal integers"); 33 | json_decref(value2); 34 | 35 | value2 = json_integer(2); 36 | if (!value2) 37 | fail("unable to create an integer"); 38 | if (json_equal(value1, value2)) 39 | fail("json_equal fails for two inequal integers"); 40 | 41 | json_decref(value1); 42 | json_decref(value2); 43 | 44 | /* real */ 45 | value1 = json_real(1.2); 46 | value2 = json_real(1.2); 47 | if (!value1 || !value2) 48 | fail("unable to create reals"); 49 | if (!json_equal(value1, value2)) 50 | fail("json_equal fails for two equal reals"); 51 | json_decref(value2); 52 | 53 | value2 = json_real(3.141592); 54 | if (!value2) 55 | fail("unable to create an real"); 56 | if (json_equal(value1, value2)) 57 | fail("json_equal fails for two inequal reals"); 58 | 59 | json_decref(value1); 60 | json_decref(value2); 61 | 62 | /* string */ 63 | value1 = json_string("foo"); 64 | value2 = json_string("foo"); 65 | if (!value1 || !value2) 66 | fail("unable to create strings"); 67 | if (!json_equal(value1, value2)) 68 | fail("json_equal fails for two equal strings"); 69 | json_decref(value2); 70 | 71 | value2 = json_string("bar"); 72 | if (!value2) 73 | fail("unable to create an string"); 74 | if (json_equal(value1, value2)) 75 | fail("json_equal fails for two inequal strings"); 76 | json_decref(value2); 77 | 78 | value2 = json_string("bar2"); 79 | if (!value2) 80 | fail("unable to create an string"); 81 | if (json_equal(value1, value2)) 82 | fail("json_equal fails for two inequal length strings"); 83 | 84 | json_decref(value1); 85 | json_decref(value2); 86 | } 87 | 88 | static void test_equal_array() { 89 | json_t *array1, *array2; 90 | 91 | array1 = json_array(); 92 | array2 = json_array(); 93 | if (!array1 || !array2) 94 | fail("unable to create arrays"); 95 | 96 | if (!json_equal(array1, array2)) 97 | fail("json_equal fails for two empty arrays"); 98 | 99 | json_array_append_new(array1, json_integer(1)); 100 | json_array_append_new(array2, json_integer(1)); 101 | json_array_append_new(array1, json_string("foo")); 102 | json_array_append_new(array2, json_string("foo")); 103 | json_array_append_new(array1, json_integer(2)); 104 | json_array_append_new(array2, json_integer(2)); 105 | if (!json_equal(array1, array2)) 106 | fail("json_equal fails for two equal arrays"); 107 | 108 | json_array_remove(array2, 2); 109 | if (json_equal(array1, array2)) 110 | fail("json_equal fails for two inequal arrays"); 111 | 112 | json_array_append_new(array2, json_integer(3)); 113 | if (json_equal(array1, array2)) 114 | fail("json_equal fails for two inequal arrays"); 115 | 116 | json_decref(array1); 117 | json_decref(array2); 118 | } 119 | 120 | static void test_equal_object() { 121 | json_t *object1, *object2; 122 | 123 | object1 = json_object(); 124 | object2 = json_object(); 125 | if (!object1 || !object2) 126 | fail("unable to create objects"); 127 | 128 | if (!json_equal(object1, object2)) 129 | fail("json_equal fails for two empty objects"); 130 | 131 | json_object_set_new(object1, "a", json_integer(1)); 132 | json_object_set_new(object2, "a", json_integer(1)); 133 | json_object_set_new(object1, "b", json_string("foo")); 134 | json_object_set_new(object2, "b", json_string("foo")); 135 | json_object_set_new(object1, "c", json_integer(2)); 136 | json_object_set_new(object2, "c", json_integer(2)); 137 | if (!json_equal(object1, object2)) 138 | fail("json_equal fails for two equal objects"); 139 | 140 | json_object_del(object2, "c"); 141 | if (json_equal(object1, object2)) 142 | fail("json_equal fails for two inequal objects"); 143 | 144 | json_object_set_new(object2, "c", json_integer(3)); 145 | if (json_equal(object1, object2)) 146 | fail("json_equal fails for two inequal objects"); 147 | 148 | json_object_del(object2, "c"); 149 | json_object_set_new(object2, "d", json_integer(2)); 150 | if (json_equal(object1, object2)) 151 | fail("json_equal fails for two inequal objects"); 152 | 153 | json_decref(object1); 154 | json_decref(object2); 155 | } 156 | 157 | static void test_equal_complex() { 158 | json_t *value1, *value2, *value3; 159 | 160 | const char *complex_json = "{" 161 | " \"integer\": 1, " 162 | " \"real\": 3.141592, " 163 | " \"string\": \"foobar\", " 164 | " \"true\": true, " 165 | " \"object\": {" 166 | " \"array-in-object\": [1,true,\"foo\",{}]," 167 | " \"object-in-object\": {\"foo\": \"bar\"}" 168 | " }," 169 | " \"array\": [\"foo\", false, null, 1.234]" 170 | "}"; 171 | 172 | value1 = json_loads(complex_json, 0, NULL); 173 | value2 = json_loads(complex_json, 0, NULL); 174 | value3 = json_loads(complex_json, 0, NULL); 175 | if (!value1 || !value2) 176 | fail("unable to parse JSON"); 177 | if (!json_equal(value1, value2)) 178 | fail("json_equal fails for two equal objects"); 179 | 180 | json_array_set_new( 181 | json_object_get(json_object_get(value2, "object"), "array-in-object"), 1, 182 | json_false()); 183 | if (json_equal(value1, value2)) 184 | fail("json_equal fails for two inequal objects"); 185 | 186 | json_object_set_new( 187 | json_object_get(json_object_get(value3, "object"), "object-in-object"), "foo", 188 | json_string("baz")); 189 | if (json_equal(value1, value3)) 190 | fail("json_equal fails for two inequal objects"); 191 | 192 | json_decref(value1); 193 | json_decref(value2); 194 | json_decref(value3); 195 | } 196 | 197 | static void run_tests() { 198 | test_equal_simple(); 199 | test_equal_array(); 200 | test_equal_object(); 201 | test_equal_complex(); 202 | } 203 | -------------------------------------------------------------------------------- /test/suites/api/test_load_callback.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2011 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #include "util.h" 9 | #include 10 | #include 11 | #include 12 | 13 | struct my_source { 14 | const char *buf; 15 | size_t off; 16 | size_t cap; 17 | }; 18 | 19 | static const char my_str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]"; 20 | 21 | static size_t greedy_reader(void *buf, size_t buflen, void *arg) { 22 | struct my_source *s = arg; 23 | if (buflen > s->cap - s->off) 24 | buflen = s->cap - s->off; 25 | if (buflen > 0) { 26 | memcpy(buf, s->buf + s->off, buflen); 27 | s->off += buflen; 28 | return buflen; 29 | } else { 30 | return 0; 31 | } 32 | } 33 | 34 | static void run_tests() { 35 | struct my_source s; 36 | json_t *json; 37 | json_error_t error; 38 | 39 | s.off = 0; 40 | s.cap = strlen(my_str); 41 | s.buf = my_str; 42 | 43 | json = json_load_callback(greedy_reader, &s, 0, &error); 44 | 45 | if (!json) 46 | fail("json_load_callback failed on a valid callback"); 47 | json_decref(json); 48 | 49 | s.off = 0; 50 | s.cap = strlen(my_str) - 1; 51 | s.buf = my_str; 52 | 53 | json = json_load_callback(greedy_reader, &s, 0, &error); 54 | if (json) { 55 | json_decref(json); 56 | fail("json_load_callback should have failed on an incomplete stream, " 57 | "but it didn't"); 58 | } 59 | if (strcmp(error.source, "") != 0) { 60 | fail("json_load_callback returned an invalid error source"); 61 | } 62 | if (strcmp(error.text, "']' expected near end of file") != 0) { 63 | fail("json_load_callback returned an invalid error message for an " 64 | "unclosed top-level array"); 65 | } 66 | 67 | json = json_load_callback(NULL, NULL, 0, &error); 68 | if (json) { 69 | json_decref(json); 70 | fail("json_load_callback should have failed on NULL load callback, but " 71 | "it didn't"); 72 | } 73 | if (strcmp(error.text, "wrong arguments") != 0) { 74 | fail("json_load_callback returned an invalid error message for a NULL " 75 | "load callback"); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /test/suites/api/test_loadb.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #include "util.h" 9 | #include 10 | #include 11 | 12 | static void run_tests() { 13 | json_t *json; 14 | json_error_t error; 15 | const char str[] = "[\"A\", {\"B\": \"C\"}, 1, 2, 3]garbage"; 16 | size_t len = strlen(str) - strlen("garbage"); 17 | 18 | json = json_loadb(str, len, 0, &error); 19 | if (!json) { 20 | fail("json_loadb failed on a valid JSON buffer"); 21 | } 22 | json_decref(json); 23 | 24 | json = json_loadb(str, len - 1, 0, &error); 25 | if (json) { 26 | json_decref(json); 27 | fail("json_loadb should have failed on an incomplete buffer, but it " 28 | "didn't"); 29 | } 30 | if (error.line != 1) { 31 | fail("json_loadb returned an invalid line number on fail"); 32 | } 33 | if (strcmp(error.text, "']' expected near end of file") != 0) { 34 | fail("json_loadb returned an invalid error message for an unclosed " 35 | "top-level array"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/suites/api/test_memory_funcs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "util.h" 5 | 6 | static int malloc_called = 0; 7 | static int free_called = 0; 8 | static size_t malloc_used = 0; 9 | 10 | /* helpers */ 11 | static void create_and_free_complex_object() { 12 | json_t *obj; 13 | 14 | obj = json_pack("{s:i,s:n,s:b,s:b,s:{s:s},s:[i,i,i]}", "foo", 42, "bar", "baz", 1, 15 | "qux", 0, "alice", "bar", "baz", "bob", 9, 8, 7); 16 | 17 | json_decref(obj); 18 | } 19 | 20 | static void create_and_free_object_with_oom() { 21 | int i; 22 | char key[4]; 23 | json_t *obj = json_object(); 24 | 25 | for (i = 0; i < 10; i++) { 26 | snprintf(key, sizeof key, "%d", i); 27 | json_object_set_new(obj, key, json_integer(i)); 28 | } 29 | 30 | json_decref(obj); 31 | } 32 | 33 | static void *my_malloc(size_t size) { 34 | malloc_called = 1; 35 | return malloc(size); 36 | } 37 | 38 | static void my_free(void *ptr) { 39 | free_called = 1; 40 | free(ptr); 41 | } 42 | 43 | static void test_simple() { 44 | json_malloc_t mfunc = NULL; 45 | json_free_t ffunc = NULL; 46 | 47 | json_set_alloc_funcs(my_malloc, my_free); 48 | json_get_alloc_funcs(&mfunc, &ffunc); 49 | create_and_free_complex_object(); 50 | 51 | if (malloc_called != 1 || free_called != 1 || mfunc != my_malloc || ffunc != my_free) 52 | fail("Custom allocation failed"); 53 | } 54 | 55 | static void *oom_malloc(size_t size) { 56 | if (malloc_used + size > 800) 57 | return NULL; 58 | 59 | malloc_used += size; 60 | return malloc(size); 61 | } 62 | 63 | static void oom_free(void *ptr) { 64 | free_called++; 65 | free(ptr); 66 | } 67 | 68 | static void test_oom() { 69 | free_called = 0; 70 | json_set_alloc_funcs(oom_malloc, oom_free); 71 | create_and_free_object_with_oom(); 72 | 73 | if (free_called == 0) 74 | fail("Allocation with OOM failed"); 75 | } 76 | 77 | /* 78 | Test the secure memory functions code given in the API reference 79 | documentation, but by using plain memset instead of 80 | guaranteed_memset(). 81 | */ 82 | 83 | static void *secure_malloc(size_t size) { 84 | /* Store the memory area size in the beginning of the block */ 85 | void *ptr = malloc(size + 8); 86 | *((size_t *)ptr) = size; 87 | return (char *)ptr + 8; 88 | } 89 | 90 | static void secure_free(void *ptr) { 91 | size_t size; 92 | 93 | ptr = (char *)ptr - 8; 94 | size = *((size_t *)ptr); 95 | 96 | /*guaranteed_*/ memset(ptr, 0, size + 8); 97 | free(ptr); 98 | } 99 | 100 | static void test_secure_funcs(void) { 101 | json_set_alloc_funcs(secure_malloc, secure_free); 102 | create_and_free_complex_object(); 103 | } 104 | 105 | static void test_bad_args(void) { 106 | /* The result of this test is not crashing. */ 107 | json_get_alloc_funcs(NULL, NULL); 108 | } 109 | 110 | static void run_tests() { 111 | test_simple(); 112 | test_secure_funcs(); 113 | test_oom(); 114 | test_bad_args(); 115 | } 116 | -------------------------------------------------------------------------------- /test/suites/api/test_number.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #include "util.h" 9 | #include 10 | #include 11 | 12 | #ifdef INFINITY 13 | // This test triggers "warning C4756: overflow in constant arithmetic" 14 | // in Visual Studio. This warning is triggered here by design, so disable it. 15 | // (This can only be done on function level so we keep these tests separate) 16 | #ifdef _MSC_VER 17 | #pragma warning(push) 18 | #pragma warning(disable : 4756) 19 | #endif 20 | static void test_inifity() { 21 | json_t *real = json_real(INFINITY); 22 | if (real != NULL) 23 | fail("could construct a real from Inf"); 24 | 25 | real = json_real(1.0); 26 | if (json_real_set(real, INFINITY) != -1) 27 | fail("could set a real to Inf"); 28 | 29 | if (json_real_value(real) != 1.0) 30 | fail("real value changed unexpectedly"); 31 | 32 | json_decref(real); 33 | #ifdef _MSC_VER 34 | #pragma warning(pop) 35 | #endif 36 | } 37 | #endif // INFINITY 38 | 39 | static void test_bad_args(void) { 40 | json_t *txt = json_string("test"); 41 | 42 | if (json_integer_value(NULL) != 0) 43 | fail("json_integer_value did not return 0 for non-integer"); 44 | if (json_integer_value(txt) != 0) 45 | fail("json_integer_value did not return 0 for non-integer"); 46 | 47 | if (!json_integer_set(NULL, 0)) 48 | fail("json_integer_set did not return error for non-integer"); 49 | if (!json_integer_set(txt, 0)) 50 | fail("json_integer_set did not return error for non-integer"); 51 | 52 | if (json_real_value(NULL) != 0.0) 53 | fail("json_real_value did not return 0.0 for non-real"); 54 | if (json_real_value(txt) != 0.0) 55 | fail("json_real_value did not return 0.0 for non-real"); 56 | 57 | if (!json_real_set(NULL, 0.0)) 58 | fail("json_real_set did not return error for non-real"); 59 | if (!json_real_set(txt, 0.0)) 60 | fail("json_real_set did not return error for non-real"); 61 | 62 | if (json_number_value(NULL) != 0.0) 63 | fail("json_number_value did not return 0.0 for non-numeric"); 64 | if (json_number_value(txt) != 0.0) 65 | fail("json_number_value did not return 0.0 for non-numeric"); 66 | 67 | if (txt->refcount != 1) 68 | fail("unexpected reference count for txt"); 69 | 70 | json_decref(txt); 71 | } 72 | 73 | static void run_tests() { 74 | json_t *integer, *real; 75 | json_int_t i; 76 | double d; 77 | 78 | integer = json_integer(5); 79 | real = json_real(100.1); 80 | 81 | if (!integer) 82 | fail("unable to create integer"); 83 | if (!real) 84 | fail("unable to create real"); 85 | 86 | i = json_integer_value(integer); 87 | if (i != 5) 88 | fail("wrong integer value"); 89 | 90 | d = json_real_value(real); 91 | if (d != 100.1) 92 | fail("wrong real value"); 93 | 94 | d = json_number_value(integer); 95 | if (d != 5.0) 96 | fail("wrong number value"); 97 | d = json_number_value(real); 98 | if (d != 100.1) 99 | fail("wrong number value"); 100 | 101 | json_decref(integer); 102 | json_decref(real); 103 | 104 | #ifdef NAN 105 | real = json_real(NAN); 106 | if (real != NULL) 107 | fail("could construct a real from NaN"); 108 | 109 | real = json_real(1.0); 110 | if (json_real_set(real, NAN) != -1) 111 | fail("could set a real to NaN"); 112 | 113 | if (json_real_value(real) != 1.0) 114 | fail("real value changed unexpectedly"); 115 | 116 | json_decref(real); 117 | #endif 118 | 119 | #ifdef INFINITY 120 | test_inifity(); 121 | #endif 122 | test_bad_args(); 123 | } 124 | -------------------------------------------------------------------------------- /test/suites/api/test_sprintf.c: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #include 3 | #include 4 | 5 | static void test_sprintf() { 6 | json_t *s = json_sprintf("foo bar %d", 42); 7 | if (!s) 8 | fail("json_sprintf returned NULL"); 9 | if (!json_is_string(s)) 10 | fail("json_sprintf didn't return a JSON string"); 11 | if (strcmp(json_string_value(s), "foo bar 42")) 12 | fail("json_sprintf generated an unexpected string"); 13 | 14 | json_decref(s); 15 | 16 | s = json_sprintf("%s", ""); 17 | if (!s) 18 | fail("json_sprintf returned NULL"); 19 | if (!json_is_string(s)) 20 | fail("json_sprintf didn't return a JSON string"); 21 | if (json_string_length(s) != 0) 22 | fail("string is not empty"); 23 | json_decref(s); 24 | 25 | if (json_sprintf("%s", "\xff\xff")) 26 | fail("json_sprintf unexpected success with invalid UTF"); 27 | } 28 | 29 | static void run_tests() { test_sprintf(); } 30 | -------------------------------------------------------------------------------- /test/suites/api/test_version.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Sean Bright 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #include "util.h" 9 | #include 10 | #include 11 | 12 | static void test_version_str(void) { 13 | if (strcmp(jansson_version_str(), JANSSON_VERSION)) { 14 | fail("jansson_version_str returned invalid version string"); 15 | } 16 | } 17 | 18 | static void test_version_cmp() { 19 | if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION, 20 | JANSSON_MICRO_VERSION)) { 21 | fail("jansson_version_cmp equality check failed"); 22 | } 23 | 24 | if (jansson_version_cmp(JANSSON_MAJOR_VERSION - 1, 0, 0) <= 0) { 25 | fail("jansson_version_cmp less than check failed"); 26 | } 27 | 28 | if (JANSSON_MINOR_VERSION) { 29 | if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION - 1, 30 | JANSSON_MICRO_VERSION) <= 0) { 31 | fail("jansson_version_cmp less than check failed"); 32 | } 33 | } 34 | 35 | if (JANSSON_MICRO_VERSION) { 36 | if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION, 37 | JANSSON_MICRO_VERSION - 1) <= 0) { 38 | fail("jansson_version_cmp less than check failed"); 39 | } 40 | } 41 | 42 | if (jansson_version_cmp(JANSSON_MAJOR_VERSION + 1, JANSSON_MINOR_VERSION, 43 | JANSSON_MICRO_VERSION) >= 0) { 44 | fail("jansson_version_cmp greater than check failed"); 45 | } 46 | 47 | if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION + 1, 48 | JANSSON_MICRO_VERSION) >= 0) { 49 | fail("jansson_version_cmp greater than check failed"); 50 | } 51 | 52 | if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION, 53 | JANSSON_MICRO_VERSION + 1) >= 0) { 54 | fail("jansson_version_cmp greater than check failed"); 55 | } 56 | } 57 | 58 | static void run_tests() { 59 | test_version_str(); 60 | test_version_cmp(); 61 | } 62 | -------------------------------------------------------------------------------- /test/suites/api/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2016 Petri Lehtinen 3 | * 4 | * Jansson is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See LICENSE for details. 6 | */ 7 | 8 | #ifndef UTIL_H 9 | #define UTIL_H 10 | 11 | #ifdef HAVE_CONFIG_H 12 | #include 13 | #endif 14 | 15 | #include 16 | #include 17 | #if HAVE_LOCALE_H 18 | #include 19 | #endif 20 | 21 | #include 22 | 23 | #define failhdr fprintf(stderr, "%s:%d: ", __FILE__, __LINE__) 24 | 25 | #define fail(msg) \ 26 | do { \ 27 | failhdr; \ 28 | fprintf(stderr, "%s\n", msg); \ 29 | exit(1); \ 30 | } while (0) 31 | 32 | /* Assumes json_error_t error */ 33 | #define check_errors(code_, texts_, num_, source_, line_, column_, position_) \ 34 | do { \ 35 | int i_, found_ = 0; \ 36 | if (json_error_code(&error) != code_) { \ 37 | failhdr; \ 38 | fprintf(stderr, "code: %d != %d\n", json_error_code(&error), code_); \ 39 | exit(1); \ 40 | } \ 41 | for (i_ = 0; i_ < num_; i_++) { \ 42 | if (strcmp(error.text, texts_[i_]) == 0) { \ 43 | found_ = 1; \ 44 | break; \ 45 | } \ 46 | } \ 47 | if (!found_) { \ 48 | failhdr; \ 49 | if (num_ == 1) { \ 50 | fprintf(stderr, "text: \"%s\" != \"%s\"\n", error.text, texts_[0]); \ 51 | } else { \ 52 | fprintf(stderr, "text: \"%s\" does not match\n", error.text); \ 53 | } \ 54 | exit(1); \ 55 | } \ 56 | if (strcmp(error.source, source_) != 0) { \ 57 | failhdr; \ 58 | \ 59 | fprintf(stderr, "source: \"%s\" != \"%s\"\n", error.source, source_); \ 60 | exit(1); \ 61 | } \ 62 | if (error.line != line_) { \ 63 | failhdr; \ 64 | fprintf(stderr, "line: %d != %d\n", error.line, line_); \ 65 | exit(1); \ 66 | } \ 67 | if (error.column != column_) { \ 68 | failhdr; \ 69 | fprintf(stderr, "column: %d != %d\n", error.column, column_); \ 70 | exit(1); \ 71 | } \ 72 | if (error.position != position_) { \ 73 | failhdr; \ 74 | fprintf(stderr, "position: %d != %d\n", error.position, position_); \ 75 | exit(1); \ 76 | } \ 77 | } while (0) 78 | 79 | /* Assumes json_error_t error */ 80 | #define check_error(code_, text_, source_, line_, column_, position_) \ 81 | check_errors(code_, &text_, 1, source_, line_, column_, position_) 82 | 83 | static void run_tests(); 84 | 85 | int main() { 86 | #ifdef HAVE_SETLOCALE 87 | setlocale(LC_ALL, ""); 88 | #endif 89 | run_tests(); 90 | return 0; 91 | } 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/array/input: -------------------------------------------------------------------------------- 1 | [1, 2] 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/array/output: -------------------------------------------------------------------------------- 1 | [1, 2] -------------------------------------------------------------------------------- /test/suites/encoding-flags/compact-array/env: -------------------------------------------------------------------------------- 1 | JSON_COMPACT=1 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/compact-array/input: -------------------------------------------------------------------------------- 1 | [1, 2] 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/compact-array/output: -------------------------------------------------------------------------------- 1 | [1,2] -------------------------------------------------------------------------------- /test/suites/encoding-flags/compact-object/env: -------------------------------------------------------------------------------- 1 | JSON_COMPACT=1 2 | HASHSEED=1 3 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/compact-object/input: -------------------------------------------------------------------------------- 1 | {"a": 1, "b": 2} 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/compact-object/output: -------------------------------------------------------------------------------- 1 | {"a":1,"b":2} -------------------------------------------------------------------------------- /test/suites/encoding-flags/ensure-ascii/env: -------------------------------------------------------------------------------- 1 | JSON_ENSURE_ASCII=1 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/ensure-ascii/input: -------------------------------------------------------------------------------- 1 | [ 2 | "foo", 3 | "å ä ö", 4 | "foo åä", 5 | "åä foo", 6 | "å foo ä", 7 | "clef g: 𝄞" 8 | ] 9 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/ensure-ascii/output: -------------------------------------------------------------------------------- 1 | ["foo", "\u00E5 \u00E4 \u00F6", "foo \u00E5\u00E4", "\u00E5\u00E4 foo", "\u00E5 foo \u00E4", "clef g: \uD834\uDD1E"] -------------------------------------------------------------------------------- /test/suites/encoding-flags/indent-array/env: -------------------------------------------------------------------------------- 1 | JSON_INDENT=4 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/indent-array/input: -------------------------------------------------------------------------------- 1 | [1, 2] 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/indent-array/output: -------------------------------------------------------------------------------- 1 | [ 2 | 1, 3 | 2 4 | ] -------------------------------------------------------------------------------- /test/suites/encoding-flags/indent-compact-array/env: -------------------------------------------------------------------------------- 1 | JSON_INDENT=4 2 | JSON_COMPACT=1 3 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/indent-compact-array/input: -------------------------------------------------------------------------------- 1 | [1, 2] 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/indent-compact-array/output: -------------------------------------------------------------------------------- 1 | [ 2 | 1, 3 | 2 4 | ] -------------------------------------------------------------------------------- /test/suites/encoding-flags/indent-compact-object/env: -------------------------------------------------------------------------------- 1 | JSON_INDENT=4 2 | JSON_COMPACT=1 3 | HASHSEED=1 4 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/indent-compact-object/input: -------------------------------------------------------------------------------- 1 | {"a": 1, "b": 2} 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/indent-compact-object/output: -------------------------------------------------------------------------------- 1 | { 2 | "a":1, 3 | "b":2 4 | } -------------------------------------------------------------------------------- /test/suites/encoding-flags/indent-object/env: -------------------------------------------------------------------------------- 1 | JSON_INDENT=4 2 | HASHSEED=1 3 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/indent-object/input: -------------------------------------------------------------------------------- 1 | {"a": 1, "b": 2} 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/indent-object/output: -------------------------------------------------------------------------------- 1 | { 2 | "a": 1, 3 | "b": 2 4 | } -------------------------------------------------------------------------------- /test/suites/encoding-flags/object/env: -------------------------------------------------------------------------------- 1 | HASHSEED=1 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/object/input: -------------------------------------------------------------------------------- 1 | {"a": 1, "b": 2} 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/object/output: -------------------------------------------------------------------------------- 1 | {"a": 1, "b": 2} -------------------------------------------------------------------------------- /test/suites/encoding-flags/preserve-order/env: -------------------------------------------------------------------------------- 1 | JSON_PRESERVE_ORDER=1 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/preserve-order/input: -------------------------------------------------------------------------------- 1 | {"foo": 1, "bar": 2, "asdf": 3, "deadbeef": 4, "badc0ffee": 5, "qwerty": 6} 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/preserve-order/output: -------------------------------------------------------------------------------- 1 | {"foo": 1, "bar": 2, "asdf": 3, "deadbeef": 4, "badc0ffee": 5, "qwerty": 6} -------------------------------------------------------------------------------- /test/suites/encoding-flags/real-precision/env: -------------------------------------------------------------------------------- 1 | JSON_REAL_PRECISION=4 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/real-precision/input: -------------------------------------------------------------------------------- 1 | [1.23456789, 1.0, 1.0000000000000002, 1.23456e99, 1.23456e-99, 0.0000000000012345] 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/real-precision/output: -------------------------------------------------------------------------------- 1 | [1.235, 1.0, 1.0, 1.235e99, 1.235e-99, 1.235e-12] -------------------------------------------------------------------------------- /test/suites/encoding-flags/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2009-2016 Petri Lehtinen 4 | # 5 | # Jansson is free software; you can redistribute it and/or modify 6 | # it under the terms of the MIT license. See LICENSE for details. 7 | 8 | is_test() { 9 | test -d $test_path 10 | } 11 | 12 | run_test() { 13 | $json_process $test_path >$test_log/stdout 2>$test_log/stderr || return 1 14 | valgrind_check $test_log/stderr || return 1 15 | } 16 | 17 | show_error() { 18 | valgrind_show_error && return 19 | cat $test_log/stderr 20 | } 21 | 22 | . $top_srcdir/test/scripts/run-tests.sh 23 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/sort-keys/env: -------------------------------------------------------------------------------- 1 | JSON_SORT_KEYS=1 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/sort-keys/input: -------------------------------------------------------------------------------- 1 | {"foo": 1, "bar": 2, "baz": 3, "quux": 4} 2 | -------------------------------------------------------------------------------- /test/suites/encoding-flags/sort-keys/output: -------------------------------------------------------------------------------- 1 | {"bar": 2, "baz": 3, "foo": 1, "quux": 4} -------------------------------------------------------------------------------- /test/suites/invalid-unicode/encoded-surrogate-half/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | unable to decode byte 0xed near '"' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/encoded-surrogate-half/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/encoded-surrogate-half/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-after-backslash/error: -------------------------------------------------------------------------------- 1 | 1 3 3 2 | unable to decode byte 0xe5 near '"\' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-after-backslash/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/invalid-utf-8-after-backslash/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-array/error: -------------------------------------------------------------------------------- 1 | 1 1 1 2 | unable to decode byte 0xe5 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-array/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/invalid-utf-8-in-array/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/error: -------------------------------------------------------------------------------- 1 | 1 4 4 2 | unable to decode byte 0xe5 near '123' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-escape/error: -------------------------------------------------------------------------------- 1 | 1 4 4 2 | unable to decode byte 0xe5 near '"\u' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-escape/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/invalid-utf-8-in-escape/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-exponent/error: -------------------------------------------------------------------------------- 1 | 1 4 4 2 | unable to decode byte 0xe5 near '1e1' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-exponent/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/invalid-utf-8-in-exponent/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-identifier/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | unable to decode byte 0xe5 near 'a' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-identifier/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/invalid-utf-8-in-identifier/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-int/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | unable to decode byte 0xe5 near '0' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-int/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/invalid-utf-8-in-int/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/error: -------------------------------------------------------------------------------- 1 | 1 3 3 2 | unable to decode byte 0xe5 near '1e' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-string/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | unable to decode byte 0xe5 near '"' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/invalid-utf-8-in-string/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/invalid-utf-8-in-string/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/lone-invalid-utf-8/error: -------------------------------------------------------------------------------- 1 | 1 0 0 2 | unable to decode byte 0xe5 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/lone-invalid-utf-8/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/lone-invalid-utf-8/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/lone-utf-8-continuation-byte/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | unable to decode byte 0x81 near '"' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/lone-utf-8-continuation-byte/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/lone-utf-8-continuation-byte/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/not-in-unicode-range/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | unable to decode byte 0xf4 near '"' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/not-in-unicode-range/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/not-in-unicode-range/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/overlong-3-byte-encoding/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | unable to decode byte 0xe0 near '"' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/overlong-3-byte-encoding/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/overlong-3-byte-encoding/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/overlong-4-byte-encoding/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | unable to decode byte 0xf0 near '"' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/overlong-4-byte-encoding/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/overlong-4-byte-encoding/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/overlong-ascii-encoding/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | unable to decode byte 0xc1 near '"' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/overlong-ascii-encoding/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/overlong-ascii-encoding/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/restricted-utf-8/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | unable to decode byte 0xfd near '"' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/restricted-utf-8/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/restricted-utf-8/input -------------------------------------------------------------------------------- /test/suites/invalid-unicode/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2009-2016 Petri Lehtinen 4 | # 5 | # Jansson is free software; you can redistribute it and/or modify 6 | # it under the terms of the MIT license. See LICENSE for details. 7 | 8 | is_test() { 9 | test -d $test_path 10 | } 11 | 12 | run_test() { 13 | $json_process $test_path >$test_log/stdout 2>$test_log/stderr || return 1 14 | valgrind_check $test_log/stderr$s || return 1 15 | } 16 | 17 | show_error() { 18 | valgrind_show_error && return 19 | cat $test_log/stderr 20 | } 21 | 22 | . $top_srcdir/test/scripts/run-tests.sh 23 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/truncated-utf-8/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | unable to decode byte 0xe0 near '"' 3 | -------------------------------------------------------------------------------- /test/suites/invalid-unicode/truncated-utf-8/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid-unicode/truncated-utf-8/input -------------------------------------------------------------------------------- /test/suites/invalid/apostrophe/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | invalid token near ''' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/apostrophe/input: -------------------------------------------------------------------------------- 1 | [' 2 | -------------------------------------------------------------------------------- /test/suites/invalid/ascii-unicode-identifier/error: -------------------------------------------------------------------------------- 1 | 1 1 1 2 | '[' or '{' expected near 'a' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/ascii-unicode-identifier/input: -------------------------------------------------------------------------------- 1 | aå 2 | -------------------------------------------------------------------------------- /test/suites/invalid/brace-comma/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | string or '}' expected near ',' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/brace-comma/input: -------------------------------------------------------------------------------- 1 | {, 2 | -------------------------------------------------------------------------------- /test/suites/invalid/bracket-comma/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | unexpected token near ',' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/bracket-comma/input: -------------------------------------------------------------------------------- 1 | [, 2 | -------------------------------------------------------------------------------- /test/suites/invalid/bracket-one-comma/error.normal: -------------------------------------------------------------------------------- 1 | 2 0 4 2 | ']' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/bracket-one-comma/error.strip: -------------------------------------------------------------------------------- 1 | 1 3 3 2 | ']' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/bracket-one-comma/input: -------------------------------------------------------------------------------- 1 | [1, 2 | -------------------------------------------------------------------------------- /test/suites/invalid/empty/error: -------------------------------------------------------------------------------- 1 | 1 0 0 2 | '[' or '{' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/empty/input: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/invalid/empty/input -------------------------------------------------------------------------------- /test/suites/invalid/extra-comma-in-array/error: -------------------------------------------------------------------------------- 1 | 1 4 4 2 | unexpected token near ']' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/extra-comma-in-array/input: -------------------------------------------------------------------------------- 1 | [1,] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/extra-comma-in-multiline-array/error: -------------------------------------------------------------------------------- 1 | 6 1 17 2 | unexpected token near ']' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/extra-comma-in-multiline-array/input: -------------------------------------------------------------------------------- 1 | [1, 2 | 2, 3 | 3, 4 | 4, 5 | 5, 6 | ] 7 | -------------------------------------------------------------------------------- /test/suites/invalid/garbage-after-newline/error: -------------------------------------------------------------------------------- 1 | 2 3 11 2 | end of file expected near 'foo' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/garbage-after-newline/input: -------------------------------------------------------------------------------- 1 | [1,2,3] 2 | foo 3 | -------------------------------------------------------------------------------- /test/suites/invalid/garbage-at-the-end/error: -------------------------------------------------------------------------------- 1 | 1 10 10 2 | end of file expected near 'foo' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/garbage-at-the-end/input: -------------------------------------------------------------------------------- 1 | [1,2,3]foo 2 | -------------------------------------------------------------------------------- /test/suites/invalid/integer-starting-with-zero/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | invalid token near '0' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/integer-starting-with-zero/input: -------------------------------------------------------------------------------- 1 | [012] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/invalid-escape/error: -------------------------------------------------------------------------------- 1 | 1 4 4 2 | invalid escape near '"\a' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/invalid-escape/input: -------------------------------------------------------------------------------- 1 | ["\a <-- invalid escape"] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/invalid-identifier/error: -------------------------------------------------------------------------------- 1 | 1 5 5 2 | invalid token near 'troo' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/invalid-identifier/input: -------------------------------------------------------------------------------- 1 | [troo 2 | -------------------------------------------------------------------------------- /test/suites/invalid/invalid-negative-integer/error: -------------------------------------------------------------------------------- 1 | 1 8 8 2 | ']' expected near 'foo' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/invalid-negative-integer/input: -------------------------------------------------------------------------------- 1 | [-123foo] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/invalid-negative-real/error: -------------------------------------------------------------------------------- 1 | 1 12 12 2 | ']' expected near 'foo' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/invalid-negative-real/input: -------------------------------------------------------------------------------- 1 | [-123.123foo] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/invalid-second-surrogate/error: -------------------------------------------------------------------------------- 1 | 1 62 62 2 | invalid Unicode '\uD888\u3210' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/invalid-second-surrogate/input: -------------------------------------------------------------------------------- 1 | ["\uD888\u3210 (first surrogate and invalid second surrogate)"] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/invalid-unicode-escape/error: -------------------------------------------------------------------------------- 1 | 1 5 5 2 | invalid escape near '"\uq' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/invalid-unicode-escape/input: -------------------------------------------------------------------------------- 1 | ["\uqqqq <-- invalid unicode escape"] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/lone-open-brace/error.normal: -------------------------------------------------------------------------------- 1 | 2 0 2 2 | string or '}' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/lone-open-brace/error.strip: -------------------------------------------------------------------------------- 1 | 1 1 1 2 | string or '}' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/lone-open-brace/input: -------------------------------------------------------------------------------- 1 | { 2 | -------------------------------------------------------------------------------- /test/suites/invalid/lone-open-bracket/error.normal: -------------------------------------------------------------------------------- 1 | 2 0 2 2 | ']' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/lone-open-bracket/error.strip: -------------------------------------------------------------------------------- 1 | 1 1 1 2 | ']' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/lone-open-bracket/input: -------------------------------------------------------------------------------- 1 | [ 2 | -------------------------------------------------------------------------------- /test/suites/invalid/lone-second-surrogate/error: -------------------------------------------------------------------------------- 1 | 1 40 40 2 | invalid Unicode '\uDFAA' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/lone-second-surrogate/input: -------------------------------------------------------------------------------- 1 | ["\uDFAA (second surrogate on it's own)"] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/minus-sign-without-number/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | invalid token near '-' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/minus-sign-without-number/input: -------------------------------------------------------------------------------- 1 | [-foo] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/negative-integer-starting-with-zero/error: -------------------------------------------------------------------------------- 1 | 1 3 3 2 | invalid token near '-0' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/negative-integer-starting-with-zero/input: -------------------------------------------------------------------------------- 1 | [-012] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/null-byte-in-object-key/error: -------------------------------------------------------------------------------- 1 | 1 15 15 2 | NUL byte in object key not supported near '"foo\u0000bar"' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/null-byte-in-object-key/input: -------------------------------------------------------------------------------- 1 | {"foo\u0000bar": 42} -------------------------------------------------------------------------------- /test/suites/invalid/null-byte-in-string/error: -------------------------------------------------------------------------------- 1 | 1 12 12 2 | control character 0x0 near '"null byte ' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/null-byte-in-string/input: -------------------------------------------------------------------------------- 1 | ["null byte not allowed"] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/null-byte-in-string/nostrip: -------------------------------------------------------------------------------- 1 | The embedded NULL byte breaks json_loads(), which is used instead of 2 | json_loadf() in the stripped tests. 3 | -------------------------------------------------------------------------------- /test/suites/invalid/null-byte-outside-string/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | invalid token near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/null-byte-outside-string/input: -------------------------------------------------------------------------------- 1 | [ 2 | -------------------------------------------------------------------------------- /test/suites/invalid/null-byte-outside-string/nostrip: -------------------------------------------------------------------------------- 1 | The embedded NULL byte breaks json_loads(), which is used instead of 2 | json_loadf() in the stripped tests. 3 | -------------------------------------------------------------------------------- /test/suites/invalid/null-escape-in-string/error: -------------------------------------------------------------------------------- 1 | 1 33 33 2 | \u0000 is not allowed without JSON_ALLOW_NUL 3 | -------------------------------------------------------------------------------- /test/suites/invalid/null-escape-in-string/input: -------------------------------------------------------------------------------- 1 | ["null escape \u0000 not allowed"] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/null/error: -------------------------------------------------------------------------------- 1 | 1 4 4 2 | '[' or '{' expected near 'null' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/null/input: -------------------------------------------------------------------------------- 1 | null 2 | -------------------------------------------------------------------------------- /test/suites/invalid/object-apostrophes/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | string or '}' expected near ''' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/object-apostrophes/input: -------------------------------------------------------------------------------- 1 | {'a' 2 | -------------------------------------------------------------------------------- /test/suites/invalid/object-garbage-at-end/error: -------------------------------------------------------------------------------- 1 | 1 12 12 2 | '}' expected near '123' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/object-garbage-at-end/input: -------------------------------------------------------------------------------- 1 | {"a":"a" 123} 2 | -------------------------------------------------------------------------------- /test/suites/invalid/object-in-unterminated-array/error.normal: -------------------------------------------------------------------------------- 1 | 2 0 4 2 | ']' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/object-in-unterminated-array/error.strip: -------------------------------------------------------------------------------- 1 | 1 3 3 2 | ']' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/object-in-unterminated-array/input: -------------------------------------------------------------------------------- 1 | [{} 2 | -------------------------------------------------------------------------------- /test/suites/invalid/object-no-colon/error.normal: -------------------------------------------------------------------------------- 1 | 2 0 5 2 | ':' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/object-no-colon/error.strip: -------------------------------------------------------------------------------- 1 | 1 4 4 2 | ':' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/object-no-colon/input: -------------------------------------------------------------------------------- 1 | {"a" 2 | -------------------------------------------------------------------------------- /test/suites/invalid/object-no-value/error.normal: -------------------------------------------------------------------------------- 1 | 2 0 6 2 | unexpected token near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/object-no-value/error.strip: -------------------------------------------------------------------------------- 1 | 1 5 5 2 | unexpected token near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/object-no-value/input: -------------------------------------------------------------------------------- 1 | {"a": 2 | -------------------------------------------------------------------------------- /test/suites/invalid/object-unterminated-value/error.normal: -------------------------------------------------------------------------------- 1 | 1 7 7 2 | unexpected newline near '"a' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/object-unterminated-value/error.strip: -------------------------------------------------------------------------------- 1 | 1 7 7 2 | premature end of input near '"a' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/object-unterminated-value/input: -------------------------------------------------------------------------------- 1 | {"a":"a 2 | -------------------------------------------------------------------------------- /test/suites/invalid/real-garbage-after-e/error: -------------------------------------------------------------------------------- 1 | 1 3 3 2 | invalid token near '1e' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/real-garbage-after-e/input: -------------------------------------------------------------------------------- 1 | [1ea] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/real-negative-overflow/error: -------------------------------------------------------------------------------- 1 | 1 15 15 2 | real number overflow near '-123123e100000' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/real-negative-overflow/input: -------------------------------------------------------------------------------- 1 | [-123123e100000] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/real-positive-overflow/error: -------------------------------------------------------------------------------- 1 | 1 14 14 2 | real number overflow near '123123e100000' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/real-positive-overflow/input: -------------------------------------------------------------------------------- 1 | [123123e100000] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/real-truncated-at-e/error: -------------------------------------------------------------------------------- 1 | 1 3 3 2 | invalid token near '1e' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/real-truncated-at-e/input: -------------------------------------------------------------------------------- 1 | [1e] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/real-truncated-at-point/error: -------------------------------------------------------------------------------- 1 | 1 3 3 2 | invalid token near '1.' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/real-truncated-at-point/input: -------------------------------------------------------------------------------- 1 | [1.] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/recursion-depth/error: -------------------------------------------------------------------------------- 1 | 1 2049 2049 2 | maximum parsing depth reached near '[' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2009-2016 Petri Lehtinen 4 | # 5 | # Jansson is free software; you can redistribute it and/or modify 6 | # it under the terms of the MIT license. See LICENSE for details. 7 | 8 | is_test() { 9 | test -d $test_path 10 | } 11 | 12 | do_run() { 13 | variant=$1 14 | s=".$1" 15 | 16 | strip="" 17 | if [ "$variant" = "strip" ]; then 18 | # This test should not be stripped 19 | [ -f $test_path/nostrip ] && return 20 | strip="--strip" 21 | fi 22 | 23 | if ! $json_process $strip $test_path >$test_log/stdout$s 2>$test_log/stderr$s; then 24 | echo $variant >$test_log/variant 25 | return 1 26 | fi 27 | valgrind_check $test_log/stderr$s || return 1 28 | } 29 | 30 | run_test() { 31 | do_run normal && do_run strip 32 | } 33 | 34 | show_error() { 35 | valgrind_show_error && return 36 | 37 | read variant < $test_log/variant 38 | s=".$variant" 39 | 40 | echo "VARIANT: $variant" 41 | cat $test_log/stderr$s 42 | } 43 | 44 | . $top_srcdir/test/scripts/run-tests.sh 45 | -------------------------------------------------------------------------------- /test/suites/invalid/tab-character-in-string/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | control character 0x9 near '"' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/tab-character-in-string/input: -------------------------------------------------------------------------------- 1 | [" <-- tab character"] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/too-big-negative-integer/error: -------------------------------------------------------------------------------- 1 | 1 32 32 2 | too big negative integer 3 | -------------------------------------------------------------------------------- /test/suites/invalid/too-big-negative-integer/input: -------------------------------------------------------------------------------- 1 | [-123123123123123123123123123123] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/too-big-positive-integer/error: -------------------------------------------------------------------------------- 1 | 1 31 31 2 | too big integer 3 | -------------------------------------------------------------------------------- /test/suites/invalid/too-big-positive-integer/input: -------------------------------------------------------------------------------- 1 | [123123123123123123123123123123] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/truncated-unicode-surrogate/error: -------------------------------------------------------------------------------- 1 | 1 46 46 2 | invalid Unicode '\uDADA' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/truncated-unicode-surrogate/input: -------------------------------------------------------------------------------- 1 | ["\uDADA (first surrogate without the second)"] 2 | -------------------------------------------------------------------------------- /test/suites/invalid/unicode-identifier/error: -------------------------------------------------------------------------------- 1 | 1 1 2 2 | '[' or '{' expected near 'å' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/unicode-identifier/input: -------------------------------------------------------------------------------- 1 | å 2 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-array-and-object/error.normal: -------------------------------------------------------------------------------- 1 | 2 0 3 2 | string or '}' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-array-and-object/error.strip: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | string or '}' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-array-and-object/input: -------------------------------------------------------------------------------- 1 | [{ 2 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-array/error.normal: -------------------------------------------------------------------------------- 1 | 2 0 5 2 | ']' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-array/error.strip: -------------------------------------------------------------------------------- 1 | 1 4 4 2 | ']' expected near end of file 3 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-array/input: -------------------------------------------------------------------------------- 1 | ["a" 2 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-empty-key/error.normal: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | unexpected newline near '"' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-empty-key/error.strip: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | premature end of input near '"' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-empty-key/input: -------------------------------------------------------------------------------- 1 | {" 2 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-key/error.normal: -------------------------------------------------------------------------------- 1 | 1 3 3 2 | unexpected newline near '"a' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-key/error.strip: -------------------------------------------------------------------------------- 1 | 1 3 3 2 | premature end of input near '"a' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-key/input: -------------------------------------------------------------------------------- 1 | {"a 2 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-object-and-array/error: -------------------------------------------------------------------------------- 1 | 1 2 2 2 | string or '}' expected near '[' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-object-and-array/input: -------------------------------------------------------------------------------- 1 | {[ 2 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-string/error.normal: -------------------------------------------------------------------------------- 1 | 1 3 3 2 | unexpected newline near '"a' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-string/error.strip: -------------------------------------------------------------------------------- 1 | 1 3 3 2 | premature end of input near '"a' 3 | -------------------------------------------------------------------------------- /test/suites/invalid/unterminated-string/input: -------------------------------------------------------------------------------- 1 | ["a 2 | -------------------------------------------------------------------------------- /test/suites/valid/complex-array/env: -------------------------------------------------------------------------------- 1 | JSON_SORT_KEYS=1 -------------------------------------------------------------------------------- /test/suites/valid/complex-array/input: -------------------------------------------------------------------------------- 1 | [1,2,3,4, 2 | "a", "b", "c", 3 | {"foo": "bar", "core": "dump"}, 4 | true, false, true, true, null, false 5 | ] 6 | -------------------------------------------------------------------------------- /test/suites/valid/complex-array/output: -------------------------------------------------------------------------------- 1 | [1, 2, 3, 4, "a", "b", "c", {"core": "dump", "foo": "bar"}, true, false, true, true, null, false] -------------------------------------------------------------------------------- /test/suites/valid/empty-array/input: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /test/suites/valid/empty-array/output: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /test/suites/valid/empty-object-in-array/input: -------------------------------------------------------------------------------- 1 | [{}] 2 | -------------------------------------------------------------------------------- /test/suites/valid/empty-object-in-array/output: -------------------------------------------------------------------------------- 1 | [{}] -------------------------------------------------------------------------------- /test/suites/valid/empty-object/input: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /test/suites/valid/empty-object/output: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /test/suites/valid/empty-string/input: -------------------------------------------------------------------------------- 1 | [""] 2 | -------------------------------------------------------------------------------- /test/suites/valid/empty-string/output: -------------------------------------------------------------------------------- 1 | [""] -------------------------------------------------------------------------------- /test/suites/valid/escaped-utf-control-char/input: -------------------------------------------------------------------------------- 1 | ["\u0012 escaped control character"] 2 | -------------------------------------------------------------------------------- /test/suites/valid/escaped-utf-control-char/output: -------------------------------------------------------------------------------- 1 | ["\u0012 escaped control character"] -------------------------------------------------------------------------------- /test/suites/valid/false/input: -------------------------------------------------------------------------------- 1 | [false] 2 | -------------------------------------------------------------------------------- /test/suites/valid/false/output: -------------------------------------------------------------------------------- 1 | [false] -------------------------------------------------------------------------------- /test/suites/valid/negative-int/input: -------------------------------------------------------------------------------- 1 | [-123] 2 | -------------------------------------------------------------------------------- /test/suites/valid/negative-int/output: -------------------------------------------------------------------------------- 1 | [-123] -------------------------------------------------------------------------------- /test/suites/valid/negative-one/input: -------------------------------------------------------------------------------- 1 | [-1] 2 | -------------------------------------------------------------------------------- /test/suites/valid/negative-one/output: -------------------------------------------------------------------------------- 1 | [-1] -------------------------------------------------------------------------------- /test/suites/valid/negative-zero/input: -------------------------------------------------------------------------------- 1 | [-0] 2 | -------------------------------------------------------------------------------- /test/suites/valid/negative-zero/output: -------------------------------------------------------------------------------- 1 | [0] -------------------------------------------------------------------------------- /test/suites/valid/null/input: -------------------------------------------------------------------------------- 1 | [null] 2 | -------------------------------------------------------------------------------- /test/suites/valid/null/output: -------------------------------------------------------------------------------- 1 | [null] -------------------------------------------------------------------------------- /test/suites/valid/one-byte-utf-8/input: -------------------------------------------------------------------------------- 1 | ["\u002c one-byte UTF-8"] 2 | -------------------------------------------------------------------------------- /test/suites/valid/one-byte-utf-8/output: -------------------------------------------------------------------------------- 1 | [", one-byte UTF-8"] -------------------------------------------------------------------------------- /test/suites/valid/real-capital-e-negative-exponent/input: -------------------------------------------------------------------------------- 1 | [1E-2] 2 | -------------------------------------------------------------------------------- /test/suites/valid/real-capital-e-negative-exponent/output: -------------------------------------------------------------------------------- 1 | [0.01] -------------------------------------------------------------------------------- /test/suites/valid/real-capital-e-positive-exponent/input: -------------------------------------------------------------------------------- 1 | [1E+2] 2 | -------------------------------------------------------------------------------- /test/suites/valid/real-capital-e-positive-exponent/output: -------------------------------------------------------------------------------- 1 | [100.0] -------------------------------------------------------------------------------- /test/suites/valid/real-capital-e/input: -------------------------------------------------------------------------------- 1 | [1E22] 2 | -------------------------------------------------------------------------------- /test/suites/valid/real-capital-e/output: -------------------------------------------------------------------------------- 1 | [1e22] -------------------------------------------------------------------------------- /test/suites/valid/real-exponent-no-dtoa/input: -------------------------------------------------------------------------------- 1 | [1.23e47, 0.1, 0.3, 9.99] 2 | -------------------------------------------------------------------------------- /test/suites/valid/real-exponent-no-dtoa/output: -------------------------------------------------------------------------------- 1 | [1.2299999999999999e47, 0.10000000000000001, 0.29999999999999999, 9.9900000000000002] -------------------------------------------------------------------------------- /test/suites/valid/real-exponent-no-dtoa/skip_if_dtoa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/valid/real-exponent-no-dtoa/skip_if_dtoa -------------------------------------------------------------------------------- /test/suites/valid/real-exponent/input: -------------------------------------------------------------------------------- 1 | [1.23e47, 0.1, 0.3, 9.99] 2 | -------------------------------------------------------------------------------- /test/suites/valid/real-exponent/output: -------------------------------------------------------------------------------- 1 | [1.23e47, 0.1, 0.3, 9.99] -------------------------------------------------------------------------------- /test/suites/valid/real-exponent/skip_unless_dtoa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akheron/jansson/96d160df90016066d04d493d1d69639474ba4f20/test/suites/valid/real-exponent/skip_unless_dtoa -------------------------------------------------------------------------------- /test/suites/valid/real-fraction-exponent/input: -------------------------------------------------------------------------------- 1 | [123.456e78] 2 | -------------------------------------------------------------------------------- /test/suites/valid/real-fraction-exponent/output: -------------------------------------------------------------------------------- 1 | [1.23456e80] -------------------------------------------------------------------------------- /test/suites/valid/real-negative-exponent/input: -------------------------------------------------------------------------------- 1 | [1e-2] 2 | -------------------------------------------------------------------------------- /test/suites/valid/real-negative-exponent/output: -------------------------------------------------------------------------------- 1 | [0.01] -------------------------------------------------------------------------------- /test/suites/valid/real-positive-exponent/input: -------------------------------------------------------------------------------- 1 | [1e+2] 2 | -------------------------------------------------------------------------------- /test/suites/valid/real-positive-exponent/output: -------------------------------------------------------------------------------- 1 | [100.0] -------------------------------------------------------------------------------- /test/suites/valid/real-subnormal-number/input: -------------------------------------------------------------------------------- 1 | [1.8011670033376514e-308] 2 | -------------------------------------------------------------------------------- /test/suites/valid/real-subnormal-number/output: -------------------------------------------------------------------------------- 1 | [1.8011670033376514e-308] -------------------------------------------------------------------------------- /test/suites/valid/real-underflow/input: -------------------------------------------------------------------------------- 1 | [123e-10000000] 2 | -------------------------------------------------------------------------------- /test/suites/valid/real-underflow/output: -------------------------------------------------------------------------------- 1 | [0.0] -------------------------------------------------------------------------------- /test/suites/valid/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2009-2016 Petri Lehtinen 4 | # 5 | # Jansson is free software; you can redistribute it and/or modify 6 | # it under the terms of the MIT license. See LICENSE for details. 7 | 8 | dtoa_enabled() { 9 | grep -q "DTOA_ENABLED 1" $top_builddir/jansson_private_config.h 10 | } 11 | 12 | is_test() { 13 | test -d $test_path 14 | } 15 | 16 | do_run() { 17 | if [ -f $test_path/skip_unless_dtoa ]; then 18 | dtoa_enabled || return 77 19 | fi 20 | if [ -f $test_path/skip_if_dtoa ]; then 21 | dtoa_enabled && return 77 22 | fi 23 | 24 | variant=$1 25 | s=".$1" 26 | 27 | strip="" 28 | [ "$variant" = "strip" ] && strip="--strip" 29 | 30 | if ! $json_process $strip $test_path >$test_log/stdout$s 2>$test_log/stderr$s; then 31 | echo $variant >$test_log/variant 32 | return 1 33 | fi 34 | valgrind_check $test_log/stderr$s || return 1 35 | } 36 | 37 | run_test() { 38 | do_run normal && do_run strip 39 | } 40 | 41 | show_error() { 42 | valgrind_show_error && return 43 | 44 | read variant < $test_log/variant 45 | s=".$variant" 46 | 47 | echo "VARIANT: $variant" 48 | cat $test_log/stderr$s 49 | } 50 | 51 | . $top_srcdir/test/scripts/run-tests.sh 52 | -------------------------------------------------------------------------------- /test/suites/valid/short-string/input: -------------------------------------------------------------------------------- 1 | ["a"] 2 | -------------------------------------------------------------------------------- /test/suites/valid/short-string/output: -------------------------------------------------------------------------------- 1 | ["a"] -------------------------------------------------------------------------------- /test/suites/valid/simple-ascii-string/input: -------------------------------------------------------------------------------- 1 | ["abcdefghijklmnopqrstuvwxyz1234567890 "] 2 | -------------------------------------------------------------------------------- /test/suites/valid/simple-ascii-string/output: -------------------------------------------------------------------------------- 1 | ["abcdefghijklmnopqrstuvwxyz1234567890 "] -------------------------------------------------------------------------------- /test/suites/valid/simple-int-0/input: -------------------------------------------------------------------------------- 1 | [0] 2 | -------------------------------------------------------------------------------- /test/suites/valid/simple-int-0/output: -------------------------------------------------------------------------------- 1 | [0] -------------------------------------------------------------------------------- /test/suites/valid/simple-int-1/input: -------------------------------------------------------------------------------- 1 | [1] 2 | -------------------------------------------------------------------------------- /test/suites/valid/simple-int-1/output: -------------------------------------------------------------------------------- 1 | [1] -------------------------------------------------------------------------------- /test/suites/valid/simple-int-123/input: -------------------------------------------------------------------------------- 1 | [123] 2 | -------------------------------------------------------------------------------- /test/suites/valid/simple-int-123/output: -------------------------------------------------------------------------------- 1 | [123] -------------------------------------------------------------------------------- /test/suites/valid/simple-object/input: -------------------------------------------------------------------------------- 1 | {"a":[]} 2 | -------------------------------------------------------------------------------- /test/suites/valid/simple-object/output: -------------------------------------------------------------------------------- 1 | {"a": []} -------------------------------------------------------------------------------- /test/suites/valid/simple-real/input: -------------------------------------------------------------------------------- 1 | [123.456789] 2 | -------------------------------------------------------------------------------- /test/suites/valid/simple-real/output: -------------------------------------------------------------------------------- 1 | [123.456789] -------------------------------------------------------------------------------- /test/suites/valid/string-escapes/input: -------------------------------------------------------------------------------- 1 | ["\"\\\/\b\f\n\r\t"] 2 | -------------------------------------------------------------------------------- /test/suites/valid/string-escapes/output: -------------------------------------------------------------------------------- 1 | ["\"\\/\b\f\n\r\t"] -------------------------------------------------------------------------------- /test/suites/valid/three-byte-utf-8/input: -------------------------------------------------------------------------------- 1 | ["\u0821 three-byte UTF-8"] 2 | -------------------------------------------------------------------------------- /test/suites/valid/three-byte-utf-8/output: -------------------------------------------------------------------------------- 1 | ["ࠡ three-byte UTF-8"] -------------------------------------------------------------------------------- /test/suites/valid/true/input: -------------------------------------------------------------------------------- 1 | [true] 2 | -------------------------------------------------------------------------------- /test/suites/valid/true/output: -------------------------------------------------------------------------------- 1 | [true] -------------------------------------------------------------------------------- /test/suites/valid/two-byte-utf-8/input: -------------------------------------------------------------------------------- 1 | ["\u0123 two-byte UTF-8"] 2 | -------------------------------------------------------------------------------- /test/suites/valid/two-byte-utf-8/output: -------------------------------------------------------------------------------- 1 | ["ģ two-byte UTF-8"] -------------------------------------------------------------------------------- /test/suites/valid/utf-8-string/input: -------------------------------------------------------------------------------- 1 | ["€þıœəßð some utf-8 ĸʒ×ŋµåäö𝄞"] 2 | -------------------------------------------------------------------------------- /test/suites/valid/utf-8-string/output: -------------------------------------------------------------------------------- 1 | ["€þıœəßð some utf-8 ĸʒ×ŋµåäö𝄞"] -------------------------------------------------------------------------------- /test/suites/valid/utf-surrogate-four-byte-encoding/input: -------------------------------------------------------------------------------- 1 | ["\uD834\uDD1E surrogate, four-byte UTF-8"] 2 | -------------------------------------------------------------------------------- /test/suites/valid/utf-surrogate-four-byte-encoding/output: -------------------------------------------------------------------------------- 1 | ["𝄞 surrogate, four-byte UTF-8"] --------------------------------------------------------------------------------