124 Commits
v2.11 ... v2.13

Author SHA1 Message Date
Petri Lehtinen
2882ead5bb jansson 2.13 2020-05-05 07:07:16 +03:00
Petri Lehtinen
4c9018cc4c Merge pull request #521 from NanXiao/patch-1
Update apiref.rst
2020-01-21 10:15:01 +02:00
Nan Xiao
e15fd861e1 Update apiref.rst 2020-01-21 14:27:52 +08:00
Petri Lehtinen
ca88677bdd Merge pull request #510 from AllenX2018/improve-build-doc
add MinGW build guideline and tips to disable building docs
2019-10-24 11:23:00 +03:00
Petri Lehtinen
6e211b24fe Fix the length of a section heading 2019-10-24 11:22:46 +03:00
Petri Lehtinen
50c9623e37 Merge pull request #509 from AllenX2018/update-CHANGES
add changes since v2.12
2019-10-24 11:19:52 +03:00
Petri Lehtinen
3704e1cd78 Small modifications to CHANGES 2019-10-24 11:19:34 +03:00
allen
67900c85d3 add changes since v2.12 2019-10-22 18:52:55 +08:00
Petri Lehtinen
d288cc157e Merge pull request #508 from akheron/clang-format
Format code with clang-format
2019-10-21 11:07:53 +03:00
AllenX2018
5b8ff675b3 add MinGW build guideline, add new version of Visual Studio 2019-10-21 15:53:33 +08:00
Petri Lehtinen
78da35682a Set autoconf bug-report param to point to github issues 2019-10-21 08:56:03 +03:00
Petri Lehtinen
bb4f99e919 Fix clang-format version checking 2019-10-21 08:56:03 +03:00
Petri Lehtinen
f912430cda Run clang-format with make check 2019-10-21 08:56:03 +03:00
Petri Lehtinen
a8f5fa5f5a Tweak clang-format configuration a bit
Set ColumnLimit to 90, remove AllowShortCaseLabelsOnASingleLine.
2019-10-21 08:56:03 +03:00
Petri Lehtinen
7c0297abe8 Support running a specific clang-format version in CI 2019-10-21 08:55:01 +03:00
Petri Lehtinen
1a95a60f80 Run clang-format in CI, fail the build if everything's not formatted 2019-10-21 08:55:01 +03:00
Petri Lehtinen
be0fca914e Add scripts for running clang-format 2019-10-21 08:55:01 +03:00
Petri Lehtinen
79fe8c3435 Run clang-format on *.c, *.h 2019-10-21 08:55:01 +03:00
Petri Lehtinen
7dc463ee4e Add clang-format configuration 2019-10-21 08:53:03 +03:00
Petri Lehtinen
79075d5393 Merge pull request #498 from AllenX2018/fix-issue441
fix issue #441: remove strtod definition in strconv.c
2019-10-21 08:51:36 +03:00
willson-chen
c3958a326c remove undef __NO_ISOCEXT for strtod compatiblity 2019-10-21 11:13:39 +08:00
Petri Lehtinen
f75dc840e4 Merge pull request #499 from AllenX2018/fix-issue281
Add json_object_update_new, json_object_update_existing_new and json_object_update_missing_new
2019-10-18 16:18:28 +03:00
Petri Lehtinen
25e706cce7 Merge branch 'master' into fix-issue281 2019-10-17 13:37:33 +03:00
Petri Lehtinen
8b022dad76 Merge pull request #505 from AllenX2018/recursive_object_update
Recursive object update
2019-10-17 08:36:28 +03:00
Petri Lehtinen
0eec0327be Merge pull request #500 from AllenX2018/fix-issue426
fix issue #426: fix pipe function in MinGW
2019-10-17 08:12:42 +03:00
Petri Lehtinen
e7bed4c109 Merge pull request #501 from AllenX2018/fix-issue481
fix issue #481
2019-10-17 08:11:19 +03:00
Petri Lehtinen
355aa42b48 Merge pull request #502 from AllenX2018/fix-issue453
fix issue #453:update FindSphinx.cmake to better align with find sphinx package.
2019-10-17 08:09:20 +03:00
Petri Lehtinen
92873e9d27 Merge pull request #503 from AllenX2018/loadfd-doc
add note for non-blocking file descriptor used for json_loadfd
2019-10-17 08:07:02 +03:00
Petri Lehtinen
9e1c37c889 Merge pull request #506 from AllenX2018/add-json_equal-test-case
fix typo & add negative test case for test_equal_complex
2019-10-17 07:33:36 +03:00
allen
010092c7bd fix typo & add negative test case for test_equal_complex 2019-10-15 17:41:57 +08:00
allen
fb602f331b update the test case of json_object_update_recursive 2019-10-14 17:32:24 +08:00
allen
00d2d274bc add loop check for json_object_update_recursive function 2019-10-12 15:36:05 +08:00
allen
b403bbba8d modify some words 2019-10-12 10:56:23 +08:00
Henrique Cabral
cb4727c4a9 Add json_object_update_recursive()
Support merging values nested within objects. For instance, merging:

    {
	"foo": 1,
	"bar": {
	    "baz": 2
	}
    }

with

    {
	"bar": {
	    "baz": 3
	}
    }

results in

    {
	"foo": 1,
	"bar": {
	    "baz": 3
	}
    }

instead of overwriting the value for the bar key.
2019-10-11 11:20:25 +08:00
allen
a585a2778e add note for non-blocking file descriptor used for json_loadfd 2019-10-10 19:43:17 +08:00
AllenX2018
4f26548e3a fix issue #453 2019-10-10 16:16:10 +08:00
allen
1f889c4b60 fix issue #481 2019-10-09 17:12:04 +08:00
allen
8682f2aab3 fix issue #281 2019-10-08 20:32:27 +08:00
AllenX2018
4f3305c506 fix issue #441
It already has "strtod" function in stdlib.h and because __USE_MINGW_ANSI_STDIO is desperated
2019-10-08 19:16:50 +08:00
AllenX2018
78ea35c8e9 fix issue #426 2019-10-08 16:19:40 +08:00
Petri Lehtinen
c436bec682 Merge pull request #496 from grdowns/vcpkg-instructions
Add vcpkg installation instructions
2019-09-27 15:08:00 +03:00
grdowns
f5c0afecdb Add vcpkg installation instructions 2019-09-26 16:54:02 -07:00
Petri Lehtinen
5371816480 Merge pull request #494 from luzpaz/typos
Fix various typos
2019-09-23 11:31:23 +03:00
Petri Lehtinen
09e455275c Merge pull request #490 from AllenX2018/master
add loop check in json deep copy #457
2019-09-23 11:30:33 +03:00
luz.paz
3adf3e6a5a Fix various typos
Found via `codespell -q 2` (v1.17.0.dev0)
2019-09-20 13:35:56 -04:00
Allen
672b6df474 Update apiref.rst
fix the documentation about json_dumps. refs #471
2019-09-18 16:18:51 +08:00
allen
53e9dd848f add the loop key length macro for circular reference detect 2019-09-16 15:50:59 +08:00
allen
63fb81faa5 add loop check in json deep copy #457 2019-08-12 11:17:25 +08:00
Corey Farrell
a1f297aa83 Merge pull request #489 from AllenX2018/master
Update CMakeLists.txt
2019-08-09 04:37:06 -04:00
Allen
e68c5ea0b5 Update CMakeLists.txt
add "-Wno-format-truncation" to supress format truncation warning in cmake
2019-08-09 15:41:57 +08:00
Corey Farrell
af66d3f4c0 Merge pull request #487 from cmeister2/cmeister2/ossfuzzcorpus
ossfuzz: Zip up all "input" files to use as a seed corpus
2019-07-26 09:43:44 -04:00
Corey Farrell
a6f6ec1856 Merge pull request #485 from cmeister2/cmeister2/fuzzerdiags
ossfuzz: Improvements to json_load_dump_fuzzer
2019-07-26 08:58:16 -04:00
Max Dymond
287b5acb07 ossfuzz: Zip up all "input" files to use as a seed corpus 2019-07-24 19:41:45 +01:00
Max Dymond
3858607be0 Depending on the dump_mode byte, dump out as a string or as a callback. 2019-07-24 19:14:17 +01:00
Corey Farrell
0ed750a7ea Merge pull request #486 from cmeister2/cmeister2/osstravis
Ensure OSS fuzz travis builds work for PRs
2019-07-24 13:46:24 -04:00
Max Dymond
7feae084b1 Use the correct branch for OSS Fuzz as well. 2019-07-24 10:50:21 +01:00
Max Dymond
a6f436fefc Ensure OSS fuzz travis builds work for PRs
Use the correct repository for cloning when doing a push build or a
pull-request.

Only do one fuzzer build!
2019-07-24 10:43:03 +01:00
Max Dymond
66dec35c8c ossfuzz: Improvements to json_load_dump_fuzzer
Add in diagnostics to json_load_dump_fuzzer so that if FUZZ_VERBOSE is
defined in the environment, additional debug information about the
current test case is output to stderr.

Replace json_dumps by json_dump_callback so that memory is not exhausted
by excessively nested json objects.
2019-07-24 10:17:19 +01:00
Corey Farrell
1ac79b2558 Merge pull request #484 from cmeister2/cmeister2/fixossafl
One byte fix to fix OSS Fuzz AFL support
2019-07-22 06:40:34 -04:00
Max Dymond
6e26599980 One byte fix to fix OSS Fuzz AFL support
"x$LIB_FUZZING_ENGINE" is not the correct filename to test for - remove
the x!
2019-07-22 11:23:54 +01:00
Corey Farrell
3bfa3f1946 Merge pull request #480 from cmeister2/cmeister2/ossfuzz
oss-fuzz: Create a fuzzing target for jansson
2019-07-22 05:29:22 -04:00
Corey Farrell
813c3e2c47 Merge pull request #483 from AllenX2018/master
correct spelling mistake
2019-07-22 04:19:26 -04:00
allen
c49fbc7082 correct spelling mistake 2019-07-22 11:00:31 +08:00
Max Dymond
24cc9dd078 Move ossfuzz directory and use Makefile.am 2019-07-19 09:52:37 +01:00
Max Dymond
100e5549b6 Create a fuzzing target for jansson 2019-06-28 14:05:39 +01:00
Corey Farrell
b333f3656d Merge pull request #465 from seanbright/jansson-version
Add runtime version checking functions
2019-03-13 08:24:41 -04:00
Sean Bright
76300601d9 Add runtime version checking functions
This patch adds two new exported functions:

* `jansson_version_str` - Returns a human-readable version number
* `jansson_version_cmp` - Returns an integer less than, equal to, or greater
  than zero if the runtime version of Jansson is found, respectively, to be
  less than, to match, or be greater than the provided major, minor, and micro.
2019-03-12 13:03:34 -04:00
Petri Lehtinen
f4498d2856 CHANGES: Fix 2.12 release date 2018-11-26 10:59:06 +02:00
Petri Lehtinen
71c4e8ec21 Merge pull request #448 from coreyfarrell/2.12
jansson 2.12
2018-11-26 09:10:04 +01:00
Corey Farrell
10afd33efb jansson 2.12 2018-11-25 03:40:56 -05:00
Corey Farrell
2a31c4f475 Merge pull request #447 from vsoch/update/install-readme
Update/install readme
2018-11-25 02:40:09 -05:00
vsoch
f44c137a84 extra comma! 2018-11-24 23:29:14 -08:00
vsoch
7197810714 small updates to README 2018-11-24 23:27:23 -08:00
Corey Farrell
4ba5c7cc5d Merge pull request #445 from coreyfarrell/fix-444
Remove inappropriate jsonp_free which caused segmentation fault.
2018-11-08 16:00:32 -05:00
Corey Farrell
e262ea5fcd Remove inappropriate jsonp_free which caused segmentation fault.
pack_string should never free str on error.  This wouldn't be a problem
except the check for `ours` was inverted.  Just remove the check for
ours since the true condition is unreachable.

json_vpack_ex also had an error check for s.has_error.  This can never
be true unless value is NULL.

Expand pack_unpack testing to cover empty format string, NULL object
value with non-null concatenated key, array containing a non-null object
after a NULL (error) string.

Fixes #444
2018-11-05 16:49:22 -05:00
Corey Farrell
6ac0eefed0 Merge pull request #436 from edgale/warnings
removed various warnings
2018-10-17 06:29:47 -04:00
Maximilian Röhrle
226b34d546 fixed extra bracket 2018-10-15 07:05:02 +02:00
Maximilian Röhrle
d115953347 removed explicit casts 2018-10-15 06:58:19 +02:00
Corey Farrell
15f77c8f47 Merge pull request #439 from coreyfarrell/codecoverage
Fix code coverage ignored paths.
2018-09-29 15:37:56 -04:00
Corey Farrell
ef080d17b5 Fix code coverage ignored paths.
* Replace 'tests/*' with '*/test/*'.
* Replace '/usr/*' with '/usr/include/*'.  This resolves an issue where
  it was impossible to test code coverage with the source in /usr/src.
* Ignore build/include/jansson.h as we just want src/jansson.h.
2018-09-29 14:36:54 -04:00
Corey Farrell
4f91b1d072 Merge pull request #438 from coreyfarrell/issue-437
json_pack: Improve handling of formats with '?' and '*'.
2018-09-28 14:47:33 -04:00
Corey Farrell
8d659113d5 More work on json_pack error reporting.
* Remove errant line-feed from pack_object error message.
* Correct error message in pack_object_inter.
* Create pack_integer / pack_real to get the correct error messages on
  failure when packing numeric values.
* Add tests for packing NAN and infinity directly, in an array and as
  an object value.
2018-09-25 18:03:06 -04:00
Corey Farrell
5df5fc5b13 json_pack: Improve handling of formats with '?' and '*'.
When NULL is received for an optional argument we should not set an
error message as this would block later error messages. If NULL is
received for a non-optional string we should set has_error. Set
has_error for UTF-8 errors to ensure optional strings with UTF-8
errors are not replaced with json_null(). Use 'purpose' argument in
NULL error messages of read_string.

Add error handling and tests for invalid formats where '+', '#', or '%'
is used on an optional string 's?' or 's*'.

Fix NULL string error messages to use 'purpose'.

Refactor skipping of '*' token, this is now handled by read_string and
pack_object_inter. This allows invalid format strings such as 's*#' and
's*+' to produce error messages.

Fixes #437
2018-09-25 16:35:19 -04:00
Petri Lehtinen
e65a490c44 Merge pull request #435 from edgale/master
unreferenced variable fix
2018-09-04 06:25:45 +03:00
Maximilian Röhrle
fc591913ac removed various warnings 2018-08-31 09:01:36 +02:00
Maximilian Röhrle
d83d3d9172 This fixes https://github.com/akheron/jansson/issues/434 2018-08-30 14:45:28 +02:00
Petri Lehtinen
020cc26b5c Rename a varialble that shadows another one
Fixes #430
2018-08-12 18:25:51 +03:00
Michal Privoznik
360b1ef5a1 Enable -Bsymbolic-functions linker flag whenever possible
It was discovered fairly recently that JSON parsing libraries use
common pattern to name their exported symbols (they all use
json_ prefix). So eventually it happens that two symbols from two
different libraries have the same name. This will lead to cryptic
crashes (see [1] and [2]). Linking with -Bsymbolic-functions
prevents this.

1: https://gitlab.gnome.org/GNOME/json-glib/issues/33
2: https://groups.google.com/forum/#!topic/jansson-users/7Efx-RI45IU

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
2018-08-09 07:54:26 +03:00
Petri Lehtinen
37147b8a23 Merge pull request #423 from coreyfarrell/gcc-8
Deal with warnings under gcc 8.
2018-08-02 11:26:11 +03:00
Petri Lehtinen
8a00a56ec4 Merge pull request #424 from Crayon2000/patch-1
Update copyright for 2018
2018-07-30 13:42:05 +03:00
Petri Lehtinen
401ece058d Merge pull request #427 from lxin/va_end
Call va_end after va_copy in json_vsprintf
2018-07-30 13:41:39 +03:00
Xin Long
66e4ee795d Call va_end after va_copy in json_vsprintf
As said in man doc:
  "Each  invocation  of va_copy() must be matched by a corresponding
   invocation of va_end() in the same function."

va_copy may alloc memory in some system, it's necessay to free it by
va_end.

Fixes: efe6c7b3f2 ("Add json_sprintf and json_vsprintf")
Signed-off-by: Xin Long <lucien.xin@gmail.com>
2018-07-25 17:44:00 +08:00
Crayon
3e13f514ce Update copyright for 2018 2018-07-14 16:34:33 -04:00
Corey Farrell
81fe13eeed Deal with warnings under gcc 8.
Recent versions of gcc have introduced compiler warnings for string
operations that could be truncated.  This caused problems with -Werror.
src/error.c used strncpy to write "..." to a string, but skipped writing
the NUL terminator.  Switch this to use memcpy.  src/load.c produced
warnings from snprintf writing error strings that could be truncated.
Added code to autotools build to detect `-Wno-format-truncation', add it
to AM_CFLAGS if supported.
2018-07-14 13:24:55 -04:00
Petri Lehtinen
aed855e692 Avoid invalid memory read in json_pack()
Initial patch by @bharjoc-bitdefender

Fixes #421
2018-07-09 22:26:35 +03:00
Petri Lehtinen
b59ac57617 Merge pull request #415 from palmerc/master
CMake variable to number comparison changed to provide meaningful error
2018-05-22 07:38:17 +03:00
Cameron Lowell Palmer
904f5c28ac CMake variable to number comparison changed to provide meaningful error
message.  Explicitly specify STATIC and PIC
2018-05-18 10:35:05 +02:00
Petri Lehtinen
80cea73bf9 Merge pull request #408 from isaachier/cmake
CMake improvements, make package relocatable
2018-05-18 08:08:32 +03:00
Petri Lehtinen
e28bcfeac8 Merge pull request #417 from akheron/visual-studio-15
Appveyor & build instructions for Visual Studio 15 2017
2018-05-07 14:22:03 +03:00
Petri Lehtinen
fda9288b5f Update build instructions for Visual Studio 2018-05-07 11:17:08 +03:00
Petri Lehtinen
9ff08f6312 Also build with VS 2017 in appveyor 2018-05-07 08:39:49 +03:00
Petri Lehtinen
dd4743a51d Merge pull request #412 from Mephistophiles/fix_defines
Fix JSON_HAVE_SYNC_BUILTINS define usage
2018-05-07 08:13:21 +03:00
Maxim Zhukov
50f29f9b1a Add JSON_HAVE_SYNC_BUILTINS and JSON_HAVE_ATOMIC_BUILTINS for autoheader
Added JSON_HAVE_SYNC_BUILTINS and JSON_HAVE_ATOMIC_BUILTINS defines to
jansson_config.h.cmake as well as in the autoheader for autoconf.
2018-03-22 17:46:29 +03:00
Petri Lehtinen
e5dbe7bb64 Merge pull request #409 from Mephistophiles/master
Fix error handling in json_pack
2018-03-22 10:40:41 +02:00
Maxim Zhukov
15105b66b4 Fix error handling in json_pack
Fixed a bug where the error message was not filled if an empty object
was passed to the json_pack.

Fixes #271
2018-03-22 11:16:40 +03:00
Petri Lehtinen
b23025d72b Merge pull request #404 from coreyfarrell/func-attrs
Build: Add JANSSON_ATTRS macro.
2018-03-20 04:55:48 +02:00
Isaac Hier
2c98c30a02 Stop using absolute paths 2018-03-11 10:54:24 -04:00
Isaac Hier
bb71db204f Fix output file name for version config 2018-03-11 10:54:14 -04:00
Isaac Hier
92760bb363 Remove warning 2018-03-11 10:54:02 -04:00
Isaac Hier
fe7873e963 Fix package version config generation 2018-03-11 10:37:15 -04:00
Isaac Hier
a586c0654f Fix CMake include 2018-03-11 10:27:48 -04:00
Isaac Hier
6d7a02beb0 Clean up CMake install 2018-03-11 10:24:27 -04:00
Isaac Hier
b70364b362 Remove absolute path references 2018-03-11 10:11:09 -04:00
Isaac Hier
6d1ae86e1c Fix config file 2018-03-11 09:59:52 -04:00
Isaac Hier
a324d18940 Rename target file 2018-03-11 09:53:06 -04:00
Isaac Hier
44f6606df8 Rename config files 2018-03-11 09:47:29 -04:00
Isaac Hier
d8798468c6 Upgrade CMake to 3.1 for Hunter 2018-03-11 09:34:45 -04:00
Corey Farrell
749bef0b6a More test coverage.
* Add test_load_callback to CMakeList.txt
* Add json_dump, json_load and json_unpack chaos testing.
2018-03-06 23:28:14 -05:00
Corey Farrell
e37e52549f Add warn_unused_result to strbuffer_init.
This adds a compiler warning when strbuffer_init return value is
ignored.  unpack_object is updated to deal with errors produced
while building unrecognized_keys.
2018-03-06 08:27:20 -05:00
Corey Farrell
ea664722d4 Build: Add JANSSON_ATTRS macro.
This macro is used to conditionally generate GCC/CLANG __attribute__
declarations if supported.

This allows the compiler to produce warnings on certain incorrect
usages.  json_sprintf and json_vsprintf will produce warnings on invalid
format string.  Many functions will produce a warning if the result is
unused.  Specifically functions which allocate new objects will warn if
the result is ignored as this always results in a memory leak.
2018-03-06 07:25:16 -05:00
Petri Lehtinen
d098c0ff86 Merge pull request #400 from coreyfarrell/branch-coverage
Enable branch coverage reporting.
2018-02-20 15:39:36 +02:00
Petri Lehtinen
2d494c169f Merge pull request #398 from coreyfarrell/test-coverage
Improve test coverage.
2018-02-20 15:39:19 +02:00
Corey Farrell
a5af280bac Enable branch coverage reporting. 2018-02-20 03:09:03 -05:00
Corey Farrell
73c22de516 Improve test coverage.
* Test equality of different length strings.
* Add tab to json_pack whitespace test.
* Test json_sprintf with empty result and invalid UTF.
* Test json_get_alloc_funcs with NULL arguments.
* Test invalid arguments.
* Add test_chaos to test allocation failure code paths.
* Remove redundant json_is_string checks from json_string_equal and
  json_string_copy.  Both functions are static and can only be called
  with a json string.

Fixes to issues found by test_chaos:
* Fix crash on OOM in pack_unpack.c:read_string().
* Unconditionally free string in string_create upon allocation failure.
  Update load.c:parse_value() to reflect this.  This resolves a leak on
  allocation failure for pack_unpack.c:pack_string() and
  value.c:json_sprintf().

Although not visible from CodeCoverage these changes significantly
increase branch coverage.  Especially in src/value.c where we previously
covered 67.4% of branches and now cover 96.3% of branches.
2018-02-15 10:12:31 -05:00
74 changed files with 4063 additions and 2812 deletions

5
.clang-format Normal file
View File

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

4
.gitignore vendored
View File

@@ -31,3 +31,7 @@ stamp-h1
/jansson_private_config.h
/build
*.exe
.idea
cmake-build-debug/
*.log
*.trs

View File

@@ -1,8 +1,13 @@
env:
global:
- CLANG_FORMAT_VERSION=9
matrix:
- JANSSON_BUILD_METHOD=cmake JANSSON_CMAKE_OPTIONS="-DJANSSON_TEST_WITH_VALGRIND=ON" JANSSON_EXTRA_INSTALL="valgrind"
- JANSSON_BUILD_METHOD=autotools
- JANSSON_BUILD_METHOD=coverage JANSSON_CMAKE_OPTIONS="-DJANSSON_COVERAGE=ON -DJANSSON_COVERALLS=ON -DCMAKE_BUILD_TYPE=Debug" JANSSON_EXTRA_INSTALL="lcov curl"
- JANSSON_BUILD_METHOD=fuzzer
- JANSSON_BUILD_METHOD=lint CLANG_FORMAT=clang-format-9
dist: bionic
language: c
compiler:
- gcc
@@ -11,12 +16,19 @@ matrix:
exclude:
- compiler: clang
env: JANSSON_BUILD_METHOD=coverage JANSSON_CMAKE_OPTIONS="-DJANSSON_COVERAGE=ON -DJANSSON_COVERALLS=ON -DCMAKE_BUILD_TYPE=Debug" JANSSON_EXTRA_INSTALL="lcov curl"
- compiler: clang
env: JANSSON_BUILD_METHOD=fuzzer
- compiler: gcc
env: JANSSON_BUILD_METHOD=lint CLANG_FORMAT=clang-format-9
allow_failures:
- env: JANSSON_BUILD_METHOD=coverage JANSSON_CMAKE_OPTIONS="-DJANSSON_COVERAGE=ON -DJANSSON_COVERALLS=ON -DCMAKE_BUILD_TYPE=Debug" JANSSON_EXTRA_INSTALL="lcov curl"
install:
- sudo apt-get update -qq
- sudo apt-get install -y -qq cmake $JANSSON_EXTRA_INSTALL
- if [ "$TRAVIS_COMPILER" = "clang" ]; then sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y && wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - && sudo apt-add-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" -y && sudo apt-get install -y -qq clang-9 clang-format-9; fi
script:
- if [ "$JANSSON_BUILD_METHOD" = "autotools" ]; then autoreconf -f -i && CFLAGS=-Werror ./configure && make check; fi
- if [ "$JANSSON_BUILD_METHOD" = "cmake" ]; then mkdir build && cd build && cmake $JANSSON_CMAKE_OPTIONS .. && cmake --build . && ctest --output-on-failure; fi
- if [ "$JANSSON_BUILD_METHOD" = "coverage" ]; then mkdir build && cd build && cmake $JANSSON_CMAKE_OPTIONS .. && cmake --build . && cmake --build . --target coveralls; fi
- if [ "$JANSSON_BUILD_METHOD" = "fuzzer" ]; then ./test/ossfuzz/travisoss.sh; fi
- if [ "$JANSSON_BUILD_METHOD" = "lint" ]; then ./scripts/clang-format-check; fi

85
CHANGES
View File

@@ -1,3 +1,88 @@
Version 2.13
============
Released 2020-05-05
* New Features:
- Add `jansson_version_str()` and `jansson_version_cmp()` for runtime
version checking (#465).
- Add `json_object_update_new()`, `json_object_update_existing_new()`
and `json_object_update_missing_new()` functions (#499).
- Add `json_object_update_recursive()` (#505).
* Build:
- Add ``-Wno-format-truncation`` to suppress format truncation warnings (#489).
* Bug fixes:
- Remove ``strtod`` macro definition for MinGW (#498).
- Add infinite loop check in `json_deep_copy()` (#490).
- Add ``pipe`` macro definition for MinGW (#500).
- Enhance ``JANSSON_ATTRS`` macro to support earlier C standard(C89) (#501).
- Update version detection for sphinx-build (#502).
* Documentation:
- Fix typos (#483, #494).
- Document that call the custom free function to free the return value
of `json_dumps()` if you have a custom malloc/free (#490).
- Add vcpkg installation instructions (#496).
- Document that non-blocking file descriptor is not supported on
`json_loadfd()` (#503).
Version 2.12
============
Released 2018-11-26
* Bug fixes:
- Fix error message in `json_pack()` for NULL object (#409).
- Avoid invalid memory read in `json_pack()` (#421).
- Call va_end after va_copy in `json_vsprintf()` (#427).
- Improve handling of formats with '?' and '*' in `json_pack()` (#438).
- Remove inappropriate `jsonp_free()` which caused segmentation fault in
error handling (#444).
* Build:
- Add function attributes for GCC and CLANG to provide warnings on improper
use of jansson routines (#404).
- Many CMake fixes (#408, #412, #415).
- Enable -Bsymbolic-functions linker flag whenever possible.
- Resolve various compiler warnings (#423, #430, #435, #436).
- Fix code coverage ignored paths (#439).
* Other:
- Test coverage improvements (#398, #400).
- Add VS 2017 to appveyor, update Visual Studio documentation (#417).
- Update copyright for 2018 (#424).
- Update install instructions in README (#401).
Version 2.11
============

View File

@@ -1,7 +1,7 @@
# Notes:
#
# Author: Paul Harris, June 2012
# Additions: Joakim Soderberg, Febuary 2013
# Additions: Joakim Soderberg, February 2013
#
# Supports: building static/shared, release/debug/etc, can also build html docs
# and some of the tests.
@@ -35,7 +35,7 @@
# >> make test (to run the tests, if you enabled them)
#
# Brief description on how it works:
# There is a small heirachy of CMakeLists.txt files which define how the
# There is a small hierarchy of CMakeLists.txt files which define how the
# project is built.
# Header file detection etc is done, and the results are written into config.h
# and jansson_config.h, which are generated from the corresponding
@@ -46,9 +46,8 @@
cmake_minimum_required (VERSION 2.8)
# required for exports? cmake_minimum_required (VERSION 2.8.6)
project (jansson C)
cmake_minimum_required (VERSION 3.1)
project(jansson C)
# Options
option(JANSSON_BUILD_SHARED_LIBS "Build shared libraries." OFF)
@@ -70,26 +69,26 @@ if (UNIX)
endif ()
# Set some nicer output dirs.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set(JANSSON_TEMP_DIR ${PROJECT_BINARY_DIR}/tmp)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(JANSSON_TEMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/tmp)
# Give the debug version a different postfix for windows,
# so both the debug and release version can be built in the
# same build-tree on Windows (MSVC).
if (WIN32)
if (WIN32 AND NOT CMAKE_DEBUG_POSTFIX)
set(CMAKE_DEBUG_POSTFIX "_d")
endif (WIN32)
endif()
# This is how I thought it should go
# set (JANSSON_VERSION "2.3.1")
# set (JANSSON_SOVERSION 2)
set(JANSSON_DISPLAY_VERSION "2.11")
set(JANSSON_DISPLAY_VERSION "2.13")
# This is what is required to match the same numbers as automake's
set(JANSSON_VERSION "4.11.0")
set(JANSSON_VERSION "4.12.0")
set(JANSSON_SOVERSION 4)
# for CheckFunctionKeywords
@@ -101,19 +100,21 @@ include (CheckFunctionKeywords)
include (CheckIncludeFiles)
include (CheckTypeSize)
# suppress format-truncation warning
include (CheckCCompilerFlag)
check_c_compiler_flag(-Wno-format-truncation HAS_NO_FORMAT_TRUNCATION)
if (HAS_NO_FORMAT_TRUNCATION)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format-truncation")
endif()
if (MSVC)
# Turn off Microsofts "security" warnings.
add_definitions( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo" )
if (JANSSON_STATIC_CRT)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
endif()
endif()
if (NOT WIN32 AND (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX))
add_definitions("-fPIC")
endif()
message("C compiler: ${CMAKE_C_COMPILER_ID}")
@@ -164,9 +165,9 @@ if (HAVE_INT32_T)
set (JSON_INT32 int32_t)
elseif (HAVE___INT32)
set (JSON_INT32 __int32)
elseif (HAVE_LONG_INT AND (${LONG_INT} EQUAL 4))
elseif (HAVE_LONG_INT AND (LONG_INT EQUAL 4))
set (JSON_INT32 long)
elseif (HAVE_INT AND (${INT} EQUAL 4))
elseif (HAVE_INT AND (INT EQUAL 4))
set (JSON_INT32 int)
else ()
message (FATAL_ERROR "Could not detect a valid 32-bit integer type")
@@ -182,12 +183,12 @@ if (HAVE_UINT32_T)
set (JSON_UINT32 uint32_t)
elseif (HAVE___UINT32)
set (JSON_UINT32 __uint32)
elseif (HAVE_UNSIGNED_LONG_INT AND (${UNSIGNED_LONG_INT} EQUAL 4))
elseif (HAVE_UNSIGNED_LONG_INT AND (UNSIGNED_LONG_INT EQUAL 4))
set (JSON_UINT32 "unsigned long")
elseif (HAVE_UNSIGNED_INT AND (${UNSIGNED_INT} EQUAL 4))
elseif (HAVE_UNSIGNED_INT AND (UNSIGNED_INT EQUAL 4))
set (JSON_UINT32 "unsigned int")
else ()
message (FATAL_ERROR "Could not detect a valid unsigned 32-bit integer type")
message (FATAL_ERROR "Could not detect a valid unsigned 32-bit integer type")
endif ()
check_type_size (uint16_t UINT16_T)
@@ -196,12 +197,12 @@ if (HAVE_UINT16_T)
set (JSON_UINT16 uint16_t)
elseif (HAVE___UINT16)
set (JSON_UINT16 __uint16)
elseif (HAVE_UNSIGNED_INT AND (${UNSIGNED_INT} EQUAL 2))
elseif (HAVE_UNSIGNED_INT AND (UNSIGNED_INT EQUAL 2))
set (JSON_UINT16 "unsigned int")
elseif (HAVE_UNSIGNED_SHORT AND (${UNSIGNED_SHORT} EQUAL 2))
elseif (HAVE_UNSIGNED_SHORT AND (UNSIGNED_SHORT EQUAL 2))
set (JSON_UINT16 "unsigned short")
else ()
message (FATAL_ERROR "Could not detect a valid unsigned 16-bit integer type")
message (FATAL_ERROR "Could not detect a valid unsigned 16-bit integer type")
endif ()
check_type_size (uint8_t UINT8_T)
@@ -214,7 +215,7 @@ else ()
set (JSON_UINT8 "unsigned char")
endif ()
# Check for ssize_t and SSIZE_T existance.
# Check for ssize_t and SSIZE_T existence.
check_type_size(ssize_t SSIZE_T)
check_type_size(SSIZE_T UPPERCASE_SSIZE_T)
if(NOT HAVE_SSIZE_T)
@@ -250,7 +251,7 @@ endif ()
# detect what to use for the 64 bit type.
# Note: I will prefer long long if I can get it, as that is what the automake system aimed for.
if (NOT DEFINED JSON_INT_T)
if (HAVE_LONG_LONG_INT AND (${LONG_LONG_INT} EQUAL 8))
if (HAVE_LONG_LONG_INT AND (LONG_LONG_INT EQUAL 8))
set (JSON_INT_T "long long")
elseif (HAVE_INT64_T)
set (JSON_INT_T int64_t)
@@ -306,6 +307,18 @@ endif()
check_c_source_compiles ("int main() { unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1); __sync_add_and_fetch(&val, 1); __sync_sub_and_fetch(&val, 1); return 0; } " HAVE_SYNC_BUILTINS)
check_c_source_compiles ("int main() { char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_RELEASE); __atomic_load_n(&v, __ATOMIC_ACQUIRE); __atomic_add_fetch(&v, 1, __ATOMIC_ACQUIRE); __atomic_sub_fetch(&v, 1, __ATOMIC_RELEASE); return 0; }" HAVE_ATOMIC_BUILTINS)
if (HAVE_SYNC_BUILTINS)
set(JSON_HAVE_SYNC_BUILTINS 1)
else()
set(JSON_HAVE_SYNC_BUILTINS 0)
endif()
if (HAVE_ATOMIC_BUILTINS)
set(JSON_HAVE_ATOMIC_BUILTINS 1)
else()
set(JSON_HAVE_ATOMIC_BUILTINS 0)
endif()
set (JANSSON_INITIAL_HASHTABLE_ORDER 3 CACHE STRING "Number of buckets new object hashtables contain is 2 raised to this power. The default is 3, so empty hashtables contain 2^3 = 8 buckets.")
# configure the public config file
@@ -338,7 +351,7 @@ set(JANSSON_HDR_PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/utf.h
${CMAKE_CURRENT_BINARY_DIR}/private_include/jansson_private_config.h)
set(JANSSON_HDR_PUBLIC
set(JANSSON_HDR_PUBLIC
${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h
${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h)
@@ -347,24 +360,26 @@ source_group("Library Private Headers" FILES ${JANSSON_HDR_PRIVATE})
source_group("Library Public Headers" FILES ${JANSSON_HDR_PUBLIC})
if(JANSSON_BUILD_SHARED_LIBS)
add_library(jansson SHARED
${JANSSON_SRC}
${JANSSON_HDR_PRIVATE}
${JANSSON_HDR_PUBLIC}
add_library(jansson SHARED
${JANSSON_SRC}
${JANSSON_HDR_PRIVATE}
${JANSSON_HDR_PUBLIC}
src/jansson.def)
set_target_properties(jansson PROPERTIES
VERSION ${JANSSON_VERSION}
SOVERSION ${JANSSON_SOVERSION})
else()
add_library(jansson
add_library(jansson STATIC
${JANSSON_SRC}
${JANSSON_HDR_PRIVATE}
${JANSSON_HDR_PRIVATE}
${JANSSON_HDR_PUBLIC})
set_target_properties(jansson PROPERTIES
POSITION_INDEPENDENT_CODE true)
endif()
if (JANSSON_EXAMPLES)
add_executable(simple_parse "${PROJECT_SOURCE_DIR}/examples/simple_parse.c")
add_executable(simple_parse "${CMAKE_CURRENT_SOURCE_DIR}/examples/simple_parse.c")
target_link_libraries(simple_parse jansson)
endif()
@@ -374,12 +389,12 @@ if (JANSSON_BUILD_DOCS)
find_package(Sphinx)
if (NOT SPHINX_FOUND)
message(WARNING "Sphinx not found. Cannot generate documentation!
message(WARNING "Sphinx not found. Cannot generate documentation!
Set -DJANSSON_BUILD_DOCS=OFF to get rid of this message.")
else()
if (Sphinx_VERSION_STRING VERSION_LESS 1.0)
message(WARNING "Your Sphinx version is too old!
This project requires Sphinx v1.0 or above to produce
message(WARNING "Your Sphinx version is too old!
This project requires Sphinx v1.0 or above to produce
proper documentation (you have v${Sphinx_VERSION_STRING}).
You will get output but it will have errors.")
endif()
@@ -432,7 +447,7 @@ if (JANSSON_BUILD_DOCS)
list(APPEND DOC_TARGETS latex)
endif()
endif()
# The doc target will build all documentation targets.
add_custom_target(doc)
@@ -487,11 +502,13 @@ if (NOT JANSSON_WITHOUT_TESTS)
set(api_tests
test_array
test_copy
test_chaos
test_dump
test_dump_callback
test_equal
test_load
test_loadb
test_load_callback
test_number
test_object
test_pack
@@ -514,7 +531,7 @@ if (NOT JANSSON_WITHOUT_TESTS)
# Create executables and tests/valgrind tests for API tests.
foreach (test ${api_tests})
build_testprog(${test} ${PROJECT_SOURCE_DIR}/test/suites/api)
build_testprog(${test} ${CMAKE_CURRENT_SOURCE_DIR}/test/suites/api)
if (JANSSON_TEST_WITH_VALGRIND)
add_test(memcheck__${test}
@@ -528,12 +545,12 @@ if (NOT JANSSON_WITHOUT_TESTS)
endforeach ()
# Test harness for the suites tests.
build_testprog(json_process ${PROJECT_SOURCE_DIR}/test/bin)
build_testprog(json_process ${CMAKE_CURRENT_SOURCE_DIR}/test/bin)
set(SUITE_TEST_CMD ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/json_process)
set(SUITES encoding-flags valid invalid invalid-unicode)
foreach (SUITE ${SUITES})
file(GLOB TESTDIRS ${jansson_SOURCE_DIR}/test/suites/${SUITE}/*)
file(GLOB TESTDIRS test/suites/${SUITE}/*)
foreach (TESTDIR ${TESTDIRS})
if (IS_DIRECTORY ${TESTDIR})
@@ -575,7 +592,7 @@ if (NOT JANSSON_WITHOUT_TESTS)
# Enable using "make check" just like the autotools project.
# By default cmake creates a target "make test"
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}
DEPENDS json_process ${api_tests})
endif ()
@@ -607,80 +624,67 @@ set(VERSION ${JANSSON_DISPLAY_VERSION})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jansson.pc.in
${CMAKE_CURRENT_BINARY_DIR}/jansson.pc @ONLY)
# Make sure the paths are absolute.
# Make sure the paths are relative.
foreach(p LIB BIN INCLUDE CMAKE)
set(var JANSSON_INSTALL_${p}_DIR)
if(NOT IS_ABSOLUTE "${${var}}")
set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}")
endif()
endforeach()
# Export targets (This is used for other CMake projects to easily find the libraries and include files).
export(TARGETS jansson
FILE "${PROJECT_BINARY_DIR}/JanssonTargets.cmake")
export(PACKAGE jansson)
# Generate the config file for the build-tree.
set(JANSSON__INCLUDE_DIRS
"${PROJECT_SOURCE_DIR}/include"
"${PROJECT_BINARY_DIR}/include")
set(JANSSON__INCLUDE_DIRS
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_BINARY_DIR}/include")
set(JANSSON_INCLUDE_DIRS ${JANSSON__INCLUDE_DIRS} CACHE PATH "Jansson include directories")
configure_file(${PROJECT_SOURCE_DIR}/cmake/JanssonConfig.cmake.in
${PROJECT_BINARY_DIR}/JanssonConfig.cmake
@ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/janssonConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/janssonConfig.cmake
@ONLY)
# Generate the config file for the installation tree.
file(RELATIVE_PATH
REL_INCLUDE_DIR
"${JANSSON_INSTALL_CMAKE_DIR}"
"${JANSSON_INSTALL_INCLUDE_DIR}") # Calculate the relative directory from the Cmake dir.
include(CMakePackageConfigHelpers)
# Note the EVENT_CMAKE_DIR is defined in JanssonConfig.cmake.in,
# we escape it here so it's evaluated when it is included instead
# so that the include dirs are given relative to where the
# config file is located.
set(JANSSON__INCLUDE_DIRS
"\${JANSSON_CMAKE_DIR}/${REL_INCLUDE_DIR}")
configure_file(${PROJECT_SOURCE_DIR}/cmake/JanssonConfig.cmake.in
${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/JanssonConfig.cmake
@ONLY)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfigVersion.cmake"
VERSION ${JANSSON_VERSION}
COMPATIBILITY ExactVersion
)
# Generate version info for both build-tree and install-tree.
configure_file(${PROJECT_SOURCE_DIR}/cmake/JanssonConfigVersion.cmake.in
${PROJECT_BINARY_DIR}/JanssonConfigVersion.cmake
@ONLY)
# Define the public headers.
set_target_properties(jansson PROPERTIES PUBLIC_HEADER "${JANSSON_HDR_PUBLIC}")
#TODO: fix this.
configure_package_config_file(
"cmake/janssonConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfig.cmake"
INSTALL_DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}"
)
#
# Install targets.
#
option(JANSSON_INSTALL "Generate installation target" ON)
if (JANSSON_INSTALL)
install(TARGETS jansson
EXPORT JanssonTargets
LIBRARY DESTINATION "${JANSSON_INSTALL_LIB_DIR}" COMPONENT lib
ARCHIVE DESTINATION "${JANSSON_INSTALL_LIB_DIR}" COMPONENT lib
RUNTIME DESTINATION "${JANSSON_INSTALL_BIN_DIR}" COMPONENT lib # Windows DLLs
PUBLIC_HEADER DESTINATION "${JANSSON_INSTALL_INCLUDE_DIR}" COMPONENT dev)
install(TARGETS jansson
EXPORT janssonTargets
LIBRARY DESTINATION "lib"
ARCHIVE DESTINATION "lib"
RUNTIME DESTINATION "bin"
INCLUDES DESTINATION "include")
# Install the pkg-config.
install (FILES
${CMAKE_CURRENT_BINARY_DIR}/jansson.pc
DESTINATION ${JANSSON_INSTALL_LIB_DIR}/pkgconfig COMPONENT dev)
install(FILES ${JANSSON_HDR_PUBLIC}
DESTINATION "include")
# Install the configs.
install(FILES
${PROJECT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/JanssonConfig.cmake
${PROJECT_BINARY_DIR}/JanssonConfigVersion.cmake
DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}" COMPONENT dev)
# Install the pkg-config.
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/jansson.pc
DESTINATION lib/pkgconfig)
# Install exports for the install-tree.
install(EXPORT JanssonTargets
DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}" COMPONENT dev)
# Install the configs.
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfigVersion.cmake
DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}")
# Install exports for the install-tree.
install(EXPORT janssonTargets
NAMESPACE jansson::
DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}")
endif()
# For use when simply using add_library from a parent project to build jansson.
set(JANSSON_LIBRARIES jansson CACHE STRING "Jansson libraries")
set(JANSSON_LIBRARIES jansson CACHE STRING "jansson libraries")

View File

@@ -1,4 +1,4 @@
Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
Copyright (c) 2009-2020 Petri Lehtinen <petri@digip.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -8,3 +8,5 @@ dvi:
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = jansson.pc
TESTS = scripts/clang-format-check

View File

@@ -30,8 +30,20 @@ source distribution for details.
Compilation and Installation
----------------------------
If you obtained a source tarball, just use the standard autotools
commands::
You can download and install Jansson using the `vcpkg <https://github.com/Microsoft/vcpkg/>`_ dependency manager:
.. code-block:: bash
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
vcpkg install jansson
The Jansson port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please `create an issue or pull request <https://github.com/Microsoft/vcpkg/>`_ on the vcpkg repository.
If you obtained a `source tarball`_ from the "Releases" section of the main
site just use the standard autotools commands::
$ ./configure
$ make
@@ -65,4 +77,5 @@ Then, point your browser to ``doc/_build/html/index.html``. Sphinx_
.. _Jansson: http://www.digip.org/jansson/
.. _`Comprehensive documentation`: http://jansson.readthedocs.io/en/latest/
.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php
.. _`source tarball`: http://www.digip.org/jansson#releases
.. _Sphinx: http://sphinx.pocoo.org/

View File

@@ -5,6 +5,8 @@ environment:
- VS: Visual Studio 11 2012
- VS: Visual Studio 12 2013
- VS: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
VS: Visual Studio 15 2017
build_script:
- md build

View File

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

View File

@@ -102,8 +102,8 @@ if (GIT_FOUND)
message("Git branch: ${GIT_BRANCH}")
message("Git author: ${GIT_AUTHOR_NAME}")
message("Git e-mail: ${GIT_AUTHOR_EMAIL}")
message("Git commiter name: ${GIT_COMMITTER_NAME}")
message("Git commiter e-mail: ${GIT_COMMITTER_EMAIL}")
message("Git committer name: ${GIT_COMMITTER_NAME}")
message("Git committer e-mail: ${GIT_COMMITTER_EMAIL}")
message("Git commit message: ${GIT_COMMIT_MESSAGE}")
endif()
@@ -265,7 +265,7 @@ foreach (GCOV_FILE ${GCOV_FILES})
# Instead of trying to parse the source from the
# gcov file, simply read the file contents from the source file.
# (Parsing it from the gcov is hard because C-code uses ; in many places
# which also happens to be the same as the CMake list delimeter).
# which also happens to be the same as the CMake list delimiter).
file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE)
string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")

View File

@@ -241,27 +241,42 @@ endif ()
# ----------------------------------------------------------------------------
# determine Sphinx version
# some quick experiments by @ploxiln
# - sphinx 1.7 and later have the version output format like "sphinx-build 1.7.2"
# - sphinx 1.2 through 1.6 have the version output format like "Sphinx (sphinx-build) 1.2.2"
# - sphinx 1.1 and before do not have a "--version" flag, but it causes the help output like "-h" does which includes version like "Sphinx v1.0.2"
if (Sphinx-build_EXECUTABLE)
# intentionally use invalid -h option here as the help that is shown then
# will include the Sphinx version information
if (Sphinx_PYTHON_EXECUTABLE)
execute_process (
COMMAND "${Sphinx_PYTHON_EXECUTABLE}" ${Sphinx_PYTHON_OPTIONS} "${Sphinx-build_EXECUTABLE}" -h
COMMAND "${Sphinx_PYTHON_EXECUTABLE}" ${Sphinx_PYTHON_OPTIONS} "${Sphinx-build_EXECUTABLE}" --version
OUTPUT_VARIABLE _Sphinx_VERSION
ERROR_VARIABLE _Sphinx_VERSION
)
elseif (UNIX)
execute_process (
COMMAND "${Sphinx-build_EXECUTABLE}" -h
COMMAND "${Sphinx-build_EXECUTABLE}" --version
OUTPUT_VARIABLE _Sphinx_VERSION
ERROR_VARIABLE _Sphinx_VERSION
)
endif ()
# The sphinx version can also contain a "b" instead of the last dot.
# For example "Sphinx v1.2b1" so we cannot just split on "."
if (_Sphinx_VERSION MATCHES "Sphinx v([0-9]+\\.[0-9]+(\\.|b)[0-9]+)")
# For example "Sphinx v1.2b1" or "Sphinx 1.7.0b2" so we cannot just split on "."
if (_Sphinx_VERSION MATCHES "sphinx-build ([0-9]+\\.[0-9]+(\\.|a?|b?)([0-9]*)(b?)([0-9]*))")
set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}")
set (_SPHINX_VERSION_FOUND)
elseif (_Sphinx_VERSION MATCHES "Sphinx v([0-9]+\\.[0-9]+(\\.|b?)([0-9]*)(b?)([0-9]*))")
set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}")
set (_SPHINX_VERSION_FOUND)
elseif (_Sphinx_VERSION MATCHES "Sphinx \\(sphinx-build\\) ([0-9]+\\.[0-9]+(\\.|a?|b?)([0-9]*)(b?)([0-9]*))")
set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}")
set (_SPHINX_VERSION_FOUND)
endif ()
endif ()
if(_SPHINX_VERSION_FOUND)
string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MAJOR ${Sphinx_VERSION_STRING})
string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MINOR ${Sphinx_VERSION_STRING})
string(REGEX REPLACE "[0-9]+\\.[0-9]+(\\.|b)([0-9]+)" "\\1" Sphinx_VERSION_PATCH ${Sphinx_VERSION_STRING})
@@ -270,7 +285,6 @@ if (Sphinx-build_EXECUTABLE)
if (Sphinx_VERSION_PATCH EQUAL 0)
string (REGEX REPLACE "\\.0$" "" Sphinx_VERSION_STRING "${Sphinx_VERSION_STRING}")
endif ()
endif()
endif ()
# ----------------------------------------------------------------------------

View File

@@ -1,17 +0,0 @@
# - Config file for the jansson package
# It defines the following variables
# JANSSON_INCLUDE_DIRS - include directories for FooBar
# JANSSON_LIBRARIES - libraries to link against
# Get the path of the current file.
get_filename_component(JANSSON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
# Set the include directories.
set(JANSSON_INCLUDE_DIRS "@JANSSON__INCLUDE_DIRS@")
# Include the project Targets file, this contains definitions for IMPORTED targets.
include(${JANSSON_CMAKE_DIR}/JanssonTargets.cmake)
# IMPORTED targets from JanssonTargets.cmake
set(JANSSON_LIBRARIES jansson)

View File

@@ -1,11 +0,0 @@
set(PACKAGE_VERSION "@JANSSON_DISPLAY_VERSION@")
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()

View File

@@ -0,0 +1,4 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/janssonTargets.cmake")
check_required_components("@PROJECT_NAME@")

View File

@@ -59,10 +59,16 @@
/* If locale.h and localeconv() are available, define to 1, otherwise to 0. */
#define JSON_HAVE_LOCALECONV @JSON_HAVE_LOCALECONV@
/* If __atomic builtins are available they will be used to manage
reference counts of json_t. */
#define JSON_HAVE_ATOMIC_BUILTINS @JSON_HAVE_ATOMIC_BUILTINS@
/* If __atomic builtins are not available we try using __sync builtins
to manage reference counts of json_t. */
#define JSON_HAVE_SYNC_BUILTINS @JSON_HAVE_SYNC_BUILTINS@
/* Maximum recursion depth for parsing JSON input.
This limits the depth of e.g. array-within-array constructions. */
#define JSON_PARSER_MAX_DEPTH 2048
#endif

View File

@@ -1,5 +1,5 @@
AC_PREREQ([2.60])
AC_INIT([jansson], [2.11], [petri@digip.org])
AC_INIT([jansson], [2.13], [https://github.com/akheron/jansson/issues])
AC_CONFIG_AUX_DIR([.])
AM_INIT_AUTOMAKE([1.10 foreign])
@@ -9,6 +9,7 @@ AC_CONFIG_HEADERS([jansson_private_config.h])
# Checks for programs.
AC_PROG_CC
AC_PROG_CXX
AC_PROG_LIBTOOL
AM_CONDITIONAL([GCC], [test x$GCC = xyes])
@@ -107,8 +108,57 @@ AC_ARG_ENABLE([initial-hashtable-order],
AC_DEFINE_UNQUOTED([INITIAL_HASHTABLE_ORDER], [$initial_hashtable_order],
[Number of buckets new object hashtables contain is 2 raised to this power. E.g. 3 -> 2^3 = 8.])
AC_ARG_ENABLE([Bsymbolic],
[AS_HELP_STRING([--disable-Bsymbolic],
[Avoid linking with -Bsymbolic-function])],
[], [with_Bsymbolic=check])
if test "x$with_Bsymbolic" != "xno" ; then
AC_MSG_CHECKING([for -Bsymbolic-functions linker flag])
saved_LDFLAGS="${LDFLAGS}"
LDFLAGS=-Wl,-Bsymbolic-functions
AC_TRY_LINK(
[], [int main (void) { return 0; }],
[AC_MSG_RESULT([yes])
have_Bsymbolic=yes],
[AC_MSG_RESULT([no])
have_Bsymbolic=no]
)
LDFLAGS="${saved_LDFLAGS}"
if test "x$with_Bsymbolic" = "xcheck" ; then
with_Bsymbolic=$have_Bsymbolic;
fi
if test "x$with_Bsymbolic:x$have_Bsymbolic" = "xyes:xno" ; then
AC_MSG_ERROR([linker support is required for -Bsymbolic])
fi
fi
AS_IF([test "x$with_Bsymbolic" = "xyes"], [JSON_BSYMBOLIC_LDFLAGS=-Wl[,]-Bsymbolic-functions])
AC_SUBST(JSON_BSYMBOLIC_LDFLAGS)
AC_ARG_ENABLE([ossfuzzers],
[AS_HELP_STRING([--enable-ossfuzzers],
[Whether to generate the fuzzers for OSS-Fuzz])],
[have_ossfuzzers=yes], [have_ossfuzzers=no])
AM_CONDITIONAL([USE_OSSFUZZERS], [test "x$have_ossfuzzers" = "xyes"])
AC_SUBST([LIB_FUZZING_ENGINE])
AM_CONDITIONAL([USE_OSSFUZZ_FLAG], [test "x$LIB_FUZZING_ENGINE" = "x-fsanitize=fuzzer"])
AM_CONDITIONAL([USE_OSSFUZZ_STATIC], [test -f "$LIB_FUZZING_ENGINE"])
if test x$GCC = xyes; then
AM_CFLAGS="-Wall -Wextra -Wdeclaration-after-statement"
AC_MSG_CHECKING(for -Wno-format-truncation)
wnoformat_truncation="-Wno-format-truncation"
AS_IF([${CC} -Wno-format-truncation -Werror -S -o /dev/null -xc /dev/null > /dev/null 2>&1],
[AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(no)
wnoformat_truncation=""])
AM_CFLAGS="-Wall -Wextra -Wdeclaration-after-statement -Wshadow ${wnoformat_truncation}"
fi
AC_SUBST([AM_CFLAGS])
@@ -120,6 +170,7 @@ AC_CONFIG_FILES([
src/jansson_config.h
test/Makefile
test/bin/Makefile
test/ossfuzz/Makefile
test/suites/Makefile
test/suites/api/Makefile
])

View File

@@ -58,6 +58,25 @@ the library:
/* Code specific to version 1.3 and above */
#endif
Additionally, there are functions to determine the version of Jansson at
runtime:
.. function:: const char *jansson_version_str()
Return the version of the Jansson library, in the same format as
the ``JANSSON_VERSION`` preprocessor constant.
.. versionadded:: 2.13
.. function:: int jansson_version_cmp(int major, int minor, int micro)
Returns an integer less than, equal to, or greater than zero if
the runtime version of Jansson is found, respectively, to be less
than, to match, or be greater than the provided *major*, *minor*, and
*micro*.
.. versionadded:: 2.13
``JANSSON_THREAD_SAFE_REFCOUNT``
If this value is defined all read-only operations and reference counting in
Jansson are thread safe. This value is not defined for versions older than
@@ -689,6 +708,30 @@ allowed in object keys.
.. versionadded:: 2.3
.. function:: int json_object_update_new(json_t *object, json_t *other)
Like :func:`json_object_update()`, but steals the reference to
*other*. This is useful when *other* is newly created and not used
after the call.
.. function:: int json_object_update_existing_new(json_t *object, json_t *other)
Like :func:`json_object_update_new()`, but only the values of existing
keys are updated. No new keys are created. Returns 0 on success or
-1 on error.
.. function:: int json_object_update_missing_new(json_t *object, json_t *other)
Like :func:`json_object_update_new()`, but only new keys are created.
The value of any existing key is not changed. Returns 0 on success
or -1 on error.
.. function:: int json_object_update_recursive(json_t *object, json_t *other)
Like :func:`json_object_update()`, but object values in *other* are
recursively merged with the corresponding values in *object* if they are also
objects, instead of overwriting them. Returns 0 on success or -1 on error.
.. function:: json_object_foreach(object, key, value)
Iterate over every key-value pair of ``object``, running the block
@@ -1072,7 +1115,9 @@ These functions output UTF-8:
Returns the JSON representation of *json* as a string, or *NULL* on
error. *flags* is described above. The return value must be freed
by the caller using :func:`free()`.
by the caller using :func:`free()`. Note that if you have called
:func:`json_set_alloc_funcs()` to override :func:`free()`, you should
call your custom free function instead to free the return value.
.. function:: size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags)
@@ -1312,7 +1357,11 @@ If no error or position information is needed, you can pass *NULL*.
It is important to note that this function can only succeed on stream
file descriptors (such as SOCK_STREAM). Using this function on a
non-stream file descriptor will result in undefined behavior. For
non-stream file descriptors, see instead :func:`json_loadb()`.
non-stream file descriptors, see instead :func:`json_loadb()`. In
addition, please note that this function cannot be used on non-blocking
file descriptors (such as a non-blocking socket). Using this function
on non-blocking file descriptors has a high risk of data loss because
it does not support resuming.
This function requires POSIX and fails on all non-POSIX systems.
@@ -1609,7 +1658,7 @@ type whose address should be passed.
Convert each item in the JSON object according to the inner format
string ``fmt``. The first, third, etc. format specifier represent
a key, and must be ``s``. The corresponding argument to unpack
functions is read as the object key. The second fourth, etc.
functions is read as the object key. The second, fourth, etc.
format specifier represent a value and is written to the address
given as the corresponding argument. **Note** that every other
argument is read from and every other is written to.

View File

@@ -41,14 +41,14 @@ master_doc = 'index'
# General information about the project.
project = u'Jansson'
copyright = u'2009-2016, Petri Lehtinen'
copyright = u'2009-2020, Petri Lehtinen'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '2.11'
version = '2.13'
# The full version, including alpha/beta/rc tags.
release = version

View File

@@ -84,6 +84,11 @@ Generating make files on unix:
cd build
cmake .. # or ccmake .. for a GUI.
.. note::
If you don't want to build docs or ``Sphinx`` is not installed, you should add ``"-DJANSSON_BUILD_DOCS=OFF"`` in the ``cmake`` command.
Then to build::
make
@@ -101,7 +106,23 @@ Creating Visual Studio project files from the command line:
md build
cd build
cmake -G "Visual Studio 10" ..
cmake -G "Visual Studio 15 2017" ..
.. note::
You should replace the name of the generator (``-G`` flag) matching
the Visual Studio version installed on your system. Currently, the
following versions are supported:
- ``Visual Studio 9 2008``
- ``Visual Studio 10 2010``
- ``Visual Studio 11 2012``
- ``Visual Studio 12 2013``
- ``Visual Studio 14 2015``
- ``Visual Studio 15 2017``
- ``Visual Studio 16 2019``
Any later version should also work.
You will now have a *Visual Studio Solution* in your build directory.
To run the unit tests build the ``RUN_TESTS`` project.
@@ -121,6 +142,21 @@ for the project, run::
cmake -LH ..
Windows (MinGW)
^^^^^^^^^^^^^^^
If you prefer using MinGW on Windows, make sure MinGW installed and ``{MinGW}/bin`` has been added to ``PATH``, then do the following commands:
.. parsed-literal::
<unpack>
cd jansson-|release|
md build
cd build
cmake -G "MinGW Makefiles" ..
mingw32-make
Mac OSX (Xcode)
^^^^^^^^^^^^^^^
If you prefer using Xcode instead of make files on OSX,

View File

@@ -8,37 +8,33 @@
#include <stdlib.h>
#include <string.h>
#include <jansson.h>
#include <curl/curl.h>
#include <jansson.h>
#define BUFFER_SIZE (256 * 1024) /* 256 KB */
#define BUFFER_SIZE (256 * 1024) /* 256 KB */
#define URL_FORMAT "https://api.github.com/repos/%s/%s/commits"
#define URL_SIZE 256
#define URL_FORMAT "https://api.github.com/repos/%s/%s/commits"
#define URL_SIZE 256
/* Return the offset of the first newline in text or the length of
text if there's no newline */
static int newline_offset(const char *text)
{
static int newline_offset(const char *text) {
const char *newline = strchr(text, '\n');
if(!newline)
if (!newline)
return strlen(text);
else
return (int)(newline - text);
}
struct write_result
{
struct write_result {
char *data;
int pos;
};
static size_t write_response(void *ptr, size_t size, size_t nmemb, void *stream)
{
static size_t write_response(void *ptr, size_t size, size_t nmemb, void *stream) {
struct write_result *result = (struct write_result *)stream;
if(result->pos + size * nmemb >= BUFFER_SIZE - 1)
{
if (result->pos + size * nmemb >= BUFFER_SIZE - 1) {
fprintf(stderr, "error: too small buffer\n");
return 0;
}
@@ -49,8 +45,7 @@ static size_t write_response(void *ptr, size_t size, size_t nmemb, void *stream)
return size * nmemb;
}
static char *request(const char *url)
{
static char *request(const char *url) {
CURL *curl = NULL;
CURLcode status;
struct curl_slist *headers = NULL;
@@ -59,17 +54,14 @@ static char *request(const char *url)
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(!curl)
if (!curl)
goto error;
data = malloc(BUFFER_SIZE);
if(!data)
if (!data)
goto error;
struct write_result write_result = {
.data = data,
.pos = 0
};
struct write_result write_result = {.data = data, .pos = 0};
curl_easy_setopt(curl, CURLOPT_URL, url);
@@ -81,16 +73,14 @@ static char *request(const char *url)
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_result);
status = curl_easy_perform(curl);
if(status != 0)
{
if (status != 0) {
fprintf(stderr, "error: unable to request data from %s:\n", url);
fprintf(stderr, "%s\n", curl_easy_strerror(status));
goto error;
}
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
if(code != 200)
{
if (code != 200) {
fprintf(stderr, "error: server responded with code %ld\n", code);
goto error;
}
@@ -105,18 +95,17 @@ static char *request(const char *url)
return data;
error:
if(data)
if (data)
free(data);
if(curl)
if (curl)
curl_easy_cleanup(curl);
if(headers)
if (headers)
curl_slist_free_all(headers);
curl_global_cleanup();
return NULL;
}
int main(int argc, char *argv[])
{
int main(int argc, char *argv[]) {
size_t i;
char *text;
char url[URL_SIZE];
@@ -124,8 +113,7 @@ int main(int argc, char *argv[])
json_t *root;
json_error_t error;
if(argc != 3)
{
if (argc != 3) {
fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]);
fprintf(stderr, "List commits at USER's REPOSITORY.\n\n");
return 2;
@@ -134,65 +122,56 @@ int main(int argc, char *argv[])
snprintf(url, URL_SIZE, URL_FORMAT, argv[1], argv[2]);
text = request(url);
if(!text)
if (!text)
return 1;
root = json_loads(text, 0, &error);
free(text);
if(!root)
{
if (!root) {
fprintf(stderr, "error: on line %d: %s\n", error.line, error.text);
return 1;
}
if(!json_is_array(root))
{
if (!json_is_array(root)) {
fprintf(stderr, "error: root is not an array\n");
json_decref(root);
return 1;
}
for(i = 0; i < json_array_size(root); i++)
{
for (i = 0; i < json_array_size(root); i++) {
json_t *data, *sha, *commit, *message;
const char *message_text;
data = json_array_get(root, i);
if(!json_is_object(data))
{
if (!json_is_object(data)) {
fprintf(stderr, "error: commit data %d is not an object\n", (int)(i + 1));
json_decref(root);
return 1;
}
sha = json_object_get(data, "sha");
if(!json_is_string(sha))
{
if (!json_is_string(sha)) {
fprintf(stderr, "error: commit %d: sha is not a string\n", (int)(i + 1));
return 1;
}
commit = json_object_get(data, "commit");
if(!json_is_object(commit))
{
if (!json_is_object(commit)) {
fprintf(stderr, "error: commit %d: commit is not an object\n", (int)(i + 1));
json_decref(root);
return 1;
}
message = json_object_get(commit, "message");
if(!json_is_string(message))
{
if (!json_is_string(message)) {
fprintf(stderr, "error: commit %d: message is not a string\n", (int)(i + 1));
json_decref(root);
return 1;
}
message_text = json_string_value(message);
printf("%.8s %.*s\n",
json_string_value(sha),
newline_offset(message_text),
printf("%.8s %.*s\n", json_string_value(sha), newline_offset(message_text),
message_text);
}

View File

@@ -74,7 +74,7 @@ function::
static char *request(const char *url);
It takes the URL as a parameter, preforms a HTTP GET request, and
It takes the URL as a parameter, performs a HTTP GET request, and
returns a newly allocated string that contains the response body. If
the request fails, an error message is printed to stderr and the
return value is *NULL*. For full details, refer to :download:`the code

View File

@@ -22,9 +22,9 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <jansson.h>
#include <stdio.h>
#include <stdlib.h>
#include <jansson.h>
/* forward refs */
void print_json(json_t *root);
@@ -40,49 +40,47 @@ void print_json_true(json_t *element, int indent);
void print_json_false(json_t *element, int indent);
void print_json_null(json_t *element, int indent);
void print_json(json_t *root) {
print_json_aux(root, 0);
}
void print_json(json_t *root) { print_json_aux(root, 0); }
void print_json_aux(json_t *element, int indent) {
switch (json_typeof(element)) {
case JSON_OBJECT:
print_json_object(element, indent);
break;
case JSON_ARRAY:
print_json_array(element, indent);
break;
case JSON_STRING:
print_json_string(element, indent);
break;
case JSON_INTEGER:
print_json_integer(element, indent);
break;
case JSON_REAL:
print_json_real(element, indent);
break;
case JSON_TRUE:
print_json_true(element, indent);
break;
case JSON_FALSE:
print_json_false(element, indent);
break;
case JSON_NULL:
print_json_null(element, indent);
break;
default:
fprintf(stderr, "unrecognized JSON type %d\n", json_typeof(element));
case JSON_OBJECT:
print_json_object(element, indent);
break;
case JSON_ARRAY:
print_json_array(element, indent);
break;
case JSON_STRING:
print_json_string(element, indent);
break;
case JSON_INTEGER:
print_json_integer(element, indent);
break;
case JSON_REAL:
print_json_real(element, indent);
break;
case JSON_TRUE:
print_json_true(element, indent);
break;
case JSON_FALSE:
print_json_false(element, indent);
break;
case JSON_NULL:
print_json_null(element, indent);
break;
default:
fprintf(stderr, "unrecognized JSON type %d\n", json_typeof(element));
}
}
void print_json_indent(int indent) {
int i;
for (i = 0; i < indent; i++) { putchar(' '); }
for (i = 0; i < indent; i++) {
putchar(' ');
}
}
const char *json_plural(int count) {
return count == 1 ? "" : "s";
}
const char *json_plural(int count) { return count == 1 ? "" : "s"; }
void print_json_object(json_t *element, int indent) {
size_t size;
@@ -98,7 +96,6 @@ void print_json_object(json_t *element, int indent) {
printf("JSON Key: \"%s\"\n", key);
print_json_aux(value, indent + 2);
}
}
void print_json_array(json_t *element, int indent) {

3
scripts/clang-format Executable file
View File

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

27
scripts/clang-format-check Executable file
View File

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

View File

@@ -20,8 +20,10 @@ libjansson_la_SOURCES = \
strconv.c \
utf.c \
utf.h \
value.c
value.c \
version.c
libjansson_la_LDFLAGS = \
-no-undefined \
-export-symbols-regex '^json_' \
-version-info 15:0:11
-version-info 16:0:12 \
@JSON_BSYMBOLIC_LDFLAGS@

View File

@@ -11,10 +11,10 @@
#include "jansson_private.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -23,11 +23,11 @@
#include "strbuffer.h"
#include "utf.h"
#define MAX_INTEGER_STR_LENGTH 100
#define MAX_REAL_STR_LENGTH 100
#define MAX_INTEGER_STR_LENGTH 100
#define MAX_REAL_STR_LENGTH 100
#define FLAGS_TO_INDENT(f) ((f) & 0x1F)
#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F)
#define FLAGS_TO_INDENT(f) ((f)&0x1F)
#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F)
struct buffer {
const size_t size;
@@ -35,35 +35,31 @@ struct buffer {
char *data;
};
static int dump_to_strbuffer(const char *buffer, size_t size, void *data)
{
static int dump_to_strbuffer(const char *buffer, size_t size, void *data) {
return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
}
static int dump_to_buffer(const char *buffer, size_t size, void *data)
{
static int dump_to_buffer(const char *buffer, size_t size, void *data) {
struct buffer *buf = (struct buffer *)data;
if(buf->used + size <= buf->size)
if (buf->used + size <= buf->size)
memcpy(&buf->data[buf->used], buffer, size);
buf->used += size;
return 0;
}
static int dump_to_file(const char *buffer, size_t size, void *data)
{
static int dump_to_file(const char *buffer, size_t size, void *data) {
FILE *dest = (FILE *)data;
if(fwrite(buffer, size, 1, dest) != 1)
if (fwrite(buffer, size, 1, dest) != 1)
return -1;
return 0;
}
static int dump_to_fd(const char *buffer, size_t size, void *data)
{
int *dest = (int *)data;
static int dump_to_fd(const char *buffer, size_t size, void *data) {
#ifdef HAVE_UNISTD_H
if(write(*dest, buffer, size) == (ssize_t)size)
int *dest = (int *)data;
if (write(*dest, buffer, size) == (ssize_t)size)
return 0;
#endif
return -1;
@@ -72,108 +68,116 @@ static int dump_to_fd(const char *buffer, size_t size, void *data)
/* 32 spaces (the maximum indentation size) */
static const char whitespace[] = " ";
static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data)
{
if(FLAGS_TO_INDENT(flags) > 0)
{
static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump,
void *data) {
if (FLAGS_TO_INDENT(flags) > 0) {
unsigned int ws_count = FLAGS_TO_INDENT(flags), n_spaces = depth * ws_count;
if(dump("\n", 1, data))
if (dump("\n", 1, data))
return -1;
while(n_spaces > 0)
{
int cur_n = n_spaces < sizeof whitespace - 1 ? n_spaces : sizeof whitespace - 1;
while (n_spaces > 0) {
int cur_n =
n_spaces < sizeof whitespace - 1 ? n_spaces : sizeof whitespace - 1;
if(dump(whitespace, cur_n, data))
if (dump(whitespace, cur_n, data))
return -1;
n_spaces -= cur_n;
}
}
else if(space && !(flags & JSON_COMPACT))
{
} else if (space && !(flags & JSON_COMPACT)) {
return dump(" ", 1, data);
}
return 0;
}
static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags)
{
static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data,
size_t flags) {
const char *pos, *end, *lim;
int32_t codepoint;
int32_t codepoint = 0;
if(dump("\"", 1, data))
if (dump("\"", 1, data))
return -1;
end = pos = str;
lim = str + len;
while(1)
{
while (1) {
const char *text;
char seq[13];
int length;
while(end < lim)
{
while (end < lim) {
end = utf8_iterate(pos, lim - pos, &codepoint);
if(!end)
if (!end)
return -1;
/* mandatory escape or control char */
if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
if (codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
break;
/* slash */
if((flags & JSON_ESCAPE_SLASH) && codepoint == '/')
if ((flags & JSON_ESCAPE_SLASH) && codepoint == '/')
break;
/* non-ASCII */
if((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F)
if ((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F)
break;
pos = end;
}
if(pos != str) {
if(dump(str, pos - str, data))
if (pos != str) {
if (dump(str, pos - str, data))
return -1;
}
if(end == pos)
if (end == pos)
break;
/* handle \, /, ", and control codes */
length = 2;
switch(codepoint)
{
case '\\': text = "\\\\"; break;
case '\"': text = "\\\""; break;
case '\b': text = "\\b"; break;
case '\f': text = "\\f"; break;
case '\n': text = "\\n"; break;
case '\r': text = "\\r"; break;
case '\t': text = "\\t"; break;
case '/': text = "\\/"; break;
default:
{
switch (codepoint) {
case '\\':
text = "\\\\";
break;
case '\"':
text = "\\\"";
break;
case '\b':
text = "\\b";
break;
case '\f':
text = "\\f";
break;
case '\n':
text = "\\n";
break;
case '\r':
text = "\\r";
break;
case '\t':
text = "\\t";
break;
case '/':
text = "\\/";
break;
default: {
/* codepoint is in BMP */
if(codepoint < 0x10000)
{
if (codepoint < 0x10000) {
snprintf(seq, sizeof(seq), "\\u%04X", (unsigned int)codepoint);
length = 6;
}
/* not in BMP -> construct a UTF-16 surrogate pair */
else
{
else {
int32_t first, last;
codepoint -= 0x10000;
first = 0xD800 | ((codepoint & 0xffc00) >> 10);
last = 0xDC00 | (codepoint & 0x003ff);
snprintf(seq, sizeof(seq), "\\u%04X\\u%04X", (unsigned int)first, (unsigned int)last);
snprintf(seq, sizeof(seq), "\\u%04X\\u%04X", (unsigned int)first,
(unsigned int)last);
length = 12;
}
@@ -182,7 +186,7 @@ static int dump_string(const char *str, size_t len, json_dump_callback_t dump, v
}
}
if(dump(text, length, data))
if (dump(text, length, data))
return -1;
str = pos = end;
@@ -191,31 +195,20 @@ static int dump_string(const char *str, size_t len, json_dump_callback_t dump, v
return dump("\"", 1, data);
}
static int compare_keys(const void *key1, const void *key2)
{
static int compare_keys(const void *key1, const void *key2) {
return strcmp(*(const char **)key1, *(const char **)key2);
}
static int loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size)
{
snprintf(key, key_size, "%p", json);
if (hashtable_get(parents, key))
return -1;
return hashtable_set(parents, key, json_null());
}
static int do_dump(const json_t *json, size_t flags, int depth,
hashtable_t *parents, json_dump_callback_t dump, void *data)
{
static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *parents,
json_dump_callback_t dump, void *data) {
int embed = flags & JSON_EMBED;
flags &= ~JSON_EMBED;
if(!json)
if (!json)
return -1;
switch(json_typeof(json)) {
switch (json_typeof(json)) {
case JSON_NULL:
return dump("null", 4, data);
@@ -225,73 +218,68 @@ static int do_dump(const json_t *json, size_t flags, int depth,
case JSON_FALSE:
return dump("false", 5, data);
case JSON_INTEGER:
{
case JSON_INTEGER: {
char buffer[MAX_INTEGER_STR_LENGTH];
int size;
size = snprintf(buffer, MAX_INTEGER_STR_LENGTH,
"%" JSON_INTEGER_FORMAT,
size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, "%" JSON_INTEGER_FORMAT,
json_integer_value(json));
if(size < 0 || size >= MAX_INTEGER_STR_LENGTH)
if (size < 0 || size >= MAX_INTEGER_STR_LENGTH)
return -1;
return dump(buffer, size, data);
}
case JSON_REAL:
{
case JSON_REAL: {
char buffer[MAX_REAL_STR_LENGTH];
int size;
double value = json_real_value(json);
size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value,
FLAGS_TO_PRECISION(flags));
if(size < 0)
if (size < 0)
return -1;
return dump(buffer, size, data);
}
case JSON_STRING:
return dump_string(json_string_value(json), json_string_length(json), dump, data, flags);
return dump_string(json_string_value(json), json_string_length(json), dump,
data, flags);
case JSON_ARRAY:
{
case JSON_ARRAY: {
size_t n;
size_t i;
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
/* Space for "0x", double the sizeof a pointer for the hex and a
* terminator. */
char key[2 + (sizeof(json) * 2) + 1];
/* detect circular references */
if (loop_check(parents, json, key, sizeof(key)))
if (jsonp_loop_check(parents, json, key, sizeof(key)))
return -1;
n = json_array_size(json);
if(!embed && dump("[", 1, data))
if (!embed && dump("[", 1, data))
return -1;
if(n == 0) {
if (n == 0) {
hashtable_del(parents, key);
return embed ? 0 : dump("]", 1, data);
}
if(dump_indent(flags, depth + 1, 0, dump, data))
if (dump_indent(flags, depth + 1, 0, dump, data))
return -1;
for(i = 0; i < n; ++i) {
if(do_dump(json_array_get(json, i), flags, depth + 1,
parents, dump, data))
for (i = 0; i < n; ++i) {
if (do_dump(json_array_get(json, i), flags, depth + 1, parents, dump,
data))
return -1;
if(i < n - 1)
{
if(dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
if (i < n - 1) {
if (dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
return -1;
}
else
{
if(dump_indent(flags, depth, 0, dump, data))
} else {
if (dump_indent(flags, depth, 0, dump, data))
return -1;
}
}
@@ -300,51 +288,46 @@ static int do_dump(const json_t *json, size_t flags, int depth,
return embed ? 0 : dump("]", 1, data);
}
case JSON_OBJECT:
{
case JSON_OBJECT: {
void *iter;
const char *separator;
int separator_length;
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
char key[2 + (sizeof(json) * 2) + 1];
char loop_key[LOOP_KEY_LEN];
if(flags & JSON_COMPACT) {
if (flags & JSON_COMPACT) {
separator = ":";
separator_length = 1;
}
else {
} else {
separator = ": ";
separator_length = 2;
}
/* detect circular references */
if (loop_check(parents, json, key, sizeof(key)))
if (jsonp_loop_check(parents, json, loop_key, sizeof(loop_key)))
return -1;
iter = json_object_iter((json_t *)json);
if(!embed && dump("{", 1, data))
if (!embed && dump("{", 1, data))
return -1;
if(!iter) {
hashtable_del(parents, key);
if (!iter) {
hashtable_del(parents, loop_key);
return embed ? 0 : dump("}", 1, data);
}
if(dump_indent(flags, depth + 1, 0, dump, data))
if (dump_indent(flags, depth + 1, 0, dump, data))
return -1;
if(flags & JSON_SORT_KEYS)
{
if (flags & JSON_SORT_KEYS) {
const char **keys;
size_t size, i;
size = json_object_size(json);
keys = jsonp_malloc(size * sizeof(const char *));
if(!keys)
if (!keys)
return -1;
i = 0;
while(iter)
{
while (iter) {
keys[i] = json_object_iter_key(iter);
iter = json_object_iter_next((json_t *)json, iter);
i++;
@@ -353,8 +336,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
qsort(keys, size, sizeof(const char *), compare_keys);
for(i = 0; i < size; i++)
{
for (i = 0; i < size; i++) {
const char *key;
json_t *value;
@@ -363,26 +345,20 @@ static int do_dump(const json_t *json, size_t flags, int depth,
assert(value);
dump_string(key, strlen(key), dump, data, flags);
if(dump(separator, separator_length, data) ||
do_dump(value, flags, depth + 1, parents, dump, data))
{
if (dump(separator, separator_length, data) ||
do_dump(value, flags, depth + 1, parents, dump, data)) {
jsonp_free(keys);
return -1;
}
if(i < size - 1)
{
if(dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
{
if (i < size - 1) {
if (dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data)) {
jsonp_free(keys);
return -1;
}
}
else
{
if(dump_indent(flags, depth, 0, dump, data))
{
} else {
if (dump_indent(flags, depth, 0, dump, data)) {
jsonp_free(keys);
return -1;
}
@@ -390,31 +366,25 @@ static int do_dump(const json_t *json, size_t flags, int depth,
}
jsonp_free(keys);
}
else
{
} else {
/* Don't sort keys */
while(iter)
{
while (iter) {
void *next = json_object_iter_next((json_t *)json, iter);
const char *key = json_object_iter_key(iter);
dump_string(key, strlen(key), dump, data, flags);
if(dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1,
parents, dump, data))
if (dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1, parents,
dump, data))
return -1;
if(next)
{
if(dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
if (next) {
if (dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
return -1;
}
else
{
if(dump_indent(flags, depth, 0, dump, data))
} else {
if (dump_indent(flags, depth, 0, dump, data))
return -1;
}
@@ -422,7 +392,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
}
}
hashtable_del(parents, key);
hashtable_del(parents, loop_key);
return embed ? 0 : dump("}", 1, data);
}
@@ -432,15 +402,14 @@ static int do_dump(const json_t *json, size_t flags, int depth,
}
}
char *json_dumps(const json_t *json, size_t flags)
{
char *json_dumps(const json_t *json, size_t flags) {
strbuffer_t strbuff;
char *result;
if(strbuffer_init(&strbuff))
if (strbuffer_init(&strbuff))
return NULL;
if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags))
if (json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags))
result = NULL;
else
result = jsonp_strdup(strbuffer_value(&strbuff));
@@ -449,50 +418,46 @@ char *json_dumps(const json_t *json, size_t flags)
return result;
}
size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags)
{
struct buffer buf = { size, 0, buffer };
size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags) {
struct buffer buf = {size, 0, buffer};
if(json_dump_callback(json, dump_to_buffer, (void *)&buf, flags))
if (json_dump_callback(json, dump_to_buffer, (void *)&buf, flags))
return 0;
return buf.used;
}
int json_dumpf(const json_t *json, FILE *output, size_t flags)
{
int json_dumpf(const json_t *json, FILE *output, size_t flags) {
return json_dump_callback(json, dump_to_file, (void *)output, flags);
}
int json_dumpfd(const json_t *json, int output, size_t flags)
{
int json_dumpfd(const json_t *json, int output, size_t flags) {
return json_dump_callback(json, dump_to_fd, (void *)&output, flags);
}
int json_dump_file(const json_t *json, const char *path, size_t flags)
{
int json_dump_file(const json_t *json, const char *path, size_t flags) {
int result;
FILE *output = fopen(path, "w");
if(!output)
if (!output)
return -1;
result = json_dumpf(json, output, flags);
if(fclose(output) != 0)
if (fclose(output) != 0)
return -1;
return result;
}
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags)
{
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data,
size_t flags) {
int res;
hashtable_t parents_set;
if(!(flags & JSON_ENCODE_ANY)) {
if(!json_is_array(json) && !json_is_object(json))
return -1;
if (!(flags & JSON_ENCODE_ANY)) {
if (!json_is_array(json) && !json_is_object(json))
return -1;
}
if (hashtable_init(&parents_set))

View File

@@ -1,42 +1,37 @@
#include <string.h>
#include "jansson_private.h"
#include <string.h>
void jsonp_error_init(json_error_t *error, const char *source)
{
if(error)
{
void jsonp_error_init(json_error_t *error, const char *source) {
if (error) {
error->text[0] = '\0';
error->line = -1;
error->column = -1;
error->position = 0;
if(source)
if (source)
jsonp_error_set_source(error, source);
else
error->source[0] = '\0';
}
}
void jsonp_error_set_source(json_error_t *error, const char *source)
{
void jsonp_error_set_source(json_error_t *error, const char *source) {
size_t length;
if(!error || !source)
if (!error || !source)
return;
length = strlen(source);
if(length < JSON_ERROR_SOURCE_LENGTH)
if (length < JSON_ERROR_SOURCE_LENGTH)
strncpy(error->source, source, length + 1);
else {
size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4;
strncpy(error->source, "...", 3);
memcpy(error->source, "...", 3);
strncpy(error->source + 3, source + extra, length - extra + 1);
}
}
void jsonp_error_set(json_error_t *error, int line, int column,
size_t position, enum json_error_code code,
const char *msg, ...)
{
void jsonp_error_set(json_error_t *error, int line, int column, size_t position,
enum json_error_code code, const char *msg, ...) {
va_list ap;
va_start(ap, msg);
@@ -44,14 +39,12 @@ void jsonp_error_set(json_error_t *error, int line, int column,
va_end(ap);
}
void jsonp_error_vset(json_error_t *error, int line, int column,
size_t position, enum json_error_code code,
const char *msg, va_list ap)
{
if(!error)
void jsonp_error_vset(json_error_t *error, int line, int column, size_t position,
enum json_error_code code, const char *msg, va_list ap) {
if (!error)
return;
if(error->text[0] != '\0') {
if (error->text[0] != '\0') {
/* error already set */
return;
}

View File

@@ -16,9 +16,9 @@
#include <stdint.h>
#endif
#include <jansson_config.h> /* for JSON_INLINE */
#include "jansson_private.h" /* for container_of() */
#include "hashtable.h"
#include "jansson_private.h" /* for container_of() */
#include <jansson_config.h> /* for JSON_INLINE */
#ifndef INITIAL_HASHTABLE_ORDER
#define INITIAL_HASHTABLE_ORDER 3
@@ -33,67 +33,56 @@ extern volatile uint32_t hashtable_seed;
/* Implementation of the hash function */
#include "lookup3.h"
#define list_to_pair(list_) container_of(list_, pair_t, list)
#define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list)
#define hash_str(key) ((size_t)hashlittle((key), strlen(key), hashtable_seed))
#define list_to_pair(list_) container_of(list_, pair_t, list)
#define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list)
#define hash_str(key) ((size_t)hashlittle((key), strlen(key), hashtable_seed))
static JSON_INLINE void list_init(list_t *list)
{
static JSON_INLINE void list_init(list_t *list) {
list->next = list;
list->prev = list;
}
static JSON_INLINE void list_insert(list_t *list, list_t *node)
{
static JSON_INLINE void list_insert(list_t *list, list_t *node) {
node->next = list;
node->prev = list->prev;
list->prev->next = node;
list->prev = node;
}
static JSON_INLINE void list_remove(list_t *list)
{
static JSON_INLINE void list_remove(list_t *list) {
list->prev->next = list->next;
list->next->prev = list->prev;
}
static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket)
{
static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket) {
return bucket->first == &hashtable->list && bucket->first == bucket->last;
}
static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket,
list_t *list)
{
if(bucket_is_empty(hashtable, bucket))
{
static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, list_t *list) {
if (bucket_is_empty(hashtable, bucket)) {
list_insert(&hashtable->list, list);
bucket->first = bucket->last = list;
}
else
{
} else {
list_insert(bucket->first, list);
bucket->first = list;
}
}
static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
const char *key, size_t hash)
{
const char *key, size_t hash) {
list_t *list;
pair_t *pair;
if(bucket_is_empty(hashtable, bucket))
if (bucket_is_empty(hashtable, bucket))
return NULL;
list = bucket->first;
while(1)
{
while (1) {
pair = list_to_pair(list);
if(pair->hash == hash && strcmp(pair->key, key) == 0)
if (pair->hash == hash && strcmp(pair->key, key) == 0)
return pair;
if(list == bucket->last)
if (list == bucket->last)
break;
list = list->next;
@@ -103,9 +92,7 @@ static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
}
/* returns 0 on success, -1 if key was not found */
static int hashtable_do_del(hashtable_t *hashtable,
const char *key, size_t hash)
{
static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t hash) {
pair_t *pair;
bucket_t *bucket;
size_t index;
@@ -114,16 +101,16 @@ static int hashtable_do_del(hashtable_t *hashtable,
bucket = &hashtable->buckets[index];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(!pair)
if (!pair)
return -1;
if(&pair->list == bucket->first && &pair->list == bucket->last)
if (&pair->list == bucket->first && &pair->list == bucket->last)
bucket->first = bucket->last = &hashtable->list;
else if(&pair->list == bucket->first)
else if (&pair->list == bucket->first)
bucket->first = pair->list.next;
else if(&pair->list == bucket->last)
else if (&pair->list == bucket->last)
bucket->last = pair->list.prev;
list_remove(&pair->list);
@@ -136,13 +123,11 @@ static int hashtable_do_del(hashtable_t *hashtable,
return 0;
}
static void hashtable_do_clear(hashtable_t *hashtable)
{
static void hashtable_do_clear(hashtable_t *hashtable) {
list_t *list, *next;
pair_t *pair;
for(list = hashtable->list.next; list != &hashtable->list; list = next)
{
for (list = hashtable->list.next; list != &hashtable->list; list = next) {
next = list->next;
pair = list_to_pair(list);
json_decref(pair->value);
@@ -150,8 +135,7 @@ static void hashtable_do_clear(hashtable_t *hashtable)
}
}
static int hashtable_do_rehash(hashtable_t *hashtable)
{
static int hashtable_do_rehash(hashtable_t *hashtable) {
list_t *list, *next;
pair_t *pair;
size_t i, index, new_size, new_order;
@@ -161,23 +145,21 @@ static int hashtable_do_rehash(hashtable_t *hashtable)
new_size = hashsize(new_order);
new_buckets = jsonp_malloc(new_size * sizeof(bucket_t));
if(!new_buckets)
if (!new_buckets)
return -1;
jsonp_free(hashtable->buckets);
hashtable->buckets = new_buckets;
hashtable->order = new_order;
for(i = 0; i < hashsize(hashtable->order); i++)
{
hashtable->buckets[i].first = hashtable->buckets[i].last =
&hashtable->list;
for (i = 0; i < hashsize(hashtable->order); i++) {
hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list;
}
list = hashtable->list.next;
list_init(&hashtable->list);
for(; list != &hashtable->list; list = next) {
for (; list != &hashtable->list; list = next) {
next = list->next;
pair = list_to_pair(list);
index = pair->hash % new_size;
@@ -187,44 +169,38 @@ static int hashtable_do_rehash(hashtable_t *hashtable)
return 0;
}
int hashtable_init(hashtable_t *hashtable)
{
int hashtable_init(hashtable_t *hashtable) {
size_t i;
hashtable->size = 0;
hashtable->order = INITIAL_HASHTABLE_ORDER;
hashtable->buckets = jsonp_malloc(hashsize(hashtable->order) * sizeof(bucket_t));
if(!hashtable->buckets)
if (!hashtable->buckets)
return -1;
list_init(&hashtable->list);
list_init(&hashtable->ordered_list);
for(i = 0; i < hashsize(hashtable->order); i++)
{
hashtable->buckets[i].first = hashtable->buckets[i].last =
&hashtable->list;
for (i = 0; i < hashsize(hashtable->order); i++) {
hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list;
}
return 0;
}
void hashtable_close(hashtable_t *hashtable)
{
void hashtable_close(hashtable_t *hashtable) {
hashtable_do_clear(hashtable);
jsonp_free(hashtable->buckets);
}
int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value)
{
int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) {
pair_t *pair;
bucket_t *bucket;
size_t hash, index;
/* rehash if the load ratio exceeds 1 */
if(hashtable->size >= hashsize(hashtable->order))
if(hashtable_do_rehash(hashtable))
if (hashtable->size >= hashsize(hashtable->order))
if (hashtable_do_rehash(hashtable))
return -1;
hash = hash_str(key);
@@ -232,25 +208,22 @@ int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value)
bucket = &hashtable->buckets[index];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(pair)
{
if (pair) {
json_decref(pair->value);
pair->value = value;
}
else
{
} else {
/* offsetof(...) returns the size of pair_t without the last,
flexible member. This way, the correct amount is
allocated. */
size_t len = strlen(key);
if(len >= (size_t)-1 - offsetof(pair_t, key)) {
if (len >= (size_t)-1 - offsetof(pair_t, key)) {
/* Avoid an overflow if the key is very long */
return -1;
}
pair = jsonp_malloc(offsetof(pair_t, key) + len + 1);
if(!pair)
if (!pair)
return -1;
pair->hash = hash;
@@ -267,8 +240,7 @@ int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value)
return 0;
}
void *hashtable_get(hashtable_t *hashtable, const char *key)
{
void *hashtable_get(hashtable_t *hashtable, const char *key) {
pair_t *pair;
size_t hash;
bucket_t *bucket;
@@ -277,28 +249,24 @@ void *hashtable_get(hashtable_t *hashtable, const char *key)
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(!pair)
if (!pair)
return NULL;
return pair->value;
}
int hashtable_del(hashtable_t *hashtable, const char *key)
{
int hashtable_del(hashtable_t *hashtable, const char *key) {
size_t hash = hash_str(key);
return hashtable_do_del(hashtable, key, hash);
}
void hashtable_clear(hashtable_t *hashtable)
{
void hashtable_clear(hashtable_t *hashtable) {
size_t i;
hashtable_do_clear(hashtable);
for(i = 0; i < hashsize(hashtable->order); i++)
{
hashtable->buckets[i].first = hashtable->buckets[i].last =
&hashtable->list;
for (i = 0; i < hashsize(hashtable->order); i++) {
hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list;
}
list_init(&hashtable->list);
@@ -306,13 +274,11 @@ void hashtable_clear(hashtable_t *hashtable)
hashtable->size = 0;
}
void *hashtable_iter(hashtable_t *hashtable)
{
void *hashtable_iter(hashtable_t *hashtable) {
return hashtable_iter_next(hashtable, &hashtable->ordered_list);
}
void *hashtable_iter_at(hashtable_t *hashtable, const char *key)
{
void *hashtable_iter_at(hashtable_t *hashtable, const char *key) {
pair_t *pair;
size_t hash;
bucket_t *bucket;
@@ -321,34 +287,30 @@ void *hashtable_iter_at(hashtable_t *hashtable, const char *key)
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(!pair)
if (!pair)
return NULL;
return &pair->ordered_list;
}
void *hashtable_iter_next(hashtable_t *hashtable, void *iter)
{
void *hashtable_iter_next(hashtable_t *hashtable, void *iter) {
list_t *list = (list_t *)iter;
if(list->next == &hashtable->ordered_list)
if (list->next == &hashtable->ordered_list)
return NULL;
return list->next;
}
void *hashtable_iter_key(void *iter)
{
void *hashtable_iter_key(void *iter) {
pair_t *pair = ordered_list_to_pair((list_t *)iter);
return pair->key;
}
void *hashtable_iter_value(void *iter)
{
void *hashtable_iter_value(void *iter) {
pair_t *pair = ordered_list_to_pair((list_t *)iter);
return pair->value;
}
void hashtable_iter_set(void *iter, json_t *value)
{
void hashtable_iter_set(void *iter, json_t *value) {
pair_t *pair = ordered_list_to_pair((list_t *)iter);
json_decref(pair->value);

View File

@@ -8,8 +8,8 @@
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include <stdlib.h>
#include "jansson.h"
#include <stdlib.h>
struct hashtable_list {
struct hashtable_list *prev;
@@ -35,16 +35,14 @@ struct hashtable_bucket {
typedef struct hashtable {
size_t size;
struct hashtable_bucket *buckets;
size_t order; /* hashtable has pow(2, order) buckets */
size_t order; /* hashtable has pow(2, order) buckets */
struct hashtable_list list;
struct hashtable_list ordered_list;
} hashtable_t;
#define hashtable_key_to_iter(key_) \
#define hashtable_key_to_iter(key_) \
(&(container_of(key_, struct hashtable_pair, key)->ordered_list))
/**
* hashtable_init - Initialize a hashtable object
*
@@ -55,7 +53,7 @@ typedef struct hashtable {
*
* Returns 0 on success, -1 on error (out of memory).
*/
int hashtable_init(hashtable_t *hashtable);
int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS((warn_unused_result));
/**
* hashtable_close - Release all resources used by a hashtable object

View File

@@ -44,7 +44,6 @@
#include "jansson.h"
static uint32_t buf_to_uint32(char *data) {
size_t i;
uint32_t result = 0;
@@ -55,8 +54,6 @@ static uint32_t buf_to_uint32(char *data) {
return result;
}
/* /dev/urandom */
#if !defined(_WIN32) && defined(USE_URANDOM)
static int seed_from_urandom(uint32_t *seed) {
@@ -97,12 +94,13 @@ static int seed_from_urandom(uint32_t *seed) {
#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI)
#include <wincrypt.h>
typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv, LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType, DWORD dwFlags);
typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);
typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags);
typedef BOOL(WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv, LPCSTR pszContainer,
LPCSTR pszProvider, DWORD dwProvType,
DWORD dwFlags);
typedef BOOL(WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);
typedef BOOL(WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags);
static int seed_from_windows_cryptoapi(uint32_t *seed)
{
static int seed_from_windows_cryptoapi(uint32_t *seed) {
HINSTANCE hAdvAPI32 = NULL;
CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL;
CRYPTGENRANDOM pCryptGenRandom = NULL;
@@ -112,10 +110,11 @@ static int seed_from_windows_cryptoapi(uint32_t *seed)
int ok;
hAdvAPI32 = GetModuleHandle(TEXT("advapi32.dll"));
if(hAdvAPI32 == NULL)
if (hAdvAPI32 == NULL)
return 1;
pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32, "CryptAcquireContextA");
pCryptAcquireContext =
(CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32, "CryptAcquireContextA");
if (!pCryptAcquireContext)
return 1;
@@ -123,11 +122,13 @@ static int seed_from_windows_cryptoapi(uint32_t *seed)
if (!pCryptGenRandom)
return 1;
pCryptReleaseContext = (CRYPTRELEASECONTEXT)GetProcAddress(hAdvAPI32, "CryptReleaseContext");
pCryptReleaseContext =
(CRYPTRELEASECONTEXT)GetProcAddress(hAdvAPI32, "CryptReleaseContext");
if (!pCryptReleaseContext)
return 1;
if (!pCryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
if (!pCryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
return 1;
ok = pCryptGenRandom(hCryptProv, sizeof(uint32_t), data);
@@ -164,7 +165,7 @@ static int seed_from_timestamp_and_pid(uint32_t *seed) {
}
static uint32_t generate_seed() {
uint32_t seed;
uint32_t seed = 0;
int done = 0;
#if !defined(_WIN32) && defined(USE_URANDOM)
@@ -190,7 +191,6 @@ static uint32_t generate_seed() {
return seed;
}
volatile uint32_t hashtable_seed = 0;
#if defined(HAVE_ATOMIC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32))
@@ -212,7 +212,7 @@ void json_object_seed(size_t seed) {
#ifdef HAVE_SCHED_YIELD
sched_yield();
#endif
} while(__atomic_load_n(&hashtable_seed, __ATOMIC_ACQUIRE) == 0);
} while (__atomic_load_n(&hashtable_seed, __ATOMIC_ACQUIRE) == 0);
}
}
}
@@ -239,7 +239,7 @@ void json_object_seed(size_t seed) {
sched_yield();
#endif
}
} while(hashtable_seed == 0);
} while (hashtable_seed == 0);
}
}
#elif defined(_WIN32)

View File

@@ -41,6 +41,7 @@ EXPORTS
json_object_update
json_object_update_existing
json_object_update_missing
json_object_update_recursive
json_object_iter
json_object_iter_at
json_object_iter_next
@@ -72,4 +73,6 @@ EXPORTS
json_vunpack_ex
json_set_alloc_funcs
json_get_alloc_funcs
jansson_version_str
jansson_version_cmp

View File

@@ -8,9 +8,9 @@
#ifndef JANSSON_H
#define JANSSON_H
#include <stdio.h>
#include <stdlib.h> /* for size_t */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h> /* for size_t */
#include "jansson_config.h"
@@ -20,18 +20,18 @@ extern "C" {
/* version */
#define JANSSON_MAJOR_VERSION 2
#define JANSSON_MINOR_VERSION 11
#define JANSSON_MICRO_VERSION 0
#define JANSSON_MAJOR_VERSION 2
#define JANSSON_MINOR_VERSION 13
#define JANSSON_MICRO_VERSION 0
/* Micro version is omitted if it's 0 */
#define JANSSON_VERSION "2.11"
#define JANSSON_VERSION "2.13"
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
#define JANSSON_VERSION_HEX ((JANSSON_MAJOR_VERSION << 16) | \
(JANSSON_MINOR_VERSION << 8) | \
(JANSSON_MICRO_VERSION << 0))
#define JANSSON_VERSION_HEX \
((JANSSON_MAJOR_VERSION << 16) | (JANSSON_MINOR_VERSION << 8) | \
(JANSSON_MICRO_VERSION << 0))
/* If __atomic or __sync builtins are available the library is thread
* safe for all read-only functions plus reference counting. */
@@ -39,6 +39,12 @@ extern "C" {
#define JANSSON_THREAD_SAFE_REFCOUNT 1
#endif
#if defined(__GNUC__) || defined(__clang__)
#define JANSSON_ATTRS(x) __attribute__(x)
#else
#define JANSSON_ATTRS(x)
#endif
/* types */
typedef enum {
@@ -71,18 +77,18 @@ typedef long json_int_t;
#endif /* JSON_INTEGER_IS_LONG_LONG */
#endif
#define json_typeof(json) ((json)->type)
#define json_is_object(json) ((json) && json_typeof(json) == JSON_OBJECT)
#define json_is_array(json) ((json) && json_typeof(json) == JSON_ARRAY)
#define json_is_string(json) ((json) && json_typeof(json) == JSON_STRING)
#define json_is_integer(json) ((json) && json_typeof(json) == JSON_INTEGER)
#define json_is_real(json) ((json) && json_typeof(json) == JSON_REAL)
#define json_is_number(json) (json_is_integer(json) || json_is_real(json))
#define json_is_true(json) ((json) && json_typeof(json) == JSON_TRUE)
#define json_is_false(json) ((json) && json_typeof(json) == JSON_FALSE)
#define json_boolean_value json_is_true
#define json_is_boolean(json) (json_is_true(json) || json_is_false(json))
#define json_is_null(json) ((json) && json_typeof(json) == JSON_NULL)
#define json_typeof(json) ((json)->type)
#define json_is_object(json) ((json) && json_typeof(json) == JSON_OBJECT)
#define json_is_array(json) ((json) && json_typeof(json) == JSON_ARRAY)
#define json_is_string(json) ((json) && json_typeof(json) == JSON_STRING)
#define json_is_integer(json) ((json) && json_typeof(json) == JSON_INTEGER)
#define json_is_real(json) ((json) && json_typeof(json) == JSON_REAL)
#define json_is_number(json) (json_is_integer(json) || json_is_real(json))
#define json_is_true(json) ((json) && json_typeof(json) == JSON_TRUE)
#define json_is_false(json) ((json) && json_typeof(json) == JSON_FALSE)
#define json_boolean_value json_is_true
#define json_is_boolean(json) (json_is_true(json) || json_is_false(json))
#define json_is_null(json) ((json) && json_typeof(json) == JSON_NULL)
/* construction, destruction, reference counting */
@@ -96,13 +102,15 @@ json_t *json_integer(json_int_t value);
json_t *json_real(double value);
json_t *json_true(void);
json_t *json_false(void);
#define json_boolean(val) ((val) ? json_true() : json_false())
#define json_boolean(val) ((val) ? json_true() : json_false())
json_t *json_null(void);
/* do not call JSON_INTERNAL_INCREF or JSON_INTERNAL_DECREF directly */
#if JSON_HAVE_ATOMIC_BUILTINS
#define JSON_INTERNAL_INCREF(json) __atomic_add_fetch(&json->refcount, 1, __ATOMIC_ACQUIRE)
#define JSON_INTERNAL_DECREF(json) __atomic_sub_fetch(&json->refcount, 1, __ATOMIC_RELEASE)
#define JSON_INTERNAL_INCREF(json) \
__atomic_add_fetch(&json->refcount, 1, __ATOMIC_ACQUIRE)
#define JSON_INTERNAL_DECREF(json) \
__atomic_sub_fetch(&json->refcount, 1, __ATOMIC_RELEASE)
#elif JSON_HAVE_SYNC_BUILTINS
#define JSON_INTERNAL_INCREF(json) __sync_add_and_fetch(&json->refcount, 1)
#define JSON_INTERNAL_DECREF(json) __sync_sub_and_fetch(&json->refcount, 1)
@@ -111,10 +119,8 @@ json_t *json_null(void);
#define JSON_INTERNAL_DECREF(json) (--json->refcount)
#endif
static JSON_INLINE
json_t *json_incref(json_t *json)
{
if(json && json->refcount != (size_t)-1)
static JSON_INLINE json_t *json_incref(json_t *json) {
if (json && json->refcount != (size_t)-1)
JSON_INTERNAL_INCREF(json);
return json;
}
@@ -122,31 +128,26 @@ json_t *json_incref(json_t *json)
/* do not call json_delete directly */
void json_delete(json_t *json);
static JSON_INLINE
void json_decref(json_t *json)
{
if(json && json->refcount != (size_t)-1 && JSON_INTERNAL_DECREF(json) == 0)
static JSON_INLINE void json_decref(json_t *json) {
if (json && json->refcount != (size_t)-1 && JSON_INTERNAL_DECREF(json) == 0)
json_delete(json);
}
#if defined(__GNUC__) || defined(__clang__)
static JSON_INLINE
void json_decrefp(json_t **json)
{
if(json) {
static JSON_INLINE void json_decrefp(json_t **json) {
if (json) {
json_decref(*json);
*json = NULL;
*json = NULL;
}
}
#define json_auto_t json_t __attribute__((cleanup(json_decrefp)))
#endif
/* error reporting */
#define JSON_ERROR_TEXT_LENGTH 160
#define JSON_ERROR_SOURCE_LENGTH 80
#define JSON_ERROR_TEXT_LENGTH 160
#define JSON_ERROR_SOURCE_LENGTH 80
typedef struct json_error_t {
int line;
@@ -185,7 +186,8 @@ static JSON_INLINE enum json_error_code json_error_code(const json_error_t *e) {
void json_object_seed(size_t seed);
size_t json_object_size(const json_t *object);
json_t *json_object_get(const json_t *object, const char *key);
json_t *json_object_get(const json_t *object, const char *key)
JANSSON_ATTRS((warn_unused_result));
int json_object_set_new(json_t *object, const char *key, json_t *value);
int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
int json_object_del(json_t *object, const char *key);
@@ -193,6 +195,7 @@ int json_object_clear(json_t *object);
int json_object_update(json_t *object, json_t *other);
int json_object_update_existing(json_t *object, json_t *other);
int json_object_update_missing(json_t *object, json_t *other);
int json_object_update_recursive(json_t *object, json_t *other);
void *json_object_iter(json_t *object);
void *json_object_iter_at(json_t *object, const char *key);
void *json_object_key_to_iter(const char *key);
@@ -201,43 +204,58 @@ const char *json_object_iter_key(void *iter);
json_t *json_object_iter_value(void *iter);
int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
#define json_object_foreach(object, key, value) \
for(key = json_object_iter_key(json_object_iter(object)); \
key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key))))
#define json_object_foreach(object, key, value) \
for (key = json_object_iter_key(json_object_iter(object)); \
key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
key = json_object_iter_key( \
json_object_iter_next(object, json_object_key_to_iter(key))))
#define json_object_foreach_safe(object, n, key, value) \
for(key = json_object_iter_key(json_object_iter(object)), \
n = json_object_iter_next(object, json_object_key_to_iter(key)); \
key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
key = json_object_iter_key(n), \
n = json_object_iter_next(object, json_object_key_to_iter(key)))
#define json_object_foreach_safe(object, n, key, value) \
for (key = json_object_iter_key(json_object_iter(object)), \
n = json_object_iter_next(object, json_object_key_to_iter(key)); \
key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
key = json_object_iter_key(n), \
n = json_object_iter_next(object, json_object_key_to_iter(key)))
#define json_array_foreach(array, index, value) \
for(index = 0; \
index < json_array_size(array) && (value = json_array_get(array, index)); \
index++)
#define json_array_foreach(array, index, value) \
for (index = 0; \
index < json_array_size(array) && (value = json_array_get(array, index)); \
index++)
static JSON_INLINE
int json_object_set(json_t *object, const char *key, json_t *value)
{
static JSON_INLINE int json_object_set(json_t *object, const char *key, json_t *value) {
return json_object_set_new(object, key, json_incref(value));
}
static JSON_INLINE
int json_object_set_nocheck(json_t *object, const char *key, json_t *value)
{
static JSON_INLINE int json_object_set_nocheck(json_t *object, const char *key,
json_t *value) {
return json_object_set_new_nocheck(object, key, json_incref(value));
}
static JSON_INLINE
int json_object_iter_set(json_t *object, void *iter, json_t *value)
{
static JSON_INLINE int json_object_iter_set(json_t *object, void *iter, json_t *value) {
return json_object_iter_set_new(object, iter, json_incref(value));
}
static JSON_INLINE int json_object_update_new(json_t *object, json_t *other) {
int ret = json_object_update(object, other);
json_decref(other);
return ret;
}
static JSON_INLINE int json_object_update_existing_new(json_t *object, json_t *other) {
int ret = json_object_update_existing(object, other);
json_decref(other);
return ret;
}
static JSON_INLINE int json_object_update_missing_new(json_t *object, json_t *other) {
int ret = json_object_update_missing(object, other);
json_decref(other);
return ret;
}
size_t json_array_size(const json_t *array);
json_t *json_array_get(const json_t *array, size_t index);
json_t *json_array_get(const json_t *array, size_t index)
JANSSON_ATTRS((warn_unused_result));
int json_array_set_new(json_t *array, size_t index, json_t *value);
int json_array_append_new(json_t *array, json_t *value);
int json_array_insert_new(json_t *array, size_t index, json_t *value);
@@ -245,21 +263,15 @@ int json_array_remove(json_t *array, size_t index);
int json_array_clear(json_t *array);
int json_array_extend(json_t *array, json_t *other);
static JSON_INLINE
int json_array_set(json_t *array, size_t ind, json_t *value)
{
static JSON_INLINE int json_array_set(json_t *array, size_t ind, json_t *value) {
return json_array_set_new(array, ind, json_incref(value));
}
static JSON_INLINE
int json_array_append(json_t *array, json_t *value)
{
static JSON_INLINE int json_array_append(json_t *array, json_t *value) {
return json_array_append_new(array, json_incref(value));
}
static JSON_INLINE
int json_array_insert(json_t *array, size_t ind, json_t *value)
{
static JSON_INLINE int json_array_insert(json_t *array, size_t ind, json_t *value) {
return json_array_insert_new(array, ind, json_incref(value));
}
@@ -278,33 +290,35 @@ int json_real_set(json_t *real, double value);
/* pack, unpack */
json_t *json_pack(const char *fmt, ...);
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...);
json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap);
json_t *json_pack(const char *fmt, ...) JANSSON_ATTRS((warn_unused_result));
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...)
JANSSON_ATTRS((warn_unused_result));
json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap)
JANSSON_ATTRS((warn_unused_result));
#define JSON_VALIDATE_ONLY 0x1
#define JSON_STRICT 0x2
#define JSON_VALIDATE_ONLY 0x1
#define JSON_STRICT 0x2
int json_unpack(json_t *root, const char *fmt, ...);
int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...);
int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap);
int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt,
va_list ap);
/* sprintf */
json_t *json_sprintf(const char *fmt, ...);
json_t *json_vsprintf(const char *fmt, va_list ap);
json_t *json_sprintf(const char *fmt, ...)
JANSSON_ATTRS((warn_unused_result, format(printf, 1, 2)));
json_t *json_vsprintf(const char *fmt, va_list ap)
JANSSON_ATTRS((warn_unused_result, format(printf, 1, 0)));
/* equality */
int json_equal(const json_t *value1, const json_t *value2);
/* copying */
json_t *json_copy(json_t *value);
json_t *json_deep_copy(const json_t *value);
json_t *json_copy(json_t *value) JANSSON_ATTRS((warn_unused_result));
json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS((warn_unused_result));
/* decoding */
@@ -316,35 +330,41 @@ json_t *json_deep_copy(const json_t *value);
typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
json_t *json_loads(const char *input, size_t flags, json_error_t *error);
json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error);
json_t *json_loadf(FILE *input, size_t flags, json_error_t *error);
json_t *json_loadfd(int input, size_t flags, json_error_t *error);
json_t *json_load_file(const char *path, size_t flags, json_error_t *error);
json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error);
json_t *json_loads(const char *input, size_t flags, json_error_t *error)
JANSSON_ATTRS((warn_unused_result));
json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error)
JANSSON_ATTRS((warn_unused_result));
json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
JANSSON_ATTRS((warn_unused_result));
json_t *json_loadfd(int input, size_t flags, json_error_t *error)
JANSSON_ATTRS((warn_unused_result));
json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
JANSSON_ATTRS((warn_unused_result));
json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags,
json_error_t *error) JANSSON_ATTRS((warn_unused_result));
/* encoding */
#define JSON_MAX_INDENT 0x1F
#define JSON_INDENT(n) ((n) & JSON_MAX_INDENT)
#define JSON_COMPACT 0x20
#define JSON_ENSURE_ASCII 0x40
#define JSON_SORT_KEYS 0x80
#define JSON_PRESERVE_ORDER 0x100
#define JSON_ENCODE_ANY 0x200
#define JSON_ESCAPE_SLASH 0x400
#define JSON_REAL_PRECISION(n) (((n) & 0x1F) << 11)
#define JSON_EMBED 0x10000
#define JSON_MAX_INDENT 0x1F
#define JSON_INDENT(n) ((n)&JSON_MAX_INDENT)
#define JSON_COMPACT 0x20
#define JSON_ENSURE_ASCII 0x40
#define JSON_SORT_KEYS 0x80
#define JSON_PRESERVE_ORDER 0x100
#define JSON_ENCODE_ANY 0x200
#define JSON_ESCAPE_SLASH 0x400
#define JSON_REAL_PRECISION(n) (((n)&0x1F) << 11)
#define JSON_EMBED 0x10000
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
char *json_dumps(const json_t *json, size_t flags);
char *json_dumps(const json_t *json, size_t flags) JANSSON_ATTRS((warn_unused_result));
size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags);
int json_dumpf(const json_t *json, FILE *output, size_t flags);
int json_dumpfd(const json_t *json, int output, size_t flags);
int json_dump_file(const json_t *json, const char *path, size_t flags);
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags);
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data,
size_t flags);
/* custom memory allocation */
@@ -354,6 +374,11 @@ typedef void (*json_free_t)(void *);
void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn);
void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn);
/* runtime version checking */
const char *jansson_version_str(void);
int jansson_version_cmp(int major, int minor, int micro);
#ifdef __cplusplus
}
#endif

View File

@@ -8,18 +8,18 @@
#ifndef JANSSON_PRIVATE_H
#define JANSSON_PRIVATE_H
#include "jansson_private_config.h"
#include <stddef.h>
#include "jansson.h"
#include "hashtable.h"
#include "jansson.h"
#include "jansson_private_config.h"
#include "strbuffer.h"
#include <stddef.h>
#define container_of(ptr_, type_, member_) \
#define container_of(ptr_, type_, member_) \
((type_ *)((char *)ptr_ - offsetof(type_, member_)))
/* On some platforms, max() may already be defined */
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
/* va_copy is a C99 feature. In C89 implementations, it's sometimes
@@ -28,7 +28,7 @@
#ifdef __va_copy
#define va_copy __va_copy
#else
#define va_copy(a, b) memcpy(&(a), &(b), sizeof(va_list))
#define va_copy(a, b) memcpy(&(a), &(b), sizeof(va_list))
#endif
#endif
@@ -72,38 +72,43 @@ json_t *jsonp_stringn_nocheck_own(const char *value, size_t len);
/* Error message formatting */
void jsonp_error_init(json_error_t *error, const char *source);
void jsonp_error_set_source(json_error_t *error, const char *source);
void jsonp_error_set(json_error_t *error, int line, int column,
size_t position, enum json_error_code code,
const char *msg, ...);
void jsonp_error_vset(json_error_t *error, int line, int column,
size_t position, enum json_error_code code,
const char *msg, va_list ap);
void jsonp_error_set(json_error_t *error, int line, int column, size_t position,
enum json_error_code code, const char *msg, ...);
void jsonp_error_vset(json_error_t *error, int line, int column, size_t position,
enum json_error_code code, const char *msg, va_list ap);
/* Locale independent string<->double conversions */
int jsonp_strtod(strbuffer_t *strbuffer, double *out);
int jsonp_dtostr(char *buffer, size_t size, double value, int prec);
/* Wrappers for custom memory functions */
void* jsonp_malloc(size_t size);
void *jsonp_malloc(size_t size) JANSSON_ATTRS((warn_unused_result));
void jsonp_free(void *ptr);
char *jsonp_strndup(const char *str, size_t length);
char *jsonp_strdup(const char *str);
char *jsonp_strndup(const char *str, size_t len);
char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS((warn_unused_result));
char *jsonp_strdup(const char *str) JANSSON_ATTRS((warn_unused_result));
char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS((warn_unused_result));
/* Circular reference check*/
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
#define LOOP_KEY_LEN (2 + (sizeof(json_t *) * 2) + 1)
int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key,
size_t key_size);
/* Windows compatibility */
#if defined(_WIN32) || defined(WIN32)
# if defined(_MSC_VER) /* MS compiller */
# if (_MSC_VER < 1900) && !defined(snprintf) /* snprintf not defined yet & not introduced */
# define snprintf _snprintf
# endif
# if (_MSC_VER < 1500) && !defined(vsnprintf) /* vsnprintf not defined yet & not introduced */
# define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a)
# endif
# else /* Other Windows compiller, old definition */
# define snprintf _snprintf
# define vsnprintf _vsnprintf
# endif
#if defined(_MSC_VER) /* MS compiller */
#if (_MSC_VER < 1900) && \
!defined(snprintf) /* snprintf not defined yet & not introduced */
#define snprintf _snprintf
#endif
#if (_MSC_VER < 1500) && \
!defined(vsnprintf) /* vsnprintf not defined yet & not introduced */
#define vsnprintf(b, c, f, a) _vsnprintf(b, c, f, a)
#endif
#else /* Other Windows compiller, old definition */
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
// clang-format off
/*
-------------------------------------------------------------------------------
lookup3.c, by Bob Jenkins, May 2006, Public Domain.
@@ -243,7 +244,7 @@ static uint32_t hashlittle(const void *key, size_t length, uint32_t initval)
* rest of the string. Every machine with memory protection I've seen
* does it on word boundaries, so is OK with this. But VALGRIND will
* still catch it and complain. The masking trick does make the hash
* noticably faster for short strings (like English words).
* noticeably faster for short strings (like English words).
*/
#ifndef NO_MASKING_TRICK

View File

@@ -20,33 +20,27 @@
static json_malloc_t do_malloc = malloc;
static json_free_t do_free = free;
void *jsonp_malloc(size_t size)
{
if(!size)
void *jsonp_malloc(size_t size) {
if (!size)
return NULL;
return (*do_malloc)(size);
}
void jsonp_free(void *ptr)
{
if(!ptr)
void jsonp_free(void *ptr) {
if (!ptr)
return;
(*do_free)(ptr);
}
char *jsonp_strdup(const char *str)
{
return jsonp_strndup(str, strlen(str));
}
char *jsonp_strdup(const char *str) { return jsonp_strndup(str, strlen(str)); }
char *jsonp_strndup(const char *str, size_t len)
{
char *jsonp_strndup(const char *str, size_t len) {
char *new_str;
new_str = jsonp_malloc(len + 1);
if(!new_str)
if (!new_str)
return NULL;
memcpy(new_str, str, len);
@@ -54,14 +48,12 @@ char *jsonp_strndup(const char *str, size_t len)
return new_str;
}
void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn)
{
void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) {
do_malloc = malloc_fn;
do_free = free_fn;
}
void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn)
{
void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn) {
if (malloc_fn)
*malloc_fn = do_malloc;
if (free_fn)

File diff suppressed because it is too large Load Diff

View File

@@ -9,22 +9,21 @@
#define _GNU_SOURCE
#endif
#include "strbuffer.h"
#include "jansson_private.h"
#include <stdlib.h>
#include <string.h>
#include "jansson_private.h"
#include "strbuffer.h"
#define STRBUFFER_MIN_SIZE 16
#define STRBUFFER_FACTOR 2
#define STRBUFFER_SIZE_MAX ((size_t)-1)
#define STRBUFFER_MIN_SIZE 16
#define STRBUFFER_FACTOR 2
#define STRBUFFER_SIZE_MAX ((size_t)-1)
int strbuffer_init(strbuffer_t *strbuff)
{
int strbuffer_init(strbuffer_t *strbuff) {
strbuff->size = STRBUFFER_MIN_SIZE;
strbuff->length = 0;
strbuff->value = jsonp_malloc(strbuff->size);
if(!strbuff->value)
if (!strbuff->value)
return -1;
/* initialize to empty */
@@ -32,9 +31,8 @@ int strbuffer_init(strbuffer_t *strbuff)
return 0;
}
void strbuffer_close(strbuffer_t *strbuff)
{
if(strbuff->value)
void strbuffer_close(strbuffer_t *strbuff) {
if (strbuff->value)
jsonp_free(strbuff->value);
strbuff->size = 0;
@@ -42,47 +40,38 @@ void strbuffer_close(strbuffer_t *strbuff)
strbuff->value = NULL;
}
void strbuffer_clear(strbuffer_t *strbuff)
{
void strbuffer_clear(strbuffer_t *strbuff) {
strbuff->length = 0;
strbuff->value[0] = '\0';
}
const char *strbuffer_value(const strbuffer_t *strbuff)
{
return strbuff->value;
}
const char *strbuffer_value(const strbuffer_t *strbuff) { return strbuff->value; }
char *strbuffer_steal_value(strbuffer_t *strbuff)
{
char *strbuffer_steal_value(strbuffer_t *strbuff) {
char *result = strbuff->value;
strbuff->value = NULL;
return result;
}
int strbuffer_append_byte(strbuffer_t *strbuff, char byte)
{
int strbuffer_append_byte(strbuffer_t *strbuff, char byte) {
return strbuffer_append_bytes(strbuff, &byte, 1);
}
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size)
{
if(size >= strbuff->size - strbuff->length)
{
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size) {
if (size >= strbuff->size - strbuff->length) {
size_t new_size;
char *new_value;
/* avoid integer overflow */
if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR
|| size > STRBUFFER_SIZE_MAX - 1
|| strbuff->length > STRBUFFER_SIZE_MAX - 1 - size)
if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR ||
size > STRBUFFER_SIZE_MAX - 1 ||
strbuff->length > STRBUFFER_SIZE_MAX - 1 - size)
return -1;
new_size = max(strbuff->size * STRBUFFER_FACTOR,
strbuff->length + size + 1);
new_size = max(strbuff->size * STRBUFFER_FACTOR, strbuff->length + size + 1);
new_value = jsonp_malloc(new_size);
if(!new_value)
if (!new_value)
return -1;
memcpy(new_value, strbuff->value, strbuff->length);
@@ -99,13 +88,11 @@ int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size)
return 0;
}
char strbuffer_pop(strbuffer_t *strbuff)
{
if(strbuff->length > 0) {
char strbuffer_pop(strbuffer_t *strbuff) {
if (strbuff->length > 0) {
char c = strbuff->value[--strbuff->length];
strbuff->value[strbuff->length] = '\0';
return c;
}
else
} else
return '\0';
}

View File

@@ -8,15 +8,16 @@
#ifndef STRBUFFER_H
#define STRBUFFER_H
#include "jansson.h"
#include <stdlib.h>
typedef struct {
char *value;
size_t length; /* bytes used */
size_t size; /* bytes allocated */
size_t length; /* bytes used */
size_t size; /* bytes allocated */
} strbuffer_t;
int strbuffer_init(strbuffer_t *strbuff);
int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS((warn_unused_result));
void strbuffer_close(strbuffer_t *strbuff);
void strbuffer_clear(strbuffer_t *strbuff);

View File

@@ -1,23 +1,16 @@
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#ifdef __MINGW32__
#undef __NO_ISOCEXT /* ensure stdlib.h will declare prototypes for mingw own 'strtod' replacement, called '__strtod' */
#endif
#include "jansson_private.h"
#include "strbuffer.h"
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
/* need jansson_private_config.h to get the correct snprintf */
#ifdef HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#ifdef __MINGW32__
#define strtod __strtod
#endif
#if JSON_HAVE_LOCALECONV
#include <locale.h>
@@ -31,41 +24,38 @@
this way. Multi-threaded programs should use uselocale() instead.
*/
static void to_locale(strbuffer_t *strbuffer)
{
static void to_locale(strbuffer_t *strbuffer) {
const char *point;
char *pos;
point = localeconv()->decimal_point;
if(*point == '.') {
if (*point == '.') {
/* No conversion needed */
return;
}
pos = strchr(strbuffer->value, '.');
if(pos)
if (pos)
*pos = *point;
}
static void from_locale(char *buffer)
{
static void from_locale(char *buffer) {
const char *point;
char *pos;
point = localeconv()->decimal_point;
if(*point == '.') {
if (*point == '.') {
/* No conversion needed */
return;
}
pos = strchr(buffer, *point);
if(pos)
if (pos)
*pos = '.';
}
#endif
int jsonp_strtod(strbuffer_t *strbuffer, double *out)
{
int jsonp_strtod(strbuffer_t *strbuffer, double *out) {
double value;
char *end;
@@ -77,7 +67,7 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out)
value = strtod(strbuffer->value, &end);
assert(end == strbuffer->value + strbuffer->length);
if((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) {
if ((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) {
/* Overflow */
return -1;
}
@@ -86,8 +76,7 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out)
return 0;
}
int jsonp_dtostr(char *buffer, size_t size, double value, int precision)
{
int jsonp_dtostr(char *buffer, size_t size, double value, int precision) {
int ret;
char *start, *end;
size_t length;
@@ -96,11 +85,11 @@ int jsonp_dtostr(char *buffer, size_t size, double value, int precision)
precision = 17;
ret = snprintf(buffer, size, "%.*g", precision, value);
if(ret < 0)
if (ret < 0)
return -1;
length = (size_t)ret;
if(length >= size)
if (length >= size)
return -1;
#if JSON_HAVE_LOCALECONV
@@ -109,10 +98,8 @@ int jsonp_dtostr(char *buffer, size_t size, double value, int precision)
/* Make sure there's a dot or 'e' in the output. Otherwise
a real is converted to an integer when decoding */
if(strchr(buffer, '.') == NULL &&
strchr(buffer, 'e') == NULL)
{
if(length + 3 >= size) {
if (strchr(buffer, '.') == NULL && strchr(buffer, 'e') == NULL) {
if (length + 3 >= size) {
/* No space to append ".0" */
return -1;
}
@@ -125,17 +112,17 @@ int jsonp_dtostr(char *buffer, size_t size, double value, int precision)
/* Remove leading '+' from positive exponent. Also remove leading
zeros from exponents (added by some printf() implementations) */
start = strchr(buffer, 'e');
if(start) {
if (start) {
start++;
end = start + 1;
if(*start == '-')
if (*start == '-')
start++;
while(*end == '0')
while (*end == '0')
end++;
if(end != start) {
if (end != start) {
memmove(start, end, length - (size_t)(end - buffer));
length -= (size_t)(end - start);
}

110
src/utf.c
View File

@@ -5,107 +5,85 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <string.h>
#include "utf.h"
#include <string.h>
int utf8_encode(int32_t codepoint, char *buffer, size_t *size)
{
if(codepoint < 0)
int utf8_encode(int32_t codepoint, char *buffer, size_t *size) {
if (codepoint < 0)
return -1;
else if(codepoint < 0x80)
{
else if (codepoint < 0x80) {
buffer[0] = (char)codepoint;
*size = 1;
}
else if(codepoint < 0x800)
{
} else if (codepoint < 0x800) {
buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6);
buffer[1] = 0x80 + ((codepoint & 0x03F));
*size = 2;
}
else if(codepoint < 0x10000)
{
} else if (codepoint < 0x10000) {
buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12);
buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6);
buffer[2] = 0x80 + ((codepoint & 0x003F));
*size = 3;
}
else if(codepoint <= 0x10FFFF)
{
} else if (codepoint <= 0x10FFFF) {
buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18);
buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12);
buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6);
buffer[3] = 0x80 + ((codepoint & 0x00003F));
*size = 4;
}
else
} else
return -1;
return 0;
}
size_t utf8_check_first(char byte)
{
size_t utf8_check_first(char byte) {
unsigned char u = (unsigned char)byte;
if(u < 0x80)
if (u < 0x80)
return 1;
if(0x80 <= u && u <= 0xBF) {
if (0x80 <= u && u <= 0xBF) {
/* second, third or fourth byte of a multi-byte
sequence, i.e. a "continuation byte" */
return 0;
}
else if(u == 0xC0 || u == 0xC1) {
} else if (u == 0xC0 || u == 0xC1) {
/* overlong encoding of an ASCII byte */
return 0;
}
else if(0xC2 <= u && u <= 0xDF) {
} else if (0xC2 <= u && u <= 0xDF) {
/* 2-byte sequence */
return 2;
}
else if(0xE0 <= u && u <= 0xEF) {
else if (0xE0 <= u && u <= 0xEF) {
/* 3-byte sequence */
return 3;
}
else if(0xF0 <= u && u <= 0xF4) {
} else if (0xF0 <= u && u <= 0xF4) {
/* 4-byte sequence */
return 4;
}
else { /* u >= 0xF5 */
} else { /* u >= 0xF5 */
/* Restricted (start of 4-, 5- or 6-byte sequence) or invalid
UTF-8 */
return 0;
}
}
size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint)
{
size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint) {
size_t i;
int32_t value = 0;
unsigned char u = (unsigned char)buffer[0];
if(size == 2)
{
if (size == 2) {
value = u & 0x1F;
}
else if(size == 3)
{
} else if (size == 3) {
value = u & 0xF;
}
else if(size == 4)
{
} else if (size == 4) {
value = u & 0x7;
}
else
} else
return 0;
for(i = 1; i < size; i++)
{
for (i = 1; i < size; i++) {
u = (unsigned char)buffer[i];
if(u < 0x80 || u > 0xBF) {
if (u < 0x80 || u > 0xBF) {
/* not a continuation byte */
return 0;
}
@@ -113,70 +91,64 @@ size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint)
value = (value << 6) + (u & 0x3F);
}
if(value > 0x10FFFF) {
if (value > 0x10FFFF) {
/* not in Unicode range */
return 0;
}
else if(0xD800 <= value && value <= 0xDFFF) {
else if (0xD800 <= value && value <= 0xDFFF) {
/* invalid code point (UTF-16 surrogate halves) */
return 0;
}
else if((size == 2 && value < 0x80) ||
(size == 3 && value < 0x800) ||
(size == 4 && value < 0x10000)) {
else if ((size == 2 && value < 0x80) || (size == 3 && value < 0x800) ||
(size == 4 && value < 0x10000)) {
/* overlong encoding */
return 0;
}
if(codepoint)
if (codepoint)
*codepoint = value;
return 1;
}
const char *utf8_iterate(const char *buffer, size_t bufsize, int32_t *codepoint)
{
const char *utf8_iterate(const char *buffer, size_t bufsize, int32_t *codepoint) {
size_t count;
int32_t value;
if(!bufsize)
if (!bufsize)
return buffer;
count = utf8_check_first(buffer[0]);
if(count <= 0)
if (count <= 0)
return NULL;
if(count == 1)
if (count == 1)
value = (unsigned char)buffer[0];
else
{
if(count > bufsize || !utf8_check_full(buffer, count, &value))
else {
if (count > bufsize || !utf8_check_full(buffer, count, &value))
return NULL;
}
if(codepoint)
if (codepoint)
*codepoint = value;
return buffer + count;
}
int utf8_check_string(const char *string, size_t length)
{
int utf8_check_string(const char *string, size_t length) {
size_t i;
for(i = 0; i < length; i++)
{
for (i = 0; i < length; i++) {
size_t count = utf8_check_first(string[i]);
if(count == 0)
if (count == 0)
return 0;
else if(count > 1)
{
if(count > length - i)
else if (count > 1) {
if (count > length - i)
return 0;
if(!utf8_check_full(&string[i], count, NULL))
if (!utf8_check_full(&string[i], count, NULL))
return 0;
i += count - 1;

View File

@@ -12,6 +12,7 @@
#include <jansson_private_config.h>
#endif
#include <stddef.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif

File diff suppressed because it is too large Load Diff

28
src/version.c Normal file
View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2019 Sean Bright <sean.bright@gmail.com>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "jansson.h"
const char *jansson_version_str(void) { return JANSSON_VERSION; }
int jansson_version_cmp(int major, int minor, int micro) {
int diff;
if ((diff = JANSSON_MAJOR_VERSION - major)) {
return diff;
}
if ((diff = JANSSON_MINOR_VERSION - minor)) {
return diff;
}
return JANSSON_MICRO_VERSION - micro;
}

6
test/.gitignore vendored
View File

@@ -1,6 +1,7 @@
logs
bin/json_process
suites/api/test_array
suites/api/test_chaos
suites/api/test_copy
suites/api/test_cpp
suites/api/test_dump
@@ -16,7 +17,4 @@ suites/api/test_pack
suites/api/test_simple
suites/api/test_sprintf
suites/api/test_unpack
run-suites.log
run-suites.trs
test-suite.log
suites/api/test_version

View File

@@ -1,4 +1,4 @@
SUBDIRS = bin suites
SUBDIRS = bin suites ossfuzz
EXTRA_DIST = scripts run-suites
TESTS = run-suites

View File

@@ -9,26 +9,25 @@
#include <jansson_private_config.h>
#endif
#include <ctype.h>
#include <jansson.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <jansson.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#endif
#if _WIN32
#include <io.h> /* for _setmode() */
#include <fcntl.h> /* for _O_BINARY */
#include <fcntl.h> /* for _O_BINARY */
#include <io.h> /* for _setmode() */
static const char dir_sep = '\\';
#else
static const char dir_sep = '/';
#endif
struct config {
int indent;
int compact;
@@ -47,8 +46,7 @@ struct config {
/* Return a pointer to the first non-whitespace character of str.
Modifies str so that all trailing whitespace characters are
replaced by '\0'. */
static const char *strip(char *str)
{
static const char *strip(char *str) {
size_t length;
char *result = str;
while (*result && l_isspace(*result))
@@ -64,9 +62,7 @@ static const char *strip(char *str)
return result;
}
static char *loadfile(FILE *file)
{
static char *loadfile(FILE *file) {
long fsize, ret;
char *buf;
@@ -74,7 +70,7 @@ static char *loadfile(FILE *file)
fsize = ftell(file);
fseek(file, 0, SEEK_SET);
buf = malloc(fsize+1);
buf = malloc(fsize + 1);
ret = fread(buf, 1, fsize, file);
if (ret != fsize)
exit(1);
@@ -83,9 +79,7 @@ static char *loadfile(FILE *file)
return buf;
}
static void read_conf(FILE *conffile)
{
static void read_conf(FILE *conffile) {
char *buffer, *line, *val;
buffer = loadfile(conffile);
@@ -124,9 +118,7 @@ static void read_conf(FILE *conffile)
free(buffer);
}
static int cmpfile(const char *str, const char *path, const char *fname)
{
static int cmpfile(const char *str, const char *path, const char *fname) {
char filename[1024], *buffer;
int ret;
FILE *file;
@@ -156,8 +148,7 @@ static int cmpfile(const char *str, const char *path, const char *fname)
return ret;
}
int use_conf(char *test_path)
{
int use_conf(char *test_path) {
int ret;
size_t flags = 0;
char filename[1024], errstr[1024];
@@ -200,8 +191,7 @@ int use_conf(char *test_path)
flags |= JSON_SORT_KEYS;
if (conf.precision < 0 || conf.precision > 31) {
fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n",
conf.precision);
fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n", conf.precision);
fclose(infile);
return 2;
}
@@ -216,15 +206,13 @@ int use_conf(char *test_path)
buffer = loadfile(infile);
json = json_loads(strip(buffer), 0, &error);
free(buffer);
}
else
} else
json = json_loadf(infile, 0, &error);
fclose(infile);
if (!json) {
sprintf(errstr, "%d %d %d\n%s\n",
error.line, error.column, error.position,
sprintf(errstr, "%d %d %d\n%s\n", error.line, error.column, error.position,
error.text);
ret = cmpfile(errstr, test_path, "error");
@@ -239,80 +227,77 @@ int use_conf(char *test_path)
return ret;
}
static int getenv_int(const char *name)
{
static int getenv_int(const char *name) {
char *value, *end;
long result;
value = getenv(name);
if(!value)
if (!value)
return 0;
result = strtol(value, &end, 10);
if(*end != '\0')
if (*end != '\0')
return 0;
return (int)result;
}
int use_env()
{
int use_env() {
int indent, precision;
size_t flags = 0;
json_t *json;
json_error_t error;
#ifdef _WIN32
#ifdef _WIN32
/* On Windows, set stdout and stderr to binary mode to avoid
outputting DOS line terminators */
_setmode(_fileno(stdout), _O_BINARY);
_setmode(_fileno(stderr), _O_BINARY);
#endif
#endif
indent = getenv_int("JSON_INDENT");
if(indent < 0 || indent > 31) {
if (indent < 0 || indent > 31) {
fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent);
return 2;
}
if(indent > 0)
if (indent > 0)
flags |= JSON_INDENT(indent);
if(getenv_int("JSON_COMPACT") > 0)
if (getenv_int("JSON_COMPACT") > 0)
flags |= JSON_COMPACT;
if(getenv_int("JSON_ENSURE_ASCII"))
if (getenv_int("JSON_ENSURE_ASCII"))
flags |= JSON_ENSURE_ASCII;
if(getenv_int("JSON_PRESERVE_ORDER"))
if (getenv_int("JSON_PRESERVE_ORDER"))
flags |= JSON_PRESERVE_ORDER;
if(getenv_int("JSON_SORT_KEYS"))
if (getenv_int("JSON_SORT_KEYS"))
flags |= JSON_SORT_KEYS;
precision = getenv_int("JSON_REAL_PRECISION");
if(precision < 0 || precision > 31) {
fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n",
precision);
if (precision < 0 || precision > 31) {
fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n", precision);
return 2;
}
if(getenv("HASHSEED"))
if (getenv("HASHSEED"))
json_object_seed(getenv_int("HASHSEED"));
if(precision > 0)
if (precision > 0)
flags |= JSON_REAL_PRECISION(precision);
if(getenv_int("STRIP")) {
if (getenv_int("STRIP")) {
/* Load to memory, strip leading and trailing whitespace */
size_t size = 0, used = 0;
char *buffer = NULL, *buf_ck = NULL;
while(1) {
while (1) {
size_t count;
size = (size == 0 ? 128 : size * 2);
buf_ck = realloc(buffer, size);
if(!buf_ck) {
if (!buf_ck) {
fprintf(stderr, "Unable to allocate %d bytes\n", (int)size);
free(buffer);
return 1;
@@ -320,7 +305,7 @@ int use_env()
buffer = buf_ck;
count = fread(buffer + used, 1, size - used, stdin);
if(count < size - used) {
if (count < size - used) {
buffer[used + count] = '\0';
break;
}
@@ -329,14 +314,12 @@ int use_env()
json = json_loads(strip(buffer), 0, &error);
free(buffer);
}
else
} else
json = json_loadf(stdin, 0, &error);
if(!json) {
fprintf(stderr, "%d %d %d\n%s\n",
error.line, error.column,
error.position, error.text);
if (!json) {
fprintf(stderr, "%d %d %d\n%s\n", error.line, error.column, error.position,
error.text);
return 1;
}
@@ -346,14 +329,13 @@ int use_env()
return 0;
}
int main(int argc, char *argv[])
{
int main(int argc, char *argv[]) {
int i;
char *test_path = NULL;
#ifdef HAVE_SETLOCALE
#ifdef HAVE_SETLOCALE
setlocale(LC_ALL, "");
#endif
#endif
if (argc < 2) {
goto usage;
@@ -370,8 +352,7 @@ int main(int argc, char *argv[])
if (conf.use_env)
return use_env();
else
{
else {
if (!test_path)
goto usage;

1
test/ossfuzz/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
json_load_dump_fuzzer

32
test/ossfuzz/Makefile.am Normal file
View File

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

View File

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

30
test/ossfuzz/ossfuzz.sh Executable file
View File

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

View File

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

3
test/ossfuzz/testinput.h Normal file
View File

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

38
test/ossfuzz/travisoss.sh Executable file
View File

@@ -0,0 +1,38 @@
#!/bin/bash
set -ex
PROJECT_NAME=jansson
# Clone the oss-fuzz repository
git clone https://github.com/google/oss-fuzz.git /tmp/ossfuzz
if [[ ! -d /tmp/ossfuzz/projects/${PROJECT_NAME} ]]
then
echo "Could not find the ${PROJECT_NAME} project in ossfuzz"
# Exit with a success code while the jansson project is not expected to exist
# on oss-fuzz.
exit 0
fi
# Work out which repo to clone from, inside Docker
if [[ ${TRAVIS_PULL_REQUEST} != "false" ]]
then
# Pull-request branch
REPO=${TRAVIS_PULL_REQUEST_SLUG}
BRANCH=${TRAVIS_PULL_REQUEST_BRANCH}
else
# Push build.
REPO=${TRAVIS_REPO_SLUG}
BRANCH=${TRAVIS_BRANCH}
fi
# Modify the oss-fuzz Dockerfile so that we're checking out the current branch on travis.
sed -i "s@https://github.com/akheron/jansson.git@-b ${BRANCH} https://github.com/${REPO}.git@" /tmp/ossfuzz/projects/${PROJECT_NAME}/Dockerfile
# Try and build the fuzzers
pushd /tmp/ossfuzz
python infra/helper.py build_image --pull ${PROJECT_NAME}
python infra/helper.py build_fuzzers ${PROJECT_NAME}
popd

View File

@@ -2,6 +2,7 @@ EXTRA_DIST = run check-exports
check_PROGRAMS = \
test_array \
test_chaos \
test_copy \
test_dump \
test_dump_callback \
@@ -15,9 +16,11 @@ check_PROGRAMS = \
test_pack \
test_simple \
test_sprintf \
test_unpack
test_unpack \
test_version
test_array_SOURCES = test_array.c util.h
test_chaos_SOURCES = test_chaos.c util.h
test_copy_SOURCES = test_copy.c util.h
test_dump_SOURCES = test_dump.c util.h
test_dump_callback_SOURCES = test_dump_callback.c util.h
@@ -30,6 +33,7 @@ test_pack_SOURCES = test_pack.c util.h
test_simple_SOURCES = test_simple.c util.h
test_sprintf_SOURCES = test_sprintf.c util.h
test_unpack_SOURCES = test_unpack.c util.h
test_version_SOURCES = test_version.c util.h
AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src
LDFLAGS = -static # for speed and Valgrind

View File

@@ -5,11 +5,10 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <jansson.h>
#include "util.h"
#include <jansson.h>
static void test_misc(void)
{
static void test_misc(void) {
json_t *array, *five, *seven, *value;
size_t i;
@@ -17,96 +16,96 @@ static void test_misc(void)
five = json_integer(5);
seven = json_integer(7);
if(!array)
if (!array)
fail("unable to create array");
if(!five || !seven)
if (!five || !seven)
fail("unable to create integer");
if(json_array_size(array) != 0)
if (json_array_size(array) != 0)
fail("empty array has nonzero size");
if(!json_array_append(array, NULL))
if (!json_array_append(array, NULL))
fail("able to append NULL");
if(json_array_append(array, five))
if (json_array_append(array, five))
fail("unable to append");
if(json_array_size(array) != 1)
if (json_array_size(array) != 1)
fail("wrong array size");
value = json_array_get(array, 0);
if(!value)
if (!value)
fail("unable to get item");
if(value != five)
if (value != five)
fail("got wrong value");
if(json_array_append(array, seven))
if (json_array_append(array, seven))
fail("unable to append value");
if(json_array_size(array) != 2)
if (json_array_size(array) != 2)
fail("wrong array size");
value = json_array_get(array, 1);
if(!value)
if (!value)
fail("unable to get item");
if(value != seven)
if (value != seven)
fail("got wrong value");
if(json_array_set(array, 0, seven))
if (json_array_set(array, 0, seven))
fail("unable to set value");
if(!json_array_set(array, 0, NULL))
if (!json_array_set(array, 0, NULL))
fail("able to set NULL");
if(json_array_size(array) != 2)
if (json_array_size(array) != 2)
fail("wrong array size");
value = json_array_get(array, 0);
if(!value)
if (!value)
fail("unable to get item");
if(value != seven)
if (value != seven)
fail("got wrong value");
if(json_array_get(array, 2) != NULL)
if (json_array_get(array, 2) != NULL)
fail("able to get value out of bounds");
if(!json_array_set(array, 2, seven))
if (!json_array_set(array, 2, seven))
fail("able to set value out of bounds");
for(i = 2; i < 30; i++) {
if(json_array_append(array, seven))
for (i = 2; i < 30; i++) {
if (json_array_append(array, seven))
fail("unable to append value");
if(json_array_size(array) != i + 1)
if (json_array_size(array) != i + 1)
fail("wrong array size");
}
for(i = 0; i < 30; i++) {
for (i = 0; i < 30; i++) {
value = json_array_get(array, i);
if(!value)
if (!value)
fail("unable to get item");
if(value != seven)
if (value != seven)
fail("got wrong value");
}
if(json_array_set_new(array, 15, json_integer(123)))
if (json_array_set_new(array, 15, json_integer(123)))
fail("unable to set new value");
value = json_array_get(array, 15);
if(!json_is_integer(value) || json_integer_value(value) != 123)
if (!json_is_integer(value) || json_integer_value(value) != 123)
fail("json_array_set_new works incorrectly");
if(!json_array_set_new(array, 15, NULL))
if (!json_array_set_new(array, 15, NULL))
fail("able to set_new NULL value");
if(json_array_append_new(array, json_integer(321)))
if (json_array_append_new(array, json_integer(321)))
fail("unable to append new value");
value = json_array_get(array, json_array_size(array) - 1);
if(!json_is_integer(value) || json_integer_value(value) != 321)
if (!json_is_integer(value) || json_integer_value(value) != 321)
fail("json_array_append_new works incorrectly");
if(!json_array_append_new(array, NULL))
if (!json_array_append_new(array, NULL))
fail("able to append_new NULL value");
json_decref(five);
@@ -114,8 +113,7 @@ static void test_misc(void)
json_decref(array);
}
static void test_insert(void)
{
static void test_insert(void) {
json_t *array, *five, *seven, *eleven, *value;
int i;
@@ -124,77 +122,71 @@ static void test_insert(void)
seven = json_integer(7);
eleven = json_integer(11);
if(!array)
if (!array)
fail("unable to create array");
if(!five || !seven || !eleven)
if (!five || !seven || !eleven)
fail("unable to create integer");
if(!json_array_insert(array, 1, five))
if (!json_array_insert(array, 1, five))
fail("able to insert value out of bounds");
if(json_array_insert(array, 0, five))
if (json_array_insert(array, 0, five))
fail("unable to insert value in an empty array");
if(json_array_get(array, 0) != five)
if (json_array_get(array, 0) != five)
fail("json_array_insert works incorrectly");
if(json_array_size(array) != 1)
if (json_array_size(array) != 1)
fail("array size is invalid after insertion");
if(json_array_insert(array, 1, seven))
if (json_array_insert(array, 1, seven))
fail("unable to insert value at the end of an array");
if(json_array_get(array, 0) != five)
if (json_array_get(array, 0) != five)
fail("json_array_insert works incorrectly");
if(json_array_get(array, 1) != seven)
if (json_array_get(array, 1) != seven)
fail("json_array_insert works incorrectly");
if(json_array_size(array) != 2)
if (json_array_size(array) != 2)
fail("array size is invalid after insertion");
if(json_array_insert(array, 1, eleven))
if (json_array_insert(array, 1, eleven))
fail("unable to insert value in the middle of an array");
if(json_array_get(array, 0) != five)
if (json_array_get(array, 0) != five)
fail("json_array_insert works incorrectly");
if(json_array_get(array, 1) != eleven)
if (json_array_get(array, 1) != eleven)
fail("json_array_insert works incorrectly");
if(json_array_get(array, 2) != seven)
if (json_array_get(array, 2) != seven)
fail("json_array_insert works incorrectly");
if(json_array_size(array) != 3)
if (json_array_size(array) != 3)
fail("array size is invalid after insertion");
if(json_array_insert_new(array, 2, json_integer(123)))
if (json_array_insert_new(array, 2, json_integer(123)))
fail("unable to insert value in the middle of an array");
value = json_array_get(array, 2);
if(!json_is_integer(value) || json_integer_value(value) != 123)
if (!json_is_integer(value) || json_integer_value(value) != 123)
fail("json_array_insert_new works incorrectly");
if(json_array_size(array) != 4)
if (json_array_size(array) != 4)
fail("array size is invalid after insertion");
for(i = 0; i < 20; i++) {
if(json_array_insert(array, 0, seven))
fail("unable to insert value at the begining of an array");
for (i = 0; i < 20; i++) {
if (json_array_insert(array, 0, seven))
fail("unable to insert value at the beginning of an array");
}
for(i = 0; i < 20; i++) {
if(json_array_get(array, i) != seven)
for (i = 0; i < 20; i++) {
if (json_array_get(array, i) != seven)
fail("json_aray_insert works incorrectly");
}
if(json_array_size(array) != 24)
if (json_array_size(array) != 24)
fail("array size is invalid after loop insertion");
json_decref(five);
@@ -203,8 +195,7 @@ static void test_insert(void)
json_decref(array);
}
static void test_remove(void)
{
static void test_remove(void) {
json_t *array, *five, *seven;
int i;
@@ -212,56 +203,50 @@ static void test_remove(void)
five = json_integer(5);
seven = json_integer(7);
if(!array)
if (!array)
fail("unable to create array");
if(!five)
if (!five)
fail("unable to create integer");
if(!seven)
if (!seven)
fail("unable to create integer");
if(!json_array_remove(array, 0))
if (!json_array_remove(array, 0))
fail("able to remove an unexisting index");
if(json_array_append(array, five))
if (json_array_append(array, five))
fail("unable to append");
if(!json_array_remove(array, 1))
if (!json_array_remove(array, 1))
fail("able to remove an unexisting index");
if(json_array_remove(array, 0))
if (json_array_remove(array, 0))
fail("unable to remove");
if(json_array_size(array) != 0)
if (json_array_size(array) != 0)
fail("array size is invalid after removing");
if(json_array_append(array, five) ||
json_array_append(array, seven) ||
json_array_append(array, five) ||
json_array_append(array, seven))
if (json_array_append(array, five) || json_array_append(array, seven) ||
json_array_append(array, five) || json_array_append(array, seven))
fail("unable to append");
if(json_array_remove(array, 2))
if (json_array_remove(array, 2))
fail("unable to remove");
if(json_array_size(array) != 3)
if (json_array_size(array) != 3)
fail("array size is invalid after removing");
if(json_array_get(array, 0) != five ||
json_array_get(array, 1) != seven ||
json_array_get(array, 2) != seven)
if (json_array_get(array, 0) != five || json_array_get(array, 1) != seven ||
json_array_get(array, 2) != seven)
fail("remove works incorrectly");
json_decref(array);
array = json_array();
for(i = 0; i < 4; i++) {
for (i = 0; i < 4; i++) {
json_array_append(array, five);
json_array_append(array, seven);
}
if(json_array_size(array) != 8)
if (json_array_size(array) != 8)
fail("unable to append 8 items to array");
/* Remove an element from a "full" array. */
@@ -272,8 +257,7 @@ static void test_remove(void)
json_decref(array);
}
static void test_clear(void)
{
static void test_clear(void) {
json_t *array, *five, *seven;
int i;
@@ -281,27 +265,27 @@ static void test_clear(void)
five = json_integer(5);
seven = json_integer(7);
if(!array)
if (!array)
fail("unable to create array");
if(!five || !seven)
if (!five || !seven)
fail("unable to create integer");
for(i = 0; i < 10; i++) {
if(json_array_append(array, five))
for (i = 0; i < 10; i++) {
if (json_array_append(array, five))
fail("unable to append");
}
for(i = 0; i < 10; i++) {
if(json_array_append(array, seven))
for (i = 0; i < 10; i++) {
if (json_array_append(array, seven))
fail("unable to append");
}
if(json_array_size(array) != 20)
if (json_array_size(array) != 20)
fail("array size is invalid after appending");
if(json_array_clear(array))
if (json_array_clear(array))
fail("unable to clear");
if(json_array_size(array) != 0)
if (json_array_size(array) != 0)
fail("array size is invalid after clearing");
json_decref(five);
@@ -309,8 +293,7 @@ static void test_clear(void)
json_decref(array);
}
static void test_extend(void)
{
static void test_extend(void) {
json_t *array1, *array2, *five, *seven;
int i;
@@ -319,32 +302,32 @@ static void test_extend(void)
five = json_integer(5);
seven = json_integer(7);
if(!array1 || !array2)
if (!array1 || !array2)
fail("unable to create array");
if(!five || !seven)
if (!five || !seven)
fail("unable to create integer");
for(i = 0; i < 10; i++) {
if(json_array_append(array1, five))
for (i = 0; i < 10; i++) {
if (json_array_append(array1, five))
fail("unable to append");
}
for(i = 0; i < 10; i++) {
if(json_array_append(array2, seven))
for (i = 0; i < 10; i++) {
if (json_array_append(array2, seven))
fail("unable to append");
}
if(json_array_size(array1) != 10 || json_array_size(array2) != 10)
if (json_array_size(array1) != 10 || json_array_size(array2) != 10)
fail("array size is invalid after appending");
if(json_array_extend(array1, array2))
if (json_array_extend(array1, array2))
fail("unable to extend");
for(i = 0; i < 10; i++) {
if(json_array_get(array1, i) != five)
for (i = 0; i < 10; i++) {
if (json_array_get(array1, i) != five)
fail("invalid array contents after extending");
}
for(i = 10; i < 20; i++) {
if(json_array_get(array1, i) != seven)
for (i = 10; i < 20; i++) {
if (json_array_get(array1, i) != seven)
fail("invalid array contents after extending");
}
@@ -354,44 +337,41 @@ static void test_extend(void)
json_decref(array2);
}
static void test_circular()
{
static void test_circular() {
json_t *array1, *array2;
/* the simple cases are checked */
array1 = json_array();
if(!array1)
if (!array1)
fail("unable to create array");
if(json_array_append(array1, array1) == 0)
if (json_array_append(array1, array1) == 0)
fail("able to append self");
if(json_array_insert(array1, 0, array1) == 0)
if (json_array_insert(array1, 0, array1) == 0)
fail("able to insert self");
if(json_array_append_new(array1, json_true()))
if (json_array_append_new(array1, json_true()))
fail("failed to append true");
if(json_array_set(array1, 0, array1) == 0)
if (json_array_set(array1, 0, array1) == 0)
fail("able to set self");
json_decref(array1);
/* create circular references */
array1 = json_array();
array2 = json_array();
if(!array1 || !array2)
if (!array1 || !array2)
fail("unable to create array");
if(json_array_append(array1, array2) ||
json_array_append(array2, array1))
if (json_array_append(array1, array2) || json_array_append(array2, array1))
fail("unable to append");
/* circularity is detected when dumping */
if(json_dumps(array1, 0) != NULL)
if (json_dumps(array1, 0) != NULL)
fail("able to dump circulars");
/* decref twice to deal with the circular references */
@@ -400,28 +380,99 @@ static void test_circular()
json_decref(array1);
}
static void test_array_foreach()
{
static void test_array_foreach() {
size_t index;
json_t *array1, *array2, *value;
array1 = json_pack("[sisisi]", "foo", 1, "bar", 2, "baz", 3);
array2 = json_array();
json_array_foreach(array1, index, value) {
json_array_append(array2, value);
}
if(!json_equal(array1, array2))
json_array_foreach(array1, index, value) { json_array_append(array2, value); }
if (!json_equal(array1, array2))
fail("json_array_foreach failed to iterate all elements");
json_decref(array1);
json_decref(array2);
}
static void test_bad_args(void) {
json_t *arr = json_array();
json_t *num = json_integer(1);
static void run_tests()
{
if (!arr || !num)
fail("failed to create required objects");
if (json_array_size(NULL) != 0)
fail("NULL array has nonzero size");
if (json_array_size(num) != 0)
fail("non-array has nonzero array size");
if (json_array_get(NULL, 0))
fail("json_array_get did not return NULL for non-array");
if (json_array_get(num, 0))
fail("json_array_get did not return NULL for non-array");
if (!json_array_set_new(NULL, 0, json_incref(num)))
fail("json_array_set_new did not return error for non-array");
if (!json_array_set_new(num, 0, json_incref(num)))
fail("json_array_set_new did not return error for non-array");
if (!json_array_set_new(arr, 0, NULL))
fail("json_array_set_new did not return error for NULL value");
if (!json_array_set_new(arr, 0, json_incref(arr)))
fail("json_array_set_new did not return error for value == array");
if (!json_array_remove(NULL, 0))
fail("json_array_remove did not return error for non-array");
if (!json_array_remove(num, 0))
fail("json_array_remove did not return error for non-array");
if (!json_array_clear(NULL))
fail("json_array_clear did not return error for non-array");
if (!json_array_clear(num))
fail("json_array_clear did not return error for non-array");
if (!json_array_append_new(NULL, json_incref(num)))
fail("json_array_append_new did not return error for non-array");
if (!json_array_append_new(num, json_incref(num)))
fail("json_array_append_new did not return error for non-array");
if (!json_array_append_new(arr, NULL))
fail("json_array_append_new did not return error for NULL value");
if (!json_array_append_new(arr, json_incref(arr)))
fail("json_array_append_new did not return error for value == array");
if (!json_array_insert_new(NULL, 0, json_incref(num)))
fail("json_array_insert_new did not return error for non-array");
if (!json_array_insert_new(num, 0, json_incref(num)))
fail("json_array_insert_new did not return error for non-array");
if (!json_array_insert_new(arr, 0, NULL))
fail("json_array_insert_new did not return error for NULL value");
if (!json_array_insert_new(arr, 0, json_incref(arr)))
fail("json_array_insert_new did not return error for value == array");
if (!json_array_extend(NULL, arr))
fail("json_array_extend did not return error for first argument "
"non-array");
if (!json_array_extend(num, arr))
fail("json_array_extend did not return error for first argument "
"non-array");
if (!json_array_extend(arr, NULL))
fail("json_array_extend did not return error for second argument "
"non-array");
if (!json_array_extend(arr, num))
fail("json_array_extend did not return error for second argument "
"non-array");
if (num->refcount != 1)
fail("unexpected reference count on num");
if (arr->refcount != 1)
fail("unexpected reference count on arr");
json_decref(num);
json_decref(arr);
}
static void run_tests() {
test_misc();
test_insert();
test_remove();
@@ -429,4 +480,5 @@ static void run_tests()
test_extend();
test_circular();
test_array_foreach();
test_bad_args();
}

View File

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

View File

@@ -5,21 +5,20 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <string.h>
#include <jansson.h>
#include "util.h"
#include <jansson.h>
#include <string.h>
static void test_copy_simple(void)
{
static void test_copy_simple(void) {
json_t *value, *copy;
if(json_copy(NULL))
if (json_copy(NULL))
fail("copying NULL doesn't return NULL");
/* true */
value = json_true();
copy = json_copy(value);
if(value != copy)
if (value != copy)
fail("copying true failed");
json_decref(value);
json_decref(copy);
@@ -27,7 +26,7 @@ static void test_copy_simple(void)
/* false */
value = json_false();
copy = json_copy(value);
if(value != copy)
if (value != copy)
fail("copying false failed");
json_decref(value);
json_decref(copy);
@@ -35,71 +34,70 @@ static void test_copy_simple(void)
/* null */
value = json_null();
copy = json_copy(value);
if(value != copy)
if (value != copy)
fail("copying null failed");
json_decref(value);
json_decref(copy);
/* string */
value = json_string("foo");
if(!value)
if (!value)
fail("unable to create a string");
copy = json_copy(value);
if(!copy)
if (!copy)
fail("unable to copy a string");
if(copy == value)
if (copy == value)
fail("copying a string doesn't copy");
if(!json_equal(copy, value))
if (!json_equal(copy, value))
fail("copying a string produces an inequal copy");
if(value->refcount != 1 || copy->refcount != 1)
if (value->refcount != 1 || copy->refcount != 1)
fail("invalid refcounts");
json_decref(value);
json_decref(copy);
/* integer */
value = json_integer(543);
if(!value)
if (!value)
fail("unable to create an integer");
copy = json_copy(value);
if(!copy)
if (!copy)
fail("unable to copy an integer");
if(copy == value)
if (copy == value)
fail("copying an integer doesn't copy");
if(!json_equal(copy, value))
if (!json_equal(copy, value))
fail("copying an integer produces an inequal copy");
if(value->refcount != 1 || copy->refcount != 1)
if (value->refcount != 1 || copy->refcount != 1)
fail("invalid refcounts");
json_decref(value);
json_decref(copy);
/* real */
value = json_real(123e9);
if(!value)
if (!value)
fail("unable to create a real");
copy = json_copy(value);
if(!copy)
if (!copy)
fail("unable to copy a real");
if(copy == value)
if (copy == value)
fail("copying a real doesn't copy");
if(!json_equal(copy, value))
if (!json_equal(copy, value))
fail("copying a real produces an inequal copy");
if(value->refcount != 1 || copy->refcount != 1)
if (value->refcount != 1 || copy->refcount != 1)
fail("invalid refcounts");
json_decref(value);
json_decref(copy);
}
static void test_deep_copy_simple(void)
{
static void test_deep_copy_simple(void) {
json_t *value, *copy;
if(json_deep_copy(NULL))
if (json_deep_copy(NULL))
fail("deep copying NULL doesn't return NULL");
/* true */
value = json_true();
copy = json_deep_copy(value);
if(value != copy)
if (value != copy)
fail("deep copying true failed");
json_decref(value);
json_decref(copy);
@@ -107,7 +105,7 @@ static void test_deep_copy_simple(void)
/* false */
value = json_false();
copy = json_deep_copy(value);
if(value != copy)
if (value != copy)
fail("deep copying false failed");
json_decref(value);
json_decref(copy);
@@ -115,82 +113,80 @@ static void test_deep_copy_simple(void)
/* null */
value = json_null();
copy = json_deep_copy(value);
if(value != copy)
if (value != copy)
fail("deep copying null failed");
json_decref(value);
json_decref(copy);
/* string */
value = json_string("foo");
if(!value)
if (!value)
fail("unable to create a string");
copy = json_deep_copy(value);
if(!copy)
if (!copy)
fail("unable to deep copy a string");
if(copy == value)
if (copy == value)
fail("deep copying a string doesn't copy");
if(!json_equal(copy, value))
if (!json_equal(copy, value))
fail("deep copying a string produces an inequal copy");
if(value->refcount != 1 || copy->refcount != 1)
if (value->refcount != 1 || copy->refcount != 1)
fail("invalid refcounts");
json_decref(value);
json_decref(copy);
/* integer */
value = json_integer(543);
if(!value)
if (!value)
fail("unable to create an integer");
copy = json_deep_copy(value);
if(!copy)
if (!copy)
fail("unable to deep copy an integer");
if(copy == value)
if (copy == value)
fail("deep copying an integer doesn't copy");
if(!json_equal(copy, value))
if (!json_equal(copy, value))
fail("deep copying an integer produces an inequal copy");
if(value->refcount != 1 || copy->refcount != 1)
if (value->refcount != 1 || copy->refcount != 1)
fail("invalid refcounts");
json_decref(value);
json_decref(copy);
/* real */
value = json_real(123e9);
if(!value)
if (!value)
fail("unable to create a real");
copy = json_deep_copy(value);
if(!copy)
if (!copy)
fail("unable to deep copy a real");
if(copy == value)
if (copy == value)
fail("deep copying a real doesn't copy");
if(!json_equal(copy, value))
if (!json_equal(copy, value))
fail("deep copying a real produces an inequal copy");
if(value->refcount != 1 || copy->refcount != 1)
if (value->refcount != 1 || copy->refcount != 1)
fail("invalid refcounts");
json_decref(value);
json_decref(copy);
}
static void test_copy_array(void)
{
static void test_copy_array(void) {
const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]";
json_t *array, *copy;
size_t i;
array = json_loads(json_array_text, 0, NULL);
if(!array)
if (!array)
fail("unable to parse an array");
copy = json_copy(array);
if(!copy)
if (!copy)
fail("unable to copy an array");
if(copy == array)
if (copy == array)
fail("copying an array doesn't copy");
if(!json_equal(copy, array))
if (!json_equal(copy, array))
fail("copying an array produces an inequal copy");
for(i = 0; i < json_array_size(copy); i++)
{
if(json_array_get(array, i) != json_array_get(copy, i))
for (i = 0; i < json_array_size(copy); i++) {
if (json_array_get(array, i) != json_array_get(copy, i))
fail("copying an array modifies its elements");
}
@@ -198,28 +194,26 @@ static void test_copy_array(void)
json_decref(copy);
}
static void test_deep_copy_array(void)
{
static void test_deep_copy_array(void) {
const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]";
json_t *array, *copy;
size_t i;
array = json_loads(json_array_text, 0, NULL);
if(!array)
if (!array)
fail("unable to parse an array");
copy = json_deep_copy(array);
if(!copy)
if (!copy)
fail("unable to deep copy an array");
if(copy == array)
if (copy == array)
fail("deep copying an array doesn't copy");
if(!json_equal(copy, array))
if (!json_equal(copy, array))
fail("deep copying an array produces an inequal copy");
for(i = 0; i < json_array_size(copy); i++)
{
if(json_array_get(array, i) == json_array_get(copy, i))
for (i = 0; i < json_array_size(copy); i++) {
if (json_array_get(array, i) == json_array_get(copy, i))
fail("deep copying an array doesn't copy its elements");
}
@@ -227,8 +221,7 @@ static void test_deep_copy_array(void)
json_decref(copy);
}
static void test_copy_object(void)
{
static void test_copy_object(void) {
const char *json_object_text =
"{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
@@ -239,21 +232,20 @@ static void test_copy_object(void)
void *iter;
object = json_loads(json_object_text, 0, NULL);
if(!object)
if (!object)
fail("unable to parse an object");
copy = json_copy(object);
if(!copy)
if (!copy)
fail("unable to copy an object");
if(copy == object)
if (copy == object)
fail("copying an object doesn't copy");
if(!json_equal(copy, object))
if (!json_equal(copy, object))
fail("copying an object produces an inequal copy");
i = 0;
iter = json_object_iter(object);
while(iter)
{
while (iter) {
const char *key;
json_t *value1, *value2;
@@ -261,7 +253,7 @@ static void test_copy_object(void)
value1 = json_object_iter_value(iter);
value2 = json_object_get(copy, key);
if(value1 != value2)
if (value1 != value2)
fail("copying an object modifies its items");
if (strcmp(key, keys[i]) != 0)
@@ -275,8 +267,7 @@ static void test_copy_object(void)
json_decref(copy);
}
static void test_deep_copy_object(void)
{
static void test_deep_copy_object(void) {
const char *json_object_text =
"{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}";
@@ -287,21 +278,20 @@ static void test_deep_copy_object(void)
void *iter;
object = json_loads(json_object_text, 0, NULL);
if(!object)
if (!object)
fail("unable to parse an object");
copy = json_deep_copy(object);
if(!copy)
if (!copy)
fail("unable to deep copy an object");
if(copy == object)
if (copy == object)
fail("deep copying an object doesn't copy");
if(!json_equal(copy, object))
if (!json_equal(copy, object))
fail("deep copying an object produces an inequal copy");
i = 0;
iter = json_object_iter(object);
while(iter)
{
while (iter) {
const char *key;
json_t *value1, *value2;
@@ -309,7 +299,7 @@ static void test_deep_copy_object(void)
value1 = json_object_iter_value(iter);
value2 = json_object_get(copy, key);
if(value1 == value2)
if (value1 == value2)
fail("deep copying an object doesn't copy its items");
if (strcmp(key, keys[i]) != 0)
@@ -323,12 +313,63 @@ static void test_deep_copy_object(void)
json_decref(copy);
}
static void run_tests()
{
static void test_deep_copy_circular_references(void) {
/* Construct a JSON object/array with a circular reference:
object: {"a": {"b": {"c": <circular reference to $.a>}}}
array: [[[<circular reference to the $[0] array>]]]
Deep copy it, remove the circular reference and deep copy again.
*/
json_t *json;
json_t *copy;
json = json_object();
json_object_set_new(json, "a", json_object());
json_object_set_new(json_object_get(json, "a"), "b", json_object());
json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c",
json_object_get(json, "a"));
copy = json_deep_copy(json);
if (copy)
fail("json_deep_copy copied a circular reference!");
json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c");
copy = json_deep_copy(json);
if (!copy)
fail("json_deep_copy failed!");
json_decref(copy);
json_decref(json);
json = json_array();
json_array_append_new(json, json_array());
json_array_append_new(json_array_get(json, 0), json_array());
json_array_append(json_array_get(json_array_get(json, 0), 0),
json_array_get(json, 0));
copy = json_deep_copy(json);
if (copy)
fail("json_deep_copy copied a circular reference!");
json_array_remove(json_array_get(json_array_get(json, 0), 0), 0);
copy = json_deep_copy(json);
if (!copy)
fail("json_deep_copy failed!");
json_decref(copy);
json_decref(json);
}
static void run_tests() {
test_copy_simple();
test_deep_copy_simple();
test_copy_array();
test_deep_copy_array();
test_copy_object();
test_deep_copy_object();
test_deep_copy_circular_references();
}

View File

@@ -13,40 +13,40 @@
#include <unistd.h>
#endif
#include "util.h"
#ifdef __MINGW32__
#include <fcntl.h>
#define pipe(fds) _pipe(fds, 1024, _O_BINARY)
#endif
static int encode_null_callback(const char *buffer, size_t size, void *data)
{
static int encode_null_callback(const char *buffer, size_t size, void *data) {
(void)buffer;
(void)size;
(void)data;
return 0;
}
static void encode_null()
{
if(json_dumps(NULL, JSON_ENCODE_ANY) != NULL)
static void encode_null() {
if (json_dumps(NULL, JSON_ENCODE_ANY) != NULL)
fail("json_dumps didn't fail for NULL");
if(json_dumpb(NULL, NULL, 0, JSON_ENCODE_ANY) != 0)
fail("json_dumps didn't fail for NULL");
if (json_dumpb(NULL, NULL, 0, JSON_ENCODE_ANY) != 0)
fail("json_dumpb didn't fail for NULL");
if(json_dumpf(NULL, stderr, JSON_ENCODE_ANY) != -1)
if (json_dumpf(NULL, stderr, JSON_ENCODE_ANY) != -1)
fail("json_dumpf didn't fail for NULL");
#ifdef HAVE_UNISTD_H
if(json_dumpfd(NULL, STDERR_FILENO, JSON_ENCODE_ANY) != -1)
if (json_dumpfd(NULL, STDERR_FILENO, JSON_ENCODE_ANY) != -1)
fail("json_dumpfd didn't fail for NULL");
#endif
/* Don't test json_dump_file to avoid creating a file */
if(json_dump_callback(NULL, encode_null_callback, NULL, JSON_ENCODE_ANY) != -1)
if (json_dump_callback(NULL, encode_null_callback, NULL, JSON_ENCODE_ANY) != -1)
fail("json_dump_callback didn't fail for NULL");
}
static void encode_twice()
{
static void encode_twice() {
/* Encode an empty object/array, add an item, encode again */
json_t *json;
@@ -54,35 +54,34 @@ static void encode_twice()
json = json_object();
result = json_dumps(json, 0);
if(!result || strcmp(result, "{}"))
fail("json_dumps failed");
if (!result || strcmp(result, "{}"))
fail("json_dumps failed");
free(result);
json_object_set_new(json, "foo", json_integer(5));
result = json_dumps(json, 0);
if(!result || strcmp(result, "{\"foo\": 5}"))
fail("json_dumps failed");
if (!result || strcmp(result, "{\"foo\": 5}"))
fail("json_dumps failed");
free(result);
json_decref(json);
json = json_array();
result = json_dumps(json, 0);
if(!result || strcmp(result, "[]"))
fail("json_dumps failed");
if (!result || strcmp(result, "[]"))
fail("json_dumps failed");
free(result);
json_array_append_new(json, json_integer(5));
result = json_dumps(json, 0);
if(!result || strcmp(result, "[5]"))
fail("json_dumps failed");
if (!result || strcmp(result, "[5]"))
fail("json_dumps failed");
free(result);
json_decref(json);
}
static void circular_references()
{
static void circular_references() {
/* Construct a JSON object/array with a circular reference:
object: {"a": {"b": {"c": <circular reference to $.a>}}}
@@ -100,13 +99,13 @@ static void circular_references()
json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c",
json_object_get(json, "a"));
if(json_dumps(json, 0))
if (json_dumps(json, 0))
fail("json_dumps encoded a circular reference!");
json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c");
result = json_dumps(json, 0);
if(!result || strcmp(result, "{\"a\": {\"b\": {}}}"))
if (!result || strcmp(result, "{\"a\": {\"b\": {}}}"))
fail("json_dumps failed!");
free(result);
@@ -118,21 +117,20 @@ static void circular_references()
json_array_append(json_array_get(json_array_get(json, 0), 0),
json_array_get(json, 0));
if(json_dumps(json, 0))
if (json_dumps(json, 0))
fail("json_dumps encoded a circular reference!");
json_array_remove(json_array_get(json_array_get(json, 0), 0), 0);
result = json_dumps(json, 0);
if(!result || strcmp(result, "[[[]]]"))
if (!result || strcmp(result, "[[[]]]"))
fail("json_dumps failed!");
free(result);
json_decref(json);
}
static void encode_other_than_array_or_object()
{
static void encode_other_than_array_or_object() {
/* Encoding anything other than array or object should only
* succeed if the JSON_ENCODE_ANY flag is used */
@@ -140,40 +138,37 @@ static void encode_other_than_array_or_object()
char *result;
json = json_string("foo");
if(json_dumps(json, 0) != NULL)
if (json_dumps(json, 0) != NULL)
fail("json_dumps encoded a string!");
if(json_dumpf(json, NULL, 0) == 0)
if (json_dumpf(json, NULL, 0) == 0)
fail("json_dumpf encoded a string!");
if(json_dumpfd(json, -1, 0) == 0)
if (json_dumpfd(json, -1, 0) == 0)
fail("json_dumpfd encoded a string!");
result = json_dumps(json, JSON_ENCODE_ANY);
if(!result || strcmp(result, "\"foo\"") != 0)
if (!result || strcmp(result, "\"foo\"") != 0)
fail("json_dumps failed to encode a string with JSON_ENCODE_ANY");
free(result);
json_decref(json);
json = json_integer(42);
if(json_dumps(json, 0) != NULL)
if (json_dumps(json, 0) != NULL)
fail("json_dumps encoded an integer!");
if(json_dumpf(json, NULL, 0) == 0)
if (json_dumpf(json, NULL, 0) == 0)
fail("json_dumpf encoded an integer!");
if(json_dumpfd(json, -1, 0) == 0)
if (json_dumpfd(json, -1, 0) == 0)
fail("json_dumpfd encoded an integer!");
result = json_dumps(json, JSON_ENCODE_ANY);
if(!result || strcmp(result, "42") != 0)
if (!result || strcmp(result, "42") != 0)
fail("json_dumps failed to encode an integer with JSON_ENCODE_ANY");
free(result);
json_decref(json);
}
static void escape_slashes()
{
static void escape_slashes() {
/* Test dump escaping slashes */
json_t *json;
@@ -183,35 +178,34 @@ static void escape_slashes()
json_object_set_new(json, "url", json_string("https://github.com/akheron/jansson"));
result = json_dumps(json, 0);
if(!result || strcmp(result, "{\"url\": \"https://github.com/akheron/jansson\"}"))
if (!result || strcmp(result, "{\"url\": \"https://github.com/akheron/jansson\"}"))
fail("json_dumps failed to not escape slashes");
free(result);
result = json_dumps(json, JSON_ESCAPE_SLASH);
if(!result || strcmp(result, "{\"url\": \"https:\\/\\/github.com\\/akheron\\/jansson\"}"))
if (!result ||
strcmp(result, "{\"url\": \"https:\\/\\/github.com\\/akheron\\/jansson\"}"))
fail("json_dumps failed to escape slashes");
free(result);
json_decref(json);
}
static void encode_nul_byte()
{
static void encode_nul_byte() {
json_t *json;
char *result;
json = json_stringn("nul byte \0 in string", 20);
result = json_dumps(json, JSON_ENCODE_ANY);
if(!result || memcmp(result, "\"nul byte \\u0000 in string\"", 27))
if (!result || memcmp(result, "\"nul byte \\u0000 in string\"", 27))
fail("json_dumps failed to dump an embedded NUL byte");
free(result);
json_decref(json);
}
static void dump_file()
{
static void dump_file() {
json_t *json;
int result;
@@ -228,8 +222,7 @@ static void dump_file()
remove("json_dump_file.json");
}
static void dumpb()
{
static void dumpb() {
char buf[2];
json_t *obj;
size_t size;
@@ -237,31 +230,30 @@ static void dumpb()
obj = json_object();
size = json_dumpb(obj, buf, sizeof(buf), 0);
if(size != 2 || strncmp(buf, "{}", 2))
fail("json_dumpb failed");
if (size != 2 || strncmp(buf, "{}", 2))
fail("json_dumpb failed");
json_decref(obj);
obj = json_pack("{s:s}", "foo", "bar");
size = json_dumpb(obj, buf, sizeof(buf), JSON_COMPACT);
if(size != 13)
fail("json_dumpb size check failed");
if (size != 13)
fail("json_dumpb size check failed");
json_decref(obj);
}
static void dumpfd()
{
static void dumpfd() {
#ifdef HAVE_UNISTD_H
int fds[2] = {-1, -1};
json_t *a, *b;
if(pipe(fds))
if (pipe(fds))
fail("pipe() failed");
a = json_pack("{s:s}", "foo", "bar");
if(json_dumpfd(a, fds[1], 0))
if (json_dumpfd(a, fds[1], 0))
fail("json_dumpfd() failed");
close(fds[1]);
@@ -278,19 +270,13 @@ static void dumpfd()
#endif
}
static void embed()
{
static const char *plains[] = {
"{\"bar\":[],\"foo\":{}}",
"[[],{}]",
"{}",
"[]",
NULL
};
static void embed() {
static const char *plains[] = {"{\"bar\":[],\"foo\":{}}", "[[],{}]", "{}", "[]",
NULL};
size_t i;
for(i = 0; plains[i]; i++) {
for (i = 0; plains[i]; i++) {
const char *plain = plains[i];
json_t *parse = NULL;
char *embed = NULL;
@@ -300,19 +286,18 @@ static void embed()
psize = strlen(plain) - 2;
embed = calloc(1, psize);
parse = json_loads(plain, 0, NULL);
esize = json_dumpb(parse, embed, psize,
JSON_COMPACT | JSON_SORT_KEYS | JSON_EMBED);
esize =
json_dumpb(parse, embed, psize, JSON_COMPACT | JSON_SORT_KEYS | JSON_EMBED);
json_decref(parse);
if(esize != psize)
if (esize != psize)
fail("json_dumpb(JSON_EMBED) returned an invalid size");
if(strncmp(plain + 1, embed, esize) != 0)
if (strncmp(plain + 1, embed, esize) != 0)
fail("json_dumps(JSON_EMBED) returned an invalid value");
free(embed);
}
}
static void run_tests()
{
static void run_tests() {
encode_null();
encode_twice();
circular_references();

View File

@@ -5,10 +5,10 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <jansson.h>
#include <string.h>
#include <stdlib.h>
#include "util.h"
#include <jansson.h>
#include <stdlib.h>
#include <string.h>
struct my_sink {
char *buf;
@@ -26,15 +26,14 @@ static int my_writer(const char *buffer, size_t len, void *data) {
return 0;
}
static void run_tests()
{
static void run_tests() {
struct my_sink s;
json_t *json;
const char str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]";
char *dumped_to_string;
json = json_loads(str, 0, NULL);
if(!json) {
if (!json) {
fail("json_loads failed");
}
@@ -64,7 +63,8 @@ static void run_tests()
json_decref(json);
free(dumped_to_string);
free(s.buf);
fail("json_dump_callback and json_dumps did not produce identical output");
fail("json_dump_callback and json_dumps did not produce identical "
"output");
}
s.off = 1;
@@ -72,7 +72,8 @@ static void run_tests()
json_decref(json);
free(dumped_to_string);
free(s.buf);
fail("json_dump_callback succeeded on a short buffer when it should have failed");
fail("json_dump_callback succeeded on a short buffer when it should "
"have failed");
}
json_decref(json);

View File

@@ -5,38 +5,37 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <jansson.h>
#include "util.h"
#include <jansson.h>
static void test_equal_simple()
{
static void test_equal_simple() {
json_t *value1, *value2;
if(json_equal(NULL, NULL))
if (json_equal(NULL, NULL))
fail("json_equal fails for two NULLs");
value1 = json_true();
if(json_equal(value1, NULL) || json_equal(NULL, value1))
if (json_equal(value1, NULL) || json_equal(NULL, value1))
fail("json_equal fails for NULL");
/* this covers true, false and null as they are singletons */
if(!json_equal(value1, value1))
if (!json_equal(value1, value1))
fail("identical objects are not equal");
json_decref(value1);
/* integer */
value1 = json_integer(1);
value2 = json_integer(1);
if(!value1 || !value2)
if (!value1 || !value2)
fail("unable to create integers");
if(!json_equal(value1, value2))
if (!json_equal(value1, value2))
fail("json_equal fails for two equal integers");
json_decref(value2);
value2 = json_integer(2);
if(!value2)
if (!value2)
fail("unable to create an integer");
if(json_equal(value1, value2))
if (json_equal(value1, value2))
fail("json_equal fails for two inequal integers");
json_decref(value1);
@@ -45,16 +44,16 @@ static void test_equal_simple()
/* real */
value1 = json_real(1.2);
value2 = json_real(1.2);
if(!value1 || !value2)
if (!value1 || !value2)
fail("unable to create reals");
if(!json_equal(value1, value2))
if (!json_equal(value1, value2))
fail("json_equal fails for two equal reals");
json_decref(value2);
value2 = json_real(3.141592);
if(!value2)
if (!value2)
fail("unable to create an real");
if(json_equal(value1, value2))
if (json_equal(value1, value2))
fail("json_equal fails for two inequal reals");
json_decref(value1);
@@ -63,32 +62,38 @@ static void test_equal_simple()
/* string */
value1 = json_string("foo");
value2 = json_string("foo");
if(!value1 || !value2)
if (!value1 || !value2)
fail("unable to create strings");
if(!json_equal(value1, value2))
if (!json_equal(value1, value2))
fail("json_equal fails for two equal strings");
json_decref(value2);
value2 = json_string("bar");
if(!value2)
if (!value2)
fail("unable to create an string");
if(json_equal(value1, value2))
if (json_equal(value1, value2))
fail("json_equal fails for two inequal strings");
json_decref(value2);
value2 = json_string("bar2");
if (!value2)
fail("unable to create an string");
if (json_equal(value1, value2))
fail("json_equal fails for two inequal length strings");
json_decref(value1);
json_decref(value2);
}
static void test_equal_array()
{
static void test_equal_array() {
json_t *array1, *array2;
array1 = json_array();
array2 = json_array();
if(!array1 || !array2)
if (!array1 || !array2)
fail("unable to create arrays");
if(!json_equal(array1, array2))
if (!json_equal(array1, array2))
fail("json_equal fails for two empty arrays");
json_array_append_new(array1, json_integer(1));
@@ -97,31 +102,30 @@ static void test_equal_array()
json_array_append_new(array2, json_string("foo"));
json_array_append_new(array1, json_integer(2));
json_array_append_new(array2, json_integer(2));
if(!json_equal(array1, array2))
if (!json_equal(array1, array2))
fail("json_equal fails for two equal arrays");
json_array_remove(array2, 2);
if(json_equal(array1, array2))
if (json_equal(array1, array2))
fail("json_equal fails for two inequal arrays");
json_array_append_new(array2, json_integer(3));
if(json_equal(array1, array2))
if (json_equal(array1, array2))
fail("json_equal fails for two inequal arrays");
json_decref(array1);
json_decref(array2);
}
static void test_equal_object()
{
static void test_equal_object() {
json_t *object1, *object2;
object1 = json_object();
object2 = json_object();
if(!object1 || !object2)
if (!object1 || !object2)
fail("unable to create objects");
if(!json_equal(object1, object2))
if (!json_equal(object1, object2))
fail("json_equal fails for two empty objects");
json_object_set_new(object1, "a", json_integer(1));
@@ -130,58 +134,67 @@ static void test_equal_object()
json_object_set_new(object2, "b", json_string("foo"));
json_object_set_new(object1, "c", json_integer(2));
json_object_set_new(object2, "c", json_integer(2));
if(!json_equal(object1, object2))
if (!json_equal(object1, object2))
fail("json_equal fails for two equal objects");
json_object_del(object2, "c");
if(json_equal(object1, object2))
if (json_equal(object1, object2))
fail("json_equal fails for two inequal objects");
json_object_set_new(object2, "c", json_integer(3));
if(json_equal(object1, object2))
if (json_equal(object1, object2))
fail("json_equal fails for two inequal objects");
json_object_del(object2, "c");
json_object_set_new(object2, "d", json_integer(2));
if(json_equal(object1, object2))
if (json_equal(object1, object2))
fail("json_equal fails for two inequal objects");
json_decref(object1);
json_decref(object2);
}
static void test_equal_complex()
{
json_t *value1, *value2;
static void test_equal_complex() {
json_t *value1, *value2, *value3;
const char *complex_json =
"{"
" \"integer\": 1, "
" \"real\": 3.141592, "
" \"string\": \"foobar\", "
" \"true\": true, "
" \"object\": {"
" \"array-in-object\": [1,true,\"foo\",{}],"
" \"object-in-object\": {\"foo\": \"bar\"}"
" },"
" \"array\": [\"foo\", false, null, 1.234]"
"}";
const char *complex_json = "{"
" \"integer\": 1, "
" \"real\": 3.141592, "
" \"string\": \"foobar\", "
" \"true\": true, "
" \"object\": {"
" \"array-in-object\": [1,true,\"foo\",{}],"
" \"object-in-object\": {\"foo\": \"bar\"}"
" },"
" \"array\": [\"foo\", false, null, 1.234]"
"}";
value1 = json_loads(complex_json, 0, NULL);
value2 = json_loads(complex_json, 0, NULL);
if(!value1 || !value2)
value3 = json_loads(complex_json, 0, NULL);
if (!value1 || !value2)
fail("unable to parse JSON");
if(!json_equal(value1, value2))
fail("json_equal fails for two inequal strings");
if (!json_equal(value1, value2))
fail("json_equal fails for two equal objects");
json_array_set_new(
json_object_get(json_object_get(value2, "object"), "array-in-object"), 1,
json_false());
if (json_equal(value1, value2))
fail("json_equal fails for two inequal objects");
json_object_set_new(
json_object_get(json_object_get(value3, "object"), "object-in-object"), "foo",
json_string("baz"));
if (json_equal(value1, value3))
fail("json_equal fails for two inequal objects");
json_decref(value1);
json_decref(value2);
/* TODO: There's no negative test case here */
json_decref(value3);
}
static void run_tests()
{
static void run_tests() {
test_equal_simple();
test_equal_array();
test_equal_object();

View File

@@ -5,34 +5,33 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "util.h"
#include <jansson.h>
#include <string.h>
#include "util.h"
static void file_not_found()
{
static void file_not_found() {
json_t *json;
json_error_t error;
char *pos;
json = json_load_file("/path/to/nonexistent/file.json", 0, &error);
if(json)
if (json)
fail("json_load_file returned non-NULL for a nonexistent file");
if(error.line != -1)
if (error.line != -1)
fail("json_load_file returned an invalid line number");
/* The error message is locale specific, only check the beginning
of the error message. */
pos = strchr(error.text, ':');
if(!pos)
if (!pos)
fail("json_load_file returne an invalid error message");
*pos = '\0';
if(strcmp(error.text, "unable to open /path/to/nonexistent/file.json") != 0)
if (strcmp(error.text, "unable to open /path/to/nonexistent/file.json") != 0)
fail("json_load_file returned an invalid error message");
if(json_error_code(&error) != json_error_cannot_open_file)
if (json_error_code(&error) != json_error_cannot_open_file)
fail("json_load_file returned an invalid error code");
}
@@ -40,47 +39,48 @@ static void very_long_file_name() {
json_t *json;
json_error_t error;
json = json_load_file("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, &error);
if(json)
json = json_load_file("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
0, &error);
if (json)
fail("json_load_file returned non-NULL for a nonexistent file");
if(error.line != -1)
if (error.line != -1)
fail("json_load_file returned an invalid line number");
if (strncmp(error.source, "...aaa", 6) != 0)
fail("error source was set incorrectly");
if(json_error_code(&error) != json_error_cannot_open_file)
if (json_error_code(&error) != json_error_cannot_open_file)
fail("error code was set incorrectly");
}
static void reject_duplicates()
{
static void reject_duplicates() {
json_error_t error;
if(json_loads("{\"foo\": 1, \"foo\": 2}", JSON_REJECT_DUPLICATES, &error))
if (json_loads("{\"foo\": 1, \"foo\": 2}", JSON_REJECT_DUPLICATES, &error))
fail("json_loads did not detect a duplicate key");
check_error(json_error_duplicate_key, "duplicate object key near '\"foo\"'", "<string>", 1, 16, 16);
check_error(json_error_duplicate_key, "duplicate object key near '\"foo\"'",
"<string>", 1, 16, 16);
}
static void disable_eof_check()
{
static void disable_eof_check() {
json_error_t error;
json_t *json;
const char *text = "{\"foo\": 1} garbage";
if(json_loads(text, 0, &error))
if (json_loads(text, 0, &error))
fail("json_loads did not detect garbage after JSON text");
check_error(json_error_end_of_input_expected, "end of file expected near 'garbage'", "<string>", 1, 18, 18);
check_error(json_error_end_of_input_expected, "end of file expected near 'garbage'",
"<string>", 1, 18, 18);
json = json_loads(text, JSON_DISABLE_EOF_CHECK, &error);
if(!json)
if (!json)
fail("json_loads failed with JSON_DISABLE_EOF_CHECK");
json_decref(json);
}
static void decode_any()
{
static void decode_any() {
json_t *json;
json_error_t error;
@@ -105,8 +105,7 @@ static void decode_any()
json_decref(json);
}
static void decode_int_as_real()
{
static void decode_int_as_real() {
json_t *json;
json_error_t error;
@@ -127,8 +126,7 @@ static void decode_int_as_real()
imprecise = "9007199254740993";
expected = 9007199254740992ll;
json = json_loads(imprecise, JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY,
&error);
json = json_loads(imprecise, JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error);
if (!json || !json_is_real(json) || expected != (json_int_t)json_real_value(json))
fail("json_load decode int as real failed - expected imprecision");
json_decref(json);
@@ -145,31 +143,28 @@ static void decode_int_as_real()
json_error_code(&error) != json_error_numeric_overflow)
fail("json_load decode int as real failed - expected overflow");
json_decref(json);
}
static void allow_nul()
{
static void allow_nul() {
const char *text = "\"nul byte \\u0000 in string\"";
const char *expected = "nul byte \0 in string";
size_t len = 20;
json_t *json;
json = json_loads(text, JSON_ALLOW_NUL | JSON_DECODE_ANY, NULL);
if(!json || !json_is_string(json))
if (!json || !json_is_string(json))
fail("unable to decode embedded NUL byte");
if(json_string_length(json) != len)
if (json_string_length(json) != len)
fail("decoder returned wrong string length");
if(memcmp(json_string_value(json), expected, len + 1))
if (memcmp(json_string_value(json), expected, len + 1))
fail("decoder returned wrong string content");
json_decref(json);
}
static void load_wrong_args()
{
static void load_wrong_args() {
json_t *json;
json_error_t error;
@@ -194,45 +189,42 @@ static void load_wrong_args()
fail("json_load_file should return NULL if the first argument is NULL");
}
static void position()
{
static void position() {
json_t *json;
size_t flags = JSON_DISABLE_EOF_CHECK;
json_error_t error;
json = json_loads("{\"foo\": \"bar\"}", 0, &error);
if(error.position != 14)
if (error.position != 14)
fail("json_loads returned a wrong position");
json_decref(json);
json = json_loads("{\"foo\": \"bar\"} baz quux", flags, &error);
if(error.position != 14)
if (error.position != 14)
fail("json_loads returned a wrong position");
json_decref(json);
}
static void error_code()
{
static void error_code() {
json_error_t error;
json_t *json = json_loads("[123] garbage", 0, &error);
if(json != NULL)
if (json != NULL)
fail("json_loads returned not NULL");
if(strlen(error.text) >= JSON_ERROR_TEXT_LENGTH)
if (strlen(error.text) >= JSON_ERROR_TEXT_LENGTH)
fail("error.text longer than expected");
if(json_error_code(&error) != json_error_end_of_input_expected)
if (json_error_code(&error) != json_error_end_of_input_expected)
fail("json_loads returned incorrect error code");
json = json_loads("{\"foo\": ", 0, &error);
if(json != NULL)
if (json != NULL)
fail("json_loads returned not NULL");
if(strlen(error.text) >= JSON_ERROR_TEXT_LENGTH)
if (strlen(error.text) >= JSON_ERROR_TEXT_LENGTH)
fail("error.text longer than expected");
if(json_error_code(&error) != json_error_premature_end_of_input)
if (json_error_code(&error) != json_error_premature_end_of_input)
fail("json_loads returned incorrect error code");
}
static void run_tests()
{
static void run_tests() {
file_not_found();
very_long_file_name();
reject_duplicates();

View File

@@ -5,10 +5,10 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <jansson.h>
#include <string.h>
#include <stdlib.h>
#include "util.h"
#include <jansson.h>
#include <stdlib.h>
#include <string.h>
struct my_source {
const char *buf;
@@ -18,8 +18,7 @@ struct my_source {
static const char my_str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]";
static size_t greedy_reader(void *buf, size_t buflen, void *arg)
{
static size_t greedy_reader(void *buf, size_t buflen, void *arg) {
struct my_source *s = arg;
if (buflen > s->cap - s->off)
buflen = s->cap - s->off;
@@ -32,8 +31,7 @@ static size_t greedy_reader(void *buf, size_t buflen, void *arg)
}
}
static void run_tests()
{
static void run_tests() {
struct my_source s;
json_t *json;
json_error_t error;
@@ -55,21 +53,25 @@ static void run_tests()
json = json_load_callback(greedy_reader, &s, 0, &error);
if (json) {
json_decref(json);
fail("json_load_callback should have failed on an incomplete stream, but it didn't");
fail("json_load_callback should have failed on an incomplete stream, "
"but it didn't");
}
if (strcmp(error.source, "<callback>") != 0) {
fail("json_load_callback returned an invalid error source");
}
if (strcmp(error.text, "']' expected near end of file") != 0) {
fail("json_load_callback returned an invalid error message for an unclosed top-level array");
fail("json_load_callback returned an invalid error message for an "
"unclosed top-level array");
}
json = json_load_callback(NULL, NULL, 0, &error);
if (json) {
json_decref(json);
fail("json_load_callback should have failed on NULL load callback, but it didn't");
fail("json_load_callback should have failed on NULL load callback, but "
"it didn't");
}
if (strcmp(error.text, "wrong arguments") != 0) {
fail("json_load_callback returned an invalid error message for a NULL load callback");
fail("json_load_callback returned an invalid error message for a NULL "
"load callback");
}
}

View File

@@ -5,19 +5,18 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "util.h"
#include <jansson.h>
#include <string.h>
#include "util.h"
static void run_tests()
{
static void run_tests() {
json_t *json;
json_error_t error;
const char str[] = "[\"A\", {\"B\": \"C\"}, 1, 2, 3]garbage";
size_t len = strlen(str) - strlen("garbage");
json = json_loadb(str, len, 0, &error);
if(!json) {
if (!json) {
fail("json_loadb failed on a valid JSON buffer");
}
json_decref(json);
@@ -25,12 +24,14 @@ static void run_tests()
json = json_loadb(str, len - 1, 0, &error);
if (json) {
json_decref(json);
fail("json_loadb should have failed on an incomplete buffer, but it didn't");
fail("json_loadb should have failed on an incomplete buffer, but it "
"didn't");
}
if(error.line != 1) {
if (error.line != 1) {
fail("json_loadb returned an invalid line number on fail");
}
if(strcmp(error.text, "']' expected near end of file") != 0) {
fail("json_loadb returned an invalid error message for an unclosed top-level array");
if (strcmp(error.text, "']' expected near end of file") != 0) {
fail("json_loadb returned an invalid error message for an unclosed "
"top-level array");
}
}

View File

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

View File

@@ -5,9 +5,9 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <math.h>
#include <jansson.h>
#include "util.h"
#include <jansson.h>
#include <math.h>
#ifdef INFINITY
// This test triggers "warning C4756: overflow in constant arithmetic"
@@ -15,20 +15,19 @@
// (This can only be done on function level so we keep these tests separate)
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning (disable: 4756)
#pragma warning(disable : 4756)
#endif
static void test_inifity()
{
static void test_inifity() {
json_t *real = json_real(INFINITY);
if (real != NULL)
fail("could construct a real from Inf");
fail("could construct a real from Inf");
real = json_real(1.0);
if (json_real_set(real, INFINITY) != -1)
fail("could set a real to Inf");
fail("could set a real to Inf");
if (json_real_value(real) != 1.0)
fail("real value changed unexpectedly");
fail("real value changed unexpectedly");
json_decref(real);
#ifdef _MSC_VER
@@ -37,8 +36,41 @@ static void test_inifity()
}
#endif // INFINITY
static void run_tests()
{
static void test_bad_args(void) {
json_t *txt = json_string("test");
if (json_integer_value(NULL) != 0)
fail("json_integer_value did not return 0 for non-integer");
if (json_integer_value(txt) != 0)
fail("json_integer_value did not return 0 for non-integer");
if (!json_integer_set(NULL, 0))
fail("json_integer_set did not return error for non-integer");
if (!json_integer_set(txt, 0))
fail("json_integer_set did not return error for non-integer");
if (json_real_value(NULL) != 0.0)
fail("json_real_value did not return 0.0 for non-real");
if (json_real_value(txt) != 0.0)
fail("json_real_value did not return 0.0 for non-real");
if (!json_real_set(NULL, 0.0))
fail("json_real_set did not return error for non-real");
if (!json_real_set(txt, 0.0))
fail("json_real_set did not return error for non-real");
if (json_number_value(NULL) != 0.0)
fail("json_number_value did not return 0.0 for non-numeric");
if (json_number_value(txt) != 0.0)
fail("json_number_value did not return 0.0 for non-numeric");
if (txt->refcount != 1)
fail("unexpected reference count for txt");
json_decref(txt);
}
static void run_tests() {
json_t *integer, *real;
json_int_t i;
double d;
@@ -46,24 +78,24 @@ static void run_tests()
integer = json_integer(5);
real = json_real(100.1);
if(!integer)
if (!integer)
fail("unable to create integer");
if(!real)
if (!real)
fail("unable to create real");
i = json_integer_value(integer);
if(i != 5)
if (i != 5)
fail("wrong integer value");
d = json_real_value(real);
if(d != 100.1)
if (d != 100.1)
fail("wrong real value");
d = json_number_value(integer);
if(d != 5.0)
if (d != 5.0)
fail("wrong number value");
d = json_number_value(real);
if(d != 100.1)
if (d != 100.1)
fail("wrong number value");
json_decref(integer);
@@ -71,14 +103,14 @@ static void run_tests()
#ifdef NAN
real = json_real(NAN);
if(real != NULL)
if (real != NULL)
fail("could construct a real from NaN");
real = json_real(1.0);
if(json_real_set(real, NAN) != -1)
if (json_real_set(real, NAN) != -1)
fail("could set a real to NaN");
if(json_real_value(real) != 1.0)
if (json_real_value(real) != 1.0)
fail("real value changed unexpectedly");
json_decref(real);
@@ -87,4 +119,5 @@ static void run_tests()
#ifdef INFINITY
test_inifity();
#endif
test_bad_args();
}

View File

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

View File

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

View File

@@ -5,88 +5,134 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <string.h>
#include <jansson.h>
#include "util.h"
#include <jansson.h>
#include <string.h>
static void test_bad_args(void) {
json_t *num = json_integer(1);
json_t *txt = json_string("test");
if (!num || !txt)
fail("failed to allocate test objects");
if (json_string_nocheck(NULL) != NULL)
fail("json_string_nocheck with NULL argument did not return NULL");
if (json_stringn_nocheck(NULL, 0) != NULL)
fail("json_stringn_nocheck with NULL argument did not return NULL");
if (json_string(NULL) != NULL)
fail("json_string with NULL argument did not return NULL");
if (json_stringn(NULL, 0) != NULL)
fail("json_stringn with NULL argument did not return NULL");
if (json_string_length(NULL) != 0)
fail("json_string_length with non-string argument did not return 0");
if (json_string_length(num) != 0)
fail("json_string_length with non-string argument did not return 0");
if (json_string_value(NULL) != NULL)
fail("json_string_value with non-string argument did not return NULL");
if (json_string_value(num) != NULL)
fail("json_string_value with non-string argument did not return NULL");
if (!json_string_setn_nocheck(NULL, "", 0))
fail("json_string_setn with non-string argument did not return error");
if (!json_string_setn_nocheck(num, "", 0))
fail("json_string_setn with non-string argument did not return error");
if (!json_string_setn_nocheck(txt, NULL, 0))
fail("json_string_setn_nocheck with NULL value did not return error");
if (!json_string_set_nocheck(txt, NULL))
fail("json_string_set_nocheck with NULL value did not return error");
if (!json_string_set(txt, NULL))
fail("json_string_set with NULL value did not return error");
if (!json_string_setn(txt, NULL, 0))
fail("json_string_setn with NULL value did not return error");
if (num->refcount != 1)
fail("unexpected reference count for num");
if (txt->refcount != 1)
fail("unexpected reference count for txt");
json_decref(num);
json_decref(txt);
}
/* Call the simple functions not covered by other tests of the public API */
static void run_tests()
{
static void run_tests() {
json_t *value;
value = json_boolean(1);
if(!json_is_true(value))
if (!json_is_true(value))
fail("json_boolean(1) failed");
json_decref(value);
value = json_boolean(-123);
if(!json_is_true(value))
if (!json_is_true(value))
fail("json_boolean(-123) failed");
json_decref(value);
value = json_boolean(0);
if(!json_is_false(value))
if (!json_is_false(value))
fail("json_boolean(0) failed");
if(json_boolean_value(value) != 0)
if (json_boolean_value(value) != 0)
fail("json_boolean_value failed");
json_decref(value);
value = json_integer(1);
if(json_typeof(value) != JSON_INTEGER)
if (json_typeof(value) != JSON_INTEGER)
fail("json_typeof failed");
if(json_is_object(value))
if (json_is_object(value))
fail("json_is_object failed");
if(json_is_array(value))
if (json_is_array(value))
fail("json_is_array failed");
if(json_is_string(value))
if (json_is_string(value))
fail("json_is_string failed");
if(!json_is_integer(value))
if (!json_is_integer(value))
fail("json_is_integer failed");
if(json_is_real(value))
if (json_is_real(value))
fail("json_is_real failed");
if(!json_is_number(value))
if (!json_is_number(value))
fail("json_is_number failed");
if(json_is_true(value))
if (json_is_true(value))
fail("json_is_true failed");
if(json_is_false(value))
if (json_is_false(value))
fail("json_is_false failed");
if(json_is_boolean(value))
if (json_is_boolean(value))
fail("json_is_boolean failed");
if(json_is_null(value))
if (json_is_null(value))
fail("json_is_null failed");
json_decref(value);
value = json_string("foo");
if(!value)
if (!value)
fail("json_string failed");
if(strcmp(json_string_value(value), "foo"))
if (strcmp(json_string_value(value), "foo"))
fail("invalid string value");
if (json_string_length(value) != 3)
fail("invalid string length");
if(json_string_set(value, "barr"))
if (json_string_set(value, "barr"))
fail("json_string_set failed");
if(strcmp(json_string_value(value), "barr"))
if (strcmp(json_string_value(value), "barr"))
fail("invalid string value");
if (json_string_length(value) != 4)
fail("invalid string length");
if(json_string_setn(value, "hi\0ho", 5))
if (json_string_setn(value, "hi\0ho", 5))
fail("json_string_set failed");
if(memcmp(json_string_value(value), "hi\0ho\0", 6))
if (memcmp(json_string_value(value), "hi\0ho\0", 6))
fail("invalid string value");
if (json_string_length(value) != 5)
fail("invalid string length");
@@ -94,32 +140,32 @@ static void run_tests()
json_decref(value);
value = json_string(NULL);
if(value)
if (value)
fail("json_string(NULL) failed");
/* invalid UTF-8 */
value = json_string("a\xefz");
if(value)
if (value)
fail("json_string(<invalid utf-8>) failed");
value = json_string_nocheck("foo");
if(!value)
if (!value)
fail("json_string_nocheck failed");
if(strcmp(json_string_value(value), "foo"))
if (strcmp(json_string_value(value), "foo"))
fail("invalid string value");
if (json_string_length(value) != 3)
fail("invalid string length");
if(json_string_set_nocheck(value, "barr"))
if (json_string_set_nocheck(value, "barr"))
fail("json_string_set_nocheck failed");
if(strcmp(json_string_value(value), "barr"))
if (strcmp(json_string_value(value), "barr"))
fail("invalid string value");
if (json_string_length(value) != 4)
fail("invalid string length");
if(json_string_setn_nocheck(value, "hi\0ho", 5))
if (json_string_setn_nocheck(value, "hi\0ho", 5))
fail("json_string_set failed");
if(memcmp(json_string_value(value), "hi\0ho\0", 6))
if (memcmp(json_string_value(value), "hi\0ho\0", 6))
fail("invalid string value");
if (json_string_length(value) != 5)
fail("invalid string length");
@@ -128,113 +174,114 @@ static void run_tests()
/* invalid UTF-8 */
value = json_string_nocheck("qu\xff");
if(!value)
if (!value)
fail("json_string_nocheck failed");
if(strcmp(json_string_value(value), "qu\xff"))
if (strcmp(json_string_value(value), "qu\xff"))
fail("invalid string value");
if (json_string_length(value) != 3)
fail("invalid string length");
if(json_string_set_nocheck(value, "\xfd\xfe\xff"))
if (json_string_set_nocheck(value, "\xfd\xfe\xff"))
fail("json_string_set_nocheck failed");
if(strcmp(json_string_value(value), "\xfd\xfe\xff"))
if (strcmp(json_string_value(value), "\xfd\xfe\xff"))
fail("invalid string value");
if (json_string_length(value) != 3)
fail("invalid string length");
json_decref(value);
value = json_integer(123);
if(!value)
if (!value)
fail("json_integer failed");
if(json_integer_value(value) != 123)
if (json_integer_value(value) != 123)
fail("invalid integer value");
if(json_number_value(value) != 123.0)
if (json_number_value(value) != 123.0)
fail("invalid number value");
if(json_integer_set(value, 321))
if (json_integer_set(value, 321))
fail("json_integer_set failed");
if(json_integer_value(value) != 321)
if (json_integer_value(value) != 321)
fail("invalid integer value");
if(json_number_value(value) != 321.0)
if (json_number_value(value) != 321.0)
fail("invalid number value");
json_decref(value);
value = json_real(123.123);
if(!value)
if (!value)
fail("json_real failed");
if(json_real_value(value) != 123.123)
if (json_real_value(value) != 123.123)
fail("invalid integer value");
if(json_number_value(value) != 123.123)
if (json_number_value(value) != 123.123)
fail("invalid number value");
if(json_real_set(value, 321.321))
if (json_real_set(value, 321.321))
fail("json_real_set failed");
if(json_real_value(value) != 321.321)
if (json_real_value(value) != 321.321)
fail("invalid real value");
if(json_number_value(value) != 321.321)
if (json_number_value(value) != 321.321)
fail("invalid number value");
json_decref(value);
value = json_true();
if(!value)
if (!value)
fail("json_true failed");
json_decref(value);
value = json_false();
if(!value)
if (!value)
fail("json_false failed");
json_decref(value);
value = json_null();
if(!value)
if (!value)
fail("json_null failed");
json_decref(value);
/* Test reference counting on singletons (true, false, null) */
value = json_true();
if(value->refcount != (size_t)-1)
fail("refcounting true works incorrectly");
if (value->refcount != (size_t)-1)
fail("refcounting true works incorrectly");
json_decref(value);
if(value->refcount != (size_t)-1)
fail("refcounting true works incorrectly");
if (value->refcount != (size_t)-1)
fail("refcounting true works incorrectly");
json_incref(value);
if(value->refcount != (size_t)-1)
fail("refcounting true works incorrectly");
if (value->refcount != (size_t)-1)
fail("refcounting true works incorrectly");
value = json_false();
if(value->refcount != (size_t)-1)
fail("refcounting false works incorrectly");
if (value->refcount != (size_t)-1)
fail("refcounting false works incorrectly");
json_decref(value);
if(value->refcount != (size_t)-1)
fail("refcounting false works incorrectly");
if (value->refcount != (size_t)-1)
fail("refcounting false works incorrectly");
json_incref(value);
if(value->refcount != (size_t)-1)
fail("refcounting false works incorrectly");
if (value->refcount != (size_t)-1)
fail("refcounting false works incorrectly");
value = json_null();
if(value->refcount != (size_t)-1)
fail("refcounting null works incorrectly");
if (value->refcount != (size_t)-1)
fail("refcounting null works incorrectly");
json_decref(value);
if(value->refcount != (size_t)-1)
fail("refcounting null works incorrectly");
if (value->refcount != (size_t)-1)
fail("refcounting null works incorrectly");
json_incref(value);
if(value->refcount != (size_t)-1)
fail("refcounting null works incorrectly");
if (value->refcount != (size_t)-1)
fail("refcounting null works incorrectly");
#ifdef json_auto_t
value = json_string("foo");
{
json_auto_t *test = json_incref(value);
/* Use test so GCC doesn't complain it is unused. */
if(!json_is_string(test))
if (!json_is_string(test))
fail("value type check failed");
}
if(value->refcount != 1)
fail("automatic decrement failed");
if (value->refcount != 1)
fail("automatic decrement failed");
json_decref(value);
#endif
test_bad_args();
}

View File

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

View File

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

View File

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

View File

@@ -22,68 +22,64 @@
#define failhdr fprintf(stderr, "%s:%d: ", __FILE__, __LINE__)
#define fail(msg) \
do { \
failhdr; \
fprintf(stderr, "%s\n", msg); \
exit(1); \
} while(0)
#define fail(msg) \
do { \
failhdr; \
fprintf(stderr, "%s\n", msg); \
exit(1); \
} while (0)
/* Assumes json_error_t error */
#define check_errors(code_, texts_, num_, source_, \
line_, column_, position_) \
do { \
int i_, found_ = 0; \
if(json_error_code(&error) != code_) { \
failhdr; \
fprintf(stderr, "code: %d != %d\n", \
json_error_code(&error), code_); \
exit(1); \
} \
for(i_ = 0; i_ < num_; i_++) { \
if(strcmp(error.text, texts_[i_]) == 0) { \
found_ = 1; \
break; \
} \
} \
if (!found_) { \
failhdr; \
if (num_ == 1) { \
fprintf(stderr, "text: \"%s\" != \"%s\"\n", error.text, texts_[0]); \
} else { \
fprintf(stderr, "text: \"%s\" does not match\n", error.text); \
} \
exit(1); \
} \
if(strcmp(error.source, source_) != 0) { \
failhdr; \
\
fprintf(stderr, "source: \"%s\" != \"%s\"\n", error.source, source_); \
exit(1); \
} \
if(error.line != line_) { \
failhdr; \
fprintf(stderr, "line: %d != %d\n", error.line, line_); \
exit(1); \
} \
if(error.column != column_) { \
failhdr; \
fprintf(stderr, "column: %d != %d\n", error.column, column_); \
exit(1); \
} \
if(error.position != position_) { \
failhdr; \
fprintf(stderr, "position: %d != %d\n", error.position, position_); \
exit(1); \
} \
} while(0)
#define check_errors(code_, texts_, num_, source_, line_, column_, position_) \
do { \
int i_, found_ = 0; \
if (json_error_code(&error) != code_) { \
failhdr; \
fprintf(stderr, "code: %d != %d\n", json_error_code(&error), code_); \
exit(1); \
} \
for (i_ = 0; i_ < num_; i_++) { \
if (strcmp(error.text, texts_[i_]) == 0) { \
found_ = 1; \
break; \
} \
} \
if (!found_) { \
failhdr; \
if (num_ == 1) { \
fprintf(stderr, "text: \"%s\" != \"%s\"\n", error.text, texts_[0]); \
} else { \
fprintf(stderr, "text: \"%s\" does not match\n", error.text); \
} \
exit(1); \
} \
if (strcmp(error.source, source_) != 0) { \
failhdr; \
\
fprintf(stderr, "source: \"%s\" != \"%s\"\n", error.source, source_); \
exit(1); \
} \
if (error.line != line_) { \
failhdr; \
fprintf(stderr, "line: %d != %d\n", error.line, line_); \
exit(1); \
} \
if (error.column != column_) { \
failhdr; \
fprintf(stderr, "column: %d != %d\n", error.column, column_); \
exit(1); \
} \
if (error.position != position_) { \
failhdr; \
fprintf(stderr, "position: %d != %d\n", error.position, position_); \
exit(1); \
} \
} while (0)
/* Assumes json_error_t error */
#define check_error(code_, text_, source_, line_, column_, position_) \
#define check_error(code_, text_, source_, line_, column_, position_) \
check_errors(code_, &text_, 1, source_, line_, column_, position_)
static void run_tests();
int main() {