Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f110bd2e58 | ||
|
|
5cd1dabb30 | ||
|
|
d606cbbc64 | ||
|
|
be749d7efa | ||
|
|
eaec82c3c5 | ||
|
|
cb1df2f88c | ||
|
|
2c914c073d | ||
|
|
4917024741 | ||
|
|
a3fadd44d1 | ||
|
|
feb05fb2fd | ||
|
|
26f38f4782 | ||
|
|
8e742e4869 | ||
|
|
543ab5d08a | ||
|
|
e2162adeed | ||
|
|
08103f048e | ||
|
|
ace800e444 | ||
|
|
00544a4a74 | ||
|
|
3550a5553d | ||
|
|
d9fe34bade | ||
|
|
f25b8448e4 | ||
|
|
ad2cb5b7ea | ||
|
|
f32703a7a1 | ||
|
|
86234db095 | ||
|
|
af5b4911de | ||
|
|
787d651e81 | ||
|
|
1571a3ebe4 | ||
|
|
0d5ecc11b6 | ||
|
|
529ec06abb | ||
|
|
3349978268 | ||
|
|
cbc05de76f | ||
|
|
7996a4a2ee | ||
|
|
ed8fefc9ca | ||
|
|
e6869c2e03 | ||
|
|
0e0c463491 | ||
|
|
2336a0348d | ||
|
|
5d50f4efe1 | ||
|
|
8abf110750 | ||
|
|
d26a42af8d | ||
|
|
6f264b5d0c | ||
|
|
5da9edc8b1 | ||
|
|
22a7d04fa0 | ||
|
|
a559eac472 | ||
|
|
d514bb866e |
23
.editorconfig
Normal file
23
.editorconfig
Normal file
@@ -0,0 +1,23 @@
|
||||
root = true
|
||||
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
indent_size = unset
|
||||
|
||||
# ignore external repositories and test inputs
|
||||
[tests/{unity,json-patch-tests,inputs}/*]
|
||||
indent_style = unset
|
||||
indent_size = unset
|
||||
end_of_line = unset
|
||||
charset = unset
|
||||
trim_trailing_whitespace = unset
|
||||
insert_final_newline = unset
|
||||
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
* text=auto
|
||||
/tests/inputs/* text eol=lf
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -14,3 +14,5 @@ libcjson.so.*
|
||||
libcjson_utils.so.*
|
||||
*.orig
|
||||
.vscode
|
||||
.idea
|
||||
cmake-build-debug
|
||||
|
||||
49
CHANGELOG.md
49
CHANGELOG.md
@@ -1,3 +1,52 @@
|
||||
1.7.9
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix a bug where `cJSON_GetObjectItemCaseSensitive` would pass a nullpointer to `strcmp` when called on an array (#315). Thanks @yuweol for reporting.
|
||||
* Fix error in `cJSON_Utils` where the case sensitivity was not respected (#317). Thanks @yuta-oxo for fixing.
|
||||
|
||||
1.7.8
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* cJSON now works with the `__stdcall` calling convention on Windows, see #295, thanks @zhindes for contributing
|
||||
|
||||
1.7.7
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix a memory leak when realloc fails (see #267), thanks @AlfieDeng for reporting
|
||||
* Fix a typo in the header file (see #266), thanks @zhaozhixu
|
||||
|
||||
1.7.6
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Add `SONAME` to the ELF files built by the Makefile (see #252), thanks @YanhaoMo for reporting
|
||||
* Add include guards and `extern "C"` to `cJSON_Utils.h` (see #256), thanks @daschfg for reporting
|
||||
|
||||
Other changes:
|
||||
--------------
|
||||
* Mark the Makefile as deprecated in the README.
|
||||
|
||||
1.7.5
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix a bug in the JSON Patch implementation of `cJSON Utils` (see #251), thanks @bobkocisko.
|
||||
|
||||
1.7.4
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix potential use after free if the `string` parameter to `cJSON_AddItemToObject` is an alias of the `string` property of the object that is added (#248). Thanks @hhallen for reporting.
|
||||
|
||||
1.7.3
|
||||
=====
|
||||
Fixes:
|
||||
------
|
||||
* Fix potential double free, thanks @projectgus for reporting (see #241)
|
||||
|
||||
1.7.2
|
||||
=====
|
||||
Fixes:
|
||||
|
||||
@@ -7,7 +7,7 @@ include(GNUInstallDirs)
|
||||
|
||||
set(PROJECT_VERSION_MAJOR 1)
|
||||
set(PROJECT_VERSION_MINOR 7)
|
||||
set(PROJECT_VERSION_PATCH 2)
|
||||
set(PROJECT_VERSION_PATCH 9)
|
||||
set(CJSON_VERSION_SO 1)
|
||||
set(CJSON_UTILS_VERSION_SO 1)
|
||||
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||
@@ -49,11 +49,15 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS)
|
||||
-Wswitch-enum
|
||||
)
|
||||
elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# Disable warning c4001 - nonstandard extension 'single line comment' was used
|
||||
# Define _CRT_SECURE_NO_WARNINGS to disable deprecation warnings for "insecure" C library functions
|
||||
list(APPEND custom_compiler_flags
|
||||
/GS
|
||||
/Za
|
||||
/sdl
|
||||
/W4
|
||||
/wd4001
|
||||
/D_CRT_SECURE_NO_WARNINGS
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -7,6 +7,8 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB)
|
||||
* [Ajay Bhargav](https://github.com/ajaybhargav)
|
||||
* [Alper Akcan](https://github.com/alperakcan)
|
||||
* [Anton Sergeev](https://github.com/anton-sergeev)
|
||||
* [Benbuck Nason](https://github.com/bnason-nf)
|
||||
* [Bob Kocisko](https://github.com/bobkocisko)
|
||||
* [Christian Schulze](https://github.com/ChristianSch)
|
||||
* [Casperinous](https://github.com/Casperinous)
|
||||
* [Debora Grosse](https://github.com/DeboraG)
|
||||
@@ -40,5 +42,10 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB)
|
||||
* [Stephan Gatzka](https://github.com/gatzka)
|
||||
* [Weston Schmidt](https://github.com/schmidtw)
|
||||
* [yangfl](https://github.com/yangfl)
|
||||
* [yuta-oxo](https://github.com/yuta-oxo)
|
||||
* [Zach Hindes](https://github.com/zhindes)
|
||||
* [Zhao Zhixu](https://github.com/zhaozhixu)
|
||||
|
||||
And probably more people on [SourceForge](https://sourceforge.net/p/cjson/bugs/search/?q=status%3Aclosed-rejected+or+status%3Aclosed-out-of-date+or+status%3Awont-fix+or+status%3Aclosed-fixed+or+status%3Aclosed&page=0)
|
||||
|
||||
Also thanks to all the people who reported bugs and suggested new features.
|
||||
|
||||
13
Makefile
13
Makefile
@@ -8,10 +8,13 @@ CJSON_TEST_SRC = cJSON.c test.c
|
||||
|
||||
LDLIBS = -lm
|
||||
|
||||
LIBVERSION = 1.7.2
|
||||
LIBVERSION = 1.7.9
|
||||
CJSON_SOVERSION = 1
|
||||
UTILS_SOVERSION = 1
|
||||
|
||||
CJSON_SO_LDFLAG=-Wl,-soname=$(CJSON_LIBNAME).so.$(CJSON_SOVERSION)
|
||||
UTILS_SO_LDFLAG=-Wl,-soname=$(UTILS_LIBNAME).so.$(UTILS_SOVERSION)
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
INCLUDE_PATH ?= include/cjson
|
||||
LIBRARY_PATH ?= lib
|
||||
@@ -23,7 +26,7 @@ INSTALL ?= cp -a
|
||||
|
||||
# validate gcc version for use fstack-protector-strong
|
||||
MIN_GCC_VERSION = "4.9"
|
||||
GCC_VERSION := "`gcc -dumpversion`"
|
||||
GCC_VERSION := "`$(CC) -dumpversion`"
|
||||
IS_GCC_ABOVE_MIN_VERSION := $(shell expr "$(GCC_VERSION)" ">=" "$(MIN_GCC_VERSION)")
|
||||
ifeq "$(IS_GCC_ABOVE_MIN_VERSION)" "1"
|
||||
CFLAGS += -fstack-protector-strong
|
||||
@@ -42,6 +45,8 @@ STATIC = a
|
||||
## create dynamic (shared) library on Darwin (base OS for MacOSX and IOS)
|
||||
ifeq (Darwin, $(uname))
|
||||
SHARED = dylib
|
||||
CJSON_SO_LDFLAG = ""
|
||||
UTILS_SO_LDFLAG = ""
|
||||
endif
|
||||
|
||||
#cJSON library names
|
||||
@@ -90,10 +95,10 @@ $(UTILS_STATIC): $(UTILS_OBJ)
|
||||
#shared libraries .so.1.0.0
|
||||
#cJSON
|
||||
$(CJSON_SHARED_VERSION): $(CJSON_OBJ)
|
||||
$(CC) -shared -o $@ $< $(LDFLAGS)
|
||||
$(CC) -shared -o $@ $< $(CJSON_SO_LDFLAG) $(LDFLAGS)
|
||||
#cJSON_Utils
|
||||
$(UTILS_SHARED_VERSION): $(UTILS_OBJ)
|
||||
$(CC) -shared -o $@ $< $(LDFLAGS)
|
||||
$(CC) -shared -o $@ $< $(UTILS_SO_LDFLAG) $(LDFLAGS)
|
||||
|
||||
#objects
|
||||
#cJSON
|
||||
|
||||
@@ -127,9 +127,11 @@ make DESTDIR=$pkgdir install
|
||||
On Windows CMake is usually used to create a Visual Studio solution file by running it inside the Developer Command Prompt for Visual Studio, for exact steps follow the official documentation from CMake and Microsoft and use the online search engine of your choice. The descriptions of the the options above still generally apply, although not all of them work on Windows.
|
||||
|
||||
#### Makefile
|
||||
**NOTE:** This Method is deprecated. Use CMake if at all possible. Makefile support is limited to fixing bugs.
|
||||
|
||||
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.
|
||||
Run this command in the directory with the source code and it will automatically compile static and shared libraries and a little test program (not the full test suite).
|
||||
|
||||
```
|
||||
make all
|
||||
@@ -296,6 +298,7 @@ In this example we want to build and parse the following JSON:
|
||||
Let's build the above JSON and print it to a string:
|
||||
```c
|
||||
//create a monitor with a list of supported resolutions
|
||||
//NOTE: Returns a heap allocated string, you are required to free it after use.
|
||||
char* create_monitor(void)
|
||||
{
|
||||
const unsigned int resolution_numbers[3][2] = {
|
||||
@@ -371,6 +374,7 @@ end:
|
||||
|
||||
Alternatively we can use the `cJSON_Add...ToObject` helper functions to make our lifes a little easier:
|
||||
```c
|
||||
//NOTE: Returns a heap allocated string, you are required to free it after use.
|
||||
char *create_monitor_with_helpers(void)
|
||||
{
|
||||
const unsigned int resolution_numbers[3][2] = {
|
||||
|
||||
72
cJSON.c
72
cJSON.c
@@ -41,7 +41,6 @@
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
|
||||
@@ -82,7 +81,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) {
|
||||
}
|
||||
|
||||
/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
|
||||
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 2)
|
||||
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 9)
|
||||
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
|
||||
#endif
|
||||
|
||||
@@ -120,22 +119,22 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned
|
||||
|
||||
typedef struct internal_hooks
|
||||
{
|
||||
void *(*allocate)(size_t size);
|
||||
void (*deallocate)(void *pointer);
|
||||
void *(*reallocate)(void *pointer, size_t size);
|
||||
void *(CJSON_CDECL *allocate)(size_t size);
|
||||
void (CJSON_CDECL *deallocate)(void *pointer);
|
||||
void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
|
||||
} internal_hooks;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
/* work around MSVC error C2322: '...' address of dillimport '...' is not static */
|
||||
static void *internal_malloc(size_t size)
|
||||
static void * CJSON_CDECL internal_malloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
static void internal_free(void *pointer)
|
||||
static void CJSON_CDECL internal_free(void *pointer)
|
||||
{
|
||||
free(pointer);
|
||||
}
|
||||
static void *internal_realloc(void *pointer, size_t size)
|
||||
static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
|
||||
{
|
||||
return realloc(pointer, size);
|
||||
}
|
||||
@@ -325,7 +324,7 @@ loop_end:
|
||||
{
|
||||
item->valueint = INT_MAX;
|
||||
}
|
||||
else if (number <= INT_MIN)
|
||||
else if (number <= (double)INT_MIN)
|
||||
{
|
||||
item->valueint = INT_MIN;
|
||||
}
|
||||
@@ -347,7 +346,7 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
|
||||
{
|
||||
object->valueint = INT_MAX;
|
||||
}
|
||||
else if (number <= INT_MIN)
|
||||
else if (number <= (double)INT_MIN)
|
||||
{
|
||||
object->valueint = INT_MIN;
|
||||
}
|
||||
@@ -1114,10 +1113,10 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i
|
||||
if (hooks->reallocate != NULL)
|
||||
{
|
||||
printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
|
||||
buffer->buffer = NULL;
|
||||
if (printed == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
buffer->buffer = NULL;
|
||||
}
|
||||
else /* otherwise copy the JSON over to a new buffer */
|
||||
{
|
||||
@@ -1311,10 +1310,6 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp
|
||||
size_t raw_length = 0;
|
||||
if (item->valuestring == NULL)
|
||||
{
|
||||
if (!output_buffer->noalloc)
|
||||
{
|
||||
output_buffer->hooks.deallocate(output_buffer->buffer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1680,7 +1675,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out
|
||||
update_offset(output_buffer);
|
||||
|
||||
/* print comma if not last */
|
||||
length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0));
|
||||
length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
|
||||
output_pointer = ensure(output_buffer, length + 1);
|
||||
if (output_pointer == NULL)
|
||||
{
|
||||
@@ -1786,7 +1781,7 @@ static cJSON *get_object_item(const cJSON * const object, const char * const nam
|
||||
current_element = object->child;
|
||||
if (case_sensitive)
|
||||
{
|
||||
while ((current_element != NULL) && (strcmp(name, current_element->string) != 0))
|
||||
while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
|
||||
{
|
||||
current_element = current_element->next;
|
||||
}
|
||||
@@ -1799,6 +1794,10 @@ static cJSON *get_object_item(const cJSON * const object, const char * const nam
|
||||
}
|
||||
}
|
||||
|
||||
if ((current_element == NULL) || (current_element->string == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return current_element;
|
||||
}
|
||||
|
||||
@@ -1899,32 +1898,37 @@ static void* cast_away_const(const void* string)
|
||||
|
||||
static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
|
||||
{
|
||||
char *new_key = NULL;
|
||||
int new_type = cJSON_Invalid;
|
||||
|
||||
if ((object == NULL) || (string == NULL) || (item == NULL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (constant_key)
|
||||
{
|
||||
new_key = (char*)cast_away_const(string);
|
||||
new_type = item->type | cJSON_StringIsConst;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
|
||||
if (new_key == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
new_type = item->type & ~cJSON_StringIsConst;
|
||||
}
|
||||
|
||||
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
|
||||
{
|
||||
hooks->deallocate(item->string);
|
||||
}
|
||||
|
||||
if (constant_key)
|
||||
{
|
||||
item->string = (char*)cast_away_const(string);
|
||||
item->type |= cJSON_StringIsConst;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
|
||||
if (key == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
item->string = key;
|
||||
item->type &= ~cJSON_StringIsConst;
|
||||
}
|
||||
item->string = new_key;
|
||||
item->type = new_type;
|
||||
|
||||
return add_item_to_array(object, item);
|
||||
}
|
||||
@@ -2300,7 +2304,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
|
||||
{
|
||||
item->valueint = INT_MAX;
|
||||
}
|
||||
else if (num <= INT_MIN)
|
||||
else if (num <= (double)INT_MIN)
|
||||
{
|
||||
item->valueint = INT_MIN;
|
||||
}
|
||||
|
||||
102
cJSON.h
102
cJSON.h
@@ -28,10 +28,60 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#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 3 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
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* 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 CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#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
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 2
|
||||
#define CJSON_VERSION_PATCH 9
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -74,55 +124,13 @@ typedef struct cJSON
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *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
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
@@ -156,7 +164,7 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
|
||||
@@ -510,7 +510,7 @@ static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive)
|
||||
while ((first != NULL) && (second != NULL))
|
||||
{
|
||||
cJSON *smaller = NULL;
|
||||
if (compare_strings((unsigned char*)first->string, (unsigned char*)second->string, false) < 0)
|
||||
if (compare_strings((unsigned char*)first->string, (unsigned char*)second->string, case_sensitive) < 0)
|
||||
{
|
||||
smaller = first;
|
||||
}
|
||||
@@ -988,6 +988,12 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_
|
||||
cJSON_AddItemToObject(parent, (char*)child_pointer, value);
|
||||
value = NULL;
|
||||
}
|
||||
else /* parent is not an object */
|
||||
{
|
||||
/* Couldn't find object to add to. */
|
||||
status = 9;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (value != NULL)
|
||||
|
||||
@@ -20,6 +20,14 @@
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON_Utils__h
|
||||
#define cJSON_Utils__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "cJSON.h"
|
||||
|
||||
/* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */
|
||||
@@ -72,3 +80,9 @@ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const obje
|
||||
/* Sorts the members of the object into alphabetical order. */
|
||||
CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object);
|
||||
CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
2
test.c
2
test.c
@@ -256,7 +256,7 @@ static void create_objects(void)
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
/* print the version */
|
||||
printf("Version: %s\n", cJSON_Version());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
if(ENABLE_CJSON_TEST)
|
||||
add_library(unity "${CJSON_LIBRARY_TYPE}" unity/src/unity.c)
|
||||
add_library(unity STATIC unity/src/unity.c)
|
||||
|
||||
# Disable -Werror for Unity
|
||||
if (FLAG_SUPPORTED_Werror)
|
||||
@@ -72,6 +72,9 @@ if(ENABLE_CJSON_TEST)
|
||||
|
||||
foreach(unity_test ${unity_tests})
|
||||
add_executable("${unity_test}" "${unity_test}.c")
|
||||
if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
|
||||
target_sources(${unity_test} PRIVATE unity_setup.c)
|
||||
endif()
|
||||
target_link_libraries("${unity_test}" "${CJSON_LIB}" unity)
|
||||
if(MEMORYCHECK_COMMAND)
|
||||
add_test(NAME "${unity_test}"
|
||||
|
||||
@@ -28,15 +28,21 @@
|
||||
#include "unity/src/unity.h"
|
||||
#include "common.h"
|
||||
|
||||
static void *failing_malloc(size_t size)
|
||||
static void * CJSON_CDECL failing_malloc(size_t size)
|
||||
{
|
||||
(void)size;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* work around MSVC error C2322: '...' address of dillimport '...' is not static */
|
||||
static void CJSON_CDECL normal_free(void *pointer)
|
||||
{
|
||||
free(pointer);
|
||||
}
|
||||
|
||||
static cJSON_Hooks failing_hooks = {
|
||||
failing_malloc,
|
||||
free
|
||||
normal_free
|
||||
};
|
||||
|
||||
static void cjson_add_null_should_add_null(void)
|
||||
@@ -372,7 +378,7 @@ static void cjson_add_array_should_fail_on_allocation_failure(void)
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ static void cjson_compare_should_compare_objects(void)
|
||||
false))
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
|
||||
@@ -80,5 +80,12 @@
|
||||
"doc": { "foo": ["bar"] },
|
||||
"patch": [ { "op": "add", "path": "/foo/-", "value": ["abc", "def"] }],
|
||||
"expected": {"foo": ["bar", ["abc", "def"]] }
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"comment": "15",
|
||||
"doc": {"foo": {"bar": 1}},
|
||||
"patch": [{"op": "add", "path": "/foo/bar/baz", "value": "5"}],
|
||||
"error": "attempting to add to subfield of non-object"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -214,6 +214,7 @@
|
||||
|
||||
{ "doc": {"foo": null},
|
||||
"patch": [{"op": "test", "path": "/foo", "value": null}],
|
||||
"expected": {"foo": null},
|
||||
"comment": "null value should be valid obj property" },
|
||||
|
||||
{ "doc": {"foo": null},
|
||||
@@ -243,14 +244,17 @@
|
||||
|
||||
{ "doc": {"foo": {"foo": 1, "bar": 2}},
|
||||
"patch": [{"op": "test", "path": "/foo", "value": {"bar": 2, "foo": 1}}],
|
||||
"expected": {"foo": {"foo": 1, "bar": 2}},
|
||||
"comment": "test should pass despite rearrangement" },
|
||||
|
||||
{ "doc": {"foo": [{"foo": 1, "bar": 2}]},
|
||||
"patch": [{"op": "test", "path": "/foo", "value": [{"bar": 2, "foo": 1}]}],
|
||||
"expected": {"foo": [{"foo": 1, "bar": 2}]},
|
||||
"comment": "test should pass despite (nested) rearrangement" },
|
||||
|
||||
{ "doc": {"foo": {"bar": [1, 2, 5, 4]}},
|
||||
"patch": [{"op": "test", "path": "/foo", "value": {"bar": [1, 2, 5, 4]}}],
|
||||
"expected": {"foo": {"bar": [1, 2, 5, 4]}},
|
||||
"comment": "test should pass - no error" },
|
||||
|
||||
{ "doc": {"foo": {"bar": [1, 2, 5, 4]}},
|
||||
@@ -264,7 +268,8 @@
|
||||
|
||||
{ "comment": "Empty-string element",
|
||||
"doc": { "": 1 },
|
||||
"patch": [{"op": "test", "path": "/", "value": 1}] },
|
||||
"patch": [{"op": "test", "path": "/", "value": 1}],
|
||||
"expected": { "": 1 } },
|
||||
|
||||
{ "doc": {
|
||||
"foo": ["bar", "baz"],
|
||||
@@ -288,8 +293,23 @@
|
||||
{"op": "test", "path": "/i\\j", "value": 5},
|
||||
{"op": "test", "path": "/k\"l", "value": 6},
|
||||
{"op": "test", "path": "/ ", "value": 7},
|
||||
{"op": "test", "path": "/m~0n", "value": 8}] },
|
||||
|
||||
{"op": "test", "path": "/m~0n", "value": 8}],
|
||||
"expected": {
|
||||
"": 0,
|
||||
" ": 7,
|
||||
"a/b": 1,
|
||||
"c%d": 2,
|
||||
"e^f": 3,
|
||||
"foo": [
|
||||
"bar",
|
||||
"baz"
|
||||
],
|
||||
"g|h": 4,
|
||||
"i\\j": 5,
|
||||
"k\"l": 6,
|
||||
"m~n": 8
|
||||
}
|
||||
},
|
||||
{ "comment": "Move to same location has no effect",
|
||||
"doc": {"foo": 1},
|
||||
"patch": [{"op": "move", "from": "/foo", "path": "/foo"}],
|
||||
@@ -388,11 +408,21 @@
|
||||
"patch": [ { "op": "copy", "path": "/-" } ],
|
||||
"error": "missing 'from' parameter" },
|
||||
|
||||
{ "comment": "missing from location to copy",
|
||||
"doc": { "foo": 1 },
|
||||
"patch": [ { "op": "copy", "from": "/bar", "path": "/foo" } ],
|
||||
"error": "missing 'from' location" },
|
||||
|
||||
{ "comment": "missing from parameter to move",
|
||||
"doc": { "foo": 1 },
|
||||
"patch": [ { "op": "move", "path": "" } ],
|
||||
"error": "missing 'from' parameter" },
|
||||
|
||||
{ "comment": "missing from location to move",
|
||||
"doc": { "foo": 1 },
|
||||
"patch": [ { "op": "move", "from": "/bar", "path": "/foo" } ],
|
||||
"error": "missing 'from' location" },
|
||||
|
||||
{ "comment": "duplicate ops",
|
||||
"doc": { "foo": "bar" },
|
||||
"patch": [ { "op": "add", "path": "/baz", "value": "qux",
|
||||
|
||||
@@ -127,6 +127,28 @@ static void cjson_get_object_item_case_sensitive_should_get_object_items(void)
|
||||
cJSON_Delete(item);
|
||||
}
|
||||
|
||||
static void cjson_get_object_item_should_not_crash_with_array(void) {
|
||||
cJSON *array = NULL;
|
||||
cJSON *found = NULL;
|
||||
array = cJSON_Parse("[1]");
|
||||
|
||||
found = cJSON_GetObjectItem(array, "name");
|
||||
TEST_ASSERT_NULL(found);
|
||||
|
||||
cJSON_Delete(array);
|
||||
}
|
||||
|
||||
static void cjson_get_object_item_case_sensitive_should_not_crash_with_array(void) {
|
||||
cJSON *array = NULL;
|
||||
cJSON *found = NULL;
|
||||
array = cJSON_Parse("[1]");
|
||||
|
||||
found = cJSON_GetObjectItemCaseSensitive(array, "name");
|
||||
TEST_ASSERT_NULL(found);
|
||||
|
||||
cJSON_Delete(array);
|
||||
}
|
||||
|
||||
static void typecheck_functions_should_check_type(void)
|
||||
{
|
||||
cJSON invalid[1];
|
||||
@@ -410,7 +432,7 @@ static void cjson_functions_shouldnt_crash_with_null_pointers(void)
|
||||
cJSON_Delete(item);
|
||||
}
|
||||
|
||||
static void *failing_realloc(void *pointer, size_t size)
|
||||
static void * CJSON_CDECL failing_realloc(void *pointer, size_t size)
|
||||
{
|
||||
(void)size;
|
||||
(void)pointer;
|
||||
@@ -508,7 +530,26 @@ static void cjson_create_array_reference_should_create_an_array_reference(void)
|
||||
cJSON_Delete(number_reference);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased(void)
|
||||
{
|
||||
cJSON *object = cJSON_CreateObject();
|
||||
cJSON *number = cJSON_CreateNumber(42);
|
||||
char *name = (char*)cJSON_strdup((const unsigned char*)"number", &global_hooks);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(object);
|
||||
TEST_ASSERT_NOT_NULL(number);
|
||||
TEST_ASSERT_NOT_NULL(name);
|
||||
|
||||
number->string = name;
|
||||
|
||||
/* The following should not have a use after free
|
||||
* that would show up in valgrind or with AddressSanitizer */
|
||||
cJSON_AddItemToObject(object, number->string, number);
|
||||
|
||||
cJSON_Delete(object);
|
||||
}
|
||||
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
@@ -516,6 +557,8 @@ int main(void)
|
||||
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(cjson_get_object_item_should_not_crash_with_array);
|
||||
RUN_TEST(cjson_get_object_item_case_sensitive_should_not_crash_with_array);
|
||||
RUN_TEST(typecheck_functions_should_check_type);
|
||||
RUN_TEST(cjson_should_not_parse_to_deeply_nested_jsons);
|
||||
RUN_TEST(cjson_set_number_value_should_set_numbers);
|
||||
@@ -530,6 +573,7 @@ int main(void)
|
||||
RUN_TEST(cjson_create_string_reference_should_create_a_string_reference);
|
||||
RUN_TEST(cjson_create_object_reference_should_create_an_object_reference);
|
||||
RUN_TEST(cjson_create_array_reference_should_create_an_array_reference);
|
||||
RUN_TEST(cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ static void parse_array_should_not_parse_non_arrays(void)
|
||||
assert_not_array("\"[]hello world!\n\"");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
/* initialize cJSON item */
|
||||
memset(item, 0, sizeof(cJSON));
|
||||
|
||||
@@ -195,7 +195,7 @@ static void test12_should_not_be_parsed(void)
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(file_test1_should_be_parsed_and_printed);
|
||||
|
||||
@@ -64,7 +64,7 @@ static void parse_hex4_should_parse_mixed_case(void)
|
||||
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BEEF"));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(parse_hex4_should_parse_all_combinations);
|
||||
|
||||
@@ -96,7 +96,7 @@ static void parse_number_should_parse_negative_reals(void)
|
||||
assert_parse_number("-123e-128", 0, -123e-128);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
/* initialize cJSON item */
|
||||
memset(item, 0, sizeof(cJSON));
|
||||
|
||||
@@ -162,7 +162,7 @@ static void parse_object_should_not_parse_non_objects(void)
|
||||
assert_not_object("\"{}hello world!\n\"");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
/* initialize cJSON item */
|
||||
memset(item, 0, sizeof(cJSON));
|
||||
|
||||
@@ -119,7 +119,7 @@ static void parse_string_should_parse_bug_94(void)
|
||||
reset(item);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
/* initialize cJSON item and error pointer */
|
||||
memset(item, 0, sizeof(cJSON));
|
||||
|
||||
@@ -96,7 +96,7 @@ static void parse_value_should_parse_object(void)
|
||||
reset(item);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
/* initialize cJSON item */
|
||||
memset(item, 0, sizeof(cJSON));
|
||||
|
||||
@@ -97,7 +97,7 @@ static void parse_with_opts_should_parse_utf8_bom(void)
|
||||
cJSON_Delete(without_bom);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ static void print_array_should_print_arrays_with_multiple_elements(void)
|
||||
assert_print_array("[1, null, true, false, [], \"hello\", {\n\t}]", "[1,null,true,false,[],\"hello\",{}]");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
/* initialize cJSON item */
|
||||
UNITY_BEGIN();
|
||||
|
||||
@@ -89,7 +89,7 @@ static void print_number_should_print_non_number(void)
|
||||
/* assert_print_number("null", -INFTY); */
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
/* initialize cJSON item */
|
||||
UNITY_BEGIN();
|
||||
|
||||
@@ -88,7 +88,7 @@ static void print_object_should_print_objects_with_multiple_elements(void)
|
||||
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)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
/* initialize cJSON item */
|
||||
UNITY_BEGIN();
|
||||
|
||||
@@ -65,7 +65,7 @@ static void print_string_should_print_utf8(void)
|
||||
assert_print_string("\"ü猫慕\"", "ü猫慕");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
/* initialize cJSON item */
|
||||
UNITY_BEGIN();
|
||||
|
||||
@@ -90,7 +90,7 @@ static void print_value_should_print_object(void)
|
||||
assert_print_value("{}");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
/* initialize cJSON item */
|
||||
UNITY_BEGIN();
|
||||
|
||||
@@ -246,7 +246,7 @@ static void supports_full_hd_should_check_for_full_hd_support(void)
|
||||
TEST_ASSERT_FALSE(supports_full_hd(monitor_without_hd));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
int CJSON_CDECL main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
||||
|
||||
3
tests/unity_setup.c
Normal file
3
tests/unity_setup.c
Normal file
@@ -0,0 +1,3 @@
|
||||
// msvc doesn't support weak-linking, so we need to define these functions.
|
||||
void setUp(void) { }
|
||||
void tearDown(void) { }
|
||||
Reference in New Issue
Block a user