Compare commits

..
22 Commits
Author SHA1 Message Date
Max Bruckner f110bd2e58 Release Version 1.7.9 2018-12-16 11:17:20 +01:00
Max Bruckner 5cd1dabb30 Add yuta-oxo to the Contributors 2018-12-16 11:16:31 +01:00
Max Bruckner d606cbbc64 Merge pull request #317 from yuta-oxo/fix_sort_list
fix bug: sort_list() returns strange results
2018-12-16 11:10:06 +01:00
Max Bruckner be749d7efa Fix crash of cJSON_GetObjectItemCaseSensitive when calling it on arrays 2018-12-16 11:06:40 +01:00
yuta-oxo eaec82c3c5 fix bug: sort_list() returns strange results 2018-12-12 15:09:53 +09:00
Max Bruckner cb1df2f88c README: Add note about needing to free print results in examples 2018-12-03 23:07:36 +01:00
Max Bruckner 2c914c073d Gitignore: Ignore CLion directories 2018-10-14 11:52:41 +02:00
Max Bruckner 4917024741 Makefile: Fix indentation 2018-10-14 11:52:19 +02:00
Max Bruckner a3fadd44d1 Add .editorconfig 2018-10-14 11:51:56 +02:00
Max Bruckner feb05fb2fd Add Benbuck Nason to the list of contributors 2018-10-14 11:22:14 +02:00
Max Bruckner 26f38f4782 Merge pull request #307 from bnason-nf/vstudio_static_analyzer_warnings
Fix most of the issues reported by the Visual Studio code analysis tool
2018-10-14 11:17:34 +02:00
Benbuck Nason 8e742e4869 Fix most of the issues reported by the Visual Studio code analysis tool. 2018-10-12 14:29:59 -07:00
Max Bruckner 543ab5d08a Update json-patch-tests 2018-10-11 00:30:43 +02:00
Max Bruckner e2162adeed Squashed 'tests/json-patch-tests/' changes from 99264bb..9ecd703
9ecd703 Merge pull request #39 from mr-mixas/test-absent-from-location-for-copy-and-move-ops
66817e7 test absent 'from' location for copy and move
09dee56 Fix anonymous test
8bae8ed Fix « test should pass - no error » test
855f2a4 Fix « test should pass despite (nested) rearrangement » test
53283fc Fix « test should pass despite rearrangement » test
ecf01e7 Fix « null value should be valid obj property » test
1586cdf Fix « Empty-string element » test

git-subtree-dir: tests/json-patch-tests
git-subtree-split: 9ecd703c08cda4864cd2d2fb580a513ec5740934
2018-10-11 00:30:43 +02:00
Max Bruckner 08103f048e Release version 1.7.8 2018-09-21 19:29:42 +02:00
Max Bruckner ace800e444 Update changelog for 1.7.8 2018-09-21 19:28:25 +02:00
Max Bruckner 00544a4a74 Contributors: Add Zach Hindes 2018-09-21 19:26:01 +02:00
Max Bruckner 3550a5553d Merge pull request #295 from zhindes/master
Support default __stdcall calling convention (/Gz) on Windows
2018-09-21 19:23:31 +02:00
Zach Hindes d9fe34bade Add newline to end of unity_setup.c 2018-09-17 09:10:20 -05:00
Zach Hindes f25b8448e4 Support default __stdcall calling convention on tests as well 2018-09-12 15:32:30 -05:00
Zach Hindes ad2cb5b7ea Enable build and test on Windows 2018-09-04 14:36:21 -05:00
Zach Hindes f32703a7a1 Support default __stdcall calling convention (/Gz) on Windows 2018-08-29 16:25:46 -05:00
31 changed files with 327 additions and 369 deletions

No files matched your search

+23
View 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
View File
@@ -0,0 +1,2 @@
* text=auto
/tests/inputs/* text eol=lf
+13
View File
@@ -1,3 +1,16 @@
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 1.7.7
===== =====
Fixes: Fixes:
+6 -1
View File
@@ -7,7 +7,7 @@ include(GNUInstallDirs)
set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MAJOR 1)
set(PROJECT_VERSION_MINOR 7) set(PROJECT_VERSION_MINOR 7)
set(PROJECT_VERSION_PATCH 7) set(PROJECT_VERSION_PATCH 9)
set(CJSON_VERSION_SO 1) set(CJSON_VERSION_SO 1)
set(CJSON_UTILS_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1)
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
@@ -49,11 +49,15 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS)
-Wswitch-enum -Wswitch-enum
) )
elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") 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 list(APPEND custom_compiler_flags
/GS /GS
/Za /Za
/sdl /sdl
/W4 /W4
/wd4001
/D_CRT_SECURE_NO_WARNINGS
) )
endif() endif()
endif() endif()
@@ -64,6 +68,7 @@ if (ENABLE_SANITIZERS)
-fno-omit-frame-pointer -fno-omit-frame-pointer
-fsanitize=address -fsanitize=address
-fsanitize=undefined -fsanitize=undefined
-fsanitize=float-divide-by-zero
-fsanitize=float-cast-overflow -fsanitize=float-cast-overflow
-fsanitize-address-use-after-scope -fsanitize-address-use-after-scope
-fsanitize=integer -fsanitize=integer
+3
View File
@@ -7,6 +7,7 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB)
* [Ajay Bhargav](https://github.com/ajaybhargav) * [Ajay Bhargav](https://github.com/ajaybhargav)
* [Alper Akcan](https://github.com/alperakcan) * [Alper Akcan](https://github.com/alperakcan)
* [Anton Sergeev](https://github.com/anton-sergeev) * [Anton Sergeev](https://github.com/anton-sergeev)
* [Benbuck Nason](https://github.com/bnason-nf)
* [Bob Kocisko](https://github.com/bobkocisko) * [Bob Kocisko](https://github.com/bobkocisko)
* [Christian Schulze](https://github.com/ChristianSch) * [Christian Schulze](https://github.com/ChristianSch)
* [Casperinous](https://github.com/Casperinous) * [Casperinous](https://github.com/Casperinous)
@@ -41,6 +42,8 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB)
* [Stephan Gatzka](https://github.com/gatzka) * [Stephan Gatzka](https://github.com/gatzka)
* [Weston Schmidt](https://github.com/schmidtw) * [Weston Schmidt](https://github.com/schmidtw)
* [yangfl](https://github.com/yangfl) * [yangfl](https://github.com/yangfl)
* [yuta-oxo](https://github.com/yuta-oxo)
* [Zach Hindes](https://github.com/zhindes)
* [Zhao Zhixu](https://github.com/zhaozhixu) * [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) 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)
+1 -1
View File
@@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c
LDLIBS = -lm LDLIBS = -lm
LIBVERSION = 1.7.7 LIBVERSION = 1.7.9
CJSON_SOVERSION = 1 CJSON_SOVERSION = 1
UTILS_SOVERSION = 1 UTILS_SOVERSION = 1
+2 -8
View File
@@ -245,12 +245,6 @@ Given some JSON in a zero terminated string, you can parse it with `cJSON_Parse`
cJSON *json = cJSON_Parse(string); cJSON *json = cJSON_Parse(string);
``` ```
Given some JSON in a string (whether zero terminated or not), you can parse it with `cJSON_ParseWithLength`.
```c
cJSON *json = cJSON_ParseWithLength(string, buffer_length);
```
It will parse the JSON and allocate a tree of `cJSON` items that represents it. Once it returns, you are fully responsible for deallocating it after use with `cJSON_Delete`. It will parse the JSON and allocate a tree of `cJSON` items that represents it. Once it returns, you are fully responsible for deallocating it after use with `cJSON_Delete`.
The allocator used by `cJSON_Parse` is `malloc` and `free` by default but can be changed (globally) with `cJSON_InitHooks`. The allocator used by `cJSON_Parse` is `malloc` and `free` by default but can be changed (globally) with `cJSON_InitHooks`.
@@ -261,8 +255,6 @@ By default, characters in the input string that follow the parsed JSON will not
If you want more options, use `cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)`. If you want more options, use `cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)`.
`return_parse_end` returns a pointer to the end of the JSON in the input string or the position that an error occurs at (thereby replacing `cJSON_GetErrorPtr` in a thread safe way). `require_null_terminated`, if set to `1` will make it an error if the input string contains data after the JSON. `return_parse_end` returns a pointer to the end of the JSON in the input string or the position that an error occurs at (thereby replacing `cJSON_GetErrorPtr` in a thread safe way). `require_null_terminated`, if set to `1` will make it an error if the input string contains data after the JSON.
If you want more options giving buffer length, use `cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)`.
### Printing JSON ### Printing JSON
Given a tree of `cJSON` items, you can print them as a string using `cJSON_Print`. Given a tree of `cJSON` items, you can print them as a string using `cJSON_Print`.
@@ -306,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: Let's build the above JSON and print it to a string:
```c ```c
//create a monitor with a list of supported resolutions //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) char* create_monitor(void)
{ {
const unsigned int resolution_numbers[3][2] = { const unsigned int resolution_numbers[3][2] = {
@@ -381,6 +374,7 @@ end:
Alternatively we can use the `cJSON_Add...ToObject` helper functions to make our lifes a little easier: Alternatively we can use the `cJSON_Add...ToObject` helper functions to make our lifes a little easier:
```c ```c
//NOTE: Returns a heap allocated string, you are required to free it after use.
char *create_monitor_with_helpers(void) char *create_monitor_with_helpers(void)
{ {
const unsigned int resolution_numbers[3][2] = { const unsigned int resolution_numbers[3][2] = {
+129 -191
View File
@@ -39,6 +39,7 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <limits.h> #include <limits.h>
#include <ctype.h> #include <ctype.h>
@@ -71,28 +72,16 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
return (const char*) (global_error.json + global_error.position); return (const char*) (global_error.json + global_error.position);
} }
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) {
{ if (!cJSON_IsString(item)) {
if (!cJSON_IsString(item))
{
return NULL; return NULL;
} }
return item->valuestring; return item->valuestring;
} }
CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item)
{
if (!cJSON_IsNumber(item))
{
return 0.0/0.0;
}
return item->valuedouble;
}
/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ /* 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 != 7) #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. #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
#endif #endif
@@ -130,22 +119,22 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned
typedef struct internal_hooks typedef struct internal_hooks
{ {
void *(*allocate)(size_t size); void *(CJSON_CDECL *allocate)(size_t size);
void (*deallocate)(void *pointer); void (CJSON_CDECL *deallocate)(void *pointer);
void *(*reallocate)(void *pointer, size_t size); void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
} internal_hooks; } internal_hooks;
#if defined(_MSC_VER) #if defined(_MSC_VER)
/* work around MSVC error C2322: '...' address of dillimport '...' is not static */ /* 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); return malloc(size);
} }
static void internal_free(void *pointer) static void CJSON_CDECL internal_free(void *pointer)
{ {
free(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); return realloc(pointer, size);
} }
@@ -235,32 +224,16 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
{ {
global_hooks.deallocate(item->valuestring); global_hooks.deallocate(item->valuestring);
item->valuestring = NULL;
} }
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
{ {
global_hooks.deallocate(item->string); global_hooks.deallocate(item->string);
item->string = NULL;
} }
global_hooks.deallocate(item); global_hooks.deallocate(item);
item = next; item = next;
} }
} }
static int double_to_saturated_integer(double number)
{
if (number >= INT_MAX)
{
return INT_MAX;
}
else if (number <= INT_MIN)
{
return INT_MIN;
}
return (int)number;
}
/* get the decimal point character of the current locale */ /* get the decimal point character of the current locale */
static unsigned char get_decimal_point(void) static unsigned char get_decimal_point(void)
{ {
@@ -282,9 +255,9 @@ typedef struct
} parse_buffer; } parse_buffer;
/* check if the given size is left to read in a given parse buffer (starting with 1) */ /* check if the given size is left to read in a given parse buffer (starting with 1) */
#define can_read(buffer, size) (((buffer)->offset + (size)) <= (buffer)->length) #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
/* check if the buffer can be accessed at the given index (starting with 0) */ /* check if the buffer can be accessed at the given index (starting with 0) */
#define can_access_at_index(buffer, index) (((buffer)->offset + (index)) < (buffer)->length) #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
/* get a pointer to the buffer at the position */ /* get a pointer to the buffer at the position */
#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
@@ -345,7 +318,21 @@ loop_end:
} }
item->valuedouble = number; item->valuedouble = number;
item->valueint = double_to_saturated_integer(number);
/* use saturation in case of overflow */
if (number >= INT_MAX)
{
item->valueint = INT_MAX;
}
else if (number <= (double)INT_MIN)
{
item->valueint = INT_MIN;
}
else
{
item->valueint = (int)number;
}
item->type = cJSON_Number; item->type = cJSON_Number;
input_buffer->offset += (size_t)(after_end - number_c_string); input_buffer->offset += (size_t)(after_end - number_c_string);
@@ -355,7 +342,18 @@ loop_end:
/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
{ {
object->valueint = double_to_saturated_integer(number); if (number >= INT_MAX)
{
object->valueint = INT_MAX;
}
else if (number <= (double)INT_MIN)
{
object->valueint = INT_MIN;
}
else
{
object->valueint = (int)number;
}
return object->valuedouble = number; return object->valuedouble = number;
} }
@@ -472,15 +470,11 @@ static void update_offset(printbuffer * const buffer)
buffer->offset += strlen((const char*)buffer_pointer); buffer->offset += strlen((const char*)buffer_pointer);
} }
#define is_nan(number) ((number) != (number))
#define is_infinity(number) (!is_nan(number) && ((number) * 0) != 0)
/* Render the number nicely from the given item into a string. */ /* Render the number nicely from the given item into a string. */
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
{ {
unsigned char *output_pointer = NULL; unsigned char *output_pointer = NULL;
double number = item->valuedouble; double d = item->valuedouble;
int integer = double_to_saturated_integer(number);
int length = 0; int length = 0;
size_t i = 0; size_t i = 0;
unsigned char number_buffer[26]; /* temporary buffer to print the number into */ unsigned char number_buffer[26]; /* temporary buffer to print the number into */
@@ -492,24 +486,21 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
return false; return false;
} }
if (is_nan(number) || is_infinity(number)) /* This checks for NaN and Infinity */
if ((d * 0) != 0)
{ {
length = sprintf((char*)number_buffer, "null"); length = sprintf((char*)number_buffer, "null");
} }
else if (number == integer) /* avoid overhead for integers */
{
length = sprintf((char*)number_buffer, "%d", integer);
}
else else
{ {
/* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
length = sprintf((char*)number_buffer, "%1.15g", number); length = sprintf((char*)number_buffer, "%1.15g", d);
/* Check whether the original double can be recovered */ /* Check whether the original double can be recovered */
if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != number)) if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d))
{ {
/* If not, print with 17 decimal places of precision */ /* If not, print with 17 decimal places of precision */
length = sprintf((char*)number_buffer, "%1.17g", number); length = sprintf((char*)number_buffer, "%1.17g", d);
} }
} }
@@ -822,7 +813,6 @@ fail:
if (output != NULL) if (output != NULL)
{ {
input_buffer->hooks.deallocate(output); input_buffer->hooks.deallocate(output);
output = NULL;
} }
if (input_pointer != NULL) if (input_pointer != NULL)
@@ -851,13 +841,12 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe
/* empty string */ /* empty string */
if (input == NULL) if (input == NULL)
{ {
const char quotes[] = "\"\""; output = ensure(output_buffer, sizeof("\"\""));
output = ensure(output_buffer, sizeof(quotes));
if (output == NULL) if (output == NULL)
{ {
return false; return false;
} }
memcpy(output, quotes, sizeof(quotes)); strcpy((char*)output, "\"\"");
return true; return true;
} }
@@ -978,11 +967,6 @@ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
return NULL; return NULL;
} }
if (cannot_access_at_index(buffer, 0))
{
return buffer;
}
while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
{ {
buffer->offset++; buffer->offset++;
@@ -1012,23 +996,8 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
return buffer; return buffer;
} }
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
{
size_t buffer_length;
if (NULL == value)
{
return NULL;
}
/* Adding null character size due to require_null_terminated. */
buffer_length = strlen(value) + sizeof("");
return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
}
/* Parse an object - create a new root, and populate. */ /* Parse an object - create a new root, and populate. */
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
{ {
parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
cJSON *item = NULL; cJSON *item = NULL;
@@ -1037,13 +1006,13 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer
global_error.json = NULL; global_error.json = NULL;
global_error.position = 0; global_error.position = 0;
if (value == NULL || 0 == buffer_length) if (value == NULL)
{ {
goto fail; goto fail;
} }
buffer.content = (const unsigned char*)value; buffer.content = (const unsigned char*)value;
buffer.length = buffer_length; buffer.length = strlen((const char*)value) + sizeof("");
buffer.offset = 0; buffer.offset = 0;
buffer.hooks = global_hooks; buffer.hooks = global_hooks;
@@ -1113,12 +1082,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
return cJSON_ParseWithOpts(value, 0, 0); return cJSON_ParseWithOpts(value, 0, 0);
} }
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) #define cjson_min(a, b) ((a < b) ? a : b)
{
return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
}
#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
{ {
@@ -1145,8 +1109,6 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i
} }
update_offset(buffer); update_offset(buffer);
/* Reallocate the buffer so that it only uses as much as it needs.
This can save up to 50% because ensure increases the buffer size by a factor of 2 */
/* check if reallocate is available */ /* check if reallocate is available */
if (hooks->reallocate != NULL) if (hooks->reallocate != NULL)
{ {
@@ -1168,7 +1130,6 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i
/* free the buffer */ /* free the buffer */
hooks->deallocate(buffer->buffer); hooks->deallocate(buffer->buffer);
buffer->buffer = NULL;
} }
return printed; return printed;
@@ -1177,13 +1138,11 @@ fail:
if (buffer->buffer != NULL) if (buffer->buffer != NULL)
{ {
hooks->deallocate(buffer->buffer); hooks->deallocate(buffer->buffer);
buffer->buffer = NULL;
} }
if (printed != NULL) if (printed != NULL)
{ {
hooks->deallocate(printed); hooks->deallocate(printed);
printed = NULL;
} }
return NULL; return NULL;
@@ -1224,27 +1183,26 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON
if (!print_value(item, &p)) if (!print_value(item, &p))
{ {
global_hooks.deallocate(p.buffer); global_hooks.deallocate(p.buffer);
p.buffer = NULL;
return NULL; return NULL;
} }
return (char*)p.buffer; return (char*)p.buffer;
} }
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt)
{ {
printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
if ((length < 0) || (buffer == NULL)) if ((len < 0) || (buf == NULL))
{ {
return false; return false;
} }
p.buffer = (unsigned char*)buffer; p.buffer = (unsigned char*)buf;
p.length = (size_t)length; p.length = (size_t)len;
p.offset = 0; p.offset = 0;
p.noalloc = true; p.noalloc = true;
p.format = format; p.format = fmt;
p.hooks = global_hooks; p.hooks = global_hooks;
return print_value(item, &p); return print_value(item, &p);
@@ -1258,52 +1216,22 @@ static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buf
return false; /* no input */ return false; /* no input */
} }
if (!can_read(input_buffer, 1))
{
return false;
}
/* parse the different types of values */ /* parse the different types of values */
switch (buffer_at_offset(input_buffer)[0])
{
/* number */
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return parse_number(item, input_buffer);
/* string */
case '\"':
return parse_string(item, input_buffer);
/* array */
case '[':
return parse_array(item, input_buffer);
/* object */
case '{':
return parse_object(item, input_buffer);
/* null */ /* null */
case 'n':
if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
{ {
item->type = cJSON_NULL; item->type = cJSON_NULL;
input_buffer->offset += 4; input_buffer->offset += 4;
return true; return true;
} }
return false; /* false */
if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
{
item->type = cJSON_False;
input_buffer->offset += 5;
return true;
}
/* true */ /* true */
case 't':
if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
{ {
item->type = cJSON_True; item->type = cJSON_True;
@@ -1311,22 +1239,28 @@ static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buf
input_buffer->offset += 4; input_buffer->offset += 4;
return true; return true;
} }
return false; /* string */
if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
/* false */
case 'f':
if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
{ {
item->type = cJSON_False; return parse_string(item, input_buffer);
input_buffer->offset += 5;
return true;
} }
return false; /* number */
if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
{
default: return parse_number(item, input_buffer);
return false;
} }
/* array */
if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
{
return parse_array(item, input_buffer);
}
/* object */
if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
{
return parse_object(item, input_buffer);
}
return false;
} }
/* Render a value to text. */ /* Render a value to text. */
@@ -1342,40 +1276,31 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp
switch ((item->type) & 0xFF) switch ((item->type) & 0xFF)
{ {
case cJSON_NULL: case cJSON_NULL:
{ output = ensure(output_buffer, 5);
const char null_string[] = "null";
output = ensure(output_buffer, sizeof(null_string));
if (output == NULL) if (output == NULL)
{ {
return false; return false;
} }
memcpy(output, null_string, sizeof(null_string)); strcpy((char*)output, "null");
return true; return true;
}
case cJSON_False: case cJSON_False:
{ output = ensure(output_buffer, 6);
const char false_string[] = "false";
output = ensure(output_buffer, sizeof(false_string));
if (output == NULL) if (output == NULL)
{ {
return false; return false;
} }
memcpy(output, false_string, sizeof(false_string)); strcpy((char*)output, "false");
return true; return true;
}
case cJSON_True: case cJSON_True:
{ output = ensure(output_buffer, 5);
const char true_string[] = "true";
output = ensure(output_buffer, sizeof(true_string));
if (output == NULL) if (output == NULL)
{ {
return false; return false;
} }
memcpy(output, true_string, sizeof(true_string)); strcpy((char*)output, "true");
return true; return true;
}
case cJSON_Number: case cJSON_Number:
return print_number(item, output_buffer); return print_number(item, output_buffer);
@@ -1750,7 +1675,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out
update_offset(output_buffer); update_offset(output_buffer);
/* print comma if not last */ /* 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); output_pointer = ensure(output_buffer, length + 1);
if (output_pointer == NULL) if (output_pointer == NULL)
{ {
@@ -1791,7 +1716,8 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out
return true; return true;
} }
static size_t get_array_size(const cJSON * const array) /* Get Array size/item / object item. */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
{ {
cJSON *child = NULL; cJSON *child = NULL;
size_t size = 0; size_t size = 0;
@@ -1809,19 +1735,7 @@ static size_t get_array_size(const cJSON * const array)
child = child->next; child = child->next;
} }
return size; /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
}
/* Get Array size/item / object item. */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
{
size_t size = get_array_size(array);
if (size > INT_MAX)
{
/* This is incorrect but can't be fixed without breaking the API */
return INT_MAX;
}
return (int)size; return (int)size;
} }
@@ -1867,7 +1781,7 @@ static cJSON *get_object_item(const cJSON * const object, const char * const nam
current_element = object->child; current_element = object->child;
if (case_sensitive) 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; current_element = current_element->next;
} }
@@ -1880,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; return current_element;
} }
@@ -2362,12 +2280,12 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
return item; return item;
} }
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b)
{ {
cJSON *item = cJSON_New_Item(&global_hooks); cJSON *item = cJSON_New_Item(&global_hooks);
if(item) if(item)
{ {
item->type = boolean ? cJSON_True : cJSON_False; item->type = b ? cJSON_True : cJSON_False;
} }
return item; return item;
@@ -2380,7 +2298,20 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
{ {
item->type = cJSON_Number; item->type = cJSON_Number;
item->valuedouble = num; item->valuedouble = num;
item->valueint = double_to_saturated_integer(num);
/* use saturation in case of overflow */
if (num >= INT_MAX)
{
item->valueint = INT_MAX;
}
else if (num <= (double)INT_MIN)
{
item->valueint = INT_MIN;
}
else
{
item->valueint = (int)num;
}
} }
return item; return item;
@@ -2955,14 +2886,6 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons
{ {
cJSON *a_element = NULL; cJSON *a_element = NULL;
cJSON *b_element = NULL; cJSON *b_element = NULL;
size_t a_size = get_array_size(a);
size_t b_size = get_array_size(b);
if (a_size != b_size)
{
return false;
}
cJSON_ArrayForEach(a_element, a) cJSON_ArrayForEach(a_element, a)
{ {
/* TODO This has O(n^2) runtime, which is horrible! */ /* TODO This has O(n^2) runtime, which is horrible! */
@@ -2978,6 +2901,22 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons
} }
} }
/* doing this twice, once on a and b to prevent true comparison if a subset of b
* TODO: Do this the proper way, this is just a fix for now */
cJSON_ArrayForEach(b_element, b)
{
a_element = get_object_item(a, b_element->string, case_sensitive);
if (a_element == NULL)
{
return false;
}
if (!cJSON_Compare(b_element, a_element, case_sensitive))
{
return false;
}
}
return true; return true;
} }
@@ -2994,5 +2933,4 @@ CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
CJSON_PUBLIC(void) cJSON_free(void *object) CJSON_PUBLIC(void) cJSON_free(void *object)
{ {
global_hooks.deallocate(object); global_hooks.deallocate(object);
object = NULL;
} }
+56 -51
View File
@@ -28,10 +28,60 @@ extern "C"
{ {
#endif #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 */ /* project version */
#define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7 #define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 7 #define CJSON_VERSION_PATCH 9
#include <stddef.h> #include <stddef.h>
@@ -74,55 +124,13 @@ typedef struct cJSON
typedef struct cJSON_Hooks typedef struct cJSON_Hooks
{ {
void *(*malloc_fn)(size_t sz); /* 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 (*free_fn)(void *ptr); void *(CJSON_CDECL *malloc_fn)(size_t sz);
void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks; } cJSON_Hooks;
typedef int cJSON_bool; 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. /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
* This is to prevent stack overflows. */ * This is to prevent stack overflows. */
#ifndef CJSON_NESTING_LIMIT #ifndef CJSON_NESTING_LIMIT
@@ -138,11 +146,9 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ /* 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 so will match cJSON_GetErrorPtr(). */ /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
/* Render a cJSON entity to text for transfer/storage. */ /* Render a cJSON entity to text for transfer/storage. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
@@ -154,7 +160,7 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON
/* 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 */ /* 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); CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
/* Delete a cJSON entity and all subentities. */ /* Delete a cJSON entity and all subentities. */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
/* Returns the number of items in an array (or object). */ /* Returns the number of items in an array (or object). */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
@@ -167,9 +173,8 @@ CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *st
/* 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. */ /* 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. */
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* Check item type and return its value */ /* Check if the item is a string and return its valuestring */
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item);
/* These functions check the type of an item */ /* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
+1 -1
View File
@@ -510,7 +510,7 @@ static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive)
while ((first != NULL) && (second != NULL)) while ((first != NULL) && (second != NULL))
{ {
cJSON *smaller = 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; smaller = first;
} }
+1 -1
View File
@@ -256,7 +256,7 @@ static void create_objects(void)
cJSON_Delete(root); cJSON_Delete(root);
} }
int main(void) int CJSON_CDECL main(void)
{ {
/* print the version */ /* print the version */
printf("Version: %s\n", cJSON_Version()); printf("Version: %s\n", cJSON_Version());
+4 -1
View File
@@ -1,5 +1,5 @@
if(ENABLE_CJSON_TEST) 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 # Disable -Werror for Unity
if (FLAG_SUPPORTED_Werror) if (FLAG_SUPPORTED_Werror)
@@ -72,6 +72,9 @@ if(ENABLE_CJSON_TEST)
foreach(unity_test ${unity_tests}) foreach(unity_test ${unity_tests})
add_executable("${unity_test}" "${unity_test}.c") 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) target_link_libraries("${unity_test}" "${CJSON_LIB}" unity)
if(MEMORYCHECK_COMMAND) if(MEMORYCHECK_COMMAND)
add_test(NAME "${unity_test}" add_test(NAME "${unity_test}"
+9 -3
View File
@@ -28,15 +28,21 @@
#include "unity/src/unity.h" #include "unity/src/unity.h"
#include "common.h" #include "common.h"
static void *failing_malloc(size_t size) static void * CJSON_CDECL failing_malloc(size_t size)
{ {
(void)size; (void)size;
return NULL; 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 = { static cJSON_Hooks failing_hooks = {
failing_malloc, failing_malloc,
free normal_free
}; };
static void cjson_add_null_should_add_null(void) 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); cJSON_Delete(root);
} }
int main(void) int CJSON_CDECL main(void)
{ {
UNITY_BEGIN(); UNITY_BEGIN();
+1 -1
View File
@@ -186,7 +186,7 @@ static void cjson_compare_should_compare_objects(void)
false)) false))
} }
int main(void) int CJSON_CDECL main(void)
{ {
UNITY_BEGIN(); UNITY_BEGIN();
+33 -3
View File
@@ -214,6 +214,7 @@
{ "doc": {"foo": null}, { "doc": {"foo": null},
"patch": [{"op": "test", "path": "/foo", "value": null}], "patch": [{"op": "test", "path": "/foo", "value": null}],
"expected": {"foo": null},
"comment": "null value should be valid obj property" }, "comment": "null value should be valid obj property" },
{ "doc": {"foo": null}, { "doc": {"foo": null},
@@ -243,14 +244,17 @@
{ "doc": {"foo": {"foo": 1, "bar": 2}}, { "doc": {"foo": {"foo": 1, "bar": 2}},
"patch": [{"op": "test", "path": "/foo", "value": {"bar": 2, "foo": 1}}], "patch": [{"op": "test", "path": "/foo", "value": {"bar": 2, "foo": 1}}],
"expected": {"foo": {"foo": 1, "bar": 2}},
"comment": "test should pass despite rearrangement" }, "comment": "test should pass despite rearrangement" },
{ "doc": {"foo": [{"foo": 1, "bar": 2}]}, { "doc": {"foo": [{"foo": 1, "bar": 2}]},
"patch": [{"op": "test", "path": "/foo", "value": [{"bar": 2, "foo": 1}]}], "patch": [{"op": "test", "path": "/foo", "value": [{"bar": 2, "foo": 1}]}],
"expected": {"foo": [{"foo": 1, "bar": 2}]},
"comment": "test should pass despite (nested) rearrangement" }, "comment": "test should pass despite (nested) rearrangement" },
{ "doc": {"foo": {"bar": [1, 2, 5, 4]}}, { "doc": {"foo": {"bar": [1, 2, 5, 4]}},
"patch": [{"op": "test", "path": "/foo", "value": {"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" }, "comment": "test should pass - no error" },
{ "doc": {"foo": {"bar": [1, 2, 5, 4]}}, { "doc": {"foo": {"bar": [1, 2, 5, 4]}},
@@ -264,7 +268,8 @@
{ "comment": "Empty-string element", { "comment": "Empty-string element",
"doc": { "": 1 }, "doc": { "": 1 },
"patch": [{"op": "test", "path": "/", "value": 1}] }, "patch": [{"op": "test", "path": "/", "value": 1}],
"expected": { "": 1 } },
{ "doc": { { "doc": {
"foo": ["bar", "baz"], "foo": ["bar", "baz"],
@@ -288,8 +293,23 @@
{"op": "test", "path": "/i\\j", "value": 5}, {"op": "test", "path": "/i\\j", "value": 5},
{"op": "test", "path": "/k\"l", "value": 6}, {"op": "test", "path": "/k\"l", "value": 6},
{"op": "test", "path": "/ ", "value": 7}, {"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", { "comment": "Move to same location has no effect",
"doc": {"foo": 1}, "doc": {"foo": 1},
"patch": [{"op": "move", "from": "/foo", "path": "/foo"}], "patch": [{"op": "move", "from": "/foo", "path": "/foo"}],
@@ -388,11 +408,21 @@
"patch": [ { "op": "copy", "path": "/-" } ], "patch": [ { "op": "copy", "path": "/-" } ],
"error": "missing 'from' parameter" }, "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", { "comment": "missing from parameter to move",
"doc": { "foo": 1 }, "doc": { "foo": 1 },
"patch": [ { "op": "move", "path": "" } ], "patch": [ { "op": "move", "path": "" } ],
"error": "missing 'from' parameter" }, "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", { "comment": "duplicate ops",
"doc": { "foo": "bar" }, "doc": { "foo": "bar" },
"patch": [ { "op": "add", "path": "/baz", "value": "qux", "patch": [ { "op": "add", "path": "/baz", "value": "qux",
+26 -36
View File
@@ -127,6 +127,28 @@ static void cjson_get_object_item_case_sensitive_should_get_object_items(void)
cJSON_Delete(item); 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) static void typecheck_functions_should_check_type(void)
{ {
cJSON invalid[1]; cJSON invalid[1];
@@ -410,7 +432,7 @@ static void cjson_functions_shouldnt_crash_with_null_pointers(void)
cJSON_Delete(item); 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)size;
(void)pointer; (void)pointer;
@@ -463,19 +485,6 @@ static void cjson_get_string_value_should_get_a_string(void)
cJSON_Delete(string); cJSON_Delete(string);
} }
static void cjson_get_number_value_should_get_a_number(void)
{
cJSON *string = cJSON_CreateString("test");
cJSON *number = cJSON_CreateNumber(1);
TEST_ASSERT_EQUAL_DOUBLE(cJSON_GetNumberValue(number), number->valuedouble);
TEST_ASSERT_DOUBLE_IS_NAN(cJSON_GetNumberValue(string));
TEST_ASSERT_DOUBLE_IS_NAN(cJSON_GetNumberValue(NULL));
cJSON_Delete(number);
cJSON_Delete(string);
}
static void cjson_create_string_reference_should_create_a_string_reference(void) { static void cjson_create_string_reference_should_create_a_string_reference(void) {
const char *string = "I am a string!"; const char *string = "I am a string!";
@@ -540,25 +549,7 @@ static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_al
cJSON_Delete(object); cJSON_Delete(object);
} }
static void is_nan_should_detect_nan(void) int CJSON_CDECL main(void)
{
double nan = 0.0/0.0;
TEST_ASSERT_TRUE(is_nan(nan));
TEST_ASSERT_FALSE(is_nan(1));
}
static void is_infinity_should_detect_infinity(void)
{
double negative_infinity = -1.0/0.0;
double positive_infinity = 1.0/0.0;
TEST_ASSERT_TRUE(is_infinity(negative_infinity));
TEST_ASSERT_TRUE(is_infinity(positive_infinity));
TEST_ASSERT_FALSE(is_infinity(1));
}
int main(void)
{ {
UNITY_BEGIN(); UNITY_BEGIN();
@@ -566,6 +557,8 @@ int main(void)
RUN_TEST(cjson_array_foreach_should_not_dereference_null_pointer); 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_should_get_object_items);
RUN_TEST(cjson_get_object_item_case_sensitive_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(typecheck_functions_should_check_type);
RUN_TEST(cjson_should_not_parse_to_deeply_nested_jsons); RUN_TEST(cjson_should_not_parse_to_deeply_nested_jsons);
RUN_TEST(cjson_set_number_value_should_set_numbers); RUN_TEST(cjson_set_number_value_should_set_numbers);
@@ -577,13 +570,10 @@ int main(void)
RUN_TEST(skip_utf8_bom_should_skip_bom); RUN_TEST(skip_utf8_bom_should_skip_bom);
RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning);
RUN_TEST(cjson_get_string_value_should_get_a_string); RUN_TEST(cjson_get_string_value_should_get_a_string);
RUN_TEST(cjson_get_number_value_should_get_a_number);
RUN_TEST(cjson_create_string_reference_should_create_a_string_reference); 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_object_reference_should_create_an_object_reference);
RUN_TEST(cjson_create_array_reference_should_create_an_array_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); RUN_TEST(cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased);
RUN_TEST(is_nan_should_detect_nan);
RUN_TEST(is_infinity_should_detect_infinity);
return UNITY_END(); return UNITY_END();
} }
+1 -1
View File
@@ -152,7 +152,7 @@ static void parse_array_should_not_parse_non_arrays(void)
assert_not_array("\"[]hello world!\n\""); assert_not_array("\"[]hello world!\n\"");
} }
int main(void) int CJSON_CDECL main(void)
{ {
/* initialize cJSON item */ /* initialize cJSON item */
memset(item, 0, sizeof(cJSON)); memset(item, 0, sizeof(cJSON));
+1 -58
View File
@@ -195,62 +195,7 @@ static void test12_should_not_be_parsed(void)
} }
} }
static void test13_should_be_parsed_without_null_termination(void) int CJSON_CDECL main(void)
{
cJSON *tree = NULL;
const char test_13[] = "{" \
"\"Image\":{" \
"\"Width\":800," \
"\"Height\":600," \
"\"Title\":\"Viewfrom15thFloor\"," \
"\"Thumbnail\":{" \
"\"Url\":\"http:/*www.example.com/image/481989943\"," \
"\"Height\":125," \
"\"Width\":\"100\"" \
"}," \
"\"IDs\":[116,943,234,38793]" \
"}" \
"}";
char test_13_wo_null[sizeof(test_13) - 1];
memcpy(test_13_wo_null, test_13, sizeof(test_13) - 1);
tree = cJSON_ParseWithLength(test_13_wo_null, sizeof(test_13) - 1);
TEST_ASSERT_NOT_NULL_MESSAGE(tree, "Failed to parse valid json.");
if (tree != NULL)
{
cJSON_Delete(tree);
}
}
static void test14_should_not_be_parsed(void)
{
cJSON *tree = NULL;
const char test_14[] = "{" \
"\"Image\":{" \
"\"Width\":800," \
"\"Height\":600," \
"\"Title\":\"Viewfrom15thFloor\"," \
"\"Thumbnail\":{" \
"\"Url\":\"http:/*www.example.com/image/481989943\"," \
"\"Height\":125," \
"\"Width\":\"100\"" \
"}," \
"\"IDs\":[116,943,234,38793]" \
"}" \
"}";
tree = cJSON_ParseWithLength(test_14, sizeof(test_14) - 2);
TEST_ASSERT_NULL_MESSAGE(tree, "Should not continue after buffer_length is reached.");
if (tree != NULL)
{
cJSON_Delete(tree);
}
}
int main(void)
{ {
UNITY_BEGIN(); UNITY_BEGIN();
RUN_TEST(file_test1_should_be_parsed_and_printed); RUN_TEST(file_test1_should_be_parsed_and_printed);
@@ -265,7 +210,5 @@ int main(void)
RUN_TEST(file_test10_should_be_parsed_and_printed); RUN_TEST(file_test10_should_be_parsed_and_printed);
RUN_TEST(file_test11_should_be_parsed_and_printed); RUN_TEST(file_test11_should_be_parsed_and_printed);
RUN_TEST(test12_should_not_be_parsed); RUN_TEST(test12_should_not_be_parsed);
RUN_TEST(test13_should_be_parsed_without_null_termination);
RUN_TEST(test14_should_not_be_parsed);
return UNITY_END(); return UNITY_END();
} }
+1 -1
View File
@@ -64,7 +64,7 @@ static void parse_hex4_should_parse_mixed_case(void)
TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BEEF")); TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BEEF"));
} }
int main(void) int CJSON_CDECL main(void)
{ {
UNITY_BEGIN(); UNITY_BEGIN();
RUN_TEST(parse_hex4_should_parse_all_combinations); RUN_TEST(parse_hex4_should_parse_all_combinations);
+1 -1
View File
@@ -96,7 +96,7 @@ static void parse_number_should_parse_negative_reals(void)
assert_parse_number("-123e-128", 0, -123e-128); assert_parse_number("-123e-128", 0, -123e-128);
} }
int main(void) int CJSON_CDECL main(void)
{ {
/* initialize cJSON item */ /* initialize cJSON item */
memset(item, 0, sizeof(cJSON)); memset(item, 0, sizeof(cJSON));
+1 -1
View File
@@ -162,7 +162,7 @@ static void parse_object_should_not_parse_non_objects(void)
assert_not_object("\"{}hello world!\n\""); assert_not_object("\"{}hello world!\n\"");
} }
int main(void) int CJSON_CDECL main(void)
{ {
/* initialize cJSON item */ /* initialize cJSON item */
memset(item, 0, sizeof(cJSON)); memset(item, 0, sizeof(cJSON));
+1 -1
View File
@@ -119,7 +119,7 @@ static void parse_string_should_parse_bug_94(void)
reset(item); reset(item);
} }
int main(void) int CJSON_CDECL main(void)
{ {
/* initialize cJSON item and error pointer */ /* initialize cJSON item and error pointer */
memset(item, 0, sizeof(cJSON)); memset(item, 0, sizeof(cJSON));
+1 -1
View File
@@ -96,7 +96,7 @@ static void parse_value_should_parse_object(void)
reset(item); reset(item);
} }
int main(void) int CJSON_CDECL main(void)
{ {
/* initialize cJSON item */ /* initialize cJSON item */
memset(item, 0, sizeof(cJSON)); memset(item, 0, sizeof(cJSON));
+1 -1
View File
@@ -97,7 +97,7 @@ static void parse_with_opts_should_parse_utf8_bom(void)
cJSON_Delete(without_bom); cJSON_Delete(without_bom);
} }
int main(void) int CJSON_CDECL main(void)
{ {
UNITY_BEGIN(); UNITY_BEGIN();
+1 -1
View File
@@ -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\",{}]"); 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 */ /* initialize cJSON item */
UNITY_BEGIN(); UNITY_BEGIN();
+1 -1
View File
@@ -89,7 +89,7 @@ static void print_number_should_print_non_number(void)
/* assert_print_number("null", -INFTY); */ /* assert_print_number("null", -INFTY); */
} }
int main(void) int CJSON_CDECL main(void)
{ {
/* initialize cJSON item */ /* initialize cJSON item */
UNITY_BEGIN(); UNITY_BEGIN();
+1 -1
View File
@@ -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\":{}}"); 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 */ /* initialize cJSON item */
UNITY_BEGIN(); UNITY_BEGIN();
+1 -1
View File
@@ -65,7 +65,7 @@ static void print_string_should_print_utf8(void)
assert_print_string("\"ü猫慕\"", "ü猫慕"); assert_print_string("\"ü猫慕\"", "ü猫慕");
} }
int main(void) int CJSON_CDECL main(void)
{ {
/* initialize cJSON item */ /* initialize cJSON item */
UNITY_BEGIN(); UNITY_BEGIN();
+1 -1
View File
@@ -90,7 +90,7 @@ static void print_value_should_print_object(void)
assert_print_value("{}"); assert_print_value("{}");
} }
int main(void) int CJSON_CDECL main(void)
{ {
/* initialize cJSON item */ /* initialize cJSON item */
UNITY_BEGIN(); UNITY_BEGIN();
+1 -1
View File
@@ -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)); TEST_ASSERT_FALSE(supports_full_hd(monitor_without_hd));
} }
int main(void) int CJSON_CDECL main(void)
{ {
UNITY_BEGIN(); UNITY_BEGIN();
+3
View File
@@ -0,0 +1,3 @@
// msvc doesn't support weak-linking, so we need to define these functions.
void setUp(void) { }
void tearDown(void) { }