Compare commits

...

131 Commits

Author SHA1 Message Date
Max Bruckner
99db5db9a4 Release version 1.4.6 2017-04-08 17:54:55 +02:00
Max Bruckner
bb5ab5916f Merge pull request #147 from DaveGamble/copy-paste-msvc
Fix copy pasting with MSVC
2017-04-08 17:26:02 +02:00
Max Bruckner
411c50f671 Don't redefine CJSON_EXPORT_SYMBOLS 2017-04-08 16:39:35 +02:00
Max Bruckner
ec2db50b6f dllexport symbols by default and add CJSON_IMPORT_SYMBOLS
This should fix copy pasting of the C and header files with the MSVC
compiler.
2017-04-08 15:54:14 +02:00
Max Bruckner
74d0525201 Merge pull request #146 from DaveGamble/locale-independence
Locale independence
2017-04-08 14:46:22 +02:00
Max Bruckner
3efef58c32 README: Add setlocale to caveats 2017-04-08 03:50:22 +02:00
Max Bruckner
65541b900c Update space requirements of cJSON_PrintPreallocated 2017-04-08 03:42:44 +02:00
Max Bruckner
c08f7e1d29 print_number: Make locale independent
This first prints the number into a temporary buffer and then copies the
number to the output.

A positive side effect is that cJSON no longer reserves more space for
the number in the output than is necessary.
2017-04-08 03:38:49 +02:00
Max Bruckner
71b96afc27 print_number: Fix comment (missing word 'zeroes') 2017-04-08 02:46:24 +02:00
Max Bruckner
749fefc0c4 Make parse_number locale independent 2017-04-08 02:41:36 +02:00
Max Bruckner
50b3c30dfa README: Add Caveats section 2017-04-08 02:19:27 +02:00
Max Bruckner
c784f76c77 cJSON_strdup: Use sizeof("") instead of 1 2017-04-08 01:29:19 +02:00
Max Bruckner
84237ff48e Replace sizeof('\0') with sizeof("")
Because sizeof('\0') is actually sizeof(int) not sizeof(char).
2017-04-08 01:29:19 +02:00
Max Bruckner
ab8489a851 Readme: Fix #143 item->name --> item->string 2017-04-06 09:56:23 +02:00
Max Bruckner
795c3acabe cJSON_Utils: Fix potential null pointer dereference
Found by coverity
2017-04-05 17:36:25 +02:00
Max Bruckner
2683d4d987 ensure: Fix overflow detection 2017-04-05 16:35:55 +02:00
Max Bruckner
3c1bfe125c Clarify deprecation of valueint 2017-04-02 23:24:53 +02:00
Max Bruckner
5916f70640 cJSON.h: Deprecate valueint 2017-04-01 22:56:04 +02:00
Max Bruckner
29cfc7a767 README: Get rid of valueint and do necessary checks 2017-04-01 22:24:48 +02:00
Max Bruckner
b1e9a6c0da README: Add missing round brackets 2017-04-01 22:24:27 +02:00
Max Bruckner
3a20692c18 Release version 1.4.5 2017-03-28 17:39:39 +02:00
Max Bruckner
2f65e80a34 Fix internal compiler error in GCC on x86 2017-03-28 17:32:20 +02:00
Max Bruckner
ef34500693 cJSON_SetNumberHelper: Fix valueint, closes #138
Thanks @mmkeeper
2017-03-28 17:29:52 +02:00
Max Bruckner
b0dfcde04c Release Version 1.4.4 2017-03-23 22:13:25 +01:00
Max Bruckner
1934059554 ensure: Validate buffer offset 2017-03-23 22:01:38 +01:00
Max Bruckner
cc84a446be ensure: Fix potential off by one error. 2017-03-23 22:01:16 +01:00
Max Bruckner
e58f7ec027 ensure: Fix potential overflow of size_t
This could only happen if the maximum SIZE_T is not at least 2 times
bigger than INT_MAX. Not sure if this can happen on real systems, but
better be safe then sorry.
2017-03-23 20:26:29 +01:00
Max Bruckner
4bfb880093 cJSON.h: Note about buffer size for cJSON_PrintPreallocated 2017-03-22 16:39:10 +01:00
Max Bruckner
b7ce06224b Release version 1.4.3 2017-03-19 11:05:33 +01:00
Max Bruckner
227d3398d6 Fix the pragmas for Wcast-qual with old gcc versions 2017-03-18 17:52:33 +01:00
Max Bruckner
466eb8e3f8 Fix wconversion with old gcc (e.g. 4.3) 2017-03-18 17:52:04 +01:00
Max Bruckner
4ec6e76ea2 tests: print_number: Fix build on 32bit ppc (and potentially others) 2017-03-18 13:25:18 +01:00
Max Bruckner
a1b37d0abe Release Version 1.4.2 2017-03-16 01:28:23 +01:00
Max Bruckner
3d971db426 README: Mention supported cmake and make versions 2017-03-16 01:25:57 +01:00
Max Bruckner
30e1e7af7c CMake: Support cmake down to 2.8.5 2017-03-16 01:09:26 +01:00
Max Bruckner
76e5296d0d CMake: Fix per target disabling of compiler flags
The compiler flag detection was working incorrectly.
2017-03-16 00:22:53 +01:00
Max Bruckner
c597601cf1 tests: run cJSON_test{,_utils} along with the other tests 2017-03-15 20:11:19 +01:00
Max Bruckner
e3d5798896 Release version 1.4.1 2017-03-15 20:11:19 +01:00
Max Bruckner
cf1842dc6f fix: print_number didn't abort when out of memory 2017-03-15 00:09:45 +01:00
Max Bruckner
030d0c14cc Merge branch 'develop' (Release 1.4.0) 2017-03-03 23:26:52 +01:00
Max Bruckner
02cd3eec37 Update version number to 1.4.0 2017-03-03 23:21:53 +01:00
Max Bruckner
bdb59f09de Add contributing guideline 2017-03-03 22:14:11 +01:00
Max Bruckner
5f783fff11 cJSON_Utils: Add gcc pragma to use default visibility for system headers 2017-03-03 00:45:50 +01:00
Max Bruckner
7969af6434 Merge pull request #124 from DaveGamble/print-bool-return
Print functions: Return boolean values instead of pointers
2017-03-03 00:42:01 +01:00
Max Bruckner
0bb1843925 print_value: return as soon as possible 2017-03-03 00:40:02 +01:00
Max Bruckner
5ea4fad263 print_string: return boolean instead of pointer 2017-03-03 00:33:11 +01:00
Max Bruckner
1749de02f8 print_number: return boolean instead of pointer 2017-03-03 00:26:58 +01:00
Max Bruckner
748f4bfd4f print_object: return boolean instead of pointer 2017-03-03 00:21:34 +01:00
Max Bruckner
bea1d102fd print_array: return boolean instead of pointer 2017-03-03 00:16:54 +01:00
Max Bruckner
d441fa05b3 print_value: return boolean instead of pointer 2017-03-03 00:11:43 +01:00
Max Bruckner
3fe72cf2b8 fuzzing: afl.c: Fix printing usage 2017-03-02 23:57:05 +01:00
Max Bruckner
d8d0ae66d3 print_number: Fix incorrect output pointer 2017-03-02 23:57:01 +01:00
Max Bruckner
9d07917feb utf16_literal_to_utf8: Eliminate Duff's Device
This fixes -Wimplicit-fallthrough warnings with GCC7.
2017-03-02 13:46:31 +01:00
Max Bruckner
ad5abf4c5b Update unity with fixes for compiler warnings 2017-03-01 23:20:30 +01:00
Max Bruckner
2c45ad7816 Squashed 'tests/unity/' changes from 2988e98..1f52255
1f52255 Merge pull request #267 from FSMaxB/fix-wconversion
7bce0b4 Fix warning with ubsan and -Wconversion
b5da224 Merge pull request #266 from FSMaxB/fix-double-promotion
1bf22d3 Fix warnings with -Wdouble-promotion

git-subtree-dir: tests/unity
git-subtree-split: 1f522558a6c4577aa937341bf856ba3b1436768a
2017-03-01 23:20:30 +01:00
Max Bruckner
6405fd15e3 CMake: Set default visibility to hidden and dllexport on windows 2017-03-01 23:19:35 +01:00
Max Bruckner
b44c917be9 tests/common: use CJSON_PUBLIC 2017-03-01 23:16:19 +01:00
Max Bruckner
2d3520e0b9 Use own cJSON_bool boolean type in the header 2017-03-01 22:50:12 +01:00
Max Bruckner
2e118df0cd tests/common.h: Remove unused prototype 2017-03-01 22:47:45 +01:00
Max Bruckner
412f4f7d62 Use CJSON_PUBLIC for typecheck functions 2017-03-01 22:47:45 +01:00
Max Bruckner
0aea75fbda Merge pull request #123 from DaveGamble/trim-numbers
Remove traling zeroes when printing floating point numbers
2017-03-01 18:38:48 +01:00
Max Bruckner
0c0dd4a5b0 tests: test trim_trailing_zeroes 2017-03-01 18:29:01 +01:00
Max Bruckner
dd4cb5400f print_number: Remove unnecessary integer handling 2017-03-01 13:28:27 +01:00
Max Bruckner
1ea72f8260 print_number: Remove trailing zeroes (for doubles) 2017-03-01 13:22:32 +01:00
Max Bruckner
e78bc42362 print_number: Return buffer + offset instead of beginning of the number 2017-03-01 13:00:52 +01:00
Max Bruckner
6f271e511f print_number: Use sprintf's return value
This is used to update the buffer offset and determine success
2017-03-01 12:56:32 +01:00
Max Bruckner
bee069b4e7 Merge pull request #122 from DaveGamble/more-compiler-flags
Add more compiler flags
2017-03-01 12:30:12 +01:00
Max Bruckner
1e0bd24f2c Revert "unity: make it work with -Wconversion"
This reverts commit 12acc57967.
2017-03-01 11:57:07 +01:00
Max Bruckner
5cf56fa4fa Add -Wparentheses compile option 2017-03-01 11:57:07 +01:00
Max Bruckner
3f349a4258 Add -Wdouble-promotion compiler flag 2017-03-01 11:57:07 +01:00
Max Bruckner
40e3781e9b CMake: Disable -Werror for Unity 2017-03-01 11:57:07 +01:00
Max Bruckner
b056d7cb74 Add -Wcomma compiler flag 2017-03-01 11:57:06 +01:00
Max Bruckner
1f422b586a Squashed 'tests/unity/' changes from 1782bab..2988e98
2988e98 Merge pull request #262 from codehearts/patch-2
1732698 Fixed incorrect TEST_PROTECT explanation in readme
3817375 Merge pull request #260 from jeremyhannon/parseUnityFixtureOutputToJUnitFormat
9d5159f Merge pull request #261 from codehearts/patch-1
65ce727 Fixed typo for TEST_PROTECT in readme
4dc04d3 Enhance parseOutput.rb to support Unity fixture output

git-subtree-dir: tests/unity
git-subtree-split: 2988e980fbc2252fa4290b608517d4ae25cd9a46
2017-03-01 09:23:18 +01:00
Max Bruckner
899529e866 Update unity 2017-03-01 09:23:18 +01:00
Max Bruckner
2837aac23e Contributors: Add Mike Jerris 2017-02-28 23:04:29 +01:00
Max Bruckner
c66d95d116 Release bugfix release 1.3.2 2017-02-28 21:43:02 +01:00
Max Bruckner
cb6df3ffad Merge pull request #121 from ffontaine/master
Do not build unity library if tests are disabled
2017-02-28 21:34:29 +01:00
Fabrice Fontaine
695d8a01a9 Do not build unity library if tests are disabled
Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2017-02-28 20:48:04 +01:00
Max Bruckner
024f690289 Merge pull request #116 from mjerris/fschanges
add CJSON_DECLARE macros to support gcc visibility and windows dllexport
2017-02-27 21:51:55 +01:00
Mike Jerris
039b1cc653 add CJSON_PUBLIC macro to public functions to support visibility and dllimport/dllexport 2017-02-27 13:47:06 -06:00
Max Bruckner
c0ff1fef9b Release 1.3.1 2017-02-26 22:04:22 +01:00
Max Bruckner
2302f4f0b2 Merge pull request #120 from DaveGamble/typecheck-functions
Typecheck functions
2017-02-26 22:00:28 +01:00
Max Bruckner
c45dc12fd7 Tests for typecheck functions 2017-02-26 21:54:01 +01:00
Max Bruckner
ed8dc53699 cJSON_Utils: Use new typecheck functions 2017-02-26 21:26:34 +01:00
Max Bruckner
c26d53f0d7 Helper function to check the type of an item
This is necessary, because you can get it wrong if you do it manually.
(when you forget the & 0xFF in the comparison)
2017-02-26 14:30:50 +01:00
Max Bruckner
29f312dd69 Merge pull request #118 from mjerris/parser
prevent read beyond end of buffer when string ends with malformed utf
2017-02-26 13:12:26 +01:00
Mike Jerris
72e6e23523 prevent read beyond end of buffer when string ends with malformed utf 2017-02-23 08:59:25 -06:00
Max Bruckner
501046247d fix clang-sanitizer warnings 2017-02-21 15:08:36 +01:00
Max Bruckner
68cd0d4a11 cJSON.c: Pass allocation functions through internal functions
This is the first step in removing the global allocator functions. Every
internal function now only accesses its locally available set of
allocators.
2017-02-21 14:50:49 +01:00
Max Bruckner
56b819bfbc tests: test cJSON_GetObjectItem and cJSON_GetObjectItemCaseSensitive 2017-02-21 11:17:08 +01:00
Max Bruckner
605422c60a cJSON: New function cJSON_GetObjectItemCaseSensitive 2017-02-21 11:17:08 +01:00
Max Bruckner
cbbcc91498 tests: cJSON_ArrayForEach 2017-02-21 09:17:49 +01:00
Max Bruckner
b47d0e34ca cJSON_ArrayForEach: Fix handling of NULL pointers 2017-02-21 09:17:34 +01:00
Max Bruckner
bc12c69b54 Merge pull request #114 from DaveGamble/simplify-print
Simplify print functions
2017-02-20 23:09:06 +01:00
Max Bruckner
1d42c9bc60 print_object: simplify code 2017-02-20 23:07:24 +01:00
Max Bruckner
b71db93e03 print_object: rename variables 2017-02-20 23:07:24 +01:00
Max Bruckner
6d5a7c8c40 print_array: simplify code 2017-02-20 23:07:24 +01:00
Max Bruckner
8c1ed3ab82 update: rename to update_offset and change offset directly 2017-02-20 23:07:24 +01:00
Max Bruckner
f16dd7e028 print_array: rename variables 2017-02-20 23:07:24 +01:00
Max Bruckner
08770fc246 print_value: rename variables 2017-02-20 23:07:23 +01:00
Max Bruckner
0ca8587acc print_string_ptr: simplify code 2017-02-20 23:07:23 +01:00
Max Bruckner
88e38d042f tests: print_string: test if NULL is printed as empty string 2017-02-20 23:07:23 +01:00
Max Bruckner
6a746a230a print_string: Add more const 2017-02-20 23:07:23 +01:00
Max Bruckner
1e999352d3 print_string_ptr: rename variables 2017-02-20 23:07:23 +01:00
Max Bruckner
6815d96617 print_number: rename variables 2017-02-20 23:07:22 +01:00
Max Bruckner
61921498d0 print_number: remove special case for 0
Now that printbuffer is used for everything, it's not needed anymore.
2017-02-20 23:07:22 +01:00
Max Bruckner
4758d62fd4 Merge pull request #113 from DaveGamble/printbuffer-only
Always print with printbuffer
2017-02-20 23:06:58 +01:00
Max Bruckner
1bc1a9748a Merge pull request #112 from DaveGamble/print-tests
Add tests for print functions
2017-02-20 11:15:53 +01:00
Max Bruckner
de36476092 tests: print_value 2017-02-20 11:11:02 +01:00
Max Bruckner
983a4cd286 tests: parse_objects: Fix name of test 2017-02-20 11:11:01 +01:00
Max Bruckner
b6abef94ff tests: print_object 2017-02-20 11:11:01 +01:00
Max Bruckner
3d66766231 tests: print_array 2017-02-20 11:11:01 +01:00
Max Bruckner
924122904e tests: print_number 2017-02-20 11:11:01 +01:00
Max Bruckner
87691a86e5 cJSON_SetNumberValue: Fix compiler warning with -Waddress 2017-02-20 11:11:01 +01:00
Max Bruckner
8aa324fdc8 tests: print_string 2017-02-20 11:11:01 +01:00
Max Bruckner
3c4d309f62 ensure: Don't accept empty printbuffers anymore 2017-02-19 04:20:21 +01:00
Max Bruckner
9bf531ca05 Remove printing without buffer 2017-02-19 04:16:57 +01:00
Max Bruckner
80354bdb06 cJSON_Print: Use printbuffer 2017-02-19 04:03:02 +01:00
Max Bruckner
fe2e0956ad Merge pull request #111 from DaveGamble/fuzzing
partial build system integration of the afl fuzzing tool
2017-02-19 02:44:28 +01:00
Max Bruckner
cf71f3d627 fuzzing: script to prepare linux kernel for afl 2017-02-18 13:18:09 +01:00
Max Bruckner
da551c753f fuzzing: Speed up afl using persistent mode (in proccess fuzzing) 2017-02-18 13:18:09 +01:00
Max Bruckner
ae4681b787 fuzzing: use llvm source code instrumentation 2017-02-18 13:18:08 +01:00
Max Bruckner
c5a09a32a9 fuzzing: Fuzz different print methods
This is achieved by encoding the type of function used in the first two
bytes.

First byte:
b: buffered

Second byte:
f: formatted
2017-02-18 13:18:08 +01:00
Max Bruckner
4785070ad3 fuzzing: Fuzz printing as well.
With one big limitation: It can only be fuzzed with what has been
parsed by the library beforehand.
2017-02-18 12:52:16 +01:00
Max Bruckner
0e0cd5bae5 CMake: Add ENABLE_FUZZING and "afl" target 2017-02-18 12:52:16 +01:00
Max Bruckner
44512f643e Merge pull request #110 from DaveGamble/ensure-improvements
ensure improvements
2017-02-18 12:18:18 +01:00
Max Bruckner
331c18d09a ensure: only memcopy what's necessary
We don't need to copy the entire printbuffer, only the part that is
used.
2017-02-18 12:07:17 +01:00
Max Bruckner
4fff92140e ensure: use realloc if possible 2017-02-18 12:07:17 +01:00
Max Bruckner
fc1d4b07df ensure: if printbuffer is null: cJSON_malloc
This allowed for the removal of a lot of if (p) checks.
2017-02-18 11:35:59 +01:00
Max Bruckner
bd073343fa rename skip -> skip_whitespace 2017-02-17 19:37:31 +01:00
Max Bruckner
7c722dca5f CMake: Add target "check" that builds and runs tests 2017-02-17 13:59:26 +01:00
47 changed files with 2426 additions and 990 deletions

54
.github/CONTRIBUTING.md vendored Normal file
View File

@@ -0,0 +1,54 @@
Contribution Guidelines
=======================
Contributions to cJSON are welcome. If you find a bug or want to improve cJSON in another way, pull requests are appreciated.
For bigger changes, in order to avoid wasted effort, please open an issue to discuss the technical details before creating a pull request.
The further sections explain the process in more detail and provides some guidelines on how contributions should look like.
Branches
--------
There are two branches to be aware of, the `master` and the `develop` branch. The `master` branch is reserved for the latest release, so only make pull requests to the `master` branch for small bug- or security fixes (these are usually just a few lines). In all other cases, please make a pull request to the `develop` branch.
Coding Style
------------
The coding style has been discussed in [#24](https://github.com/DaveGamble/cJSON/issues/24). The basics are:
* Use 4 tabs for indentation
* No oneliners (conditions, loops, variable declarations ...)
* Always use parenthesis for control structures
* Don't implicitly rely on operator precedence, use round brackets in expressions. e.g. `(a > b) && (c < d)` instead of `a>b && c<d`
* opening curly braces start in the next line
* use spaces around operators
* lines should not have trailing whitespace
* use spaces between function parameters
* use pronouncable variable names, not just a combination of letters
Example:
```c
/* calculate the new length of the string in a printbuffer and update the offset */
static void update_offset(printbuffer * const buffer)
{
const unsigned char *buffer_pointer = NULL;
if ((buffer == NULL) || (buffer->buffer == NULL))
{
return;
}
buffer_pointer = buffer->buffer + buffer->offset;
buffer->offset += strlen((const char*)buffer_pointer);
}
```
Unit Tests
----------
cJSON uses the [Unity](https://github.com/ThrowTheSwitch/Unity) library for unit tests. The tests are located in the `tests` directory. In order to add a new test, either add it to one of the existing files (if it fits) or add a new C file for the test. That new file has to be added to the list of tests in `tests/CMakeLists.txt`.
All new features have to be covered by unit tests.
Other Notes
-----------
* Internal functions are to be declared static.
* Wrap the return type of external function in the `CJSON_PUBLIC` macro.

View File

@@ -1,15 +1,13 @@
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
cmake_minimum_required(VERSION 2.8)
subdirs(tests)
cmake_minimum_required(VERSION 2.8.5)
include(GNUInstallDirs)
project(cJSON C)
set(PROJECT_VERSION_MAJOR 1)
set(PROJECT_VERSION_MINOR 3)
set(PROJECT_VERSION_PATCH 0)
set(PROJECT_VERSION_MINOR 4)
set(PROJECT_VERSION_PATCH 6)
set(CJSON_VERSION_SO 1)
set(CJSON_UTILS_VERSION_SO 1)
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
@@ -40,6 +38,9 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS)
-Wconversion
-Wc++-compat
-fstack-protector-strong
-Wcomma
-Wdouble-promotion
-Wparentheses
)
endif()
@@ -58,6 +59,16 @@ if (ENABLE_SANITIZERS)
)
endif()
option(ENABLE_PUBLIC_SYMBOLS "Export library symbols." On)
if (ENABLE_PUBLIC_SYMBOLS)
list(APPEND custom_compiler_flags -fvisibility=hidden)
add_definitions(-DCJSON_EXPORT_SYMBOLS -DCJSON_API_VISIBILITY)
endif()
option(ENABLE_HIDDEN_SYMBOLS "Hide library symbols." Off)
if (ENABLE_HIDDEN_SYMBOLS)
add_definitions(-DCJSON_HIDE_SYMBOLS -UCJSON_API_VISIBILITY)
endif()
# apply custom compiler flags
foreach(compiler_flag ${custom_compiler_flags})
#remove problematic characters
@@ -65,10 +76,13 @@ foreach(compiler_flag ${custom_compiler_flags})
CHECK_C_COMPILER_FLAG(${compiler_flag} "FLAG_SUPPORTED_${current_variable}")
if (FLAG_SUPPORTED_${current_variable})
list(APPEND supported_compiler_flags)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${compiler_flag}")
endif()
endforeach()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${supported_compiler_flags}")
#variables for pkg-config
set(prefix "${CMAKE_INSTALL_PREFIX}")
set(libdir "${CMAKE_INSTALL_LIBDIR}")
@@ -154,9 +168,30 @@ if(ENABLE_CJSON_TEST)
add_executable("${TEST_CJSON}" test.c)
target_link_libraries("${TEST_CJSON}" "${CJSON_LIB}")
add_test(NAME ${TEST_CJSON} COMMAND "${CMAKE_CURRENT_BINARY_DIR}/${TEST_CJSON}")
# Disable -fsanitize=float-divide-by-zero for cJSON_test
if (FLAG_SUPPORTED_fsanitizefloatdividebyzero)
if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize=float-divide-by-zero")
else()
target_compile_options(${TEST_CJSON} PRIVATE "-fno-sanitize=float-divide-by-zero")
endif()
endif()
if(ENABLE_CJSON_UTILS)
set(TEST_CJSON_UTILS cJSON_test_utils)
add_executable("${TEST_CJSON_UTILS}" test_utils.c)
target_link_libraries("${TEST_CJSON_UTILS}" "${CJSON_UTILS_LIB}")
add_test(NAME ${TEST_CJSON_UTILS} COMMAND "${CMAKE_CURRENT_BINARY_DIR}/${TEST_CJSON_UTILS}")
endif()
#"check" target that automatically builds everything and runs the tests
add_custom_target(check
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
DEPENDS ${TEST_CJSON} ${TEST_CJSON_UTILS})
endif()
add_subdirectory(tests)
add_subdirectory(fuzzing)

View File

@@ -21,6 +21,7 @@ Contributors
* [Linus Wallgren](https://github.com/ecksun)
* [Max Bruckner](https://github.com/FSMaxB)
* Mike Pontillo
* [Mike Jerris](https://github.com/mjerris)
* Paulo Antonio Alvarez
* [Rafael Leal Dias](https://github.com/rafaeldias)
* [Rod Vagg](https://github.com/rvagg)

View File

@@ -10,7 +10,7 @@ UTILS_TEST_SRC = cJSON.c cJSON_Utils.c test_utils.c
LDLIBS = -lm
LIBVERSION = 1.3.0
LIBVERSION = 1.4.6
CJSON_SOVERSION = 1
UTILS_SOVERSION = 1

View File

@@ -9,6 +9,7 @@ Ultralightweight JSON parser in ANSI C.
* [Building](#building)
* [Some JSON](#some-json)
* [Here's the structure](#heres-the-structure)
* [Caveats](#caveats)
* [Enjoy cJSON!](#enjoy-cjson)
## License
@@ -62,7 +63,7 @@ Because the entire library is only one C file and one header file, you can just
cJSON is written in ANSI C (C89) in order to support as many platforms and compilers as possible.
#### CMake
With CMake, cJSON supports a full blown build system. This way you get the most features. With CMake it is recommended to do an out of tree build, meaning the compiled files are put in a directory separate from the source files. So in order to build cJSON with CMake on a Unix platform, make a `build` directory and run CMake inside it.
With CMake, cJSON supports a full blown build system. This way you get the most features. CMake with an equal or higher version than 2.8.5 is supported. With CMake it is recommended to do an out of tree build, meaning the compiled files are put in a directory separate from the source files. So in order to build cJSON with CMake on a Unix platform, make a `build` directory and run CMake inside it.
```
mkdir build
@@ -97,10 +98,8 @@ make
make DESTDIR=$pkgdir install
```
CMake supports a lot of different platforms, not only UNIX Makefiles, but only UNIX Makefiles have been tested. It works on GNU/Linux and has been confirmed to compile on some versions of macOS, Cygwin, FreeBSD, Solaris and OpenIndiana.
#### Makefile
If you don't have CMake available, but still have make. You can use the makefile to build cJSON:
If you don't have CMake available, but still have GNU make. You can use the makefile to build cJSON:
Run this command in the directory with the source code and it will automatically compile static and shared libraries and a little test program.
@@ -138,13 +137,19 @@ What's the framerate?
```c
cJSON *format = cJSON_GetObjectItem(root, "format");
int framerate = cJSON_GetObjectItem(format, "frame rate")->valueint;
cJSON *framerate_item = cJSON_GetObjectItem(format, "frame rate");
double framerate = 0;
if (cJSON_IsNumber(framerate_item))
{
framerate = framerate_item->valuedouble;
}
```
Want to change the framerate?
```c
cJSON_GetObjectItem(format, "frame rate")->valueint = 25;
cJSON *framerate_item = cJSON_GetObjectItem(format, "frame rate");
cJSON_SetNumberValue(framerate_item, 25);
```
Back to disk?
@@ -203,7 +208,7 @@ typedef struct cJSON {
int type;
char *valuestring;
int valueint;
int valueint; /* writing to valueint is DEPRECATED, please use cJSON_SetNumberValue instead */
double valuedouble;
char *string;
@@ -219,8 +224,7 @@ A `child` entry will have `prev == 0`, but next potentially points on. The last
The type expresses *Null*/*True*/*False*/*Number*/*String*/*Array*/*Object*, all of which are `#defined` in
`cJSON.h`.
A *Number* has `valueint` and `valuedouble`. If you're expecting an `int`, read `valueint`, if not read
`valuedouble`.
A *Number* has `valueint` and `valuedouble`. `valueint` is a relict of the past, so always use `valuedouble`.
Any entry which is in the linked list which is the child of an object will have a `string`
which is the "name" of the entry. When I said "name" in the above example, that's `string`.
@@ -237,8 +241,8 @@ void parse_and_callback(cJSON *item, const char *prefix)
{
while (item)
{
char *newprefix = malloc(strlen(prefix) + strlen(item->name) + 2);
sprintf(newprefix, "%s/%s", prefix, item->name);
char *newprefix = malloc(strlen(prefix) + strlen(item->string) + 2);
sprintf(newprefix, "%s/%s", prefix, item->string);
int dorecurse = callback(newprefix, item->type, item);
if (item->child && dorecurse)
{
@@ -261,22 +265,22 @@ int callback(const char *name, int type, cJSON *item)
{
/* populate name */
}
else if (!strcmp(name, "format/type")
else if (!strcmp(name, "format/type"))
{
/* handle "rect" */ }
else if (!strcmp(name, "format/width")
else if (!strcmp(name, "format/width"))
{
/* 800 */
}
else if (!strcmp(name, "format/height")
else if (!strcmp(name, "format/height"))
{
/* 600 */
}
else if (!strcmp(name, "format/interlace")
else if (!strcmp(name, "format/interlace"))
{
/* false */
}
else if (!strcmp(name, "format/frame rate")
else if (!strcmp(name, "format/frame rate"))
{
/* 24 */
}
@@ -369,6 +373,29 @@ The `test.c` code shows how to handle a bunch of typical cases. If you uncomment
the code, it'll load, parse and print a bunch of test files, also from [json.org](http://json.org),
which are more complex than I'd care to try and stash into a `const char array[]`.
### Caveats
#### C Standard
cJSON is written in ANSI C (or C89, C90). If your compiler or C library doesn't follow this standard, correct behavior is not guaranteed.
NOTE: ANSI C is not C++ therefore it shouldn't be compiled by a C++ compiler. You can compile it with a C compiler and link it with your C++ code however. Although compiling with a C++ compiler might work, correct behavior is not guaranteed.
#### Floating Point Numbers
cJSON does not officially support any `double` implementations other than IEE754 double precision floating point numbers. It might still work with other implementations but bugs with these will be considered invalid.
The maximum length of a floating point literal that cJSON supports is currently 63 characters.
#### Thread Safety
In general cJSON is **not thread safe**.
However it is thread safe under the following conditions:
* `cJSON_GetErrorPtr` is never used (the `return_parse_end` parameter of `cJSON_ParseWithOpts` can be used instead)
* `cJSON_InitHooks` is only ever called before using cJSON in any threads.
* `setlocale` is never called before all calls to cJSON functions have returned.
# Enjoy cJSON!
- Dave Gamble, Aug 2009

1622
cJSON.c

File diff suppressed because it is too large Load Diff

159
cJSON.h
View File

@@ -30,11 +30,8 @@ extern "C"
/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 3
#define CJSON_VERSION_PATCH 0
/* returns the version of cJSON as a string */
extern const char* cJSON_Version(void);
#define CJSON_VERSION_MINOR 4
#define CJSON_VERSION_PATCH 6
#include <stddef.h>
@@ -66,7 +63,7 @@ typedef struct cJSON
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* The item's number, if type==cJSON_Number */
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
@@ -81,84 +78,146 @@ typedef struct cJSON_Hooks
void (*free_fn)(void *ptr);
} cJSON_Hooks;
typedef int cJSON_bool;
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif
#ifdef __WINDOWS__
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options:
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
For *nix builds that support visibility attribute, you can define similar behavior by
setting default visibility to hidden by adding
-fvisibility=hidden (for gcc)
or
-xldscope=hidden (for sun cc)
to CFLAGS
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
*/
/* export symbols by default, this is necessary for copy pasting the C and header file */
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_EXPORT_SYMBOLS
#endif
#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type) type __stdcall
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall
#endif
#else /* !WIN32 */
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#else
#define CJSON_PUBLIC(type) type
#endif
#endif
/* returns the version of cJSON as a string */
CJSON_PUBLIC(const char*) cJSON_Version(void);
/* Supply malloc, realloc and free functions to cJSON */
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
extern cJSON *cJSON_Parse(const char *value);
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
extern char *cJSON_Print(const cJSON *item);
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
extern char *cJSON_PrintUnformatted(const cJSON *item);
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
extern char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, int fmt);
/* Render a cJSON entity to text using a buffer already allocated in memory with length buf_len. Returns 1 on success and 0 on failure. */
extern int cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const int fmt);
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
/* Delete a cJSON entity and all subentities. */
extern void cJSON_Delete(cJSON *c);
CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
/* Returns the number of items in an array (or object). */
extern int cJSON_GetArraySize(const cJSON *array);
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
extern cJSON *cJSON_GetArrayItem(const cJSON *array, int item);
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int item);
/* Get item "string" from object. Case insensitive. */
extern cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string);
extern int cJSON_HasObjectItem(const cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON *object, const char *string);
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
extern const char *cJSON_GetErrorPtr(void);
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
/* These calls create a cJSON item of the appropriate type. */
extern cJSON *cJSON_CreateNull(void);
extern cJSON *cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateBool(int b);
extern cJSON *cJSON_CreateNumber(double num);
extern cJSON *cJSON_CreateString(const char *string);
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* raw json */
extern cJSON *cJSON_CreateRaw(const char *raw);
extern cJSON *cJSON_CreateArray(void);
extern cJSON *cJSON_CreateObject(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
/* These utilities create an Array of count items. */
extern cJSON *cJSON_CreateIntArray(const int *numbers, int count);
extern cJSON *cJSON_CreateFloatArray(const float *numbers, int count);
extern cJSON *cJSON_CreateDoubleArray(const double *numbers, int count);
extern cJSON *cJSON_CreateStringArray(const char **strings, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
/* Append item to the specified array/object. */
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
* writing to `item->string` */
extern void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
/* Remove/Detatch items from Arrays/Objects. */
extern cJSON *cJSON_DetachItemFromArray(cJSON *array, int which);
extern void cJSON_DeleteItemFromArray(cJSON *array, int which);
extern cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string);
extern void cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
/* Update array items. */
extern void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
extern void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
extern cJSON *cJSON_Duplicate(const cJSON *item, int recurse);
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
need to be released. With recurse!=0, it will duplicate any children connected to the item.
The item->next and ->prev pointers are always zero on return from Duplicate. */
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */
extern cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
extern void cJSON_Minify(char *json);
CJSON_PUBLIC(void) cJSON_Minify(char *json);
/* Macros for creating things quickly. */
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
@@ -172,11 +231,11 @@ extern void cJSON_Minify(char *json);
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/* helper for the cJSON_SetNumberValue macro */
extern double cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object) ? cJSON_SetNumberHelper(object, (double)number) : (number))
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
/* Macro for iterating over an array */
#define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next)
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
#ifdef __cplusplus
}

View File

@@ -1,8 +1,10 @@
#pragma GCC visibility push(default)
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#pragma GCC visibility pop
#include "cJSON_Utils.h"
@@ -31,7 +33,7 @@ static int cJSONUtils_strcasecmp(const unsigned char *s1, const unsigned char *s
{
return 1;
}
for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)
for(; tolower(*s1) == tolower(*s2); (void)++s1, ++s2)
{
if(*s1 == 0)
{
@@ -49,7 +51,7 @@ static int cJSONUtils_Pstrcasecmp(const unsigned char *a, const unsigned char *e
{
return (a == e) ? 0 : 1; /* both NULL? */
}
for (; *a && *e && (*e != '/'); a++, e++) /* compare until next '/' */
for (; *a && *e && (*e != '/'); (void)a++, e++) /* compare until next '/' */
{
if (*e == '~')
{
@@ -81,7 +83,7 @@ static int cJSONUtils_Pstrcasecmp(const unsigned char *a, const unsigned char *e
static size_t cJSONUtils_PointerEncodedstrlen(const unsigned char *s)
{
size_t l = 0;
for (; *s; s++, l++)
for (; *s; (void)s++, l++)
{
if ((*s == '~') || (*s == '/'))
{
@@ -115,9 +117,8 @@ static void cJSONUtils_PointerEncodedstrcpy(unsigned char *d, const unsigned cha
*d = '\0';
}
char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target)
CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target)
{
int type = object->type;
size_t c = 0;
cJSON *obj = 0;
@@ -128,12 +129,12 @@ char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target)
}
/* recursively search all children of the object */
for (obj = object->child; obj; obj = obj->next, c++)
for (obj = object->child; obj; (void)(obj = obj->next), c++)
{
unsigned char *found = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(obj, target);
if (found)
{
if ((type & 0xFF) == cJSON_Array)
if (cJSON_IsArray(object))
{
/* reserve enough memory for a 64 bit integer + '/' and '\0' */
unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + 23);
@@ -150,7 +151,7 @@ char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target)
return (char*)ret;
}
else if ((type & 0xFF) == cJSON_Object)
else if (cJSON_IsObject(object))
{
unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + cJSONUtils_PointerEncodedstrlen((unsigned char*)obj->string) + 2);
*ret = '/';
@@ -171,12 +172,12 @@ char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target)
return NULL;
}
cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer)
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer)
{
/* follow path of the pointer */
while ((*pointer++ == '/') && object)
{
if ((object->type & 0xFF) == cJSON_Array)
if (cJSON_IsArray(object))
{
size_t which = 0;
/* parse array index */
@@ -195,7 +196,7 @@ cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer)
}
object = cJSON_GetArrayItem(object, (int)which);
}
else if ((object->type & 0xFF) == cJSON_Object)
else if (cJSON_IsObject(object))
{
object = object->child;
/* GetObjectItem. */
@@ -227,13 +228,13 @@ static void cJSONUtils_InplaceDecodePointerString(unsigned char *string)
return;
}
for (; *string; s2++, string++)
for (; *string; (void)s2++, string++)
{
*s2 = (*string != '~')
*s2 = (unsigned char) ((*string != '~')
? (*string)
: ((*(++string) == '0')
? '~'
: '/');
: '/'));
}
*s2 = '\0';
@@ -269,11 +270,11 @@ static cJSON *cJSONUtils_PatchDetach(cJSON *object, const unsigned char *path)
/* Couldn't find object to remove child from. */
ret = NULL;
}
else if ((parent->type & 0xFF) == cJSON_Array)
else if (cJSON_IsArray(parent))
{
ret = cJSON_DetachItemFromArray(parent, atoi((char*)childptr));
}
else if ((parent->type & 0xFF) == cJSON_Object)
else if (cJSON_IsObject(parent))
{
ret = cJSON_DetachItemFromObject(parent, (char*)childptr);
}
@@ -299,7 +300,7 @@ static int cJSONUtils_Compare(cJSON *a, cJSON *b)
/* string mismatch. */
return (strcmp(a->valuestring, b->valuestring) != 0) ? -3 : 0;
case cJSON_Array:
for (a = a->child, b = b->child; a && b; a = a->next, b = b->next)
for ((void)(a = a->child), b = b->child; a && b; (void)(a = a->next), b = b->next)
{
int err = cJSONUtils_Compare(a, b);
if (err)
@@ -467,14 +468,14 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
cJSONUtils_InplaceDecodePointerString(childptr);
/* add, remove, replace, move, copy, test. */
if (!parent)
if ((parent == NULL) || (childptr == NULL))
{
/* Couldn't find object to add to. */
free(parentptr);
cJSON_Delete(value);
return 9;
}
else if ((parent->type & 0xFF) == cJSON_Array)
else if (cJSON_IsArray(parent))
{
if (!strcmp((char*)childptr, "-"))
{
@@ -485,7 +486,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
cJSON_InsertItemInArray(parent, atoi((char*)childptr), value);
}
}
else if ((parent->type & 0xFF) == cJSON_Object)
else if (cJSON_IsObject(parent))
{
cJSON_DeleteItemFromObject(parent, (char*)childptr);
cJSON_AddItemToObject(parent, (char*)childptr, value);
@@ -499,7 +500,7 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
return 0;
}
int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches)
CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches)
{
int err = 0;
@@ -508,7 +509,7 @@ int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches)
return 1;
}
if ((patches->type & 0xFF) != cJSON_Array)
if (cJSON_IsArray(patches))
{
/* malformed patches. */
return 1;
@@ -551,7 +552,7 @@ static void cJSONUtils_GeneratePatch(cJSON *patches, const unsigned char *op, co
cJSON_AddItemToArray(patches, patch);
}
void cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val)
CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val)
{
cJSONUtils_GeneratePatch(array, (const unsigned char*)op, (const unsigned char*)path, 0, val);
}
@@ -590,7 +591,7 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path,
size_t c = 0;
unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + 23); /* Allow space for 64bit int. */
/* generate patches for all array elements that exist in "from" and "to" */
for (c = 0, from = from->child, to = to->child; from && to; from = from->next, to = to->next, c++)
for ((void)(c = 0), (void)(from = from->child), to = to->child; from && to; (void)(from = from->next), (void)(to = to->next), c++)
{
/* check if conversion to unsigned long is valid
* This should be eliminated at compile time by dead code elimination
@@ -604,7 +605,7 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path,
cJSONUtils_CompareToPatch(patches, newpath, from, to);
}
/* remove leftover elements from 'from' that are not in 'to' */
for (; from; from = from->next, c++)
for (; from; (void)(from = from->next), c++)
{
/* check if conversion to unsigned long is valid
* This should be eliminated at compile time by dead code elimination
@@ -618,7 +619,7 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path,
cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, newpath, 0);
}
/* add new elements in 'to' that were not in 'from' */
for (; to; to = to->next, c++)
for (; to; (void)(to = to->next), c++)
{
cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to);
}
@@ -671,7 +672,7 @@ static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path,
}
}
cJSON* cJSONUtils_GeneratePatches(cJSON *from, cJSON *to)
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to)
{
cJSON *patches = cJSON_CreateArray();
cJSONUtils_CompareToPatch(patches, (const unsigned char*)"", from, to);
@@ -786,21 +787,21 @@ static cJSON *cJSONUtils_SortList(cJSON *list)
return list;
}
void cJSONUtils_SortObject(cJSON *object)
CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object)
{
object->child = cJSONUtils_SortList(object->child);
}
cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch)
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch)
{
if (!patch || ((patch->type & 0xFF) != cJSON_Object))
if (!cJSON_IsObject(patch))
{
/* scalar value, array or NULL, just duplicate */
cJSON_Delete(target);
return cJSON_Duplicate(patch, 1);
}
if (!target || ((target->type & 0xFF) != cJSON_Object))
if (!cJSON_IsObject(target))
{
cJSON_Delete(target);
target = cJSON_CreateObject();
@@ -809,7 +810,7 @@ cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch)
patch = patch->child;
while (patch)
{
if ((patch->type & 0xFF) == cJSON_NULL)
if (cJSON_IsNull(patch))
{
/* NULL is the indicator to remove a value, see RFC7396 */
cJSON_DeleteItemFromObject(target, patch->string);
@@ -824,7 +825,7 @@ cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch)
return target;
}
cJSON *cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to)
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to)
{
cJSON *patch = NULL;
if (!to)
@@ -832,7 +833,7 @@ cJSON *cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to)
/* patch to delete everything */
return cJSON_CreateNull();
}
if (((to->type & 0xFF) != cJSON_Object) || !from || ((from->type & 0xFF) != cJSON_Object))
if (!cJSON_IsObject(to) || !cJSON_IsObject(from))
{
return cJSON_Duplicate(to, 1);
}

View File

@@ -1,14 +1,14 @@
#include "cJSON.h"
/* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */
cJSON *cJSONUtils_GetPointer(cJSON *object, const char *pointer);
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer);
/* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */
cJSON* cJSONUtils_GeneratePatches(cJSON *from, cJSON *to);
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to);
/* Utility for generating patch array entries. */
void cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val);
CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val);
/* Returns 0 for success. */
int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches);
CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches);
/*
// Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use:
@@ -33,12 +33,12 @@ int cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches);
/* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */
/* target will be modified by patch. return value is new ptr for target. */
cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch);
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch);
/* generates a patch to move from -> to */
cJSON *cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to);
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to);
/* Given a root object and a target object, construct a pointer from one to the other. */
char *cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target);
CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target);
/* Sorts the members of the object into alphabetical order. */
void cJSONUtils_SortObject(cJSON *object);
CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object);

1
fuzzing/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
afl-build

28
fuzzing/CMakeLists.txt Normal file
View File

@@ -0,0 +1,28 @@
option(ENABLE_FUZZING "Create executables and targets for fuzzing cJSON with afl." Off)
if (ENABLE_FUZZING)
find_program(AFL_FUZZ afl-fuzz)
if ("${AFL_FUZZ}" MATCHES "AFL_FUZZ-NOTFOUND")
message(FATAL_ERROR "Couldn't find afl-fuzz.")
endif()
add_executable(afl-main afl.c)
target_link_libraries(afl-main "${CJSON_LIB}")
if (NOT ENABLE_SANITIZERS)
message(FATAL_ERROR "Enable sanitizers with -DENABLE_SANITIZERS=On to do fuzzing.")
endif()
option(ENABLE_FUZZING_PRINT "Fuzz printing functions together with parser." On)
set(fuzz_print_parameter "no")
if (ENABLE_FUZZING_PRINT)
set(fuzz_print_parameter "yes")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error")
add_custom_target(afl
COMMAND "${AFL_FUZZ}" -i "${CMAKE_CURRENT_SOURCE_DIR}/inputs" -o "${CMAKE_CURRENT_BINARY_DIR}/findings" -x "${CMAKE_CURRENT_SOURCE_DIR}/json.dict" -- "${CMAKE_CURRENT_BINARY_DIR}/afl-main" "@@" "${fuzz_print_parameter}"
DEPENDS afl-main)
endif()

5
fuzzing/afl-prepare-linux.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
set -x
echo core | sudo tee /proc/sys/kernel/core_pattern
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

176
fuzzing/afl.c Normal file
View File

@@ -0,0 +1,176 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../cJSON.h"
static char *read_file(const char *filename)
{
FILE *file = NULL;
long length = 0;
char *content = NULL;
size_t read_chars = 0;
/* open in read binary mode */
file = fopen(filename, "rb");
if (file == NULL)
{
goto cleanup;
}
/* get the length */
if (fseek(file, 0, SEEK_END) != 0)
{
goto cleanup;
}
length = ftell(file);
if (length < 0)
{
goto cleanup;
}
if (fseek(file, 0, SEEK_SET) != 0)
{
goto cleanup;
}
/* allocate content buffer */
content = (char*)malloc((size_t)length + sizeof(""));
if (content == NULL)
{
goto cleanup;
}
/* read the file into memory */
read_chars = fread(content, sizeof(char), (size_t)length, file);
if ((long)read_chars != length)
{
free(content);
content = NULL;
goto cleanup;
}
content[read_chars] = '\0';
cleanup:
if (file != NULL)
{
fclose(file);
}
return content;
}
int main(int argc, char** argv)
{
const char *filename = NULL;
cJSON *item = NULL;
char *json = NULL;
int status = EXIT_FAILURE;
char *printed_json = NULL;
if ((argc < 2) || (argc > 3))
{
printf("Usage:\n");
printf("%s input_file [enable_printing]\n", argv[0]);
printf("\t input_file: file containing the test data\n");
printf("\t enable_printing: print after parsing, 'yes' or 'no', defaults to 'no'\n");
goto cleanup;
}
filename = argv[1];
#if __AFL_HAVE_MANUAL_CONTROL
while (__AFL_LOOP(1000))
{
#endif
status = EXIT_SUCCESS;
json = read_file(filename);
if ((json == NULL) || (json[0] == '\0') || (json[1] == '\0'))
{
status = EXIT_FAILURE;
goto cleanup;
}
item = cJSON_Parse(json + 2);
if (item == NULL)
{
goto cleanup;
}
if ((argc == 3) && (strncmp(argv[2], "yes", 3) == 0))
{
int do_format = 0;
if (json[1] == 'f')
{
do_format = 1;
}
if (json[0] == 'b')
{
/* buffered printing */
printed_json = cJSON_PrintBuffered(item, 1, do_format);
}
else
{
/* unbuffered printing */
if (do_format)
{
printed_json = cJSON_Print(item);
}
else
{
printed_json = cJSON_PrintUnformatted(item);
}
}
if (printed_json == NULL)
{
status = EXIT_FAILURE;
goto cleanup;
}
printf("%s\n", printed_json);
}
cleanup:
if (item != NULL)
{
cJSON_Delete(item);
item = NULL;
}
if (json != NULL)
{
free(json);
json = NULL;
}
if (printed_json != NULL)
{
free(printed_json);
printed_json = NULL;
}
#if __AFL_HAVE_MANUAL_CONTROL
}
#endif
return status;
}

9
fuzzing/afl.sh Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/bash
mkdir -p afl-build || exit 1
cd afl-build || exit 1
#cleanup
rm -r -- *
CC=afl-clang-fast cmake ../.. -DENABLE_FUZZING=On -DENABLE_SANITIZERS=On -DBUILD_SHARED_LIBS=Off
make afl

22
fuzzing/inputs/test1 Normal file
View File

@@ -0,0 +1,22 @@
bf{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}

1
fuzzing/inputs/test10 Normal file
View File

@@ -0,0 +1 @@
bf["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]

8
fuzzing/inputs/test11 Normal file
View File

@@ -0,0 +1,8 @@
bf{
"name": "Jack (\"Bee\") Nimble",
"format": {"type": "rect",
"width": 1920,
"height": 1080,
"interlace": false,"frame rate": 24
}
}

11
fuzzing/inputs/test2 Normal file
View File

@@ -0,0 +1,11 @@
bf{"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}}

26
fuzzing/inputs/test3 Normal file
View File

@@ -0,0 +1,26 @@
bf{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}

26
fuzzing/inputs/test3.bu Normal file
View File

@@ -0,0 +1,26 @@
bu{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}

26
fuzzing/inputs/test3.uf Normal file
View File

@@ -0,0 +1,26 @@
uf{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}

26
fuzzing/inputs/test3.uu Normal file
View File

@@ -0,0 +1,26 @@
uu{"widget": {
"debug": "on",
"window": {
"title": "Sample Konfabulator Widget",
"name": "main_window",
"width": 500,
"height": 500
},
"image": {
"src": "Images/Sun.png",
"name": "sun1",
"hOffset": 250,
"vOffset": 250,
"alignment": "center"
},
"text": {
"data": "Click Here",
"size": 36,
"style": "bold",
"name": "text1",
"hOffset": 250,
"vOffset": 100,
"alignment": "center",
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
}
}}

88
fuzzing/inputs/test4 Normal file
View File

@@ -0,0 +1,88 @@
bf{"web-app": {
"servlet": [
{
"servlet-name": "cofaxCDS",
"servlet-class": "org.cofax.cds.CDSServlet",
"init-param": {
"configGlossary:installationAt": "Philadelphia, PA",
"configGlossary:adminEmail": "ksm@pobox.com",
"configGlossary:poweredBy": "Cofax",
"configGlossary:poweredByIcon": "/images/cofax.gif",
"configGlossary:staticPath": "/content/static",
"templateProcessorClass": "org.cofax.WysiwygTemplate",
"templateLoaderClass": "org.cofax.FilesTemplateLoader",
"templatePath": "templates",
"templateOverridePath": "",
"defaultListTemplate": "listTemplate.htm",
"defaultFileTemplate": "articleTemplate.htm",
"useJSP": false,
"jspListTemplate": "listTemplate.jsp",
"jspFileTemplate": "articleTemplate.jsp",
"cachePackageTagsTrack": 200,
"cachePackageTagsStore": 200,
"cachePackageTagsRefresh": 60,
"cacheTemplatesTrack": 100,
"cacheTemplatesStore": 50,
"cacheTemplatesRefresh": 15,
"cachePagesTrack": 200,
"cachePagesStore": 100,
"cachePagesRefresh": 10,
"cachePagesDirtyRead": 10,
"searchEngineListTemplate": "forSearchEnginesList.htm",
"searchEngineFileTemplate": "forSearchEngines.htm",
"searchEngineRobotsDb": "WEB-INF/robots.db",
"useDataStore": true,
"dataStoreClass": "org.cofax.SqlDataStore",
"redirectionClass": "org.cofax.SqlRedirection",
"dataStoreName": "cofax",
"dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
"dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
"dataStoreUser": "sa",
"dataStorePassword": "dataStoreTestQuery",
"dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
"dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
"dataStoreInitConns": 10,
"dataStoreMaxConns": 100,
"dataStoreConnUsageLimit": 100,
"dataStoreLogLevel": "debug",
"maxUrlLength": 500}},
{
"servlet-name": "cofaxEmail",
"servlet-class": "org.cofax.cds.EmailServlet",
"init-param": {
"mailHost": "mail1",
"mailHostOverride": "mail2"}},
{
"servlet-name": "cofaxAdmin",
"servlet-class": "org.cofax.cds.AdminServlet"},
{
"servlet-name": "fileServlet",
"servlet-class": "org.cofax.cds.FileServlet"},
{
"servlet-name": "cofaxTools",
"servlet-class": "org.cofax.cms.CofaxToolsServlet",
"init-param": {
"templatePath": "toolstemplates/",
"log": 1,
"logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
"logMaxSize": "",
"dataLog": 1,
"dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
"dataLogMaxSize": "",
"removePageCache": "/content/admin/remove?cache=pages&id=",
"removeTemplateCache": "/content/admin/remove?cache=templates&id=",
"fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
"lookInContext": 1,
"adminGroupID": 4,
"betaServer": true}}],
"servlet-mapping": {
"cofaxCDS": "/",
"cofaxEmail": "/cofaxutil/aemail/*",
"cofaxAdmin": "/admin/*",
"fileServlet": "/static/*",
"cofaxTools": "/tools/*"},
"taglib": {
"taglib-uri": "cofax.tld",
"taglib-location": "/WEB-INF/tlds/cofax.tld"}}}

27
fuzzing/inputs/test5 Normal file
View File

@@ -0,0 +1,27 @@
bf{"menu": {
"header": "SVG Viewer",
"items": [
{"id": "Open"},
{"id": "OpenNew", "label": "Open New"},
null,
{"id": "ZoomIn", "label": "Zoom In"},
{"id": "ZoomOut", "label": "Zoom Out"},
{"id": "OriginalView", "label": "Original View"},
null,
{"id": "Quality"},
{"id": "Pause"},
{"id": "Mute"},
null,
{"id": "Find", "label": "Find..."},
{"id": "FindAgain", "label": "Find Again"},
{"id": "Copy"},
{"id": "CopyAgain", "label": "Copy Again"},
{"id": "CopySVG", "label": "Copy SVG"},
{"id": "ViewSVG", "label": "View SVG"},
{"id": "ViewSource", "label": "View Source"},
{"id": "SaveAs", "label": "Save As"},
null,
{"id": "Help"},
{"id": "About", "label": "About Adobe CVG Viewer..."}
]
}}

16
fuzzing/inputs/test6 Normal file
View File

@@ -0,0 +1,16 @@
bf<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
html, body, iframe { margin: 0; padding: 0; height: 100%; }
iframe { display: block; width: 100%; border: none; }
</style>
<title>Application Error</title>
</head>
<body>
<iframe src="//s3.amazonaws.com/heroku_pages/error.html">
<p>Application Error</p>
</iframe>
</body>
</html>

22
fuzzing/inputs/test7 Normal file
View File

@@ -0,0 +1,22 @@
bf[
{
"precision": "zip",
"Latitude": 37.7668,
"Longitude": -122.3959,
"Address": "",
"City": "SAN FRANCISCO",
"State": "CA",
"Zip": "94107",
"Country": "US"
},
{
"precision": "zip",
"Latitude": 37.371991,
"Longitude": -122.026020,
"Address": "",
"City": "SUNNYVALE",
"State": "CA",
"Zip": "94085",
"Country": "US"
}
]

13
fuzzing/inputs/test8 Normal file
View File

@@ -0,0 +1,13 @@
bf{
"Image": {
"Width": 800,
"Height": 600,
"Title": "View from 15th Floor",
"Thumbnail": {
"Url": "http:/*www.example.com/image/481989943",
"Height": 125,
"Width": "100"
},
"IDs": [116, 943, 234, 38793]
}
}

5
fuzzing/inputs/test9 Normal file
View File

@@ -0,0 +1,5 @@
bf[
[0, -1, 0],
[1, 0, 0],
[0, 0, 1]
]

47
fuzzing/json.dict Normal file
View File

@@ -0,0 +1,47 @@
#
# AFL dictionary for JSON
# -----------------------------
#
object_start="{"
object_end="}"
object_empty="{}"
object_one_element="{\"one\":1}"
object_two_elements="{\"1\":1,\"2\":2}"
object_separator=":"
array_start="["
array_end="]"
array_empty="[]"
array_one_element="[1]"
array_two_elements="[1,2]"
separator=","
escape_sequence_b="\\b"
escape_sequence_f="\\f"
escape_sequence_n="\\n"
escape_sequence_r="\\r"
escape_sequence_t="\\t"
escape_sequence_quote="\\\""
escape_sequence_backslash="\\\\"
escapce_sequence_slash="\\/"
escpae_sequence_utf16_base="\\u"
escape_sequence_utf16="\\u12ab"
number_integer="1"
number_double="1.0"
number_negative_integer="-1"
number_negative_double="-1.0"
number_engineering1="1e1"
number_engineering2="1e-1"
number_positive_integer="+1"
number_positive_double="+1.0"
number_e="e"
number_plus="+"
number_minus="-"
number_separator="."
null="null"
true="true"
false="false"

4
test.c
View File

@@ -53,8 +53,8 @@ static int print_preallocated(cJSON *root)
out = cJSON_Print(root);
/* create buffer to succeed */
/* the extra 64 bytes are in case a floating point value is printed */
len = strlen(out) + 64;
/* the extra 5 bytes are because of inaccuracies when reserving memory */
len = strlen(out) + 5;
buf = (char*)malloc(len);
if (buf == NULL)
{

View File

@@ -1,6 +1,31 @@
add_library(unity unity/src/unity.c)
if(ENABLE_CJSON_TEST)
add_library(unity unity/src/unity.c)
# Disable -Werror for Unity
if (FLAG_SUPPORTED_Werror)
if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error")
else()
target_compile_options(unity PRIVATE "-Wno-error")
endif()
endif()
# Disable -fvisibility=hidden for Unity
if (FLAG_SUPPORTED_fvisibilityhidden)
if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=default")
else()
target_compile_options(unity PRIVATE "-fvisibility=default")
endif()
endif()
# Disable -fsanitize=float-divide-by-zero for Unity (GCC bug on x86 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80097)
if (FLAG_SUPPORTED_fsanitizefloatdividebyzero AND (CMAKE_C_COMPILER_ID STREQUAL "GNU"))
if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize=float-divide-by-zero")
else()
target_compile_options(unity PRIVATE "-fno-sanitize=float-divide-by-zero")
endif()
endif()
#copy test files
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/inputs")
file(GLOB test_files "inputs/*")
@@ -14,6 +39,12 @@ if(ENABLE_CJSON_TEST)
parse_array
parse_object
parse_value
print_string
print_number
print_array
print_object
print_value
misc_tests
)
add_library(test-common common.c)
@@ -34,10 +65,12 @@ if(ENABLE_CJSON_TEST)
target_link_libraries("${unity_test}" "${CJSON_LIB}" unity test-common)
if(MEMORYCHECK_COMMAND)
add_test(NAME "${unity_test}"
COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "./${unity_test}")
COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "${CMAKE_CURRENT_BINARY_DIR}/${unity_test}")
else()
add_test(NAME "${unity_test}"
COMMAND "./${unity_test}")
endif()
endforeach()
add_dependencies(check ${unity_tests})
endif()

View File

@@ -22,7 +22,7 @@
#include "common.h"
extern void reset(cJSON *item)
CJSON_PUBLIC(void) reset(cJSON *item)
{
if ((item != NULL) && (item->child != NULL))
{
@@ -30,17 +30,17 @@ extern void reset(cJSON *item)
}
if ((item->valuestring != NULL) && !(item->type & cJSON_IsReference))
{
cJSON_free(item->valuestring);
global_hooks.deallocate(item->valuestring);
}
if ((item->string != NULL) && !(item->type & cJSON_StringIsConst))
{
cJSON_free(item->string);
global_hooks.deallocate(item->string);
}
memset(item, 0, sizeof(cJSON));
}
extern char *read_file(const char *filename)
CJSON_PUBLIC(char*) read_file(const char *filename)
{
FILE *file = NULL;
long length = 0;
@@ -70,7 +70,7 @@ extern char *read_file(const char *filename)
}
/* allocate content buffer */
content = (char*)malloc((size_t)length + sizeof('\0'));
content = (char*)malloc((size_t)length + sizeof(""));
if (content == NULL)
{
goto cleanup;

View File

@@ -25,9 +25,8 @@
#include "../cJSON.c"
extern void reset(cJSON *item);
extern char *read_file(const char *filename);
extern cjbool assert_is_invalid(cJSON *item);
CJSON_PUBLIC(void) reset(cJSON *item);
CJSON_PUBLIC(char*) read_file(const char *filename);
/* assertion helper macros */
#define assert_has_type(item, item_type) TEST_ASSERT_BITS_MESSAGE(0xFF, item_type, item->type, "Item doesn't have expected type.")

View File

@@ -1,7 +1,7 @@
[{
"precision": "zip",
"Latitude": 37.766800,
"Longitude": -122.395900,
"Latitude": 37.7668,
"Longitude": -122.3959,
"Address": "",
"City": "SAN FRANCISCO",
"State": "CA",
@@ -10,7 +10,7 @@
}, {
"precision": "zip",
"Latitude": 37.371991,
"Longitude": -122.026020,
"Longitude": -122.02602,
"Address": "",
"City": "SUNNYVALE",
"State": "CA",

197
tests/misc_tests.c Normal file
View File

@@ -0,0 +1,197 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void cjson_array_foreach_should_loop_over_arrays(void)
{
cJSON array[1];
cJSON elements[10];
cJSON *element_pointer = NULL;
size_t i = 0;
memset(array, 0, sizeof(array));
memset(elements, 0, sizeof(elements));
/* create array */
array[0].child = &elements[0];
elements[0].prev = NULL;
elements[9].next = NULL;
for (i = 0; i < 9; i++)
{
elements[i].next = &elements[i + 1];
elements[i + 1].prev = &elements[i];
}
i = 0;
cJSON_ArrayForEach(element_pointer, array)
{
TEST_ASSERT_TRUE_MESSAGE(element_pointer == &elements[i], "Not iterating over array properly");
i++;
}
}
static void cjson_array_foreach_should_not_dereference_null_pointer(void)
{
cJSON *array = NULL;
cJSON *element = NULL;
cJSON_ArrayForEach(element, array);
}
static void cjson_get_object_item_should_get_object_items(void)
{
cJSON *item = NULL;
cJSON *found = NULL;
item = cJSON_Parse("{\"one\":1, \"Two\":2, \"tHree\":3}");
found = cJSON_GetObjectItem(NULL, "test");
TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL pointer.");
found = cJSON_GetObjectItem(item, NULL);
TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL string.");
found = cJSON_GetObjectItem(item, "one");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 1);
found = cJSON_GetObjectItem(item, "tWo");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 2);
found = cJSON_GetObjectItem(item, "three");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 3);
found = cJSON_GetObjectItem(item, "four");
TEST_ASSERT_NULL_MESSAGE(found, "Should not find something that isn't there.");
cJSON_Delete(item);
}
static void cjson_get_object_item_case_sensitive_should_get_object_items(void)
{
cJSON *item = NULL;
cJSON *found = NULL;
item = cJSON_Parse("{\"one\":1, \"Two\":2, \"tHree\":3}");
found = cJSON_GetObjectItemCaseSensitive(NULL, "test");
TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL pointer.");
found = cJSON_GetObjectItemCaseSensitive(item, NULL);
TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL string.");
found = cJSON_GetObjectItemCaseSensitive(item, "one");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 1);
found = cJSON_GetObjectItemCaseSensitive(item, "Two");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 2);
found = cJSON_GetObjectItemCaseSensitive(item, "tHree");
TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find item.");
TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 3);
found = cJSON_GetObjectItemCaseSensitive(item, "One");
TEST_ASSERT_NULL_MESSAGE(found, "Should not find something that isn't there.");
cJSON_Delete(item);
}
static void typecheck_functions_should_check_type(void)
{
cJSON invalid[1];
cJSON item[1];
invalid->type = cJSON_Invalid;
invalid->type |= cJSON_StringIsConst;
item->type = cJSON_False;
item->type |= cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsInvalid(NULL));
TEST_ASSERT_FALSE(cJSON_IsInvalid(item));
TEST_ASSERT_TRUE(cJSON_IsInvalid(invalid));
item->type = cJSON_False | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsFalse(NULL));
TEST_ASSERT_FALSE(cJSON_IsFalse(invalid));
TEST_ASSERT_TRUE(cJSON_IsFalse(item));
TEST_ASSERT_TRUE(cJSON_IsBool(item));
item->type = cJSON_True | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsTrue(NULL));
TEST_ASSERT_FALSE(cJSON_IsTrue(invalid));
TEST_ASSERT_TRUE(cJSON_IsTrue(item));
TEST_ASSERT_TRUE(cJSON_IsBool(item));
item->type = cJSON_NULL | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsNull(NULL));
TEST_ASSERT_FALSE(cJSON_IsNull(invalid));
TEST_ASSERT_TRUE(cJSON_IsNull(item));
item->type = cJSON_Number | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsNumber(NULL));
TEST_ASSERT_FALSE(cJSON_IsNumber(invalid));
TEST_ASSERT_TRUE(cJSON_IsNumber(item));
item->type = cJSON_String | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsString(NULL));
TEST_ASSERT_FALSE(cJSON_IsString(invalid));
TEST_ASSERT_TRUE(cJSON_IsString(item));
item->type = cJSON_Array | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsArray(NULL));
TEST_ASSERT_FALSE(cJSON_IsArray(invalid));
TEST_ASSERT_TRUE(cJSON_IsArray(item));
item->type = cJSON_Object | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsObject(NULL));
TEST_ASSERT_FALSE(cJSON_IsObject(invalid));
TEST_ASSERT_TRUE(cJSON_IsObject(item));
item->type = cJSON_Raw | cJSON_StringIsConst;
TEST_ASSERT_FALSE(cJSON_IsRaw(NULL));
TEST_ASSERT_FALSE(cJSON_IsRaw(invalid));
TEST_ASSERT_TRUE(cJSON_IsRaw(item));
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(cjson_array_foreach_should_loop_over_arrays);
RUN_TEST(cjson_array_foreach_should_not_dereference_null_pointer);
RUN_TEST(cjson_get_object_item_should_get_object_items);
RUN_TEST(cjson_get_object_item_case_sensitive_should_get_object_items);
RUN_TEST(typecheck_functions_should_check_type);
return UNITY_END();
}

View File

@@ -46,13 +46,13 @@ static void assert_is_array(cJSON *array_item)
static void assert_not_array(const char *json)
{
TEST_ASSERT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer));
TEST_ASSERT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer, &global_hooks));
assert_is_invalid(item);
}
static void assert_parse_array(const char *json)
{
TEST_ASSERT_NOT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer));
TEST_ASSERT_NOT_NULL(parse_array(item, (const unsigned char*)json, &error_pointer, &global_hooks));
assert_is_array(item);
}
@@ -124,7 +124,7 @@ static void parse_array_should_parse_arrays_with_multiple_elements(void)
i = 0;
(i < (sizeof(expected_types)/sizeof(int)))
&& (node != NULL);
i++, node = node->next)
(void)i++, node = node->next)
{
TEST_ASSERT_BITS(0xFF, expected_types[i], node->type);
}

View File

@@ -54,14 +54,14 @@ static void assert_is_child(cJSON *child_item, const char *name, int type)
static void assert_not_object(const char *json)
{
TEST_ASSERT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer));
TEST_ASSERT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer, &global_hooks));
assert_is_invalid(item);
reset(item);
}
static void assert_parse_object(const char *json)
{
TEST_ASSERT_NOT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer));
TEST_ASSERT_NOT_NULL(parse_object(item, (const unsigned char*)json, &error_pointer, &global_hooks));
assert_is_object(item);
}
@@ -76,7 +76,7 @@ static void parse_object_should_parse_empty_objects(void)
reset(item);
}
static void parse_array_should_parse_arrays_with_one_element(void)
static void parse_object_should_parse_objects_with_one_element(void)
{
assert_parse_object("{\"one\":1}");
@@ -134,7 +134,7 @@ static void parse_object_should_parse_objects_with_multiple_elements(void)
i = 0;
(i < (sizeof(expected_types)/sizeof(int)))
&& (node != NULL);
i++, node = node->next)
(void)i++, node = node->next)
{
assert_is_child(node, expected_names[i], expected_types[i]);
}
@@ -163,6 +163,6 @@ int main(void)
RUN_TEST(parse_object_should_parse_empty_objects);
RUN_TEST(parse_object_should_not_parse_non_objects);
RUN_TEST(parse_object_should_parse_objects_with_multiple_elements);
RUN_TEST(parse_array_should_parse_arrays_with_one_element);
RUN_TEST(parse_object_should_parse_objects_with_one_element);
return UNITY_END();
}

View File

@@ -47,15 +47,15 @@ static void assert_is_string(cJSON *string_item)
static void assert_parse_string(const char *string, const char *expected)
{
TEST_ASSERT_NOT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer), "Couldn't parse string.");
TEST_ASSERT_NOT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer, &global_hooks), "Couldn't parse string.");
assert_is_string(item);
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, item->valuestring, "The parsed result isn't as expected.");
cJSON_free(item->valuestring);
global_hooks.deallocate(item->valuestring);
item->valuestring = NULL;
}
#define assert_not_parse_string(string) \
TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer), "Malformed string should not be accepted");\
TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer, &global_hooks), "Malformed string should not be accepted");\
assert_is_invalid(item)

View File

@@ -44,7 +44,7 @@ static void assert_is_value(cJSON *value_item, int type)
static void assert_parse_value(const char *string, int type)
{
TEST_ASSERT_NOT_NULL(parse_value(item, (const unsigned char*)string, &error_pointer));
TEST_ASSERT_NOT_NULL(parse_value(item, (const unsigned char*)string, &error_pointer, &global_hooks));
assert_is_value(item, type);
}

92
tests/print_array.c Normal file
View File

@@ -0,0 +1,92 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void assert_print_array(const char * const expected, const char * const input)
{
unsigned char printed_unformatted[1024];
unsigned char printed_formatted[1024];
const unsigned char *error_pointer;
cJSON item[1];
printbuffer formatted_buffer;
printbuffer unformatted_buffer;
/* buffer for formatted printing */
formatted_buffer.buffer = printed_formatted;
formatted_buffer.length = sizeof(printed_formatted);
formatted_buffer.offset = 0;
formatted_buffer.noalloc = true;
/* buffer for unformatted printing */
unformatted_buffer.buffer = printed_unformatted;
unformatted_buffer.length = sizeof(printed_unformatted);
unformatted_buffer.offset = 0;
unformatted_buffer.noalloc = true;
memset(item, 0, sizeof(item));
TEST_ASSERT_NOT_NULL_MESSAGE(parse_array(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse array.");
TEST_ASSERT_TRUE_MESSAGE(print_array(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted array is not correct.");
TEST_ASSERT_TRUE_MESSAGE(print_array(item, 0, true, &formatted_buffer, &global_hooks), "Failed to print formatted string.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted array is not correct.");
reset(item);
}
static void print_array_should_print_empty_arrays(void)
{
assert_print_array("[]", "[]");
}
static void print_array_should_print_arrays_with_one_element(void)
{
assert_print_array("[1]", "[1]");
assert_print_array("[\"hello!\"]", "[\"hello!\"]");
assert_print_array("[[]]", "[[]]");
assert_print_array("[null]", "[null]");
}
static void print_array_should_print_arrays_with_multiple_elements(void)
{
assert_print_array("[1, 2, 3]", "[1,2,3]");
assert_print_array("[1, null, true, false, [], \"hello\", {\n\t}]", "[1,null,true,false,[],\"hello\",{}]");
}
int main(void)
{
/* initialize cJSON item */
UNITY_BEGIN();
RUN_TEST(print_array_should_print_empty_arrays);
RUN_TEST(print_array_should_print_arrays_with_one_element);
RUN_TEST(print_array_should_print_arrays_with_multiple_elements);
return UNITY_END();
}

113
tests/print_number.c Normal file
View File

@@ -0,0 +1,113 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void assert_print_number(const char *expected, double input)
{
unsigned char printed[1024];
cJSON item[1];
printbuffer buffer;
buffer.buffer = printed;
buffer.length = sizeof(printed);
buffer.offset = 0;
buffer.noalloc = true;
memset(item, 0, sizeof(item));
cJSON_SetNumberValue(item, input);
TEST_ASSERT_TRUE_MESSAGE(print_number(item, &buffer, &global_hooks), "Failed to print number.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, buffer.buffer, "Printed number is not as expected.");
}
static void print_number_should_print_zero(void)
{
assert_print_number("0", 0);
}
static void print_number_should_print_negative_integers(void)
{
assert_print_number("-1", -1);
assert_print_number("-32768", -32768);
assert_print_number("-2147483648", -2147483648.0);
}
static void print_number_should_print_positive_integers(void)
{
assert_print_number("1", 1);
assert_print_number("32767", 32767);
assert_print_number("2147483647", 2147483647);
}
static void print_number_should_print_positive_reals(void)
{
assert_print_number("0.123", 0.123);
assert_print_number("1.000000e-09", 10e-10);
assert_print_number("1000000000000", 10e11);
assert_print_number("1.230000e+129", 123e+127);
assert_print_number("0", 123e-128); /* TODO: Maybe this shouldn't be 0 */
}
static void print_number_should_print_negative_reals(void)
{
assert_print_number("-0.0123", -0.0123);
assert_print_number("-1.000000e-09", -10e-10);
assert_print_number("-1000000000000000000000", -10e20);
assert_print_number("-1.230000e+129", -123e+127);
assert_print_number("-1.230000e-126", -123e-128);
}
static void print_number_should_print_non_number(void)
{
TEST_IGNORE();
/* FIXME: Cannot test this easily in C89! */
/* assert_print_number("null", NaN); */
/* assert_print_number("null", INFTY); */
/* assert_print_number("null", -INFTY); */
}
static void trim_trailing_zeroes_should_trim_trailing_zeroes(void)
{
TEST_ASSERT_EQUAL_INT(2, trim_trailing_zeroes((const unsigned char*)"10.00", (int)(sizeof("10.00") - 1), '.'));
TEST_ASSERT_EQUAL_INT(0, trim_trailing_zeroes((const unsigned char*)".00", (int)(sizeof(".00") - 1), '.'));
TEST_ASSERT_EQUAL_INT(0, trim_trailing_zeroes((const unsigned char*)"00", (int)(sizeof("00") - 1), '.'));
TEST_ASSERT_EQUAL_INT(-1, trim_trailing_zeroes(NULL, 10, '.'));
TEST_ASSERT_EQUAL_INT(-1, trim_trailing_zeroes((const unsigned char*)"", 0, '.'));
}
int main(void)
{
/* initialize cJSON item */
UNITY_BEGIN();
RUN_TEST(print_number_should_print_zero);
RUN_TEST(print_number_should_print_negative_integers);
RUN_TEST(print_number_should_print_positive_integers);
RUN_TEST(print_number_should_print_positive_reals);
RUN_TEST(print_number_should_print_negative_reals);
RUN_TEST(print_number_should_print_non_number);
RUN_TEST(trim_trailing_zeroes_should_trim_trailing_zeroes);
return UNITY_END();
}

92
tests/print_object.c Normal file
View File

@@ -0,0 +1,92 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void assert_print_object(const char * const expected, const char * const input)
{
unsigned char printed_unformatted[1024];
unsigned char printed_formatted[1024];
const unsigned char *error_pointer;
cJSON item[1];
printbuffer formatted_buffer;
printbuffer unformatted_buffer;
/* buffer for formatted printing */
formatted_buffer.buffer = printed_formatted;
formatted_buffer.length = sizeof(printed_formatted);
formatted_buffer.offset = 0;
formatted_buffer.noalloc = true;
/* buffer for unformatted printing */
unformatted_buffer.buffer = printed_unformatted;
unformatted_buffer.length = sizeof(printed_unformatted);
unformatted_buffer.offset = 0;
unformatted_buffer.noalloc = true;
memset(item, 0, sizeof(item));
TEST_ASSERT_NOT_NULL_MESSAGE(parse_object(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse object.");
TEST_ASSERT_TRUE_MESSAGE(print_object(item, 0, false, &unformatted_buffer, &global_hooks), "Failed to print unformatted string.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted object is not correct.");
TEST_ASSERT_TRUE_MESSAGE(print_object(item, 0, true, &formatted_buffer, &global_hooks), "Failed to print formatted string.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted ojbect is not correct.");
reset(item);
}
static void print_object_should_print_empty_objects(void)
{
assert_print_object("{\n}", "{}");
}
static void print_object_should_print_objects_with_one_element(void)
{
assert_print_object("{\n\t\"one\":\t1\n}", "{\"one\":1}");
assert_print_object("{\n\t\"hello\":\t\"world!\"\n}", "{\"hello\":\"world!\"}");
assert_print_object("{\n\t\"array\":\t[]\n}", "{\"array\":[]}");
assert_print_object("{\n\t\"null\":\tnull\n}", "{\"null\":null}");
}
static void print_object_should_print_objects_with_multiple_elements(void)
{
assert_print_object("{\n\t\"one\":\t1,\n\t\"two\":\t2,\n\t\"three\":\t3\n}", "{\"one\":1,\"two\":2,\"three\":3}");
assert_print_object("{\n\t\"one\":\t1,\n\t\"NULL\":\tnull,\n\t\"TRUE\":\ttrue,\n\t\"FALSE\":\tfalse,\n\t\"array\":\t[],\n\t\"world\":\t\"hello\",\n\t\"object\":\t{\n\t}\n}", "{\"one\":1,\"NULL\":null,\"TRUE\":true,\"FALSE\":false,\"array\":[],\"world\":\"hello\",\"object\":{}}");
}
int main(void)
{
/* initialize cJSON item */
UNITY_BEGIN();
RUN_TEST(print_object_should_print_empty_objects);
RUN_TEST(print_object_should_print_objects_with_one_element);
RUN_TEST(print_object_should_print_objects_with_multiple_elements);
return UNITY_END();
}

77
tests/print_string.c Normal file
View File

@@ -0,0 +1,77 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void assert_print_string(const char *expected, const char *input)
{
unsigned char printed[1024];
printbuffer buffer;
buffer.buffer = printed;
buffer.length = sizeof(printed);
buffer.offset = 0;
buffer.noalloc = true;
TEST_ASSERT_TRUE_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer, &global_hooks), "Failed to print string.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed, "The printed string isn't as expected.");
}
static void print_string_should_print_empty_strings(void)
{
assert_print_string("\"\"", "");
assert_print_string("\"\"", NULL);
}
static void print_string_should_print_ascii(void)
{
char ascii[0x7F];
size_t i = 1;
/* create ascii table */
for (i = 1; i < 0x7F; i++)
{
ascii[i-1] = (char)i;
}
ascii[0x7F-1] = '\0';
assert_print_string("\"\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"",
ascii);
}
static void print_string_should_print_utf8(void)
{
assert_print_string("\"ü猫慕\"", "ü猫慕");
}
int main(void)
{
/* initialize cJSON item */
UNITY_BEGIN();
RUN_TEST(print_string_should_print_empty_strings);
RUN_TEST(print_string_should_print_ascii);
RUN_TEST(print_string_should_print_utf8);
return UNITY_END();
}

102
tests/print_value.c Normal file
View File

@@ -0,0 +1,102 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void assert_print_value(const char *input)
{
unsigned char printed[1024];
const unsigned char *error_pointer = NULL;
cJSON item[1];
printbuffer buffer;
buffer.buffer = printed;
buffer.length = sizeof(printed);
buffer.offset = 0;
buffer.noalloc = true;
memset(item, 0, sizeof(item));
TEST_ASSERT_NOT_NULL_MESSAGE(parse_value(item, (const unsigned char*)input, &error_pointer, &global_hooks), "Failed to parse value.");
TEST_ASSERT_TRUE_MESSAGE(print_value(item, 0, false, &buffer, &global_hooks), "Failed to print value.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(input, buffer.buffer, "Printed value is not as expected.");
reset(item);
}
static void print_value_should_print_null(void)
{
assert_print_value("null");
}
static void print_value_should_print_true(void)
{
assert_print_value("true");
}
static void print_value_should_print_false(void)
{
assert_print_value("false");
}
static void print_value_should_print_number(void)
{
assert_print_value("1.5");
}
static void print_value_should_print_string(void)
{
assert_print_value("\"\"");
assert_print_value("\"hello\"");
}
static void print_value_should_print_array(void)
{
assert_print_value("[]");
}
static void print_value_should_print_object(void)
{
assert_print_value("{}");
}
int main(void)
{
/* initialize cJSON item */
UNITY_BEGIN();
RUN_TEST(print_value_should_print_null);
RUN_TEST(print_value_should_print_true);
RUN_TEST(print_value_should_print_false);
RUN_TEST(print_value_should_print_number);
RUN_TEST(print_value_should_print_string);
RUN_TEST(print_value_should_print_array);
RUN_TEST(print_value_should_print_object);
return UNITY_END();
}

View File

@@ -41,13 +41,13 @@ Example:
main()
{
if (TEST_PROTECT() == 0)
if (TEST_PROTECT())
{
MyTest();
}
}
If MyTest calls `TEST_ABORT`, program control will immediately return to `TEST_PROTECT` with a non-zero return value.
If MyTest calls `TEST_ABORT`, program control will immediately return to `TEST_PROTECT` with a return value of zero.
Unity Assertion Summary

View File

@@ -65,6 +65,17 @@ class ParseOutput
@arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\"/>"
end
end
# Test was flagged as having passed so format the output.
# This is using the Unity fixture output and not the original Unity output.
def testPassedUnityFixture(array)
testSuite = array[0].sub("TEST(", "")
testSuite = testSuite.sub(",", "")
testName = array[1].sub(")", "")
if @xmlOut == true
@arrayList.push " <testcase classname=\"" + testSuite + "\" name=\"" + testName + "\"/>"
end
end
# Test was flagged as being ingored so format the output
def testIgnored(array)
@@ -73,6 +84,14 @@ class ParseOutput
reason = array[lastItem].chomp
testSuiteVerify(array[@className])
printf "%-40s IGNORED\n", testName
if testName.start_with? "TEST("
array2 = testName.split(" ")
@testSuite = array2[0].sub("TEST(", "")
@testSuite = @testSuite.sub(",", "")
testName = array2[1].sub(")", "")
end
if @xmlOut == true
@arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">"
@arrayList.push " <skipped type=\"TEST IGNORED\"> " + reason + " </skipped>"
@@ -87,6 +106,14 @@ class ParseOutput
reason = array[lastItem].chomp + " at line: " + array[lastItem - 3]
testSuiteVerify(array[@className])
printf "%-40s FAILED\n", testName
if testName.start_with? "TEST("
array2 = testName.split(" ")
@testSuite = array2[0].sub("TEST(", "")
@testSuite = @testSuite.sub(",", "")
testName = array2[1].sub(")", "")
end
if @xmlOut == true
@arrayList.push " <testcase classname=\"" + @testSuite + "\" name=\"" + testName + "\">"
@arrayList.push " <failure type=\"ASSERT FAILED\"> " + reason + " </failure>"
@@ -138,7 +165,7 @@ class ParseOutput
lineSize = lineArray.size
# If we were able to split the line then we can look to see if any of our target words
# were found. Case is important.
if lineSize >= 4
if ((lineSize >= 4) || (line.start_with? "TEST("))
# Determine if this test passed
if line.include? ":PASS"
testPassed(lineArray)
@@ -149,6 +176,12 @@ class ParseOutput
elsif line.include? ":IGNORE:"
testIgnored(lineArray)
testIgnore += 1
elsif line.start_with? "TEST("
if line.include? " PASS"
lineArray = line.split(" ")
testPassedUnityFixture(lineArray)
testPass += 1
end
# If none of the keywords are found there are no more tests for this suite so clear
# the test flag
else

View File

@@ -669,7 +669,7 @@ void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected,
UnityTestResultsFailBegin(lineNumber);
UnityPrint(UnityStrElement);
UnityPrintNumberUnsigned(num_elements - elements - 1);
UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(*ptr_expected, *ptr_actual);
UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)*ptr_expected, (UNITY_DOUBLE)*ptr_actual);
UnityAddMsgIfSpecified(msg);
UNITY_FAIL_AND_BAIL;
}
@@ -691,7 +691,7 @@ void UnityAssertFloatsWithin(const UNITY_FLOAT delta,
if (!UnityFloatsWithin(delta, expected, actual))
{
UnityTestResultsFailBegin(lineNumber);
UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual);
UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)expected, (UNITY_DOUBLE)actual);
UnityAddMsgIfSpecified(msg);
UNITY_FAIL_AND_BAIL;
}
@@ -746,7 +746,7 @@ void UnityAssertFloatSpecial(const UNITY_FLOAT actual,
UnityPrint(trait_names[trait_index]);
UnityPrint(UnityStrWas);
#ifndef UNITY_EXCLUDE_FLOAT_PRINT
UnityPrintFloat(actual);
UnityPrintFloat((UNITY_DOUBLE)actual);
#else
if (should_be_trait)
UnityPrint(UnityStrNot);