Compare commits

...

47 Commits

Author SHA1 Message Date
Max Bruckner
05f75e360b Release Version 1.4.7 2017-04-18 21:35:21 +02:00
Max Bruckner
32626cc251 Update Changelog 2017-04-18 18:02:32 +02:00
Max Bruckner
24cf9308de README: Caveat about zero terminated strings 2017-04-18 17:58:36 +02:00
Max Bruckner
51d3df6c9f cJSON_GetObjectItemCaseSensitive: Fix inconsistent prototype
Thanks @PawelWMS
2017-04-18 17:37:43 +02:00
Max Bruckner
cea3fe4165 Caveats: Add note about UTF-8 encoding 2017-04-12 21:22:07 +02:00
Max Bruckner
f11b5eadc8 Update Changelog for 1.4.7 2017-04-11 16:44:55 +02:00
Max Bruckner
075a06f40b cJSONUtils_ApplyPatches: Fix not accepting arrays
This was completely broken, arrays weren't accepted.
2017-04-11 16:41:50 +02:00
Max Bruckner
3c18c83513 Add Changelog 2017-04-09 19:06:12 +02:00
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
12 changed files with 444 additions and 132 deletions

177
CHANGELOG.md Normal file
View File

@@ -0,0 +1,177 @@
1.4.7
=====
Fixes:
------
* Fix `cJSONUtils_ApplyPatches`, it was completely broken and apparently nobody noticed (or at least reported it) (075a06f40bdc4f836c7dd7cad690d253a57cfc50)
* Fix inconsistent prototype for `cJSON_GetObjectItemCaseSensitive` (51d3df6c9f7b56b860c8fb24abe7bab255cd4fa9) thanks @PawelWMS
1.4.6
=====
Fixes:
------
* Several corrections in the README
* Making clear that `valueint` should not be written to
* Fix overflow detection in `ensure` (2683d4d9873df87c4bdccc523903ddd78d1ad250)
* Fix a potential null pointer dereference in cJSON_Utils (795c3acabed25c9672006b2c0f40be8845064827)
* Replace incorrect `sizeof('\0')` with `sizeof("")` (84237ff48e69825c94261c624eb0376d0c328139)
* Add caveats section to the README (50b3c30dfa89830f8f477ce33713500740ac3b79)
* Make cJSON locale independent (#146) Thanks @peterh for reporting
* Fix compiling without CMake with MSVC (#147) Thanks @dertuxmalwieder for reporting
1.4.5
=====
Fixes:
------
* Fix bug in `cJSON_SetNumberHelper`, thanks @mmkeeper (#138 ef34500693e8c4a2849d41a4bd66fd19c9ec46c2)
* Workaround for internal compiler error in GCC 5.4.0 and 6.3.1 on x86 (2f65e80a3471d053fdc3f8aed23d01dd1782a5cb [GCC bugreport](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80097))
1.4.4
=====
Fixes:
--------
* Fix a theoretical integer overflow, (not sure if it is possible on actual hardware) e58f7ec027d00b7cdcbf63e518c1b5268b29b3da
* Fix an off by one error (cc84a446be20cc283bafdc4d94c050ba1111ac02), thanks @gatzka
* Double check the offset of the print buffer in `ensure` (1934059554b9a0971e00f79e96900f422cfdd114)
Improvements:
-------------
* Add a note in the header about required buffer size when using `cJSON_PrintPreallocated` (4bfb88009342fb568295a7f6dc4b7fee74fbf022)
1.4.3
=====
Fixes:
------
* Fix compilation of the tests on 32 bit PowerPC and potentially other systems (4ec6e76ea2eec16f54b58e8c95b4c734e59481e4)
* Fix compilation with old GCC compilers (4.3+ were tested) (227d3398d6b967879761ebe02c1b63dbd6ea6e0d, 466eb8e3f8a65080f2b3ca4a79ab7b72bd539dba), see also #126
1.4.2
=====
Fixes:
------
* Fix minimum required cmake version (30e1e7af7c63db9b55f5a3cda977a6c032f0b132)
* Fix detection of supported compiler flags (76e5296d0d05ceb3018a9901639e0e171b44a557)
* Run `cJSON_test` and `cJSON_test_utils` along with unity tests (c597601cf151a757dcf800548f18034d4ddfe2cb)
1.4.1
=====
Fix: Make `print_number` abort with a failure in out of memory situations (cf1842dc6f64c49451a022308b4415e4d468be0a)
1.4.0
=====
Features
--------
* Functions to check the type of an item (#120)
* Use dllexport on windows and fvisibility on Unix systems for public functions (#116), thanks @mjerris
* Remove trailing zeroes from printed numbers (#123)
* Expose the internal boolean type `cJSON_bool` in the header (2d3520e0b9d0eb870e8886e8a21c571eeddbb310)
Fixes
-----
* Fix handling of NULL pointers in `cJSON_ArrayForEach` (b47d0e34caaef298edfb7bd09a72cfff21d231ff)
* Make it compile with GCC 7 (fix -Wimplicit-fallthrough warning) (9d07917feb1b613544a7513d19233d4c851ad7ad)
Other Improvements
------------------
* internally use realloc if available (#110)
* builtin support for fuzzing with [afl](http://lcamtuf.coredump.cx/afl/) (#111)
* unit tests for the print functions (#112)
* Always use buffered printing (#113)
* simplify the print functions (#114)
* Add the compiler flags `-Wdouble-conversion`, `-Wparentheses` and `-Wcomma` (#122)
1.3.2
=====
Fix:
----
- Don't build the unity library if testing is disabled ( #121 ). Thanks @ffontaine
1.3.1
=====
Bugfix release that fixes an out of bounds read #118. This shouldn't have any security implications.
1.3.0
=====
This release includes a lot of rework in the parser and includes the Cunity unit testing framework, as well as some fixes. I increased the minor version number because there were quite a lot of internal changes.
Features:
---------
- New type for cJSON structs: `cJSON_Invalid` (#108)
Fixes:
------
- runtime checks for a lot of potential integer overflows
- fix incorrect return in cJSON_PrintBuffered (cf9d57d56cac21fc59465b8d26cf29bf6d2a87b3)
- fix several potential issues found by [Coverity](https://scan.coverity.com/projects/cjson)
- fix potentially undefined behavior when assigning big numbers to `valueint` (41e2837df1b1091643aff073f2313f6ff3cc10f4)
- Numbers exceeding `INT_MAX` or lower than `INT_MIN` will be explicitly assigned to `valueint` as `INT_MAX` and `INT_MIN` respectively (saturation on overflow).
- fix the `cJSON_SetNumberValue` macro (87f77274de6b3af00fb9b9a7f3b900ef382296c2), this slightly changes the behavior, see commit message
Introduce unit tests
--------------------
Started writing unit tests with the [Cunity](https://github.com/ThrowTheSwitch/Unity) testing framework. Currently this covers the parser functions.
Also:
- Support for running the tests with [Valgrind](http://valgrind.org)
- Support for compiling the tests with [AddressSanitizer](https://github.com/google/sanitizers) and [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html).
- `travis.yml` file for running unit tests on travis. (not enabled for the repository yet though #102)
Simplifications
---------------
After having unit tests for the parser function in place, I started refactoring the parser functions (as well as others) and making them easier to read and maintain.
- Use `strtod` from the standard library for parsing numbers (074766997246481dfc72bfa78f07898a2716473f)
- Use goto-fail in several parser functions (#100)
- Rewrite/restructure all of the parsing functions to be easier to understand and have less code paths doing the same as another. (#109)
- Simplify the buffer allocation strategy to always doubling the needed amount (9f6fa94c91a87b71e4c6868dbf2ce431a48517b0)
- Combined `cJSON_AddItemToObject` and `cJSON_AddItemToObjectCS` to one function (cf862d0fed7f9407e4b046d78d3d8050d2080d12)
Other changes
-------------
- Prevent the usage of incompatible C and header versions via preprocessor directive (123bb1af7bfae41d805337fef4b41045ef6c7d25)
- Let CMake automatically detect compiler flags
- Add new compiler flags (`-Wundef`, `-Wswitch-default`, `-Wconversion`, `-fstack-protector-strong`) (#98)
- Change internal sizes from `int` to `size_t` (ecd5678527a6bc422da694e5be9e9979878fe6a0)
- Change internal strings from `char*` to `unsigned char*` (28b9ba4334e0f7309e867e874a31f395c0ac2474)
- Add `const` in more places
1.2.1
=====
Fixes:
------
- Fixes a potential null pointer dereference in cJSON_Utils, discovered using clang's static analyzer by @bnason-nf (#96)
1.2.0
=====
Features:
---------
- Add a new type of cJSON item for raw JSON and support printing it. Thanks @loigu (#65, #90)
Fixes:
------
- Compiler warning if const is casted away, Thanks @gatzka (#83)
- Fix compile error with strict-overflow on PowerPC, (#85)
- Fix typo in the README, thanks @MicroJoe (#88)
- Add compile flag for compatibility with C++ compilers
1.1.0
=====
- Add a function `cJSON_PrintPreallocated` to print to a preallocated buffer, thanks @ChisholmKyle (#72)
- More compiler warnings when using Clang or GCC, thanks @gatzka (#75, #78)
- fixed a memory leak in `cJSON_Duplicate`, thanks @alperakcan (#81)
- fix the `ENABLE_CUSTOM_COMPILER_FLAGS` cmake option
1.0.2
=====
Rename internal boolean type, see #71.
1.0.1
=====
Small bugfix release.
- Fixes a bug with the use of the cJSON structs type in cJSON_Utils, see d47339e2740360e6e0994527d5e4752007480f3a
- improve code readability
- initialize all variables
1.0.0
=====
This is the first official versioned release of cJSON. It provides an API version for the shared library and improved Makefile and CMake build files.

View File

@@ -1,7 +1,5 @@
set(CMAKE_LEGACY_CYGWIN_WIN32 0)
cmake_minimum_required(VERSION 2.8)
subdirs(tests fuzzing)
cmake_minimum_required(VERSION 2.8.5)
include(GNUInstallDirs)
@@ -9,7 +7,7 @@ project(cJSON C)
set(PROJECT_VERSION_MAJOR 1)
set(PROJECT_VERSION_MINOR 4)
set(PROJECT_VERSION_PATCH 0)
set(PROJECT_VERSION_PATCH 7)
set(CJSON_VERSION_SO 1)
set(CJSON_UTILS_VERSION_SO 1)
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
@@ -78,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}")
@@ -167,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

@@ -10,7 +10,7 @@ UTILS_TEST_SRC = cJSON.c cJSON_Utils.c test_utils.c
LDLIBS = -lm
LIBVERSION = 1.4.0
LIBVERSION = 1.4.7
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,37 @@ 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
#### Zero Character
cJSON doesn't support strings that contain the zero character `'\0'` or `\u0000`. This is impossible with the current API because strings are zero terminated.
#### Character Encoding
cJSON only supports UTF-8 encoded input and will always produce UTF-8 as output (If the input contained invalid UTF-8, it will most likely propagate it through to the output, thereby making the output non-valid UTF-8).
#### 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

175
cJSON.c
View File

@@ -31,6 +31,7 @@
#include <float.h>
#include <limits.h>
#include <ctype.h>
#include <locale.h>
#pragma GCC visibility pop
#include "cJSON.h"
@@ -47,7 +48,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
}
/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 4) || (CJSON_VERSION_PATCH != 0)
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 4) || (CJSON_VERSION_PATCH != 7)
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
#endif
@@ -100,7 +101,7 @@ static unsigned char* cJSON_strdup(const unsigned char* str, const internal_hook
return NULL;
}
len = strlen((const char*)str) + 1;
len = strlen((const char*)str) + sizeof("");
if (!(copy = (unsigned char*)hooks->allocate(len)))
{
return NULL;
@@ -177,19 +178,63 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *c)
}
}
/* get the decimal point character of the current locale */
static unsigned char get_decimal_point(void)
{
struct lconv *lconv = localeconv();
return (unsigned char) lconv->decimal_point[0];
}
/* Parse the input text to generate a number, and populate the result into item. */
static const unsigned char *parse_number(cJSON * const item, const unsigned char * const input)
{
double number = 0;
unsigned char *after_end = NULL;
unsigned char number_c_string[64];
unsigned char decimal_point = get_decimal_point();
size_t i = 0;
if (input == NULL)
{
return NULL;
}
number = strtod((const char*)input, (char**)&after_end);
if (input == after_end)
/* copy the number into a temporary buffer and replace '.' with the decimal point
* of the current locale (for strtod) */
for (i = 0; (i < (sizeof(number_c_string) - 1)) && (input[i] != '\0'); i++)
{
switch (input[i])
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '+':
case '-':
case 'e':
case 'E':
number_c_string[i] = input[i];
break;
case '.':
number_c_string[i] = decimal_point;
break;
default:
goto loop_end;
}
}
loop_end:
number_c_string[i] = '\0';
number = strtod((const char*)number_c_string, (char**)&after_end);
if (number_c_string == after_end)
{
return NULL; /* parse_error */
}
@@ -212,7 +257,7 @@ static const unsigned char *parse_number(cJSON * const item, const unsigned char
item->type = cJSON_Number;
return after_end;
return input + (after_end - number_c_string);
}
/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
@@ -228,7 +273,7 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
}
else
{
object->valueint = cJSON_Number;
object->valueint = (int)number;
}
return object->valuedouble = number;
@@ -253,13 +298,19 @@ static unsigned char* ensure(printbuffer * const p, size_t needed, const interna
return NULL;
}
if ((p->length > 0) && (p->offset >= p->length))
{
/* make sure that offset is valid */
return NULL;
}
if (needed > INT_MAX)
{
/* sizes bigger than INT_MAX are currently not supported */
return NULL;
}
needed += p->offset;
needed += p->offset + 1;
if (needed <= p->length)
{
return p->buffer + p->offset;
@@ -270,8 +321,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed, const interna
}
/* calculate new buffer size */
newsize = needed * 2;
if (newsize > INT_MAX)
if (needed > (INT_MAX / 2))
{
/* overflow of int, use INT_MAX if possible */
if (needed <= INT_MAX)
@@ -283,6 +333,10 @@ static unsigned char* ensure(printbuffer * const p, size_t needed, const interna
return NULL;
}
}
else
{
newsize = needed * 2;
}
if (hooks->reallocate != NULL)
{
@@ -327,34 +381,24 @@ static void update_offset(printbuffer * const buffer)
}
/* Removes trailing zeroes from the end of a printed number */
static cJSON_bool trim_trailing_zeroes(printbuffer * const buffer)
static int trim_trailing_zeroes(const unsigned char * const number, int length, const unsigned char decimal_point)
{
size_t offset = 0;
unsigned char *content = NULL;
if ((buffer == NULL) || (buffer->buffer == NULL) || (buffer->offset < 1))
if ((number == NULL) || (length <= 0))
{
return false;
return -1;
}
offset = buffer->offset - 1;
content = buffer->buffer;
while ((offset > 0) && (content[offset] == '0'))
while ((length > 0) && (number[length - 1] == '0'))
{
offset--;
length--;
}
if ((offset > 0) && (content[offset] == '.'))
if ((length > 0) && (number[length - 1] == decimal_point))
{
offset--;
/* remove trailing decimal_point */
length--;
}
offset++;
content[offset] = '\0';
buffer->offset = offset;
return true;
return length;
}
/* Render the number nicely from the given item into a string. */
@@ -363,51 +407,74 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
unsigned char *output_pointer = NULL;
double d = item->valuedouble;
int length = 0;
cJSON_bool trim_zeroes = true; /* should at the end be removed? */
size_t i = 0;
cJSON_bool trim_zeroes = true; /* should zeroes at the end be removed? */
unsigned char number_buffer[64]; /* temporary buffer to print the number into */
unsigned char decimal_point = get_decimal_point();
if (output_buffer == NULL)
{
return false;
}
/* This is a nice tradeoff. */
output_pointer = ensure(output_buffer, 64, hooks);
if (output_pointer != NULL)
{
/* This checks for NaN and Infinity */
if ((d * 0) != 0)
{
length = sprintf((char*)output_pointer, "null");
length = sprintf((char*)number_buffer, "null");
}
else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60))
{
/* integer */
length = sprintf((char*)output_pointer, "%.0f", d);
length = sprintf((char*)number_buffer, "%.0f", d);
trim_zeroes = false; /* don't remove zeroes for "big integers" */
}
else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9))
{
length = sprintf((char*)output_pointer, "%e", d);
length = sprintf((char*)number_buffer, "%e", d);
trim_zeroes = false; /* don't remove zeroes in engineering notation */
}
else
{
length = sprintf((char*)output_pointer, "%f", d);
}
length = sprintf((char*)number_buffer, "%f", d);
}
/* sprintf failed */
if (length < 0)
/* sprintf failed or buffer overrun occured */
if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
{
return false;
}
output_buffer->offset += (size_t)length;
if (trim_zeroes)
{
return trim_trailing_zeroes(output_buffer);
length = trim_trailing_zeroes(number_buffer, length, decimal_point);
if (length <= 0)
{
return false;
}
}
/* reserve appropriate space in the output */
output_pointer = ensure(output_buffer, (size_t)length, hooks);
if (output_pointer == NULL)
{
return false;
}
/* copy the printed number to the output and replace locale
* dependent decimal point with '.' */
for (i = 0; i < ((size_t)length); i++)
{
if (number_buffer[i] == decimal_point)
{
output_pointer[i] = '.';
continue;
}
output_pointer[i] = number_buffer[i];
}
output_pointer[i] = '\0';
output_buffer->offset += (size_t)length;
return true;
}
@@ -617,7 +684,7 @@ static const unsigned char *parse_string(cJSON * const item, const unsigned char
/* This is at most how much we need for the output */
allocation_length = (size_t) (input_end - input) - skipped_bytes;
output = (unsigned char*)hooks->allocate(allocation_length + sizeof('\0'));
output = (unsigned char*)hooks->allocate(allocation_length + sizeof(""));
if (output == NULL)
{
goto fail; /* allocation failure */
@@ -1090,7 +1157,7 @@ static cJSON_bool print_value(const cJSON * const item, const size_t depth, cons
return false;
}
raw_length = strlen(item->valuestring) + sizeof('\0');
raw_length = strlen(item->valuestring) + sizeof("");
output = ensure(output_buffer, raw_length, hooks);
if (output == NULL)
{
@@ -1224,7 +1291,7 @@ static cJSON_bool print_array(const cJSON * const item, const size_t depth, cons
update_offset(output_buffer);
if (current_element->next)
{
length = format ? 2 : 1;
length = (size_t) (format ? 2 : 1);
output_pointer = ensure(output_buffer, length + 1, hooks);
if (output_pointer == NULL)
{
@@ -1360,7 +1427,7 @@ static cJSON_bool print_object(const cJSON * const item, const size_t depth, con
}
/* Compose the output: */
length = format ? 2 : 1; /* fmt: {\n */
length = (size_t) (format ? 2 : 1); /* fmt: {\n */
output_pointer = ensure(output_buffer, length + 1, hooks);
if (output_pointer == NULL)
{
@@ -1398,7 +1465,7 @@ static cJSON_bool print_object(const cJSON * const item, const size_t depth, con
}
update_offset(output_buffer);
length = format ? 2 : 1;
length = (size_t) (format ? 2 : 1);
output_pointer = ensure(output_buffer, length, hooks);
if (output_pointer == NULL)
{
@@ -1419,7 +1486,7 @@ static cJSON_bool print_object(const cJSON * const item, const size_t depth, con
update_offset(output_buffer);
/* print comma if not last */
length = (size_t) (format ? 1 : 0) + (current_item->next ? 1 : 0);
length = (size_t) ((format ? 1 : 0) + (current_item->next ? 1 : 0));
output_pointer = ensure(output_buffer, length + 1, hooks);
if (output_pointer == NULL)
{
@@ -1578,6 +1645,10 @@ CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSO
item->type &= ~cJSON_StringIsConst;
}
#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
#pragma GCC diagnostic push
#endif
#pragma GCC diagnostic ignored "-Wcast-qual"
/* Add an item to an object with constant string as key */
CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
{
@@ -1589,13 +1660,13 @@ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJ
{
global_hooks.deallocate(item->string);
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
item->string = (char*)string;
#pragma GCC diagnostic pop
item->type |= cJSON_StringIsConst;
cJSON_AddItemToArray(object, item);
}
#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
#pragma GCC diagnostic pop
#endif
CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
{

21
cJSON.h
View File

@@ -31,7 +31,7 @@ extern "C"
/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 4
#define CJSON_VERSION_PATCH 0
#define CJSON_VERSION_PATCH 7
#include <stddef.h>
@@ -63,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;
@@ -88,7 +88,8 @@ typedef int cJSON_bool;
/* 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
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
@@ -102,11 +103,16 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ
*/
/* 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
#else
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall
#endif
#else /* !WIN32 */
@@ -132,8 +138,9 @@ CJSON_PUBLIC(char *) cJSON_Print(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 */
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 length buf_len. Returns 1 on success and 0 on failure. */
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const 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. */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
@@ -142,7 +149,7 @@ CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int item);
/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const 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. */

View File

@@ -230,11 +230,11 @@ static void cJSONUtils_InplaceDecodePointerString(unsigned char *string)
for (; *string; (void)s2++, string++)
{
*s2 = (*string != '~')
*s2 = (unsigned char) ((*string != '~')
? (*string)
: ((*(++string) == '0')
? '~'
: '/');
: '/'));
}
*s2 = '\0';
@@ -468,7 +468,7 @@ 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);
@@ -504,12 +504,7 @@ CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches)
{
int err = 0;
if (patches == NULL)
{
return 1;
}
if (cJSON_IsArray(patches))
if (!cJSON_IsArray(patches))
{
/* malformed patches. */
return 1;

View File

@@ -56,7 +56,7 @@ static 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;

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

@@ -2,15 +2,29 @@ if(ENABLE_CJSON_TEST)
add_library(unity unity/src/unity.c)
# Disable -Werror for Unity
list(FIND custom_compiler_flags "-Werror" werror_found)
if (werror_found)
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
list(FIND custom_compiler_flags "-fvisibility=hidden" visibility_found)
if (visibility_found)
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")
@@ -46,20 +60,17 @@ if(ENABLE_CJSON_TEST)
endif()
endif()
#"check" target that automatically builds everything and runs the tests
add_custom_target(check
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
DEPENDS ${unity_tests})
foreach(unity_test ${unity_tests})
add_executable("${unity_test}" "${unity_test}.c")
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

@@ -70,7 +70,7 @@ CJSON_PUBLIC(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

@@ -50,7 +50,7 @@ static void print_number_should_print_negative_integers(void)
{
assert_print_number("-1", -1);
assert_print_number("-32768", -32768);
assert_print_number("-2147483648", -2147483648);
assert_print_number("-2147483648", -2147483648.0);
}
static void print_number_should_print_positive_integers(void)
@@ -89,17 +89,11 @@ static void print_number_should_print_non_number(void)
static void trim_trailing_zeroes_should_trim_trailing_zeroes(void)
{
printbuffer buffer;
unsigned char number[100];
buffer.length = sizeof(number);
buffer.buffer = number;
strcpy((char*)number, "10.00");
buffer.offset = sizeof("10.00") - 1;
TEST_ASSERT_TRUE(trim_trailing_zeroes(&buffer));
TEST_ASSERT_EQUAL_UINT8('\0', buffer.buffer[buffer.offset]);
TEST_ASSERT_EQUAL_STRING("10", number);
TEST_ASSERT_EQUAL_UINT(sizeof("10") - 1, buffer.offset);
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)