Compare commits

..

41 Commits

Author SHA1 Message Date
Max Bruckner 3c8935676a Merge pull request #355 from DaveGamble/release-1.7.12
Release 1.7.12
2019-05-17 01:05:59 +02:00
Max Bruckner b93fd34044 Update changelog and contributors 2019-05-17 00:37:26 +02:00
Max Bruckner 687b1a2fe1 Update version to 1.7.12 2019-05-16 20:03:12 +02:00
Max Bruckner 08d2bc766a Fix infinite loop in cJSON_Minify 2019-05-16 20:01:02 +02:00
Max Bruckner 465352fb99 Merge pull request #352 from tan-wei/master
Add link dependency to fix tests link error when ENABLE_CJSON_UTILS is ON
2019-05-11 12:06:26 +02:00
Winterreise 19ff92da79 Add link dependency to fix tests link error when ENABLE_CJSON_UTILS is ON 2019-05-11 07:37:33 +08:00
Max Bruckner 62bc2e3432 Merge pull request #347 from raiden00pl/master
Undef true and false first also for cJSON_Utils.c
2019-04-28 13:31:46 +02:00
raiden00pl 359567fdde Undef true and false first also for cJSON_Utils.c 2019-04-28 10:33:44 +02:00
Max Bruckner 0b5a7abf48 Merge pull request #340 from ldm0/master
Typo Fix
2019-04-15 23:06:11 +02:00
Max Bruckner 93688cbe72 Merge pull request #344 from DaveGamble/release-1.7.11
Release 1.7.11
2019-04-15 00:17:19 +02:00
Max Bruckner 6b249213dd Fix clang -Wcomma warning 2019-04-15 00:06:35 +02:00
Max Bruckner 09ebae8149 Release cJSON 1.7.11 2019-04-14 23:58:02 +02:00
Max Bruckner a43fa56a63 Rewrite cJSON_Minify, fixing buffer overflows, fixes #338
Also first tests for cJSON_Minify.
Thanks @bigric3 for reporting
2019-04-14 23:18:48 +02:00
Max Bruckner 5a52eaddfd Undef true and false first, fixes #339
Thanks  @raiden00pl for reporting
2019-04-13 01:44:23 +02:00
Donough Liu add86a6be8 Update cJSON.c 2019-03-18 22:56:34 +08:00
Max Bruckner c69134d017 Release Version 1.7.10 2018-12-20 18:15:05 +01:00
Max Bruckner 563d861f92 cJSON_Utils: sort_lists: Properly split the lists
Since `prev` is not used anymore after that by the algorithm it should
have been fine anyways, still splitting it correctly in the first place
is probably a good idea.
Thanks @andysCaplin for the fix!
2018-12-20 18:12:23 +01:00
Max Bruckner 6820448db5 libcjson.pc.in: Use Libs.private instead of Private
Thanks @shiluotang
2018-12-20 18:04:52 +01:00
Max Bruckner d44b594ab3 Add missing changelog entry 2018-12-16 11:21:35 +01:00
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
33 changed files with 648 additions and 440 deletions
+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
+37
View File
@@ -1,3 +1,40 @@
1.7.12
======
Fixes:
------
* Fix infinite loop in `cJSON_Minify` (potential Denial of Service), thanks @Alanscut for reporting. See #354
* Fix link error for Visual Studio. Thanks @tan-wei, see #352
* Undefine `true` and `false` for `cJSON_Utils` before redefining them. Thanks @raiden00pl, see #347
1.7.11
======
Fixes:
------
* Fix a bug where cJSON_Minify could overflow it's buffer, both reading and writing. This is a security issue. (see #338). Big thanks @bigric3 for reporting.
* Unset `true` and `false` macros before setting them if they exist. See #339, thanks @raiden00pl for reporting
1.7.10
======
Fixes:
------
* Fix package config file for `libcjson`. Thanks @shiluotang for reporting (#321)
* Correctly split lists in `cJSON_Utils`'s merge sort. Thanks @andysCaplin for the fix (#322)
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.
* Fix some warnings detected by the Visual Studio Static Analyzer (#307). Thanks @bnason-nf
1.7.8
=====
Fixes:
------
* cJSON now works with the `__stdcall` calling convention on Windows, see #295, thanks @zhindes for contributing
1.7.7
=====
Fixes:
+6 -1
View File
@@ -7,7 +7,7 @@ include(GNUInstallDirs)
set(PROJECT_VERSION_MAJOR 1)
set(PROJECT_VERSION_MINOR 7)
set(PROJECT_VERSION_PATCH 7)
set(PROJECT_VERSION_PATCH 12)
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()
@@ -64,6 +68,7 @@ if (ENABLE_SANITIZERS)
-fno-omit-frame-pointer
-fsanitize=address
-fsanitize=undefined
-fsanitize=float-divide-by-zero
-fsanitize=float-cast-overflow
-fsanitize-address-use-after-scope
-fsanitize=integer
+6
View File
@@ -7,12 +7,14 @@ 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)
* [dieyushi](https://github.com/dieyushi)
* [Dōngwén Huáng (黄东文)](https://github.com/DongwenHuang)
* [Donough Liu](https://github.com/ldm0)
* Eswar Yaganti
* [Evan Todd](https://github.com/etodd)
* [Fabrice Fontaine](https://github.com/ffontaine)
@@ -33,14 +35,18 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB)
* [Pawel Winogrodzki](https://github.com/PawelWMS)
* [prefetchnta](https://github.com/prefetchnta)
* [Rafael Leal Dias](https://github.com/rafaeldias)
* [raiden00pl](https://github.com/raiden00pl)
* [Robin Mallinson](https://github.com/rmallins)
* [Rod Vagg](https://github.com/rvagg)
* [Roland Meertens](https://github.com/rmeertens)
* [Romain Porte](https://github.com/MicroJoe)
* [Simon Ricaldone](https://github.com/simon-p-r)
* [Stephan Gatzka](https://github.com/gatzka)
* [tan-wei](https://github.com/tan-wei)
* [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)
+2 -2
View File
@@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c
LDLIBS = -lm
LIBVERSION = 1.7.7
LIBVERSION = 1.7.12
CJSON_SOVERSION = 1
UTILS_SOVERSION = 1
@@ -46,7 +46,7 @@ STATIC = a
ifeq (Darwin, $(uname))
SHARED = dylib
CJSON_SO_LDFLAG = ""
UTILS_SO_LDFLAG = ""
UTILS_SO_LDFLAG = ""
endif
#cJSON library names
+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);
```
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`.
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)`.
`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
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:
```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] = {
@@ -381,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] = {
+235 -260
View File
@@ -39,6 +39,7 @@
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
@@ -57,7 +58,14 @@
#include "cJSON.h"
/* define our own boolean type */
#ifdef true
#undef true
#endif
#define true ((cJSON_bool)1)
#ifdef false
#undef false
#endif
#define false ((cJSON_bool)0)
typedef struct {
@@ -71,28 +79,16 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
return (const char*) (global_error.json + global_error.position);
}
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item)
{
if (!cJSON_IsString(item))
{
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) {
if (!cJSON_IsString(item)) {
return NULL;
}
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 */
#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 != 12)
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
#endif
@@ -130,22 +126,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);
}
@@ -155,6 +151,9 @@ static void *internal_realloc(void *pointer, size_t size)
#define internal_realloc realloc
#endif
/* strlen of character literals resolved at compile time */
#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
@@ -235,32 +234,16 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
{
global_hooks.deallocate(item->valuestring);
item->valuestring = NULL;
}
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
{
global_hooks.deallocate(item->string);
item->string = NULL;
}
global_hooks.deallocate(item);
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 */
static unsigned char get_decimal_point(void)
{
@@ -282,9 +265,9 @@ typedef struct
} parse_buffer;
/* 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) */
#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))
/* get a pointer to the buffer at the position */
#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
@@ -345,7 +328,21 @@ loop_end:
}
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;
input_buffer->offset += (size_t)(after_end - number_c_string);
@@ -355,7 +352,18 @@ loop_end:
/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
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;
}
@@ -472,15 +480,11 @@ static void update_offset(printbuffer * const buffer)
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. */
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
{
unsigned char *output_pointer = NULL;
double number = item->valuedouble;
int integer = double_to_saturated_integer(number);
double d = item->valuedouble;
int length = 0;
size_t i = 0;
unsigned char number_buffer[26]; /* temporary buffer to print the number into */
@@ -492,28 +496,25 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
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");
}
else if (number == integer) /* avoid overhead for integers */
{
length = sprintf((char*)number_buffer, "%d", integer);
}
else
{
/* 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 */
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 */
length = sprintf((char*)number_buffer, "%1.17g", number);
length = sprintf((char*)number_buffer, "%1.17g", d);
}
}
/* sprintf failed or buffer overrun occured */
/* sprintf failed or buffer overrun occurred */
if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
{
return false;
@@ -822,7 +823,6 @@ fail:
if (output != NULL)
{
input_buffer->hooks.deallocate(output);
output = NULL;
}
if (input_pointer != NULL)
@@ -851,13 +851,12 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe
/* empty string */
if (input == NULL)
{
const char quotes[] = "\"\"";
output = ensure(output_buffer, sizeof(quotes));
output = ensure(output_buffer, sizeof("\"\""));
if (output == NULL)
{
return false;
}
memcpy(output, quotes, sizeof(quotes));
strcpy((char*)output, "\"\"");
return true;
}
@@ -978,11 +977,6 @@ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
return NULL;
}
if (cannot_access_at_index(buffer, 0))
{
return buffer;
}
while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
{
buffer->offset++;
@@ -1012,23 +1006,8 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const 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. */
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 } };
cJSON *item = NULL;
@@ -1037,13 +1016,13 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer
global_error.json = NULL;
global_error.position = 0;
if (value == NULL || 0 == buffer_length)
if (value == NULL)
{
goto fail;
}
buffer.content = (const unsigned char*)value;
buffer.length = buffer_length;
buffer.length = strlen((const char*)value) + sizeof("");
buffer.offset = 0;
buffer.hooks = global_hooks;
@@ -1113,12 +1092,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
return cJSON_ParseWithOpts(value, 0, 0);
}
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length)
{
return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
}
#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
#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)
{
@@ -1145,8 +1119,6 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i
}
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 */
if (hooks->reallocate != NULL)
{
@@ -1168,7 +1140,6 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i
/* free the buffer */
hooks->deallocate(buffer->buffer);
buffer->buffer = NULL;
}
return printed;
@@ -1177,13 +1148,11 @@ fail:
if (buffer->buffer != NULL)
{
hooks->deallocate(buffer->buffer);
buffer->buffer = NULL;
}
if (printed != NULL)
{
hooks->deallocate(printed);
printed = NULL;
}
return NULL;
@@ -1224,27 +1193,26 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON
if (!print_value(item, &p))
{
global_hooks.deallocate(p.buffer);
p.buffer = NULL;
return NULL;
}
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 } };
if ((length < 0) || (buffer == NULL))
if ((len < 0) || (buf == NULL))
{
return false;
}
p.buffer = (unsigned char*)buffer;
p.length = (size_t)length;
p.buffer = (unsigned char*)buf;
p.length = (size_t)len;
p.offset = 0;
p.noalloc = true;
p.format = format;
p.format = fmt;
p.hooks = global_hooks;
return print_value(item, &p);
@@ -1258,75 +1226,51 @@ static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buf
return false; /* no input */
}
if (!can_read(input_buffer, 1))
{
return false;
}
/* parse the different types of values */
switch (buffer_at_offset(input_buffer)[0])
/* null */
if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 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 */
case 'n':
if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
{
item->type = cJSON_NULL;
input_buffer->offset += 4;
return true;
}
return false;
/* true */
case 't':
if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
{
item->type = cJSON_True;
item->valueint = 1;
input_buffer->offset += 4;
return true;
}
return false;
/* false */
case 'f':
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;
}
return false;
default:
return false;
item->type = cJSON_NULL;
input_buffer->offset += 4;
return true;
}
/* 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 */
if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
{
item->type = cJSON_True;
item->valueint = 1;
input_buffer->offset += 4;
return true;
}
/* string */
if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
{
return parse_string(item, input_buffer);
}
/* 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'))))
{
return parse_number(item, input_buffer);
}
/* 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. */
@@ -1342,40 +1286,31 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp
switch ((item->type) & 0xFF)
{
case cJSON_NULL:
{
const char null_string[] = "null";
output = ensure(output_buffer, sizeof(null_string));
output = ensure(output_buffer, 5);
if (output == NULL)
{
return false;
}
memcpy(output, null_string, sizeof(null_string));
strcpy((char*)output, "null");
return true;
}
case cJSON_False:
{
const char false_string[] = "false";
output = ensure(output_buffer, sizeof(false_string));
output = ensure(output_buffer, 6);
if (output == NULL)
{
return false;
}
memcpy(output, false_string, sizeof(false_string));
strcpy((char*)output, "false");
return true;
}
case cJSON_True:
{
const char true_string[] = "true";
output = ensure(output_buffer, sizeof(true_string));
output = ensure(output_buffer, 5);
if (output == NULL)
{
return false;
}
memcpy(output, true_string, sizeof(true_string));
strcpy((char*)output, "true");
return true;
}
case cJSON_Number:
return print_number(item, output_buffer);
@@ -1630,7 +1565,7 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu
buffer_skip_whitespace(input_buffer);
if (!parse_string(current_item, input_buffer))
{
goto fail; /* faile to parse name */
goto fail; /* failed to parse name */
}
buffer_skip_whitespace(input_buffer);
@@ -1750,7 +1685,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)
{
@@ -1791,7 +1726,8 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out
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;
size_t size = 0;
@@ -1803,25 +1739,13 @@ static size_t get_array_size(const cJSON * const array)
child = array->child;
while (child != NULL)
while(child != NULL)
{
size++;
child = child->next;
}
return size;
}
/* 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;
}
/* FIXME: Can overflow here. Cannot be fixed without breaking the API */
return (int)size;
}
@@ -1867,7 +1791,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;
}
@@ -1880,6 +1804,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;
}
@@ -2362,12 +2290,12 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
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);
if(item)
{
item->type = boolean ? cJSON_True : cJSON_False;
item->type = b ? cJSON_True : cJSON_False;
}
return item;
@@ -2380,7 +2308,20 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
{
item->type = cJSON_Number;
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;
@@ -2699,69 +2640,96 @@ fail:
return NULL;
}
static void skip_oneline_comment(char **input)
{
*input += static_strlen("//");
for (; (*input)[0] != '\0'; ++(*input))
{
if ((*input)[0] == '\n') {
*input += static_strlen("\n");
return;
}
}
}
static void skip_multiline_comment(char **input)
{
*input += static_strlen("/*");
for (; (*input)[0] != '\0'; ++(*input))
{
if (((*input)[0] == '*') && ((*input)[1] == '/'))
{
*input += static_strlen("*/");
return;
}
}
}
static void minify_string(char **input, char **output) {
(*output)[0] = (*input)[0];
*input += static_strlen("\"");
*output += static_strlen("\"");
for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
(*output)[0] = (*input)[0];
if ((*input)[0] == '\"') {
(*output)[0] = '\"';
*input += static_strlen("\"");
*output += static_strlen("\"");
return;
} else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
(*output)[1] = (*input)[1];
*input += static_strlen("\"");
*output += static_strlen("\"");
}
}
}
CJSON_PUBLIC(void) cJSON_Minify(char *json)
{
unsigned char *into = (unsigned char*)json;
char *into = json;
if (json == NULL)
{
return;
}
while (*json)
while (json[0] != '\0')
{
if (*json == ' ')
switch (json[0])
{
json++;
}
else if (*json == '\t')
{
/* Whitespace characters. */
json++;
}
else if (*json == '\r')
{
json++;
}
else if (*json=='\n')
{
json++;
}
else if ((*json == '/') && (json[1] == '/'))
{
/* double-slash comments, to end of line. */
while (*json && (*json != '\n'))
{
case ' ':
case '\t':
case '\r':
case '\n':
json++;
}
}
else if ((*json == '/') && (json[1] == '*'))
{
/* multiline comments. */
while (*json && !((*json == '*') && (json[1] == '/')))
{
json++;
}
json += 2;
}
else if (*json == '\"')
{
/* string literals, which are \" sensitive. */
*into++ = (unsigned char)*json++;
while (*json && (*json != '\"'))
{
if (*json == '\\')
break;
case '/':
if (json[1] == '/')
{
*into++ = (unsigned char)*json++;
skip_oneline_comment(&json);
}
*into++ = (unsigned char)*json++;
}
*into++ = (unsigned char)*json++;
}
else
{
/* All other characters. */
*into++ = (unsigned char)*json++;
else if (json[1] == '*')
{
skip_multiline_comment(&json);
} else {
json++;
}
break;
case '\"':
minify_string(&json, (char**)&into);
break;
default:
into[0] = json[0];
json++;
into++;
}
}
@@ -2955,14 +2923,6 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons
{
cJSON *a_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)
{
/* TODO This has O(n^2) runtime, which is horrible! */
@@ -2978,6 +2938,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;
}
@@ -2994,5 +2970,4 @@ CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
CJSON_PUBLIC(void) cJSON_free(void *object)
{
global_hooks.deallocate(object);
object = NULL;
}
+56 -51
View File
@@ -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 7
#define CJSON_VERSION_PATCH 12
#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
@@ -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. */
/* 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_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. */
/* 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_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. */
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 */
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
/* Delete a cJSON entity and all subentities. */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
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);
@@ -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. */
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(double) cJSON_GetNumberValue(cJSON *item);
/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
+9 -1
View File
@@ -50,7 +50,14 @@
#include "cJSON_Utils.h"
/* define our own boolean type */
#ifdef true
#undef true
#endif
#define true ((cJSON_bool)1)
#ifdef false
#undef false
#endif
#define false ((cJSON_bool)0)
static unsigned char* cJSONUtils_strdup(const unsigned char* const string)
@@ -499,6 +506,7 @@ static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive)
{
/* Split the lists */
second->prev->next = NULL;
second->prev = NULL;
}
/* Recursively sort the sub-lists. */
@@ -510,7 +518,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;
}
+1 -1
View File
@@ -6,5 +6,5 @@ Version: @PROJECT_VERSION@
Description: Ultralightweight JSON parser in ANSI C
URL: https://github.com/DaveGamble/cJSON
Libs: -L${libdir} -lcjson
Libs.Private: -lm
Libs.private: -lm
Cflags: -I${includedir}
+1 -1
View File
@@ -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());
+8 -1
View File
@@ -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)
@@ -57,6 +57,7 @@ if(ENABLE_CJSON_TEST)
compare_tests
cjson_add
readme_examples
minify_tests
)
option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.")
@@ -72,6 +73,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}"
@@ -98,6 +102,9 @@ if(ENABLE_CJSON_TEST)
foreach (cjson_utils_test ${cjson_utils_tests})
add_executable("${cjson_utils_test}" "${cjson_utils_test}.c")
target_link_libraries("${cjson_utils_test}" "${CJSON_LIB}" "${CJSON_UTILS_LIB}" unity)
if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
target_sources(${cjson_utils_test} PRIVATE unity_setup.c)
endif()
if(MEMORYCHECK_COMMAND)
add_test(NAME "${cjson_utils_test}"
COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "${CMAKE_CURRENT_BINARY_DIR}/${cjson_utils_test}")
+9 -3
View File
@@ -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();
+1 -1
View File
@@ -186,7 +186,7 @@ static void cjson_compare_should_compare_objects(void)
false))
}
int main(void)
int CJSON_CDECL main(void)
{
UNITY_BEGIN();
+33 -3
View File
@@ -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",
+174
View File
@@ -0,0 +1,174 @@
/*
Copyright (c) 2009-2019 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "unity/examples/unity_config.h"
#include "unity/src/unity.h"
#include "common.h"
static void cjson_minify_should_not_overflow_buffer(void)
{
char unclosed_multiline_comment[] = "/* bla";
char pending_escape[] = "\"\\";
cJSON_Minify(unclosed_multiline_comment);
TEST_ASSERT_EQUAL_STRING("", unclosed_multiline_comment);
cJSON_Minify(pending_escape);
TEST_ASSERT_EQUAL_STRING("\"\\", pending_escape);
}
static void cjson_minify_should_remove_single_line_comments(void)
{
const char to_minify[] = "{// this is {} \"some kind\" of [] comment /*, don't you see\n}";
char* minified = (char*) malloc(sizeof(to_minify));
TEST_ASSERT_NOT_NULL(minified);
strcpy(minified, to_minify);
cJSON_Minify(minified);
TEST_ASSERT_EQUAL_STRING("{}", minified);
free(minified);
}
static void cjson_minify_should_remove_spaces(void)
{
const char to_minify[] = "{ \"key\":\ttrue\r\n }";
char* minified = (char*) malloc(sizeof(to_minify));
TEST_ASSERT_NOT_NULL(minified);
strcpy(minified, to_minify);
cJSON_Minify(minified);
TEST_ASSERT_EQUAL_STRING("{\"key\":true}", minified);
free(minified);
}
static void cjson_minify_should_remove_multiline_comments(void)
{
const char to_minify[] = "{/* this is\n a /* multi\n //line \n {comment \"\\\" */}";
char* minified = (char*) malloc(sizeof(to_minify));
TEST_ASSERT_NOT_NULL(minified);
strcpy(minified, to_minify);
cJSON_Minify(minified);
TEST_ASSERT_EQUAL_STRING("{}", minified);
free(minified);
}
static void cjson_minify_should_not_modify_strings(void)
{
const char to_minify[] = "\"this is a string \\\" \\t bla\"";
char* minified = (char*) malloc(sizeof(to_minify));
TEST_ASSERT_NOT_NULL(minified);
strcpy(minified, to_minify);
cJSON_Minify(minified);
TEST_ASSERT_EQUAL_STRING(to_minify, minified);
free(minified);
}
static void cjson_minify_should_minify_json(void) {
const char to_minify[] =
"{\n"
" \"glossary\": { // comment\n"
" \"title\": \"example glossary\",\n"
" /* multi\n"
" line */\n"
" \"GlossDiv\": {\n"
" \"title\": \"S\",\n"
" \"GlossList\": {\n"
" \"GlossEntry\": {\n"
" \"ID\": \"SGML\",\n"
" \"SortAs\": \"SGML\",\n"
" \"Acronym\": \"SGML\",\n"
" \"Abbrev\": \"ISO 8879:1986\",\n"
" \"GlossDef\": {\n"
" \"GlossSeeAlso\": [\"GML\", \"XML\"]\n"
" },\n"
" \"GlossSee\": \"markup\"\n"
" }\n"
" }\n"
" }\n"
" }\n"
"}";
const char* minified =
"{"
"\"glossary\":{"
"\"title\":\"example glossary\","
"\"GlossDiv\":{"
"\"title\":\"S\","
"\"GlossList\":{"
"\"GlossEntry\":{"
"\"ID\":\"SGML\","
"\"SortAs\":\"SGML\","
"\"Acronym\":\"SGML\","
"\"Abbrev\":\"ISO 8879:1986\","
"\"GlossDef\":{"
"\"GlossSeeAlso\":[\"GML\",\"XML\"]"
"},"
"\"GlossSee\":\"markup\""
"}"
"}"
"}"
"}"
"}";
char *buffer = (char*) malloc(sizeof(to_minify));
strcpy(buffer, to_minify);
cJSON_Minify(buffer);
TEST_ASSERT_EQUAL_STRING(minified, buffer);
free(buffer);
}
static void cjson_minify_should_not_loop_infinitely(void) {
char string[] = { '8', ' ', '/', ' ', '5', '\n', '\0' };
/* this should not be an infinite loop */
cJSON_Minify(string);
}
int CJSON_CDECL main(void)
{
UNITY_BEGIN();
RUN_TEST(cjson_minify_should_not_overflow_buffer);
RUN_TEST(cjson_minify_should_minify_json);
RUN_TEST(cjson_minify_should_remove_single_line_comments);
RUN_TEST(cjson_minify_should_remove_multiline_comments);
RUN_TEST(cjson_minify_should_remove_spaces);
RUN_TEST(cjson_minify_should_not_modify_strings);
RUN_TEST(cjson_minify_should_not_loop_infinitely);
return UNITY_END();
}
+26 -36
View File
@@ -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;
@@ -463,19 +485,6 @@ static void cjson_get_string_value_should_get_a_string(void)
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) {
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);
}
static void is_nan_should_detect_nan(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)
int CJSON_CDECL main(void)
{
UNITY_BEGIN();
@@ -566,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);
@@ -577,13 +570,10 @@ int main(void)
RUN_TEST(skip_utf8_bom_should_skip_bom);
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_number_value_should_get_a_number);
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);
RUN_TEST(is_nan_should_detect_nan);
RUN_TEST(is_infinity_should_detect_infinity);
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\"");
}
int main(void)
int CJSON_CDECL main(void)
{
/* initialize cJSON item */
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)
{
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)
int CJSON_CDECL main(void)
{
UNITY_BEGIN();
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_test11_should_be_parsed_and_printed);
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();
}
+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"));
}
int main(void)
int CJSON_CDECL main(void)
{
UNITY_BEGIN();
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);
}
int main(void)
int CJSON_CDECL main(void)
{
/* initialize cJSON item */
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\"");
}
int main(void)
int CJSON_CDECL main(void)
{
/* initialize cJSON item */
memset(item, 0, sizeof(cJSON));
+1 -1
View File
@@ -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));
+1 -1
View File
@@ -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));
+1 -1
View File
@@ -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();
+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\",{}]");
}
int main(void)
int CJSON_CDECL main(void)
{
/* initialize cJSON item */
UNITY_BEGIN();
+1 -1
View File
@@ -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();
+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\":{}}");
}
int main(void)
int CJSON_CDECL main(void)
{
/* initialize cJSON item */
UNITY_BEGIN();
+1 -1
View File
@@ -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();
+1 -1
View File
@@ -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();
+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));
}
int main(void)
int CJSON_CDECL main(void)
{
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) { }