From 06f4152008a9b3505d28fd63182c02c628b1ead9 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 19 Jan 2018 00:11:07 +0100 Subject: [PATCH 01/38] print: Comment about why the buffer is reallocated --- cJSON.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cJSON.c b/cJSON.c index 7e71ea9e..f3a3d1eb 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1110,6 +1110,8 @@ 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) { From b2bbc11d44c23395653e003ed5d6c821625a260c Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 20 Jan 2018 14:43:50 +0100 Subject: [PATCH 02/38] Fix #234: Different argument names between declaration and definition --- cJSON.c | 14 +++++++------- cJSON.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cJSON.c b/cJSON.c index f3a3d1eb..caf9934c 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1192,20 +1192,20 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON return (char*)p.buffer; } -CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) { printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - if ((len < 0) || (buf == NULL)) + if ((length < 0) || (buffer == NULL)) { return false; } - p.buffer = (unsigned char*)buf; - p.length = (size_t)len; + p.buffer = (unsigned char*)buffer; + p.length = (size_t)length; p.offset = 0; p.noalloc = true; - p.format = fmt; + p.format = format; p.hooks = global_hooks; return print_value(item, &p); @@ -2279,12 +2279,12 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) return item; } -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) { - item->type = b ? cJSON_True : cJSON_False; + item->type = boolean ? cJSON_True : cJSON_False; } return item; diff --git a/cJSON.h b/cJSON.h index a9c68fa2..edcac07b 100644 --- a/cJSON.h +++ b/cJSON.h @@ -152,7 +152,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 *c); +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); /* Returns the number of items in an array (or object). */ CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); From 3e2c29528a3139145d60fb38d624c5d1d6f4d96f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 20 Jan 2018 15:43:56 +0100 Subject: [PATCH 03/38] CMake: Remove -fsanitize=float-divide-by-zero This is so that NaN and INFINITY values can be produced. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 09039f62..2062f97f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,6 @@ 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 From 5ed383a0d18d88c7d0b4ad0550093572c333daca Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 20 Jan 2018 15:14:27 +0100 Subject: [PATCH 04/38] is_nan and is_infinity macros --- cJSON.c | 6 ++++-- tests/misc_tests.c | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index caf9934c..d9a9cf2b 100644 --- a/cJSON.c +++ b/cJSON.c @@ -471,6 +471,9 @@ 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) { @@ -487,8 +490,7 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out return false; } - /* This checks for NaN and Infinity */ - if ((d * 0) != 0) + if (is_nan(d) || is_infinity(d)) { length = sprintf((char*)number_buffer, "null"); } diff --git a/tests/misc_tests.c b/tests/misc_tests.c index a0b4f7eb..aae52052 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -527,6 +527,24 @@ 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) { UNITY_BEGIN(); @@ -550,6 +568,8 @@ int main(void) 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(); } From 0914640d7913bbaf7ba86ca5c38630740ce82cd8 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 29 Jan 2018 20:12:12 +0100 Subject: [PATCH 05/38] Extract helper: double_to_saturated_integer --- cJSON.c | 58 +++++++++++++++++---------------------------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/cJSON.c b/cJSON.c index d9a9cf2b..11747b3d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -235,6 +235,20 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) } } +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) { @@ -319,21 +333,7 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu } item->valuedouble = number; - - /* use saturation in case of overflow */ - if (number >= INT_MAX) - { - item->valueint = INT_MAX; - } - else if (number <= INT_MIN) - { - item->valueint = INT_MIN; - } - else - { - item->valueint = (int)number; - } - + item->valueint = double_to_saturated_integer(number); item->type = cJSON_Number; input_buffer->offset += (size_t)(after_end - number_c_string); @@ -343,18 +343,7 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) { - if (number >= INT_MAX) - { - object->valueint = INT_MAX; - } - else if (number <= INT_MIN) - { - object->valueint = INT_MIN; - } - else - { - object->valueint = (int)number; - } + object->valueint = double_to_saturated_integer(number); return object->valuedouble = number; } @@ -2299,20 +2288,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) { item->type = cJSON_Number; item->valuedouble = num; - - /* use saturation in case of overflow */ - if (num >= INT_MAX) - { - item->valueint = INT_MAX; - } - else if (num <= INT_MIN) - { - item->valueint = INT_MIN; - } - else - { - item->valueint = (int)num; - } + item->valueint = double_to_saturated_integer(num); } return item; From 952b1017abb5c96d86d317e6d044b78d290692f7 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 29 Jan 2018 20:24:42 +0100 Subject: [PATCH 06/38] print_number: Introduce fast path for integers. Thanks @Tangerino for suggesting this optimisation. --- cJSON.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/cJSON.c b/cJSON.c index 11747b3d..c0a61ab4 100644 --- a/cJSON.c +++ b/cJSON.c @@ -467,7 +467,8 @@ static void update_offset(printbuffer * const buffer) static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) { unsigned char *output_pointer = NULL; - double d = item->valuedouble; + double number = item->valuedouble; + int integer = double_to_saturated_integer(number); int length = 0; size_t i = 0; unsigned char number_buffer[26]; /* temporary buffer to print the number into */ @@ -479,20 +480,24 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out return false; } - if (is_nan(d) || is_infinity(d)) + if (is_nan(number) || is_infinity(number)) { 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", d); + length = sprintf((char*)number_buffer, "%1.15g", number); /* Check whether the original double can be recovered */ - if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != number)) { /* If not, print with 17 decimal places of precision */ - length = sprintf((char*)number_buffer, "%1.17g", d); + length = sprintf((char*)number_buffer, "%1.17g", number); } } From f4cc4d7c6307625b70728a4c2403396931b28641 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 31 Jan 2018 10:31:14 +0100 Subject: [PATCH 07/38] parse_value: Check only first character at first This should improve performance --- cJSON.c | 108 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 42 deletions(-) diff --git a/cJSON.c b/cJSON.c index c0a61ab4..5f480504 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1215,51 +1215,75 @@ static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buf return false; /* no input */ } - /* parse the different types of values */ - /* null */ - 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; - } - /* false */ - if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + if (!can_read(input_buffer, 1)) { - 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; } - return false; + /* 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 */ + 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; + } } /* Render a value to text. */ From 0715259635d5bc4a56a31f633f35658f0f3262fa Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 15:54:47 +0100 Subject: [PATCH 08/38] cJSON_Compare: Performance improvement for objects Check the size to prevent comparing objects equal if they are prefixes of each other. --- cJSON.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/cJSON.c b/cJSON.c index 5f480504..283a060b 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1739,8 +1739,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out return true; } -/* Get Array size/item / object item. */ -CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +static size_t get_array_size(const cJSON * const array) { cJSON *child = NULL; size_t size = 0; @@ -1752,13 +1751,25 @@ CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) child = array->child; - while(child != NULL) + while (child != NULL) { size++; child = child->next; } - /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + 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; + } return (int)size; } @@ -2892,6 +2903,14 @@ 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! */ @@ -2907,22 +2926,6 @@ 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; } From ce5f31ac47ce4bbb84ed2c4ee12da303c78687b3 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 19:14:19 +0100 Subject: [PATCH 09/38] Remove superfluous null checks in can_read/access_at_index macros --- cJSON.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index 283a060b..b6a3c480 100644 --- a/cJSON.c +++ b/cJSON.c @@ -270,9 +270,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 != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +#define can_read(buffer, size) (((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 != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define can_access_at_index(buffer, index) (((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) From b06fb10f9489d52bfb156e52cbd09c9739af0f74 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 25 Mar 2018 14:20:48 +0200 Subject: [PATCH 10/38] cJSON.c: Remove unnecessary includes --- cJSON.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index b6a3c480..8f3d076f 100644 --- a/cJSON.c +++ b/cJSON.c @@ -39,9 +39,7 @@ #include #include -#include #include -#include #include #include From 08a2ad3c59a7915f826c8259fc8496a0e8f6076d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 25 Mar 2018 14:25:46 +0200 Subject: [PATCH 11/38] is_{nan,infinity}: Wrap macro arguments in parentheses --- cJSON.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index 8f3d076f..87997754 100644 --- a/cJSON.c +++ b/cJSON.c @@ -458,8 +458,8 @@ 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) +#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) From 1f4044a7070e5df383bfe5745e5e81e725973202 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 25 Mar 2018 15:11:56 +0200 Subject: [PATCH 12/38] cJSON.c: Remove unused cast --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 87997754..547a59d0 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1007,7 +1007,7 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return } buffer.content = (const unsigned char*)value; - buffer.length = strlen((const char*)value) + sizeof(""); + buffer.length = strlen(value) + sizeof(""); buffer.offset = 0; buffer.hooks = global_hooks; From fd5281bdd86e1a4ed891c192ffb96688f02fa843 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 25 Mar 2018 15:12:15 +0200 Subject: [PATCH 13/38] cJSON: cjson_min: Wrap arguments in parentheses --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 547a59d0..6d0b3e33 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1077,7 +1077,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) return cJSON_ParseWithOpts(value, 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) { From 3ebc06196a866ed01438fa4e74cedd756dac8787 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 25 Mar 2018 23:31:36 +0200 Subject: [PATCH 14/38] Gitignore: add CLion files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e2e312b5..58edf92c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ libcjson.so.* libcjson_utils.so.* *.orig .vscode +.idea +cmake-build-debug From 677f0cb1bbc7214a057ff4d8e01d54c8205b0e10 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 31 Jan 2018 22:22:53 +0100 Subject: [PATCH 15/38] Rename internal_hooks -> internal_configuration, cJSON_New_item -> create_item --- cJSON.c | 174 +++++++++++++++++++++---------------------- tests/common.h | 4 +- tests/misc_tests.c | 9 +-- tests/parse_array.c | 4 +- tests/parse_object.c | 4 +- tests/parse_string.c | 6 +- tests/parse_value.c | 2 +- tests/print_array.c | 6 +- tests/print_number.c | 2 +- tests/print_object.c | 6 +- tests/print_string.c | 2 +- tests/print_value.c | 4 +- 12 files changed, 111 insertions(+), 112 deletions(-) diff --git a/cJSON.c b/cJSON.c index 6d0b3e33..0aafbe63 100644 --- a/cJSON.c +++ b/cJSON.c @@ -116,12 +116,12 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned return tolower(*string1) - tolower(*string2); } -typedef struct internal_hooks +typedef struct internal_configuration { void *(*allocate)(size_t size); void (*deallocate)(void *pointer); void *(*reallocate)(void *pointer, size_t size); -} internal_hooks; +} internal_configuration; #if defined(_MSC_VER) /* work around MSVC error C2322: '...' address of dillimport '...' is not static */ @@ -143,9 +143,9 @@ static void *internal_realloc(void *pointer, size_t size) #define internal_realloc realloc #endif -static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; +static internal_configuration global_configuration = { internal_malloc, internal_free, internal_realloc }; -static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +static unsigned char* custom_strdup(const unsigned char* string, const internal_configuration * const configuration) { size_t length = 0; unsigned char *copy = NULL; @@ -156,7 +156,7 @@ static unsigned char* cJSON_strdup(const unsigned char* string, const internal_h } length = strlen((const char*)string) + sizeof(""); - copy = (unsigned char*)hooks->allocate(length); + copy = (unsigned char*)configuration->allocate(length); if (copy == NULL) { return NULL; @@ -171,36 +171,36 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) if (hooks == NULL) { /* Reset hooks */ - global_hooks.allocate = malloc; - global_hooks.deallocate = free; - global_hooks.reallocate = realloc; + global_configuration.allocate = malloc; + global_configuration.deallocate = free; + global_configuration.reallocate = realloc; return; } - global_hooks.allocate = malloc; + global_configuration.allocate = malloc; if (hooks->malloc_fn != NULL) { - global_hooks.allocate = hooks->malloc_fn; + global_configuration.allocate = hooks->malloc_fn; } - global_hooks.deallocate = free; + global_configuration.deallocate = free; if (hooks->free_fn != NULL) { - global_hooks.deallocate = hooks->free_fn; + global_configuration.deallocate = hooks->free_fn; } /* use realloc only if both free and malloc are used */ - global_hooks.reallocate = NULL; - if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + global_configuration.reallocate = NULL; + if ((global_configuration.allocate == malloc) && (global_configuration.deallocate == free)) { - global_hooks.reallocate = realloc; + global_configuration.reallocate = realloc; } } /* Internal constructor. */ -static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +static cJSON *create_item(const internal_configuration * const configuration) { - cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + cJSON* node = (cJSON*)configuration->allocate(sizeof(cJSON)); if (node) { memset(node, '\0', sizeof(cJSON)); @@ -222,13 +222,13 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) } if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) { - global_hooks.deallocate(item->valuestring); + global_configuration.deallocate(item->valuestring); } if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { - global_hooks.deallocate(item->string); + global_configuration.deallocate(item->string); } - global_hooks.deallocate(item); + global_configuration.deallocate(item); item = next; } } @@ -264,7 +264,7 @@ typedef struct size_t length; size_t offset; size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ - internal_hooks hooks; + internal_configuration configuration; } parse_buffer; /* check if the given size is left to read in a given parse buffer (starting with 1) */ @@ -354,7 +354,7 @@ typedef struct size_t depth; /* current nesting depth (for formatted printing) */ cJSON_bool noalloc; cJSON_bool format; /* is this print a formatted print */ - internal_hooks hooks; + internal_configuration configuration; } printbuffer; /* realloc printbuffer if necessary to have at least "needed" bytes more */ @@ -408,13 +408,13 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) newsize = needed * 2; } - if (p->hooks.reallocate != NULL) + if (p->configuration.reallocate != NULL) { /* reallocate with realloc if available */ - newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + newbuffer = (unsigned char*)p->configuration.reallocate(p->buffer, newsize); if (newbuffer == NULL) { - p->hooks.deallocate(p->buffer); + p->configuration.deallocate(p->buffer); p->length = 0; p->buffer = NULL; @@ -424,10 +424,10 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) else { /* otherwise reallocate manually */ - newbuffer = (unsigned char*)p->hooks.allocate(newsize); + newbuffer = (unsigned char*)p->configuration.allocate(newsize); if (!newbuffer) { - p->hooks.deallocate(p->buffer); + p->configuration.deallocate(p->buffer); p->length = 0; p->buffer = NULL; @@ -437,7 +437,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) { memcpy(newbuffer, p->buffer, p->offset + 1); } - p->hooks.deallocate(p->buffer); + p->configuration.deallocate(p->buffer); } p->length = newsize; p->buffer = newbuffer; @@ -729,7 +729,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu /* This is at most how much we need for the output */ allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; - output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + output = (unsigned char*)input_buffer->configuration.allocate(allocation_length + sizeof("")); if (output == NULL) { goto fail; /* allocation failure */ @@ -807,7 +807,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu fail: if (output != NULL) { - input_buffer->hooks.deallocate(output); + input_buffer->configuration.deallocate(output); } if (input_pointer != NULL) @@ -1009,9 +1009,9 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return buffer.content = (const unsigned char*)value; buffer.length = strlen(value) + sizeof(""); buffer.offset = 0; - buffer.hooks = global_hooks; + buffer.configuration = global_configuration; - item = cJSON_New_Item(&global_hooks); + item = create_item(&global_configuration); if (item == NULL) /* memory fail */ { goto fail; @@ -1079,7 +1079,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) #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_configuration * const configuration) { static const size_t default_buffer_size = 256; printbuffer buffer[1]; @@ -1088,10 +1088,10 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i memset(buffer, 0, sizeof(buffer)); /* create buffer */ - buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->buffer = (unsigned char*) configuration->allocate(default_buffer_size); buffer->length = default_buffer_size; buffer->format = format; - buffer->hooks = *hooks; + buffer->configuration = *configuration; if (buffer->buffer == NULL) { goto fail; @@ -1107,9 +1107,9 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i /* 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) + if (configuration->reallocate != NULL) { - printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); + printed = (unsigned char*) configuration->reallocate(buffer->buffer, buffer->offset + 1); buffer->buffer = NULL; if (printed == NULL) { goto fail; @@ -1117,7 +1117,7 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i } else /* otherwise copy the JSON over to a new buffer */ { - printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + printed = (unsigned char*) configuration->allocate(buffer->offset + 1); if (printed == NULL) { goto fail; @@ -1126,7 +1126,7 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i printed[buffer->offset] = '\0'; /* just to be sure */ /* free the buffer */ - hooks->deallocate(buffer->buffer); + configuration->deallocate(buffer->buffer); } return printed; @@ -1134,12 +1134,12 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i fail: if (buffer->buffer != NULL) { - hooks->deallocate(buffer->buffer); + configuration->deallocate(buffer->buffer); } if (printed != NULL) { - hooks->deallocate(printed); + configuration->deallocate(printed); } return NULL; @@ -1148,12 +1148,12 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i /* Render a cJSON item/entity/structure to text. */ CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) { - return (char*)print(item, true, &global_hooks); + return (char*)print(item, true, &global_configuration); } CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) { - return (char*)print(item, false, &global_hooks); + return (char*)print(item, false, &global_configuration); } CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) @@ -1165,7 +1165,7 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON return NULL; } - p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + p.buffer = (unsigned char*)global_configuration.allocate((size_t)prebuffer); if (!p.buffer) { return NULL; @@ -1175,11 +1175,11 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON p.offset = 0; p.noalloc = false; p.format = fmt; - p.hooks = global_hooks; + p.configuration = global_configuration; if (!print_value(item, &p)) { - global_hooks.deallocate(p.buffer); + global_configuration.deallocate(p.buffer); return NULL; } @@ -1200,7 +1200,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, cons p.offset = 0; p.noalloc = true; p.format = format; - p.hooks = global_hooks; + p.configuration = global_configuration; return print_value(item, &p); } @@ -1397,7 +1397,7 @@ static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buf do { /* allocate next item */ - cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + cJSON *new_item = create_item(&(input_buffer->configuration)); if (new_item == NULL) { goto fail; /* allocation failure */ @@ -1551,7 +1551,7 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu do { /* allocate next item */ - cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + cJSON *new_item = create_item(&(input_buffer->configuration)); if (new_item == NULL) { goto fail; /* allocation failure */ @@ -1852,7 +1852,7 @@ static void suffix_object(cJSON *prev, cJSON *item) } /* Utility for handling references. */ -static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +static cJSON *create_reference(const cJSON *item, const internal_configuration * const configuration) { cJSON *reference = NULL; if (item == NULL) @@ -1860,7 +1860,7 @@ static cJSON *create_reference(const cJSON *item, const internal_hooks * const h return NULL; } - reference = cJSON_New_Item(hooks); + reference = create_item(configuration); if (reference == NULL) { return NULL; @@ -1924,7 +1924,7 @@ static void* cast_away_const(const void* string) #endif -static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_configuration * const configuration, const cJSON_bool constant_key) { char *new_key = NULL; int new_type = cJSON_Invalid; @@ -1941,7 +1941,7 @@ static cJSON_bool add_item_to_object(cJSON * const object, const char * const st } else { - new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + new_key = (char*)custom_strdup((const unsigned char*)string, configuration); if (new_key == NULL) { return false; @@ -1952,7 +1952,7 @@ static cJSON_bool add_item_to_object(cJSON * const object, const char * const st if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { - hooks->deallocate(item->string); + configuration->deallocate(item->string); } item->string = new_key; @@ -1963,13 +1963,13 @@ static cJSON_bool add_item_to_object(cJSON * const object, const char * const st CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) { - add_item_to_object(object, string, item, &global_hooks, false); + add_item_to_object(object, string, item, &global_configuration, false); } /* Add an item to an object with constant string as key */ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) { - add_item_to_object(object, string, item, &global_hooks, true); + add_item_to_object(object, string, item, &global_configuration, true); } CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) @@ -1979,7 +1979,7 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) return; } - add_item_to_array(array, create_reference(item, &global_hooks)); + add_item_to_array(array, create_reference(item, &global_configuration)); } CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) @@ -1989,13 +1989,13 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *str return; } - add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); + add_item_to_object(object, string, create_reference(item, &global_configuration), &global_configuration, false); } CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) { cJSON *null = cJSON_CreateNull(); - if (add_item_to_object(object, name, null, &global_hooks, false)) + if (add_item_to_object(object, name, null, &global_configuration, false)) { return null; } @@ -2007,7 +2007,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * co CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) { cJSON *true_item = cJSON_CreateTrue(); - if (add_item_to_object(object, name, true_item, &global_hooks, false)) + if (add_item_to_object(object, name, true_item, &global_configuration, false)) { return true_item; } @@ -2019,7 +2019,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * co CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) { cJSON *false_item = cJSON_CreateFalse(); - if (add_item_to_object(object, name, false_item, &global_hooks, false)) + if (add_item_to_object(object, name, false_item, &global_configuration, false)) { return false_item; } @@ -2031,7 +2031,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * c CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) { cJSON *bool_item = cJSON_CreateBool(boolean); - if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + if (add_item_to_object(object, name, bool_item, &global_configuration, false)) { return bool_item; } @@ -2043,7 +2043,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * co CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) { cJSON *number_item = cJSON_CreateNumber(number); - if (add_item_to_object(object, name, number_item, &global_hooks, false)) + if (add_item_to_object(object, name, number_item, &global_configuration, false)) { return number_item; } @@ -2055,7 +2055,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) { cJSON *string_item = cJSON_CreateString(string); - if (add_item_to_object(object, name, string_item, &global_hooks, false)) + if (add_item_to_object(object, name, string_item, &global_configuration, false)) { return string_item; } @@ -2067,7 +2067,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) { cJSON *raw_item = cJSON_CreateRaw(raw); - if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + if (add_item_to_object(object, name, raw_item, &global_configuration, false)) { return raw_item; } @@ -2079,7 +2079,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * con CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) { cJSON *object_item = cJSON_CreateObject(); - if (add_item_to_object(object, name, object_item, &global_hooks, false)) + if (add_item_to_object(object, name, object_item, &global_configuration, false)) { return object_item; } @@ -2091,7 +2091,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) { cJSON *array = cJSON_CreateArray(); - if (add_item_to_object(object, name, array, &global_hooks, false)) + if (add_item_to_object(object, name, array, &global_configuration, false)) { return array; } @@ -2256,7 +2256,7 @@ static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSO { cJSON_free(replacement->string); } - replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->string = (char*)custom_strdup((const unsigned char*)string, &global_configuration); replacement->type &= ~cJSON_StringIsConst; cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); @@ -2277,7 +2277,7 @@ CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const c /* Create basic types: */ CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) { - cJSON *item = cJSON_New_Item(&global_hooks); + cJSON *item = create_item(&global_configuration); if(item) { item->type = cJSON_NULL; @@ -2288,7 +2288,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) { - cJSON *item = cJSON_New_Item(&global_hooks); + cJSON *item = create_item(&global_configuration); if(item) { item->type = cJSON_True; @@ -2299,7 +2299,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) { - cJSON *item = cJSON_New_Item(&global_hooks); + cJSON *item = create_item(&global_configuration); if(item) { item->type = cJSON_False; @@ -2310,7 +2310,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) { - cJSON *item = cJSON_New_Item(&global_hooks); + cJSON *item = create_item(&global_configuration); if(item) { item->type = boolean ? cJSON_True : cJSON_False; @@ -2321,7 +2321,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) { - cJSON *item = cJSON_New_Item(&global_hooks); + cJSON *item = create_item(&global_configuration); if(item) { item->type = cJSON_Number; @@ -2334,11 +2334,11 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) { - cJSON *item = cJSON_New_Item(&global_hooks); + cJSON *item = create_item(&global_configuration); if(item) { item->type = cJSON_String; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + item->valuestring = (char*)custom_strdup((const unsigned char*)string, &global_configuration); if(!item->valuestring) { cJSON_Delete(item); @@ -2351,7 +2351,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) { - cJSON *item = cJSON_New_Item(&global_hooks); + cJSON *item = create_item(&global_configuration); if (item != NULL) { item->type = cJSON_String | cJSON_IsReference; @@ -2363,7 +2363,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) { - cJSON *item = cJSON_New_Item(&global_hooks); + cJSON *item = create_item(&global_configuration); if (item != NULL) { item->type = cJSON_Object | cJSON_IsReference; item->child = (cJSON*)cast_away_const(child); @@ -2373,7 +2373,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) } CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { - cJSON *item = cJSON_New_Item(&global_hooks); + cJSON *item = create_item(&global_configuration); if (item != NULL) { item->type = cJSON_Array | cJSON_IsReference; item->child = (cJSON*)cast_away_const(child); @@ -2384,11 +2384,11 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) { - cJSON *item = cJSON_New_Item(&global_hooks); + cJSON *item = create_item(&global_configuration); if(item) { item->type = cJSON_Raw; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + item->valuestring = (char*)custom_strdup((const unsigned char*)raw, &global_configuration); if(!item->valuestring) { cJSON_Delete(item); @@ -2401,7 +2401,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) { - cJSON *item = cJSON_New_Item(&global_hooks); + cJSON *item = create_item(&global_configuration); if(item) { item->type=cJSON_Array; @@ -2412,7 +2412,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) { - cJSON *item = cJSON_New_Item(&global_hooks); + cJSON *item = create_item(&global_configuration); if (item) { item->type = cJSON_Object; @@ -2579,7 +2579,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) goto fail; } /* Create new item */ - newitem = cJSON_New_Item(&global_hooks); + newitem = create_item(&global_configuration); if (!newitem) { goto fail; @@ -2590,7 +2590,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) newitem->valuedouble = item->valuedouble; if (item->valuestring) { - newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + newitem->valuestring = (char*)custom_strdup((unsigned char*)item->valuestring, &global_configuration); if (!newitem->valuestring) { goto fail; @@ -2598,7 +2598,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) } if (item->string) { - newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)custom_strdup((unsigned char*)item->string, &global_configuration); if (!newitem->string) { goto fail; @@ -2934,10 +2934,10 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons CJSON_PUBLIC(void *) cJSON_malloc(size_t size) { - return global_hooks.allocate(size); + return global_configuration.allocate(size); } CJSON_PUBLIC(void) cJSON_free(void *object) { - global_hooks.deallocate(object); + global_configuration.deallocate(object); } diff --git a/tests/common.h b/tests/common.h index 4db6bf8c..caf0e500 100644 --- a/tests/common.h +++ b/tests/common.h @@ -33,11 +33,11 @@ void reset(cJSON *item) { } if ((item->valuestring != NULL) && !(item->type & cJSON_IsReference)) { - global_hooks.deallocate(item->valuestring); + global_configuration.deallocate(item->valuestring); } if ((item->string != NULL) && !(item->type & cJSON_StringIsConst)) { - global_hooks.deallocate(item->string); + global_configuration.deallocate(item->string); } memset(item, 0, sizeof(cJSON)); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index aae52052..e5eaf5fc 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -10,8 +10,7 @@ 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 +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 @@ -432,7 +431,7 @@ static void skip_utf8_bom_should_skip_bom(void) parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; buffer.content = string; buffer.length = sizeof(string); - buffer.hooks = global_hooks; + buffer.configuration = global_configuration; TEST_ASSERT_TRUE(skip_utf8_bom(&buffer) == &buffer); TEST_ASSERT_EQUAL_UINT(3U, (unsigned int)buffer.offset); @@ -444,7 +443,7 @@ static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void) parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; buffer.content = string; buffer.length = sizeof(string); - buffer.hooks = global_hooks; + buffer.configuration = global_configuration; buffer.offset = 1; TEST_ASSERT_NULL(skip_utf8_bom(&buffer)); @@ -512,7 +511,7 @@ static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_al { cJSON *object = cJSON_CreateObject(); cJSON *number = cJSON_CreateNumber(42); - char *name = (char*)cJSON_strdup((const unsigned char*)"number", &global_hooks); + char *name = (char*)custom_strdup((const unsigned char*)"number", &global_configuration); TEST_ASSERT_NOT_NULL(object); TEST_ASSERT_NOT_NULL(number); diff --git a/tests/parse_array.c b/tests/parse_array.c index 69e0f411..dcf2d638 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -47,7 +47,7 @@ static void assert_not_array(const char *json) parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); - buffer.hooks = global_hooks; + buffer.configuration = global_configuration; TEST_ASSERT_FALSE(parse_array(item, &buffer)); assert_is_invalid(item); @@ -58,7 +58,7 @@ static void assert_parse_array(const char *json) parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); - buffer.hooks = global_hooks; + buffer.configuration = global_configuration; TEST_ASSERT_TRUE(parse_array(item, &buffer)); assert_is_array(item); diff --git a/tests/parse_object.c b/tests/parse_object.c index 09858455..990758d9 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -55,7 +55,7 @@ static void assert_not_object(const char *json) parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); - parsebuffer.hooks = global_hooks; + parsebuffer.configuration = global_configuration; TEST_ASSERT_FALSE(parse_object(item, &parsebuffer)); assert_is_invalid(item); @@ -67,7 +67,7 @@ static void assert_parse_object(const char *json) parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); - parsebuffer.hooks = global_hooks; + parsebuffer.configuration = global_configuration; TEST_ASSERT_TRUE(parse_object(item, &parsebuffer)); assert_is_object(item); diff --git a/tests/parse_string.c b/tests/parse_string.c index ceb1a896..66e96eaa 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -48,12 +48,12 @@ static void assert_parse_string(const char *string, const char *expected) parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); - buffer.hooks = global_hooks; + buffer.configuration = global_configuration; TEST_ASSERT_TRUE_MESSAGE(parse_string(item, &buffer), "Couldn't parse string."); assert_is_string(item); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, item->valuestring, "The parsed result isn't as expected."); - global_hooks.deallocate(item->valuestring); + global_configuration.deallocate(item->valuestring); item->valuestring = NULL; } @@ -62,7 +62,7 @@ static void assert_not_parse_string(const char * const string) parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); - buffer.hooks = global_hooks; + buffer.configuration = global_configuration; TEST_ASSERT_FALSE_MESSAGE(parse_string(item, &buffer), "Malformed string should not be accepted."); assert_is_invalid(item); diff --git a/tests/parse_value.c b/tests/parse_value.c index 08ec3e7a..3e8fb27c 100644 --- a/tests/parse_value.c +++ b/tests/parse_value.c @@ -46,7 +46,7 @@ static void assert_parse_value(const char *string, int type) parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; buffer.content = (const unsigned char*) string; buffer.length = strlen(string) + sizeof(""); - buffer.hooks = global_hooks; + buffer.configuration = global_configuration; TEST_ASSERT_TRUE(parse_value(item, &buffer)); assert_is_value(item, type); diff --git a/tests/print_array.c b/tests/print_array.c index 4bee17f9..5cf556cd 100644 --- a/tests/print_array.c +++ b/tests/print_array.c @@ -37,21 +37,21 @@ static void assert_print_array(const char * const expected, const char * const i parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)input; parsebuffer.length = strlen(input) + sizeof(""); - parsebuffer.hooks = global_hooks; + parsebuffer.configuration = global_configuration; /* buffer for formatted printing */ formatted_buffer.buffer = printed_formatted; formatted_buffer.length = sizeof(printed_formatted); formatted_buffer.offset = 0; formatted_buffer.noalloc = true; - formatted_buffer.hooks = global_hooks; + formatted_buffer.configuration = global_configuration; /* buffer for unformatted printing */ unformatted_buffer.buffer = printed_unformatted; unformatted_buffer.length = sizeof(printed_unformatted); unformatted_buffer.offset = 0; unformatted_buffer.noalloc = true; - unformatted_buffer.hooks = global_hooks; + unformatted_buffer.configuration = global_configuration; memset(item, 0, sizeof(item)); TEST_ASSERT_TRUE_MESSAGE(parse_array(item, &parsebuffer), "Failed to parse array."); diff --git a/tests/print_number.c b/tests/print_number.c index 5ebb3489..79c4e6b3 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -33,7 +33,7 @@ static void assert_print_number(const char *expected, double input) buffer.length = sizeof(printed); buffer.offset = 0; buffer.noalloc = true; - buffer.hooks = global_hooks; + buffer.configuration = global_configuration; memset(item, 0, sizeof(item)); cJSON_SetNumberValue(item, input); diff --git a/tests/print_object.c b/tests/print_object.c index 70bbb43c..5b9b0a5a 100644 --- a/tests/print_object.c +++ b/tests/print_object.c @@ -38,21 +38,21 @@ static void assert_print_object(const char * const expected, const char * const /* buffer for parsing */ parsebuffer.content = (const unsigned char*)input; parsebuffer.length = strlen(input) + sizeof(""); - parsebuffer.hooks = global_hooks; + parsebuffer.configuration = global_configuration; /* buffer for formatted printing */ formatted_buffer.buffer = printed_formatted; formatted_buffer.length = sizeof(printed_formatted); formatted_buffer.offset = 0; formatted_buffer.noalloc = true; - formatted_buffer.hooks = global_hooks; + formatted_buffer.configuration = global_configuration; /* buffer for unformatted printing */ unformatted_buffer.buffer = printed_unformatted; unformatted_buffer.length = sizeof(printed_unformatted); unformatted_buffer.offset = 0; unformatted_buffer.noalloc = true; - unformatted_buffer.hooks = global_hooks; + unformatted_buffer.configuration = global_configuration; memset(item, 0, sizeof(item)); TEST_ASSERT_TRUE_MESSAGE(parse_object(item, &parsebuffer), "Failed to parse object."); diff --git a/tests/print_string.c b/tests/print_string.c index 83de1e7a..8b696806 100644 --- a/tests/print_string.c +++ b/tests/print_string.c @@ -32,7 +32,7 @@ static void assert_print_string(const char *expected, const char *input) buffer.length = sizeof(printed); buffer.offset = 0; buffer.noalloc = true; - buffer.hooks = global_hooks; + buffer.configuration = global_configuration; TEST_ASSERT_TRUE_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer), "Failed to print string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed, "The printed string isn't as expected."); diff --git a/tests/print_value.c b/tests/print_value.c index d5908232..1c8599f6 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -38,11 +38,11 @@ static void assert_print_value(const char *input) buffer.length = sizeof(printed); buffer.offset = 0; buffer.noalloc = true; - buffer.hooks = global_hooks; + buffer.configuration = global_configuration; parsebuffer.content = (const unsigned char*)input; parsebuffer.length = strlen(input) + sizeof(""); - parsebuffer.hooks = global_hooks; + parsebuffer.configuration = global_configuration; memset(item, 0, sizeof(item)); From 27977adc930348a149d4b2fc175ac6571330a0a5 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 31 Jan 2018 23:28:48 +0100 Subject: [PATCH 16/38] Put format into internal_configuration --- cJSON.c | 47 ++++++++++++++++++++++---------------------- cJSON.h | 2 +- tests/misc_tests.c | 6 +++--- tests/parse_array.c | 4 ++-- tests/parse_number.c | 2 +- tests/parse_object.c | 4 ++-- tests/parse_string.c | 4 ++-- tests/parse_value.c | 2 +- tests/print_array.c | 10 +++++----- tests/print_number.c | 2 +- tests/print_object.c | 10 +++++----- tests/print_string.c | 2 +- tests/print_value.c | 5 +++-- 13 files changed, 51 insertions(+), 49 deletions(-) diff --git a/cJSON.c b/cJSON.c index 0aafbe63..c797e526 100644 --- a/cJSON.c +++ b/cJSON.c @@ -118,6 +118,7 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned typedef struct internal_configuration { + cJSON_bool format; void *(*allocate)(size_t size); void (*deallocate)(void *pointer); void *(*reallocate)(void *pointer, size_t size); @@ -143,7 +144,7 @@ static void *internal_realloc(void *pointer, size_t size) #define internal_realloc realloc #endif -static internal_configuration global_configuration = { internal_malloc, internal_free, internal_realloc }; +static internal_configuration global_configuration = { true, internal_malloc, internal_free, internal_realloc }; static unsigned char* custom_strdup(const unsigned char* string, const internal_configuration * const configuration) { @@ -353,7 +354,6 @@ typedef struct size_t offset; size_t depth; /* current nesting depth (for formatted printing) */ cJSON_bool noalloc; - cJSON_bool format; /* is this print a formatted print */ internal_configuration configuration; } printbuffer; @@ -994,7 +994,7 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) /* Parse an object - create a new root, and populate. */ 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, 0 } }; cJSON *item = NULL; /* reset error position */ @@ -1079,7 +1079,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) #define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) -static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_configuration * const configuration) +static unsigned char *print(const cJSON * const item, const internal_configuration * const configuration) { static const size_t default_buffer_size = 256; printbuffer buffer[1]; @@ -1090,7 +1090,6 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i /* create buffer */ buffer->buffer = (unsigned char*) configuration->allocate(default_buffer_size); buffer->length = default_buffer_size; - buffer->format = format; buffer->configuration = *configuration; if (buffer->buffer == NULL) { @@ -1148,17 +1147,19 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i /* Render a cJSON item/entity/structure to text. */ CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) { - return (char*)print(item, true, &global_configuration); + return (char*)print(item, &global_configuration); } CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) { - return (char*)print(item, false, &global_configuration); + internal_configuration configuration = global_configuration; + configuration.format = false; + return (char*)print(item, &configuration); } -CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool format) { - printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + printbuffer p = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; if (prebuffer < 0) { @@ -1174,8 +1175,8 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON p.length = (size_t)prebuffer; p.offset = 0; p.noalloc = false; - p.format = fmt; p.configuration = global_configuration; + p.configuration.format = format; if (!print_value(item, &p)) { @@ -1188,7 +1189,7 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) { - 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)) { @@ -1199,8 +1200,8 @@ CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, cons p.length = (size_t)length; p.offset = 0; p.noalloc = true; - p.format = format; p.configuration = global_configuration; + p.configuration.format = format; return print_value(item, &p); } @@ -1485,14 +1486,14 @@ static cJSON_bool print_array(const cJSON * const item, printbuffer * const outp update_offset(output_buffer); if (current_element->next) { - length = (size_t) (output_buffer->format ? 2 : 1); + length = (size_t) (output_buffer->configuration.format ? 2 : 1); output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) { return false; } *output_pointer++ = ','; - if(output_buffer->format) + if(output_buffer->configuration.format) { *output_pointer++ = ' '; } @@ -1636,7 +1637,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out } /* Compose the output: */ - length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + length = (size_t) (output_buffer->configuration.format ? 2 : 1); /* fmt: {\n */ output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) { @@ -1645,7 +1646,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out *output_pointer++ = '{'; output_buffer->depth++; - if (output_buffer->format) + if (output_buffer->configuration.format) { *output_pointer++ = '\n'; } @@ -1653,7 +1654,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out while (current_item) { - if (output_buffer->format) + if (output_buffer->configuration.format) { size_t i; output_pointer = ensure(output_buffer, output_buffer->depth); @@ -1675,14 +1676,14 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out } update_offset(output_buffer); - length = (size_t) (output_buffer->format ? 2 : 1); + length = (size_t) (output_buffer->configuration.format ? 2 : 1); output_pointer = ensure(output_buffer, length); if (output_pointer == NULL) { return false; } *output_pointer++ = ':'; - if (output_buffer->format) + if (output_buffer->configuration.format) { *output_pointer++ = '\t'; } @@ -1696,7 +1697,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->configuration.format ? 1 : 0) + (current_item->next ? 1 : 0)); output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) { @@ -1707,7 +1708,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out *output_pointer++ = ','; } - if (output_buffer->format) + if (output_buffer->configuration.format) { *output_pointer++ = '\n'; } @@ -1717,12 +1718,12 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out current_item = current_item->next; } - output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + output_pointer = ensure(output_buffer, output_buffer->configuration.format ? (output_buffer->depth + 1) : 2); if (output_pointer == NULL) { return false; } - if (output_buffer->format) + if (output_buffer->configuration.format) { size_t i; for (i = 0; i < (output_buffer->depth - 1); i++) diff --git a/cJSON.h b/cJSON.h index edcac07b..0943175b 100644 --- a/cJSON.h +++ b/cJSON.h @@ -147,7 +147,7 @@ CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); /* Render a cJSON entity to text for transfer/storage without any formatting. */ CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ -CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool format); /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index e5eaf5fc..686b571a 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -418,7 +418,7 @@ static void *failing_realloc(void *pointer, size_t size) static void ensure_should_fail_on_failed_realloc(void) { - printbuffer buffer = {NULL, 10, 0, 0, false, false, {&malloc, &free, &failing_realloc}}; + printbuffer buffer = {NULL, 10, 0, 0, false, {false, &malloc, &free, &failing_realloc}}; buffer.buffer = (unsigned char*)malloc(100); TEST_ASSERT_NOT_NULL(buffer.buffer); @@ -428,7 +428,7 @@ static void ensure_should_fail_on_failed_realloc(void) static void skip_utf8_bom_should_skip_bom(void) { const unsigned char string[] = "\xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; buffer.content = string; buffer.length = sizeof(string); buffer.configuration = global_configuration; @@ -440,7 +440,7 @@ static void skip_utf8_bom_should_skip_bom(void) static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void) { const unsigned char string[] = " \xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; buffer.content = string; buffer.length = sizeof(string); buffer.configuration = global_configuration; diff --git a/tests/parse_array.c b/tests/parse_array.c index dcf2d638..0ece51d9 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -44,7 +44,7 @@ static void assert_is_array(cJSON *array_item) static void assert_not_array(const char *json) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); buffer.configuration = global_configuration; @@ -55,7 +55,7 @@ static void assert_not_array(const char *json) static void assert_parse_array(const char *json) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/parse_number.c b/tests/parse_number.c index f499ab65..c83d85e8 100644 --- a/tests/parse_number.c +++ b/tests/parse_number.c @@ -45,7 +45,7 @@ static void assert_is_number(cJSON *number_item) static void assert_parse_number(const char *string, int integer, double real) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); diff --git a/tests/parse_object.c b/tests/parse_object.c index 990758d9..2535d879 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -52,7 +52,7 @@ static void assert_is_child(cJSON *child_item, const char *name, int type) static void assert_not_object(const char *json) { - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); parsebuffer.configuration = global_configuration; @@ -64,7 +64,7 @@ static void assert_not_object(const char *json) static void assert_parse_object(const char *json) { - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); parsebuffer.configuration = global_configuration; diff --git a/tests/parse_string.c b/tests/parse_string.c index 66e96eaa..6e34362a 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -45,7 +45,7 @@ static void assert_is_string(cJSON *string_item) static void assert_parse_string(const char *string, const char *expected) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; @@ -59,7 +59,7 @@ static void assert_parse_string(const char *string, const char *expected) static void assert_not_parse_string(const char * const string) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/parse_value.c b/tests/parse_value.c index 3e8fb27c..40365465 100644 --- a/tests/parse_value.c +++ b/tests/parse_value.c @@ -43,7 +43,7 @@ static void assert_is_value(cJSON *value_item, int type) static void assert_parse_value(const char *string, int type) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; buffer.content = (const unsigned char*) string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/print_array.c b/tests/print_array.c index 5cf556cd..399e23e8 100644 --- a/tests/print_array.c +++ b/tests/print_array.c @@ -31,10 +31,10 @@ static void assert_print_array(const char * const expected, const char * const i cJSON item[1]; - printbuffer formatted_buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; + printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)input; parsebuffer.length = strlen(input) + sizeof(""); parsebuffer.configuration = global_configuration; @@ -56,11 +56,11 @@ static void assert_print_array(const char * const expected, const char * const i memset(item, 0, sizeof(item)); TEST_ASSERT_TRUE_MESSAGE(parse_array(item, &parsebuffer), "Failed to parse array."); - unformatted_buffer.format = false; + unformatted_buffer.configuration.format = false; TEST_ASSERT_TRUE_MESSAGE(print_array(item, &unformatted_buffer), "Failed to print unformatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted array is not correct."); - formatted_buffer.format = true; + formatted_buffer.configuration.format = true; TEST_ASSERT_TRUE_MESSAGE(print_array(item, &formatted_buffer), "Failed to print formatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted array is not correct."); diff --git a/tests/print_number.c b/tests/print_number.c index 79c4e6b3..2d00d342 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -28,7 +28,7 @@ static void assert_print_number(const char *expected, double input) { unsigned char printed[1024]; cJSON item[1]; - printbuffer buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; diff --git a/tests/print_object.c b/tests/print_object.c index 5b9b0a5a..15e61883 100644 --- a/tests/print_object.c +++ b/tests/print_object.c @@ -31,9 +31,9 @@ static void assert_print_object(const char * const expected, const char * const cJSON item[1]; - printbuffer formatted_buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; + printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; /* buffer for parsing */ parsebuffer.content = (const unsigned char*)input; @@ -57,11 +57,11 @@ static void assert_print_object(const char * const expected, const char * const memset(item, 0, sizeof(item)); TEST_ASSERT_TRUE_MESSAGE(parse_object(item, &parsebuffer), "Failed to parse object."); - unformatted_buffer.format = false; + unformatted_buffer.configuration.format = false; TEST_ASSERT_TRUE_MESSAGE(print_object(item, &unformatted_buffer), "Failed to print unformatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted object is not correct."); - formatted_buffer.format = true; + formatted_buffer.configuration.format = true; TEST_ASSERT_TRUE_MESSAGE(print_object(item, &formatted_buffer), "Failed to print formatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted ojbect is not correct."); diff --git a/tests/print_string.c b/tests/print_string.c index 8b696806..e7d46aa6 100644 --- a/tests/print_string.c +++ b/tests/print_string.c @@ -27,7 +27,7 @@ static void assert_print_string(const char *expected, const char *input) { unsigned char printed[1024]; - printbuffer buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; diff --git a/tests/print_value.c b/tests/print_value.c index 1c8599f6..a0c929d5 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -32,13 +32,14 @@ static void assert_print_value(const char *input) { unsigned char printed[1024]; cJSON item[1]; - printbuffer buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; buffer.noalloc = true; buffer.configuration = global_configuration; + buffer.configuration.format = false; parsebuffer.content = (const unsigned char*)input; parsebuffer.length = strlen(input) + sizeof(""); From 7030dc7c5be57ab303d02c7c832df001376f976e Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 1 Feb 2018 00:00:36 +0100 Subject: [PATCH 17/38] Put buffer_size into internal_configuration --- cJSON.c | 41 ++++++++++++++++------------------------- tests/misc_tests.c | 6 +++--- tests/parse_array.c | 4 ++-- tests/parse_number.c | 2 +- tests/parse_object.c | 4 ++-- tests/parse_string.c | 4 ++-- tests/parse_value.c | 2 +- tests/print_array.c | 6 +++--- tests/print_number.c | 2 +- tests/print_object.c | 6 +++--- tests/print_string.c | 2 +- tests/print_value.c | 4 ++-- 12 files changed, 37 insertions(+), 46 deletions(-) diff --git a/cJSON.c b/cJSON.c index c797e526..6db57f07 100644 --- a/cJSON.c +++ b/cJSON.c @@ -118,6 +118,7 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned typedef struct internal_configuration { + size_t buffer_size; cJSON_bool format; void *(*allocate)(size_t size); void (*deallocate)(void *pointer); @@ -144,7 +145,13 @@ static void *internal_realloc(void *pointer, size_t size) #define internal_realloc realloc #endif -static internal_configuration global_configuration = { true, internal_malloc, internal_free, internal_realloc }; +static internal_configuration global_configuration = { + 256, /* default buffer size */ + true, /* enable formatting by default */ + internal_malloc, + internal_free, + internal_realloc +}; static unsigned char* custom_strdup(const unsigned char* string, const internal_configuration * const configuration) { @@ -994,7 +1001,7 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) /* Parse an object - create a new root, and populate. */ 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, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; cJSON *item = NULL; /* reset error position */ @@ -1081,15 +1088,14 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) static unsigned char *print(const cJSON * const item, const internal_configuration * const configuration) { - static const size_t default_buffer_size = 256; printbuffer buffer[1]; unsigned char *printed = NULL; memset(buffer, 0, sizeof(buffer)); /* create buffer */ - buffer->buffer = (unsigned char*) configuration->allocate(default_buffer_size); - buffer->length = default_buffer_size; + buffer->buffer = (unsigned char*) configuration->allocate(configuration->buffer_size); + buffer->length = configuration->buffer_size; buffer->configuration = *configuration; if (buffer->buffer == NULL) { @@ -1159,37 +1165,22 @@ CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool format) { - printbuffer p = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; + internal_configuration configuration = global_configuration; if (prebuffer < 0) { return NULL; } - p.buffer = (unsigned char*)global_configuration.allocate((size_t)prebuffer); - if (!p.buffer) - { - return NULL; - } + configuration.buffer_size = (size_t)prebuffer; + configuration.format = format; - p.length = (size_t)prebuffer; - p.offset = 0; - p.noalloc = false; - p.configuration = global_configuration; - p.configuration.format = format; - - if (!print_value(item, &p)) - { - global_configuration.deallocate(p.buffer); - return NULL; - } - - return (char*)p.buffer; + return (char*)print(item, &configuration); } CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) { - printbuffer p = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; + printbuffer p = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; if ((length < 0) || (buffer == NULL)) { diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 686b571a..96a18694 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -418,7 +418,7 @@ static void *failing_realloc(void *pointer, size_t size) static void ensure_should_fail_on_failed_realloc(void) { - printbuffer buffer = {NULL, 10, 0, 0, false, {false, &malloc, &free, &failing_realloc}}; + printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, &malloc, &free, &failing_realloc}}; buffer.buffer = (unsigned char*)malloc(100); TEST_ASSERT_NOT_NULL(buffer.buffer); @@ -428,7 +428,7 @@ static void ensure_should_fail_on_failed_realloc(void) static void skip_utf8_bom_should_skip_bom(void) { const unsigned char string[] = "\xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; buffer.content = string; buffer.length = sizeof(string); buffer.configuration = global_configuration; @@ -440,7 +440,7 @@ static void skip_utf8_bom_should_skip_bom(void) static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void) { const unsigned char string[] = " \xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; buffer.content = string; buffer.length = sizeof(string); buffer.configuration = global_configuration; diff --git a/tests/parse_array.c b/tests/parse_array.c index 0ece51d9..c8f1fcfa 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -44,7 +44,7 @@ static void assert_is_array(cJSON *array_item) static void assert_not_array(const char *json) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); buffer.configuration = global_configuration; @@ -55,7 +55,7 @@ static void assert_not_array(const char *json) static void assert_parse_array(const char *json) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/parse_number.c b/tests/parse_number.c index c83d85e8..69fcfd1c 100644 --- a/tests/parse_number.c +++ b/tests/parse_number.c @@ -45,7 +45,7 @@ static void assert_is_number(cJSON *number_item) static void assert_parse_number(const char *string, int integer, double real) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); diff --git a/tests/parse_object.c b/tests/parse_object.c index 2535d879..8b927f1e 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -52,7 +52,7 @@ static void assert_is_child(cJSON *child_item, const char *name, int type) static void assert_not_object(const char *json) { - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); parsebuffer.configuration = global_configuration; @@ -64,7 +64,7 @@ static void assert_not_object(const char *json) static void assert_parse_object(const char *json) { - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); parsebuffer.configuration = global_configuration; diff --git a/tests/parse_string.c b/tests/parse_string.c index 6e34362a..2eefc646 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -45,7 +45,7 @@ static void assert_is_string(cJSON *string_item) static void assert_parse_string(const char *string, const char *expected) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; @@ -59,7 +59,7 @@ static void assert_parse_string(const char *string, const char *expected) static void assert_not_parse_string(const char * const string) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/parse_value.c b/tests/parse_value.c index 40365465..18e4101a 100644 --- a/tests/parse_value.c +++ b/tests/parse_value.c @@ -43,7 +43,7 @@ static void assert_is_value(cJSON *value_item, int type) static void assert_parse_value(const char *string, int type) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*) string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/print_array.c b/tests/print_array.c index 399e23e8..5b6cd1bd 100644 --- a/tests/print_array.c +++ b/tests/print_array.c @@ -31,10 +31,10 @@ static void assert_print_array(const char * const expected, const char * const i cJSON item[1]; - printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; - printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; + printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)input; parsebuffer.length = strlen(input) + sizeof(""); parsebuffer.configuration = global_configuration; diff --git a/tests/print_number.c b/tests/print_number.c index 2d00d342..c2780a14 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -28,7 +28,7 @@ static void assert_print_number(const char *expected, double input) { unsigned char printed[1024]; cJSON item[1]; - printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; diff --git a/tests/print_object.c b/tests/print_object.c index 15e61883..ca24580b 100644 --- a/tests/print_object.c +++ b/tests/print_object.c @@ -31,9 +31,9 @@ static void assert_print_object(const char * const expected, const char * const cJSON item[1]; - printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; - printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; + printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; /* buffer for parsing */ parsebuffer.content = (const unsigned char*)input; diff --git a/tests/print_string.c b/tests/print_string.c index e7d46aa6..cd7d17af 100644 --- a/tests/print_string.c +++ b/tests/print_string.c @@ -27,7 +27,7 @@ static void assert_print_string(const char *expected, const char *input) { unsigned char printed[1024]; - printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; diff --git a/tests/print_value.c b/tests/print_value.c index a0c929d5..8b6e4eac 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -32,8 +32,8 @@ static void assert_print_value(const char *input) { unsigned char printed[1024]; cJSON item[1]; - printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; From d4e81cfe570219b3b1ecea7d3023c1672f21f588 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 1 Feb 2018 01:20:37 +0100 Subject: [PATCH 18/38] cJSON_Delete: Extract delete_item with internal_configuration --- cJSON.c | 62 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/cJSON.c b/cJSON.c index 6db57f07..b1ca0352 100644 --- a/cJSON.c +++ b/cJSON.c @@ -218,7 +218,7 @@ static cJSON *create_item(const internal_configuration * const configuration) } /* Delete a cJSON structure. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +static void delete_item(cJSON *item, const internal_configuration * const configuration) { cJSON *next = NULL; while (item != NULL) @@ -226,21 +226,27 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) next = item->next; if (!(item->type & cJSON_IsReference) && (item->child != NULL)) { - cJSON_Delete(item->child); + delete_item(item->child, configuration); } if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) { - global_configuration.deallocate(item->valuestring); + configuration->deallocate(item->valuestring); } if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { - global_configuration.deallocate(item->string); + configuration->deallocate(item->string); } - global_configuration.deallocate(item); + configuration->deallocate(item); item = next; } } +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + delete_item(item, &global_configuration); +} + static int double_to_saturated_integer(double number) { if (number >= INT_MAX) @@ -1049,7 +1055,7 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return fail: if (item != NULL) { - cJSON_Delete(item); + delete_item(item, &global_configuration); } if (value != NULL) @@ -1438,7 +1444,7 @@ static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buf fail: if (head != NULL) { - cJSON_Delete(head); + delete_item(head, &input_buffer->configuration); } return false; @@ -1609,7 +1615,7 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu fail: if (head != NULL) { - cJSON_Delete(head); + delete_item(head, &input_buffer->configuration); } return false; @@ -1992,7 +1998,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * co return null; } - cJSON_Delete(null); + delete_item(null, &global_configuration); return NULL; } @@ -2004,7 +2010,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * co return true_item; } - cJSON_Delete(true_item); + delete_item(true_item, &global_configuration); return NULL; } @@ -2016,7 +2022,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * c return false_item; } - cJSON_Delete(false_item); + delete_item(false_item, &global_configuration); return NULL; } @@ -2028,7 +2034,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * co return bool_item; } - cJSON_Delete(bool_item); + delete_item(bool_item, &global_configuration); return NULL; } @@ -2040,7 +2046,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * return number_item; } - cJSON_Delete(number_item); + delete_item(number_item, &global_configuration); return NULL; } @@ -2052,7 +2058,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * return string_item; } - cJSON_Delete(string_item); + delete_item(string_item, &global_configuration); return NULL; } @@ -2064,7 +2070,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * con return raw_item; } - cJSON_Delete(raw_item); + delete_item(raw_item, &global_configuration); return NULL; } @@ -2076,7 +2082,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * return object_item; } - cJSON_Delete(object_item); + delete_item(object_item, &global_configuration); return NULL; } @@ -2088,7 +2094,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * c return array; } - cJSON_Delete(array); + delete_item(array, &global_configuration); return NULL; } @@ -2134,7 +2140,7 @@ CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) { - cJSON_Delete(cJSON_DetachItemFromArray(array, which)); + delete_item(cJSON_DetachItemFromArray(array, which), &global_configuration); } CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) @@ -2153,12 +2159,12 @@ CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, con CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) { - cJSON_Delete(cJSON_DetachItemFromObject(object, string)); + delete_item(cJSON_DetachItemFromObject(object, string), &global_configuration); } CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) { - cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); + delete_item(cJSON_DetachItemFromObjectCaseSensitive(object, string), &global_configuration); } /* Replace array/object items with new ones. */ @@ -2221,7 +2227,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON item->next = NULL; item->prev = NULL; - cJSON_Delete(item); + delete_item(item, &global_configuration); return true; } @@ -2333,7 +2339,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) item->valuestring = (char*)custom_strdup((const unsigned char*)string, &global_configuration); if(!item->valuestring) { - cJSON_Delete(item); + delete_item(item, &global_configuration); return NULL; } } @@ -2383,7 +2389,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) item->valuestring = (char*)custom_strdup((const unsigned char*)raw, &global_configuration); if(!item->valuestring) { - cJSON_Delete(item); + delete_item(item, &global_configuration); return NULL; } } @@ -2432,7 +2438,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) n = cJSON_CreateNumber(numbers[i]); if (!n) { - cJSON_Delete(a); + delete_item(a, &global_configuration); return NULL; } if(!i) @@ -2468,7 +2474,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) n = cJSON_CreateNumber((double)numbers[i]); if(!n) { - cJSON_Delete(a); + delete_item(a, &global_configuration); return NULL; } if(!i) @@ -2504,7 +2510,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) n = cJSON_CreateNumber(numbers[i]); if(!n) { - cJSON_Delete(a); + delete_item(a, &global_configuration); return NULL; } if(!i) @@ -2540,7 +2546,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) n = cJSON_CreateString(strings[i]); if(!n) { - cJSON_Delete(a); + delete_item(a, &global_configuration); return NULL; } if(!i) @@ -2631,7 +2637,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) fail: if (newitem != NULL) { - cJSON_Delete(newitem); + delete_item(newitem, &global_configuration); } return NULL; From f02f79ecbbb374e086ea093a5135fc0488ed267e Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 1 Feb 2018 01:24:36 +0100 Subject: [PATCH 19/38] cJSON_ParseWithOpts: Extract pasrse with internal_configuration Also introduces a allow_data_after_json property in the internal configuration. --- cJSON.c | 67 ++++++++++++++++++++++++++------------------ cJSON.h | 4 +-- tests/misc_tests.c | 6 ++-- tests/parse_array.c | 4 +-- tests/parse_number.c | 2 +- tests/parse_object.c | 4 +-- tests/parse_string.c | 4 +-- tests/parse_value.c | 2 +- tests/print_array.c | 6 ++-- tests/print_number.c | 2 +- tests/print_object.c | 6 ++-- tests/print_string.c | 2 +- tests/print_value.c | 4 +-- 13 files changed, 63 insertions(+), 50 deletions(-) diff --git a/cJSON.c b/cJSON.c index b1ca0352..f361fcbc 100644 --- a/cJSON.c +++ b/cJSON.c @@ -120,6 +120,7 @@ typedef struct internal_configuration { size_t buffer_size; cJSON_bool format; + cJSON_bool allow_data_after_json; void *(*allocate)(size_t size); void (*deallocate)(void *pointer); void *(*reallocate)(void *pointer, size_t size); @@ -148,6 +149,7 @@ static void *internal_realloc(void *pointer, size_t size) static internal_configuration global_configuration = { 256, /* default buffer size */ true, /* enable formatting by default */ + true, /* allow data after the JSON by default */ internal_malloc, internal_free, internal_realloc @@ -1005,39 +1007,38 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) } /* Parse an object - create a new root, and populate. */ -CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +static cJSON *parse(const char * const json, const internal_configuration * const configuration, size_t *end_position) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; cJSON *item = NULL; - /* reset error position */ + /* reset global error position */ global_error.json = NULL; global_error.position = 0; - if (value == NULL) + if (json == NULL) { goto fail; } - buffer.content = (const unsigned char*)value; - buffer.length = strlen(value) + sizeof(""); + buffer.content = (const unsigned char*)json; + buffer.length = strlen(json) + sizeof(""); buffer.offset = 0; - buffer.configuration = global_configuration; + buffer.configuration = *configuration; - item = create_item(&global_configuration); - if (item == NULL) /* memory fail */ + item = create_item(configuration); + if (item == NULL) { goto fail; } if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) { - /* parse failure. ep is set. */ + /* parse failure. error position is set. */ goto fail; } - /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ - if (require_null_terminated) + if (!configuration->allow_data_after_json) { buffer_skip_whitespace(&buffer); if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') @@ -1045,23 +1046,20 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return goto fail; } } - if (return_parse_end) - { - *return_parse_end = (const char*)buffer_at_offset(&buffer); - } + *end_position = buffer.offset; return item; fail: if (item != NULL) { - delete_item(item, &global_configuration); + delete_item(item, configuration); } - if (value != NULL) + if (json != NULL) { error local_error; - local_error.json = (const unsigned char*)value; + local_error.json = (const unsigned char*)json; local_error.position = 0; if (buffer.offset < buffer.length) @@ -1073,21 +1071,36 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return local_error.position = buffer.length - 1; } - if (return_parse_end != NULL) - { - *return_parse_end = (const char*)local_error.json + local_error.position; - } - + *end_position = local_error.position; global_error = local_error; } return NULL; } +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *json, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + size_t end_position = 0; + internal_configuration configuration = global_configuration; + cJSON *item = NULL; + + configuration.allow_data_after_json = !require_null_terminated; + item = parse(json, &configuration, &end_position); + + if (return_parse_end != NULL) + { + *return_parse_end = json + end_position; + } + + return item; +} + /* Default options for cJSON_Parse */ -CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *json) { - return cJSON_ParseWithOpts(value, 0, 0); + size_t end_position = 0; + return parse(json, &global_configuration, &end_position); } #define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) @@ -1186,7 +1199,7 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) { - printbuffer p = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + printbuffer p = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; if ((length < 0) || (buffer == NULL)) { diff --git a/cJSON.h b/cJSON.h index 0943175b..153bcf5e 100644 --- a/cJSON.h +++ b/cJSON.h @@ -137,10 +137,10 @@ 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_Parse(const char *json); /* 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_ParseWithOpts(const char *json, 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); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 96a18694..09e20e91 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -418,7 +418,7 @@ static void *failing_realloc(void *pointer, size_t size) static void ensure_should_fail_on_failed_realloc(void) { - printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, &malloc, &free, &failing_realloc}}; + printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, &malloc, &free, &failing_realloc}}; buffer.buffer = (unsigned char*)malloc(100); TEST_ASSERT_NOT_NULL(buffer.buffer); @@ -428,7 +428,7 @@ static void ensure_should_fail_on_failed_realloc(void) static void skip_utf8_bom_should_skip_bom(void) { const unsigned char string[] = "\xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; buffer.content = string; buffer.length = sizeof(string); buffer.configuration = global_configuration; @@ -440,7 +440,7 @@ static void skip_utf8_bom_should_skip_bom(void) static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void) { const unsigned char string[] = " \xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; buffer.content = string; buffer.length = sizeof(string); buffer.configuration = global_configuration; diff --git a/tests/parse_array.c b/tests/parse_array.c index c8f1fcfa..d6503d2f 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -44,7 +44,7 @@ static void assert_is_array(cJSON *array_item) static void assert_not_array(const char *json) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); buffer.configuration = global_configuration; @@ -55,7 +55,7 @@ static void assert_not_array(const char *json) static void assert_parse_array(const char *json) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/parse_number.c b/tests/parse_number.c index 69fcfd1c..6bcf9feb 100644 --- a/tests/parse_number.c +++ b/tests/parse_number.c @@ -45,7 +45,7 @@ static void assert_is_number(cJSON *number_item) static void assert_parse_number(const char *string, int integer, double real) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); diff --git a/tests/parse_object.c b/tests/parse_object.c index 8b927f1e..eef951b4 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -52,7 +52,7 @@ static void assert_is_child(cJSON *child_item, const char *name, int type) static void assert_not_object(const char *json) { - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); parsebuffer.configuration = global_configuration; @@ -64,7 +64,7 @@ static void assert_not_object(const char *json) static void assert_parse_object(const char *json) { - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); parsebuffer.configuration = global_configuration; diff --git a/tests/parse_string.c b/tests/parse_string.c index 2eefc646..30ecd656 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -45,7 +45,7 @@ static void assert_is_string(cJSON *string_item) static void assert_parse_string(const char *string, const char *expected) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; @@ -59,7 +59,7 @@ static void assert_parse_string(const char *string, const char *expected) static void assert_not_parse_string(const char * const string) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/parse_value.c b/tests/parse_value.c index 18e4101a..dddf75af 100644 --- a/tests/parse_value.c +++ b/tests/parse_value.c @@ -43,7 +43,7 @@ static void assert_is_value(cJSON *value_item, int type) static void assert_parse_value(const char *string, int type) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*) string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/print_array.c b/tests/print_array.c index 5b6cd1bd..239c2c9d 100644 --- a/tests/print_array.c +++ b/tests/print_array.c @@ -31,10 +31,10 @@ static void assert_print_array(const char * const expected, const char * const i cJSON item[1]; - printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; - printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)input; parsebuffer.length = strlen(input) + sizeof(""); parsebuffer.configuration = global_configuration; diff --git a/tests/print_number.c b/tests/print_number.c index c2780a14..02e850bd 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -28,7 +28,7 @@ static void assert_print_number(const char *expected, double input) { unsigned char printed[1024]; cJSON item[1]; - printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; diff --git a/tests/print_object.c b/tests/print_object.c index ca24580b..b3749130 100644 --- a/tests/print_object.c +++ b/tests/print_object.c @@ -31,9 +31,9 @@ static void assert_print_object(const char * const expected, const char * const cJSON item[1]; - printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; - printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; /* buffer for parsing */ parsebuffer.content = (const unsigned char*)input; diff --git a/tests/print_string.c b/tests/print_string.c index cd7d17af..6b0e6b26 100644 --- a/tests/print_string.c +++ b/tests/print_string.c @@ -27,7 +27,7 @@ static void assert_print_string(const char *expected, const char *input) { unsigned char printed[1024]; - printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; diff --git a/tests/print_value.c b/tests/print_value.c index 8b6e4eac..a887151f 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -32,8 +32,8 @@ static void assert_print_value(const char *input) { unsigned char printed[1024]; cJSON item[1]; - printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; From ba8fe0f47918c32bf0a2bcde046811e2211add2b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 1 Feb 2018 01:45:31 +0100 Subject: [PATCH 20/38] internal_configuration: Add case_sensitive --- cJSON.c | 6 ++++-- tests/misc_tests.c | 6 +++--- tests/parse_array.c | 4 ++-- tests/parse_number.c | 2 +- tests/parse_object.c | 4 ++-- tests/parse_string.c | 4 ++-- tests/parse_value.c | 2 +- tests/print_array.c | 6 +++--- tests/print_number.c | 2 +- tests/print_object.c | 6 +++--- tests/print_string.c | 2 +- tests/print_value.c | 4 ++-- 12 files changed, 25 insertions(+), 23 deletions(-) diff --git a/cJSON.c b/cJSON.c index f361fcbc..746ab7ba 100644 --- a/cJSON.c +++ b/cJSON.c @@ -121,6 +121,7 @@ typedef struct internal_configuration size_t buffer_size; cJSON_bool format; cJSON_bool allow_data_after_json; + cJSON_bool case_sensitive; void *(*allocate)(size_t size); void (*deallocate)(void *pointer); void *(*reallocate)(void *pointer, size_t size); @@ -150,6 +151,7 @@ static internal_configuration global_configuration = { 256, /* default buffer size */ true, /* enable formatting by default */ true, /* allow data after the JSON by default */ + true, /* case sensitive by default */ internal_malloc, internal_free, internal_realloc @@ -1009,7 +1011,7 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) /* Parse an object - create a new root, and populate. */ static cJSON *parse(const char * const json, const internal_configuration * const configuration, size_t *end_position) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; cJSON *item = NULL; /* reset global error position */ @@ -1199,7 +1201,7 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) { - printbuffer p = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + printbuffer p = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; if ((length < 0) || (buffer == NULL)) { diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 09e20e91..353a1991 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -418,7 +418,7 @@ static void *failing_realloc(void *pointer, size_t size) static void ensure_should_fail_on_failed_realloc(void) { - printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, &malloc, &free, &failing_realloc}}; + printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, &malloc, &free, &failing_realloc}}; buffer.buffer = (unsigned char*)malloc(100); TEST_ASSERT_NOT_NULL(buffer.buffer); @@ -428,7 +428,7 @@ static void ensure_should_fail_on_failed_realloc(void) static void skip_utf8_bom_should_skip_bom(void) { const unsigned char string[] = "\xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; buffer.content = string; buffer.length = sizeof(string); buffer.configuration = global_configuration; @@ -440,7 +440,7 @@ static void skip_utf8_bom_should_skip_bom(void) static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void) { const unsigned char string[] = " \xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; buffer.content = string; buffer.length = sizeof(string); buffer.configuration = global_configuration; diff --git a/tests/parse_array.c b/tests/parse_array.c index d6503d2f..d4c4f42c 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -44,7 +44,7 @@ static void assert_is_array(cJSON *array_item) static void assert_not_array(const char *json) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); buffer.configuration = global_configuration; @@ -55,7 +55,7 @@ static void assert_not_array(const char *json) static void assert_parse_array(const char *json) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/parse_number.c b/tests/parse_number.c index 6bcf9feb..1751c5ef 100644 --- a/tests/parse_number.c +++ b/tests/parse_number.c @@ -45,7 +45,7 @@ static void assert_is_number(cJSON *number_item) static void assert_parse_number(const char *string, int integer, double real) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); diff --git a/tests/parse_object.c b/tests/parse_object.c index eef951b4..415048a0 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -52,7 +52,7 @@ static void assert_is_child(cJSON *child_item, const char *name, int type) static void assert_not_object(const char *json) { - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); parsebuffer.configuration = global_configuration; @@ -64,7 +64,7 @@ static void assert_not_object(const char *json) static void assert_parse_object(const char *json) { - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); parsebuffer.configuration = global_configuration; diff --git a/tests/parse_string.c b/tests/parse_string.c index 30ecd656..c17b973b 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -45,7 +45,7 @@ static void assert_is_string(cJSON *string_item) static void assert_parse_string(const char *string, const char *expected) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; @@ -59,7 +59,7 @@ static void assert_parse_string(const char *string, const char *expected) static void assert_not_parse_string(const char * const string) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/parse_value.c b/tests/parse_value.c index dddf75af..5269a6db 100644 --- a/tests/parse_value.c +++ b/tests/parse_value.c @@ -43,7 +43,7 @@ static void assert_is_value(cJSON *value_item, int type) static void assert_parse_value(const char *string, int type) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; buffer.content = (const unsigned char*) string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/print_array.c b/tests/print_array.c index 239c2c9d..70a984bd 100644 --- a/tests/print_array.c +++ b/tests/print_array.c @@ -31,10 +31,10 @@ static void assert_print_array(const char * const expected, const char * const i cJSON item[1]; - printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; - printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; parsebuffer.content = (const unsigned char*)input; parsebuffer.length = strlen(input) + sizeof(""); parsebuffer.configuration = global_configuration; diff --git a/tests/print_number.c b/tests/print_number.c index 02e850bd..4cb6d346 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -28,7 +28,7 @@ static void assert_print_number(const char *expected, double input) { unsigned char printed[1024]; cJSON item[1]; - printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; diff --git a/tests/print_object.c b/tests/print_object.c index b3749130..d49a95c3 100644 --- a/tests/print_object.c +++ b/tests/print_object.c @@ -31,9 +31,9 @@ static void assert_print_object(const char * const expected, const char * const cJSON item[1]; - printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; - printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; /* buffer for parsing */ parsebuffer.content = (const unsigned char*)input; diff --git a/tests/print_string.c b/tests/print_string.c index 6b0e6b26..37494a96 100644 --- a/tests/print_string.c +++ b/tests/print_string.c @@ -27,7 +27,7 @@ static void assert_print_string(const char *expected, const char *input) { unsigned char printed[1024]; - printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; diff --git a/tests/print_value.c b/tests/print_value.c index a887151f..abb7c169 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -32,8 +32,8 @@ static void assert_print_value(const char *input) { unsigned char printed[1024]; cJSON item[1]; - printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; From 515d11f55aa35eff25234467883f9e6b2766374a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 1 Feb 2018 02:01:17 +0100 Subject: [PATCH 21/38] default_configuration: Macro for the internal_configuration defaults --- cJSON.c | 24 +++++++++++++----------- tests/misc_tests.c | 4 ++-- tests/parse_array.c | 4 ++-- tests/parse_number.c | 2 +- tests/parse_object.c | 4 ++-- tests/parse_string.c | 4 ++-- tests/parse_value.c | 2 +- tests/print_array.c | 6 +++--- tests/print_number.c | 2 +- tests/print_object.c | 6 +++--- tests/print_string.c | 2 +- tests/print_value.c | 4 ++-- 12 files changed, 33 insertions(+), 31 deletions(-) diff --git a/cJSON.c b/cJSON.c index 746ab7ba..29292b8f 100644 --- a/cJSON.c +++ b/cJSON.c @@ -147,15 +147,17 @@ static void *internal_realloc(void *pointer, size_t size) #define internal_realloc realloc #endif -static internal_configuration global_configuration = { - 256, /* default buffer size */ - true, /* enable formatting by default */ - true, /* allow data after the JSON by default */ - true, /* case sensitive by default */ - internal_malloc, - internal_free, - internal_realloc -}; +#define default_configuration {\ + 256, /* default buffer size */\ + true, /* enable formatting by default */\ + true, /* allow data after the JSON by default */\ + true, /* case sensitive by default */\ + internal_malloc,\ + internal_free,\ + internal_realloc\ +} + +static internal_configuration global_configuration = default_configuration; static unsigned char* custom_strdup(const unsigned char* string, const internal_configuration * const configuration) { @@ -1011,7 +1013,7 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) /* Parse an object - create a new root, and populate. */ static cJSON *parse(const char * const json, const internal_configuration * const configuration, size_t *end_position) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; cJSON *item = NULL; /* reset global error position */ @@ -1201,7 +1203,7 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) { - printbuffer p = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + printbuffer p = { 0, 0, 0, 0, 0, default_configuration}; if ((length < 0) || (buffer == NULL)) { diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 353a1991..b4893d54 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -428,7 +428,7 @@ static void ensure_should_fail_on_failed_realloc(void) static void skip_utf8_bom_should_skip_bom(void) { const unsigned char string[] = "\xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; buffer.content = string; buffer.length = sizeof(string); buffer.configuration = global_configuration; @@ -440,7 +440,7 @@ static void skip_utf8_bom_should_skip_bom(void) static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void) { const unsigned char string[] = " \xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; buffer.content = string; buffer.length = sizeof(string); buffer.configuration = global_configuration; diff --git a/tests/parse_array.c b/tests/parse_array.c index d4c4f42c..4143966f 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -44,7 +44,7 @@ static void assert_is_array(cJSON *array_item) static void assert_not_array(const char *json) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); buffer.configuration = global_configuration; @@ -55,7 +55,7 @@ static void assert_not_array(const char *json) static void assert_parse_array(const char *json) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/parse_number.c b/tests/parse_number.c index 1751c5ef..5850265d 100644 --- a/tests/parse_number.c +++ b/tests/parse_number.c @@ -45,7 +45,7 @@ static void assert_is_number(cJSON *number_item) static void assert_parse_number(const char *string, int integer, double real) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); diff --git a/tests/parse_object.c b/tests/parse_object.c index 415048a0..0f46a22a 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -52,7 +52,7 @@ static void assert_is_child(cJSON *child_item, const char *name, int type) static void assert_not_object(const char *json) { - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, default_configuration }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); parsebuffer.configuration = global_configuration; @@ -64,7 +64,7 @@ static void assert_not_object(const char *json) static void assert_parse_object(const char *json) { - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, default_configuration }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); parsebuffer.configuration = global_configuration; diff --git a/tests/parse_string.c b/tests/parse_string.c index c17b973b..d22f7c81 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -45,7 +45,7 @@ static void assert_is_string(cJSON *string_item) static void assert_parse_string(const char *string, const char *expected) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; @@ -59,7 +59,7 @@ static void assert_parse_string(const char *string, const char *expected) static void assert_not_parse_string(const char * const string) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/parse_value.c b/tests/parse_value.c index 5269a6db..2b17fc8b 100644 --- a/tests/parse_value.c +++ b/tests/parse_value.c @@ -43,7 +43,7 @@ static void assert_is_value(cJSON *value_item, int type) static void assert_parse_value(const char *string, int type) { - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; buffer.content = (const unsigned char*) string; buffer.length = strlen(string) + sizeof(""); buffer.configuration = global_configuration; diff --git a/tests/print_array.c b/tests/print_array.c index 70a984bd..05636c30 100644 --- a/tests/print_array.c +++ b/tests/print_array.c @@ -31,10 +31,10 @@ static void assert_print_array(const char * const expected, const char * const i cJSON item[1]; - printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; - printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + printbuffer formatted_buffer = { 0, 0, 0, 0, 0, default_configuration }; + printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, default_configuration }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + parse_buffer parsebuffer = { 0, 0, 0, 0, default_configuration }; parsebuffer.content = (const unsigned char*)input; parsebuffer.length = strlen(input) + sizeof(""); parsebuffer.configuration = global_configuration; diff --git a/tests/print_number.c b/tests/print_number.c index 4cb6d346..c5174c5d 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -28,7 +28,7 @@ static void assert_print_number(const char *expected, double input) { unsigned char printed[1024]; cJSON item[1]; - printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, default_configuration }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; diff --git a/tests/print_object.c b/tests/print_object.c index d49a95c3..582a10be 100644 --- a/tests/print_object.c +++ b/tests/print_object.c @@ -31,9 +31,9 @@ static void assert_print_object(const char * const expected, const char * const cJSON item[1]; - printbuffer formatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; - printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + printbuffer formatted_buffer = { 0, 0, 0, 0, 0, default_configuration }; + printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, default_configuration }; + parse_buffer parsebuffer = { 0, 0, 0, 0, default_configuration }; /* buffer for parsing */ parsebuffer.content = (const unsigned char*)input; diff --git a/tests/print_string.c b/tests/print_string.c index 37494a96..c0a8eee3 100644 --- a/tests/print_string.c +++ b/tests/print_string.c @@ -27,7 +27,7 @@ static void assert_print_string(const char *expected, const char *input) { unsigned char printed[1024]; - printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, default_configuration }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; diff --git a/tests/print_value.c b/tests/print_value.c index abb7c169..45a9d2ce 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -32,8 +32,8 @@ static void assert_print_value(const char *input) { unsigned char printed[1024]; cJSON item[1]; - printbuffer buffer = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; - parse_buffer parsebuffer = { 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } }; + printbuffer buffer = { 0, 0, 0, 0, 0, default_configuration }; + parse_buffer parsebuffer = { 0, 0, 0, 0, default_configuration }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; From dd1ba72ce20d9e91fd8f5dbcf532541f05c18ee6 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 16:42:43 +0100 Subject: [PATCH 22/38] cJSON_Compare: Extract compare with internal_configuration --- cJSON.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/cJSON.c b/cJSON.c index 29292b8f..55beb0b1 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1816,7 +1816,7 @@ CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) return get_array_item(array, (size_t)index); } -static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +static cJSON *get_object_item(const cJSON * const object, const char * const name, const internal_configuration * const configuration) { cJSON *current_element = NULL; @@ -1826,7 +1826,7 @@ static cJSON *get_object_item(const cJSON * const object, const char * const nam } current_element = object->child; - if (case_sensitive) + if (configuration->case_sensitive) { while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) { @@ -1846,12 +1846,16 @@ static cJSON *get_object_item(const cJSON * const object, const char * const nam CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) { - return get_object_item(object, string, false); + internal_configuration configuration = default_configuration; + configuration.case_sensitive = false; + return get_object_item(object, string, &configuration); } CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) { - return get_object_item(object, string, true); + internal_configuration configuration = default_configuration; + configuration.case_sensitive = true; + return get_object_item(object, string, &configuration); } CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) @@ -2259,7 +2263,7 @@ CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newi cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); } -static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, const internal_configuration * const configuration) { if ((replacement == NULL) || (string == NULL)) { @@ -2274,19 +2278,23 @@ static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSO replacement->string = (char*)custom_strdup((const unsigned char*)string, &global_configuration); replacement->type &= ~cJSON_StringIsConst; - cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); + cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, configuration), replacement); return true; } CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) { - replace_item_in_object(object, string, newitem, false); + internal_configuration configuration = global_configuration; + configuration.case_sensitive = false; + replace_item_in_object(object, string, newitem, &configuration); } CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) { - replace_item_in_object(object, string, newitem, true); + internal_configuration configuration = global_configuration; + configuration.case_sensitive = true; + replace_item_in_object(object, string, newitem, &configuration); } /* Create basic types: */ @@ -2830,7 +2838,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) return (item->type & 0xFF) == cJSON_Raw; } -CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const internal_configuration * const configuration) { if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) { @@ -2895,7 +2903,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons for (; (a_element != NULL) && (b_element != NULL);) { - if (!cJSON_Compare(a_element, b_element, case_sensitive)) + if (!compare(a_element, b_element, configuration)) { return false; } @@ -2927,13 +2935,13 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons cJSON_ArrayForEach(a_element, a) { /* TODO This has O(n^2) runtime, which is horrible! */ - b_element = get_object_item(b, a_element->string, case_sensitive); + b_element = get_object_item(b, a_element->string, configuration); if (b_element == NULL) { return false; } - if (!cJSON_Compare(a_element, b_element, case_sensitive)) + if (!compare(a_element, b_element, configuration)) { return false; } @@ -2947,6 +2955,13 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons } } +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + internal_configuration configuration = global_configuration; + configuration.case_sensitive = case_sensitive; + return compare(a, b, &configuration); +} + CJSON_PUBLIC(void *) cJSON_malloc(size_t size) { return global_configuration.allocate(size); From 98e0b586ca0f03135a5daee6ca10fa6f687bd2f5 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 1 Feb 2018 10:26:58 +0100 Subject: [PATCH 23/38] Add cJSON_Allocators new style allocator struct --- cJSON.c | 120 ++++++++++++++++++++++++++----------------- cJSON.h | 8 +++ tests/common.h | 4 +- tests/misc_tests.c | 6 ++- tests/parse_string.c | 2 +- 5 files changed, 89 insertions(+), 51 deletions(-) diff --git a/cJSON.c b/cJSON.c index 55beb0b1..008292b8 100644 --- a/cJSON.c +++ b/cJSON.c @@ -122,9 +122,10 @@ typedef struct internal_configuration cJSON_bool format; cJSON_bool allow_data_after_json; cJSON_bool case_sensitive; - void *(*allocate)(size_t size); - void (*deallocate)(void *pointer); - void *(*reallocate)(void *pointer, size_t size); + cJSON_Allocators allocators; + void *userdata; + + } internal_configuration; #if defined(_MSC_VER) @@ -137,24 +138,45 @@ static void internal_free(void *pointer) { free(pointer); } -static void *internal_realloc(void *pointer, size_t size) -{ - return realloc(pointer, size); -} #else #define internal_malloc malloc #define internal_free free -#define internal_realloc realloc #endif +/* old style allocators for cJSON_InitHooks */ +static cJSON_Hooks global_allocators = { + internal_malloc, + internal_free +}; + +/* wrappers around global old style allocators */ +static void *global_allocate_wrapper(size_t size, void *userdata) +{ + (void)userdata; + return global_allocators.malloc_fn(size); +} +static void *global_reallocate_wrapper(void *pointer, size_t size, void *userdata) +{ + (void)userdata; + return realloc(pointer, size); +} +static void global_deallocate_wrapper(void *pointer, void *userdata) +{ + (void)userdata; + global_allocators.free_fn(pointer); +} + #define default_configuration {\ 256, /* default buffer size */\ true, /* enable formatting by default */\ true, /* allow data after the JSON by default */\ true, /* case sensitive by default */\ - internal_malloc,\ - internal_free,\ - internal_realloc\ + {\ + global_allocate_wrapper,\ + global_deallocate_wrapper,\ + global_reallocate_wrapper\ + },\ + NULL /* no userdata */\ } static internal_configuration global_configuration = default_configuration; @@ -170,7 +192,7 @@ static unsigned char* custom_strdup(const unsigned char* string, const internal_ } length = strlen((const char*)string) + sizeof(""); - copy = (unsigned char*)configuration->allocate(length); + copy = (unsigned char*)configuration->allocators.allocate(length, configuration->userdata); if (copy == NULL) { return NULL; @@ -182,39 +204,45 @@ static unsigned char* custom_strdup(const unsigned char* string, const internal_ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) { + /* set the wrappers in the global configuration */ + global_configuration.userdata = NULL; + global_configuration.allocators.allocate = global_allocate_wrapper; + global_configuration.allocators.deallocate = global_deallocate_wrapper; + global_configuration.allocators.reallocate = global_reallocate_wrapper; + if (hooks == NULL) { - /* Reset hooks */ - global_configuration.allocate = malloc; - global_configuration.deallocate = free; - global_configuration.reallocate = realloc; + /* reset global allocators */ + global_allocators.malloc_fn = internal_malloc; + global_allocators.free_fn = internal_free; + return; } - global_configuration.allocate = malloc; + global_allocators.malloc_fn = internal_malloc; if (hooks->malloc_fn != NULL) { - global_configuration.allocate = hooks->malloc_fn; + global_allocators.malloc_fn = hooks->malloc_fn; } - global_configuration.deallocate = free; + global_allocators.free_fn = internal_free; if (hooks->free_fn != NULL) { - global_configuration.deallocate = hooks->free_fn; + global_allocators.free_fn = hooks->free_fn; } /* use realloc only if both free and malloc are used */ - global_configuration.reallocate = NULL; - if ((global_configuration.allocate == malloc) && (global_configuration.deallocate == free)) + global_configuration.allocators.reallocate = NULL; + if ((hooks->malloc_fn == malloc) && (hooks->free_fn == free)) { - global_configuration.reallocate = realloc; + global_configuration.allocators.reallocate = global_reallocate_wrapper; } } /* Internal constructor. */ static cJSON *create_item(const internal_configuration * const configuration) { - cJSON* node = (cJSON*)configuration->allocate(sizeof(cJSON)); + cJSON* node = (cJSON*)configuration->allocators.allocate(sizeof(cJSON), configuration->userdata); if (node) { memset(node, '\0', sizeof(cJSON)); @@ -236,13 +264,13 @@ static void delete_item(cJSON *item, const internal_configuration * const config } if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) { - configuration->deallocate(item->valuestring); + configuration->allocators.deallocate(item->valuestring, configuration->userdata); } if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { - configuration->deallocate(item->string); + configuration->allocators.deallocate(item->string, configuration->userdata); } - configuration->deallocate(item); + configuration->allocators.deallocate(item, configuration->userdata); item = next; } } @@ -427,13 +455,13 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) newsize = needed * 2; } - if (p->configuration.reallocate != NULL) + if (*p->configuration.allocators.reallocate != NULL) { /* reallocate with realloc if available */ - newbuffer = (unsigned char*)p->configuration.reallocate(p->buffer, newsize); + newbuffer = (unsigned char*)p->configuration.allocators.reallocate(p->buffer, newsize, p->configuration.userdata); if (newbuffer == NULL) { - p->configuration.deallocate(p->buffer); + p->configuration.allocators.deallocate(p->buffer, p->configuration.userdata); p->length = 0; p->buffer = NULL; @@ -443,10 +471,10 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) else { /* otherwise reallocate manually */ - newbuffer = (unsigned char*)p->configuration.allocate(newsize); + newbuffer = (unsigned char*)p->configuration.allocators.allocate(newsize, p->configuration.userdata); if (!newbuffer) { - p->configuration.deallocate(p->buffer); + p->configuration.allocators.deallocate(p->buffer, p->configuration.userdata); p->length = 0; p->buffer = NULL; @@ -456,7 +484,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) { memcpy(newbuffer, p->buffer, p->offset + 1); } - p->configuration.deallocate(p->buffer); + p->configuration.allocators.deallocate(p->buffer, p->configuration.userdata); } p->length = newsize; p->buffer = newbuffer; @@ -748,7 +776,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu /* This is at most how much we need for the output */ allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; - output = (unsigned char*)input_buffer->configuration.allocate(allocation_length + sizeof("")); + output = (unsigned char*)input_buffer->configuration.allocators.allocate(allocation_length + sizeof(""), input_buffer->configuration.userdata); if (output == NULL) { goto fail; /* allocation failure */ @@ -826,7 +854,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu fail: if (output != NULL) { - input_buffer->configuration.deallocate(output); + input_buffer->configuration.allocators.deallocate(output, input_buffer->configuration.userdata); } if (input_pointer != NULL) @@ -1117,7 +1145,7 @@ static unsigned char *print(const cJSON * const item, const internal_configurati memset(buffer, 0, sizeof(buffer)); /* create buffer */ - buffer->buffer = (unsigned char*) configuration->allocate(configuration->buffer_size); + buffer->buffer = (unsigned char*)configuration->allocators.allocate(configuration->buffer_size, configuration->userdata); buffer->length = configuration->buffer_size; buffer->configuration = *configuration; if (buffer->buffer == NULL) @@ -1135,9 +1163,9 @@ static unsigned char *print(const cJSON * const item, const internal_configurati /* 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 (configuration->reallocate != NULL) + if (configuration->allocators.reallocate != NULL) { - printed = (unsigned char*) configuration->reallocate(buffer->buffer, buffer->offset + 1); + printed = (unsigned char*)configuration->allocators.reallocate(buffer->buffer, buffer->offset + 1, configuration->userdata); buffer->buffer = NULL; if (printed == NULL) { goto fail; @@ -1145,7 +1173,7 @@ static unsigned char *print(const cJSON * const item, const internal_configurati } else /* otherwise copy the JSON over to a new buffer */ { - printed = (unsigned char*) configuration->allocate(buffer->offset + 1); + printed = (unsigned char*)configuration->allocators.allocate(buffer->offset + 1, configuration->userdata); if (printed == NULL) { goto fail; @@ -1154,7 +1182,7 @@ static unsigned char *print(const cJSON * const item, const internal_configurati printed[buffer->offset] = '\0'; /* just to be sure */ /* free the buffer */ - configuration->deallocate(buffer->buffer); + configuration->allocators.deallocate(buffer->buffer, configuration->userdata); } return printed; @@ -1162,12 +1190,12 @@ static unsigned char *print(const cJSON * const item, const internal_configurati fail: if (buffer->buffer != NULL) { - configuration->deallocate(buffer->buffer); + configuration->allocators.deallocate(buffer->buffer, configuration->userdata); } if (printed != NULL) { - configuration->deallocate(printed); + configuration->allocators.deallocate(printed, configuration->userdata); } return NULL; @@ -1203,7 +1231,7 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) { - printbuffer p = { 0, 0, 0, 0, 0, default_configuration}; + printbuffer p = { 0, 0, 0, 0, 0, default_configuration }; if ((length < 0) || (buffer == NULL)) { @@ -1971,7 +1999,7 @@ static cJSON_bool add_item_to_object(cJSON * const object, const char * const st if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { - configuration->deallocate(item->string); + configuration->allocators.deallocate(item->string, configuration->userdata); } item->string = new_key; @@ -2964,10 +2992,10 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons CJSON_PUBLIC(void *) cJSON_malloc(size_t size) { - return global_configuration.allocate(size); + return global_configuration.allocators.allocate(size, global_configuration.userdata); } CJSON_PUBLIC(void) cJSON_free(void *object) { - global_configuration.deallocate(object); + global_configuration.allocators.deallocate(object, global_configuration.userdata); } diff --git a/cJSON.h b/cJSON.h index 153bcf5e..36974ebd 100644 --- a/cJSON.h +++ b/cJSON.h @@ -78,6 +78,14 @@ typedef struct cJSON_Hooks void (*free_fn)(void *ptr); } cJSON_Hooks; +/* new style allocators with userdata (e.g. for pool allocators) */ +typedef struct cJSON_Allocators +{ + void *(*allocate)(size_t size, void *userdata); + void (*deallocate)(void *pointer, void *userdata); + void *(*reallocate)(void *pointer, size_t size, void *userdata); /* optional */ +} cJSON_Allocators; + typedef int cJSON_bool; #if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) diff --git a/tests/common.h b/tests/common.h index caf0e500..27c7587b 100644 --- a/tests/common.h +++ b/tests/common.h @@ -33,11 +33,11 @@ void reset(cJSON *item) { } if ((item->valuestring != NULL) && !(item->type & cJSON_IsReference)) { - global_configuration.deallocate(item->valuestring); + global_configuration.allocators.deallocate(item->valuestring, global_configuration.userdata); } if ((item->string != NULL) && !(item->type & cJSON_StringIsConst)) { - global_configuration.deallocate(item->string); + global_configuration.allocators.deallocate(item->string, global_configuration.userdata); } memset(item, 0, sizeof(cJSON)); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index b4893d54..18e3d336 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -409,16 +409,18 @@ static void cjson_functions_shouldnt_crash_with_null_pointers(void) cJSON_Delete(item); } -static void *failing_realloc(void *pointer, size_t size) +static void *failing_realloc(void *pointer, size_t size, void *userdata) { (void)size; (void)pointer; + (void)userdata; return NULL; } static void ensure_should_fail_on_failed_realloc(void) { - printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, &malloc, &free, &failing_realloc}}; + printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, {global_allocate_wrapper, global_deallocate_wrapper, failing_realloc}, NULL } }; + buffer.configuration.userdata = &buffer; buffer.buffer = (unsigned char*)malloc(100); TEST_ASSERT_NOT_NULL(buffer.buffer); diff --git a/tests/parse_string.c b/tests/parse_string.c index d22f7c81..39955e56 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -53,7 +53,7 @@ static void assert_parse_string(const char *string, const char *expected) TEST_ASSERT_TRUE_MESSAGE(parse_string(item, &buffer), "Couldn't parse string."); assert_is_string(item); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, item->valuestring, "The parsed result isn't as expected."); - global_configuration.deallocate(item->valuestring); + global_configuration.allocators.deallocate(item->valuestring, global_configuration.userdata); item->valuestring = NULL; } From 877fac0f9099ccda90a4ee40f04e46d9f6cefaed Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 1 Feb 2018 10:51:38 +0100 Subject: [PATCH 24/38] allocation helpers for allocating with a configuration --- cJSON.c | 58 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/cJSON.c b/cJSON.c index 008292b8..97e9141b 100644 --- a/cJSON.c +++ b/cJSON.c @@ -166,6 +166,20 @@ static void global_deallocate_wrapper(void *pointer, void *userdata) global_allocators.free_fn(pointer); } +/* helpers to allocate memory from a configuration */ +static void *allocate(const internal_configuration * const configuration, size_t size) +{ + return configuration->allocators.allocate(size, configuration->userdata); +} +static void *reallocate(const internal_configuration * const configuration, void *pointer, size_t size) +{ + return configuration->allocators.reallocate(pointer, size, configuration->userdata); +} +static void deallocate(const internal_configuration * const configuration, void *pointer) +{ + configuration->allocators.deallocate(pointer, configuration->userdata); +} + #define default_configuration {\ 256, /* default buffer size */\ true, /* enable formatting by default */\ @@ -192,7 +206,7 @@ static unsigned char* custom_strdup(const unsigned char* string, const internal_ } length = strlen((const char*)string) + sizeof(""); - copy = (unsigned char*)configuration->allocators.allocate(length, configuration->userdata); + copy = (unsigned char*)allocate(configuration, length); if (copy == NULL) { return NULL; @@ -242,7 +256,7 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) /* Internal constructor. */ static cJSON *create_item(const internal_configuration * const configuration) { - cJSON* node = (cJSON*)configuration->allocators.allocate(sizeof(cJSON), configuration->userdata); + cJSON* node = (cJSON*)allocate(configuration, sizeof(cJSON)); if (node) { memset(node, '\0', sizeof(cJSON)); @@ -264,13 +278,13 @@ static void delete_item(cJSON *item, const internal_configuration * const config } if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) { - configuration->allocators.deallocate(item->valuestring, configuration->userdata); + deallocate(configuration, item->valuestring); } if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { - configuration->allocators.deallocate(item->string, configuration->userdata); + deallocate(configuration, item->string); } - configuration->allocators.deallocate(item, configuration->userdata); + deallocate(configuration, item); item = next; } } @@ -455,13 +469,13 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) newsize = needed * 2; } - if (*p->configuration.allocators.reallocate != NULL) + if (p->configuration.allocators.reallocate != NULL) { /* reallocate with realloc if available */ - newbuffer = (unsigned char*)p->configuration.allocators.reallocate(p->buffer, newsize, p->configuration.userdata); + newbuffer = (unsigned char*)reallocate(&p->configuration, p->buffer, newsize); if (newbuffer == NULL) { - p->configuration.allocators.deallocate(p->buffer, p->configuration.userdata); + deallocate(&p->configuration, p->buffer); p->length = 0; p->buffer = NULL; @@ -471,10 +485,10 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) else { /* otherwise reallocate manually */ - newbuffer = (unsigned char*)p->configuration.allocators.allocate(newsize, p->configuration.userdata); + newbuffer = (unsigned char*)allocate(&p->configuration, newsize); if (!newbuffer) { - p->configuration.allocators.deallocate(p->buffer, p->configuration.userdata); + deallocate(&p->configuration, p->buffer); p->length = 0; p->buffer = NULL; @@ -484,7 +498,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) { memcpy(newbuffer, p->buffer, p->offset + 1); } - p->configuration.allocators.deallocate(p->buffer, p->configuration.userdata); + deallocate(&p->configuration, p->buffer); } p->length = newsize; p->buffer = newbuffer; @@ -776,7 +790,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu /* This is at most how much we need for the output */ allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; - output = (unsigned char*)input_buffer->configuration.allocators.allocate(allocation_length + sizeof(""), input_buffer->configuration.userdata); + output = (unsigned char*)allocate(&input_buffer->configuration, allocation_length + sizeof("")); if (output == NULL) { goto fail; /* allocation failure */ @@ -854,7 +868,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu fail: if (output != NULL) { - input_buffer->configuration.allocators.deallocate(output, input_buffer->configuration.userdata); + deallocate(&input_buffer->configuration, output); } if (input_pointer != NULL) @@ -1145,7 +1159,7 @@ static unsigned char *print(const cJSON * const item, const internal_configurati memset(buffer, 0, sizeof(buffer)); /* create buffer */ - buffer->buffer = (unsigned char*)configuration->allocators.allocate(configuration->buffer_size, configuration->userdata); + buffer->buffer = (unsigned char*)allocate(configuration, configuration->buffer_size); buffer->length = configuration->buffer_size; buffer->configuration = *configuration; if (buffer->buffer == NULL) @@ -1165,7 +1179,7 @@ static unsigned char *print(const cJSON * const item, const internal_configurati /* check if reallocate is available */ if (configuration->allocators.reallocate != NULL) { - printed = (unsigned char*)configuration->allocators.reallocate(buffer->buffer, buffer->offset + 1, configuration->userdata); + printed = (unsigned char*)reallocate(configuration, buffer->buffer, buffer->offset + 1); buffer->buffer = NULL; if (printed == NULL) { goto fail; @@ -1173,7 +1187,7 @@ static unsigned char *print(const cJSON * const item, const internal_configurati } else /* otherwise copy the JSON over to a new buffer */ { - printed = (unsigned char*)configuration->allocators.allocate(buffer->offset + 1, configuration->userdata); + printed = (unsigned char*)allocate(configuration, buffer->offset + 1); if (printed == NULL) { goto fail; @@ -1182,7 +1196,7 @@ static unsigned char *print(const cJSON * const item, const internal_configurati printed[buffer->offset] = '\0'; /* just to be sure */ /* free the buffer */ - configuration->allocators.deallocate(buffer->buffer, configuration->userdata); + deallocate(configuration, buffer->buffer); } return printed; @@ -1190,12 +1204,12 @@ static unsigned char *print(const cJSON * const item, const internal_configurati fail: if (buffer->buffer != NULL) { - configuration->allocators.deallocate(buffer->buffer, configuration->userdata); + deallocate(configuration, buffer->buffer); } if (printed != NULL) { - configuration->allocators.deallocate(printed, configuration->userdata); + deallocate(configuration, printed); } return NULL; @@ -1999,7 +2013,7 @@ static cJSON_bool add_item_to_object(cJSON * const object, const char * const st if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { - configuration->allocators.deallocate(item->string, configuration->userdata); + deallocate(configuration, item->string); } item->string = new_key; @@ -2992,10 +3006,10 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons CJSON_PUBLIC(void *) cJSON_malloc(size_t size) { - return global_configuration.allocators.allocate(size, global_configuration.userdata); + return global_allocators.malloc_fn(size); } CJSON_PUBLIC(void) cJSON_free(void *object) { - global_configuration.allocators.deallocate(object, global_configuration.userdata); + global_allocators.free_fn(object); } From 9d801d64eacdc900da8daa7527c5f2a663cd2b89 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 1 Feb 2018 22:13:39 +0100 Subject: [PATCH 25/38] cJSON_CreateConfiguration, cJSON_ConfigurationChange{Allocators,Userdata} --- cJSON.c | 136 +++++++++++++++++++++++++++++++++- cJSON.h | 42 ++++++++++- tests/CMakeLists.txt | 1 + tests/configuration_tests.c | 143 ++++++++++++++++++++++++++++++++++++ 4 files changed, 319 insertions(+), 3 deletions(-) create mode 100644 tests/configuration_tests.c diff --git a/cJSON.c b/cJSON.c index 97e9141b..6386cc44 100644 --- a/cJSON.c +++ b/cJSON.c @@ -60,6 +60,10 @@ #define true ((cJSON_bool)1) #define false ((cJSON_bool)0) +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t)-1) +#endif + typedef struct { const unsigned char *json; size_t position; @@ -124,8 +128,6 @@ typedef struct internal_configuration cJSON_bool case_sensitive; cJSON_Allocators allocators; void *userdata; - - } internal_configuration; #if defined(_MSC_VER) @@ -193,6 +195,9 @@ static void deallocate(const internal_configuration * const configuration, void NULL /* no userdata */\ } +/* this is necessary to assign the default configuration after initialization */ +static const internal_configuration global_default_configuration = default_configuration; + static internal_configuration global_configuration = default_configuration; static unsigned char* custom_strdup(const unsigned char* string, const internal_configuration * const configuration) @@ -2880,6 +2885,133 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) return (item->type & 0xFF) == cJSON_Raw; } +static size_t get_size_from_number(const cJSON * const number) +{ + if (number->valuedouble >= SIZE_MAX) + { + return SIZE_MAX; + } + + if (number->valuedouble <= 0) + { + return 0; + } + + return (size_t)number->valuedouble; +} + +CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON * const json, const cJSON_Allocators * const allocators, void *allocator_userdata) +{ + internal_configuration *configuration = NULL; + cJSON *option = NULL; + const cJSON_Allocators *local_allocators = &global_configuration.allocators; + + if (allocators != NULL) + { + if ((allocators->allocate == NULL) || (allocators->deallocate == NULL)) + { + goto fail; + } + + local_allocators = allocators; + } + + if ((json != NULL) && !cJSON_IsObject(json)) + { + goto fail; + } + + configuration = (internal_configuration*)local_allocators->allocate(sizeof(internal_configuration), allocator_userdata); + if (configuration == NULL) + { + goto fail; + } + + /* initialize with the default */ + *configuration = global_default_configuration; + configuration->userdata = allocator_userdata; + configuration->allocators = *local_allocators; + + if (json == NULL) + { + /* default configuration */ + return configuration; + } + + /* then overwrite with other options if they exist */ + + option = get_object_item(json, "buffer_size", &global_configuration); + if (cJSON_IsNumber(option)) + { + configuration->buffer_size = get_size_from_number(option); + } + + option = get_object_item(json, "format", &global_configuration); + if (cJSON_IsTrue(option)) + { + configuration->format = true; + } + else if (cJSON_IsFalse(option)) + { + configuration->format = false; + } + + option = get_object_item(json, "case_sensitive", &global_configuration); + if (cJSON_IsTrue(option)) + { + configuration->case_sensitive = true; + } + else if (cJSON_IsFalse(option)) + { + configuration->case_sensitive = false; + } + + option = get_object_item(json, "allow_data_after_json", &global_configuration); + if (cJSON_IsTrue(option)) + { + configuration->allow_data_after_json = true; + } + else if (cJSON_IsFalse(option)) + { + configuration->allow_data_after_json = false; + } + + return (cJSON_Configuration)configuration; + +fail: + if (configuration != NULL) + { + local_allocators->deallocate(configuration, allocator_userdata); + } + + return NULL; +} + +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllocators(cJSON_Configuration configuration, const cJSON_Allocators allocators) +{ + if ((configuration == NULL) || (allocators.allocate == NULL) || (allocators.deallocate == NULL)) + { + return NULL; + } + + ((internal_configuration*)configuration)->allocators = allocators; + ((internal_configuration*)configuration)->userdata = NULL; + + return configuration; +} + +/* Change the allocator userdata attached to a cJSON_Configuration */ +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeUserdata(cJSON_Configuration configuration, void *userdata) +{ + if (configuration == NULL) + { + return NULL; + } + + ((internal_configuration*)configuration)->userdata = userdata; + return configuration; +} + static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const internal_configuration * const configuration) { if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) diff --git a/cJSON.h b/cJSON.h index 36974ebd..8b434c4e 100644 --- a/cJSON.h +++ b/cJSON.h @@ -87,6 +87,7 @@ typedef struct cJSON_Allocators } cJSON_Allocators; typedef int cJSON_bool; +typedef void* cJSON_Configuration; #if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) #define __WINDOWS__ @@ -140,7 +141,46 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* returns the version of cJSON as a string */ CJSON_PUBLIC(const char*) cJSON_Version(void); -/* Supply malloc, realloc and free functions to cJSON */ +/* Create a configuration object that can be passed to several functions + * to configure their behavior. + * A configuration is given in JSON form (case sensitive) and can optionally contain any + * of the following options: + * - buffer_size: number of bytes that the printbuffer should be initially + * - format: boolean that indicates if the output should be formatted + * - case_sensitive: boolean that indicates if object keys should be considered case_sensitive + * - allow_data_after_json: boolean that indicates if parsing succeeds if the JSON in the + * input is followed by non JSON data + * + * + * If NULL is passed to a function that expects an object of type cJSON_Configuration, + * the following default configuration is used: + * { + * "buffer_size": 256, + * "format": true, + * "case_sensitive": true, + * "allow_data_after_json": true + * } + * + * A cJSON_Configuration object is dynamically allocated and you are responsible to free it + * after use. + * + * If allocators is a NULL pointer, the global default allocators are used (the one that is set + * by cJSON_InitHooks, malloc/free by default). + * The allocator is automatically attached to the configuration, so it will be used by functions + * that the configuration is passed to. This can be changed later with + * cJSON_ConfigurationChangeAllocator. + * + * allocator_userdata can be used to pass custom data to your allocator. It also gets attached to + * the configuration automatically. This can later be changed with + * cJSON_ConfigurationChangeUserdata. + * */ +CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON * const json, const cJSON_Allocators * const allocators, void *allocator_userdata); +/* Change the allocators of a cJSON_Configuration and reset the userdata */ +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllocators(cJSON_Configuration configuration, const cJSON_Allocators allocators); +/* Change the allocator userdata attached to a cJSON_Configuration */ +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeUserdata(cJSON_Configuration configuration, void *userdata); + +/* Supply malloc and free functions to cJSON globally */ 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. */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 79672927..14bdf34e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -57,6 +57,7 @@ if(ENABLE_CJSON_TEST) compare_tests cjson_add readme_examples + configuration_tests ) option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.") diff --git a/tests/configuration_tests.c b/tests/configuration_tests.c new file mode 100644 index 00000000..e4489a9b --- /dev/null +++ b/tests/configuration_tests.c @@ -0,0 +1,143 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include +#include + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" + +static void create_configuration_should_create_a_configuration(void) +{ + cJSON *json = NULL; + internal_configuration *configuration = NULL; + int userdata = 1; + + json = cJSON_Parse("{\"buffer_size\":1024,\"format\":false,\"case_sensitive\":false,\"allow_data_after_json\":false}"); + TEST_ASSERT_NOT_NULL(json); + configuration = (internal_configuration*)cJSON_CreateConfiguration(json, NULL, &userdata); + cJSON_Delete(json); + json = NULL; + TEST_ASSERT_NOT_NULL(configuration); + TEST_ASSERT_EQUAL_MESSAGE(configuration->buffer_size, 1024, "buffer_size has an incorrect value."); + TEST_ASSERT_FALSE_MESSAGE(configuration->format, "format has an incorrect value."); + TEST_ASSERT_FALSE_MESSAGE(configuration->case_sensitive, "case_sensitive has an incorrect value."); + TEST_ASSERT_FALSE_MESSAGE(configuration->allow_data_after_json, "allow_data_after_json has an incorrect value."); + TEST_ASSERT_TRUE_MESSAGE(configuration->userdata == &userdata, "Incorrect userdata"); + TEST_ASSERT_TRUE_MESSAGE(global_allocate_wrapper == configuration->allocators.allocate, "Wrong malloc."); + TEST_ASSERT_TRUE_MESSAGE(global_reallocate_wrapper == configuration->allocators.reallocate, "Wrong realloc."); + TEST_ASSERT_TRUE_MESSAGE(global_deallocate_wrapper == configuration->allocators.deallocate, "Wrong realloc."); + + free(configuration); +} + +static void create_configuration_should_work_with_an_empty_object(void) +{ + internal_configuration *configuration = NULL; + int userdata = 1; + + configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, &userdata); + TEST_ASSERT_NOT_NULL(configuration); + TEST_ASSERT_EQUAL_MESSAGE(configuration->buffer_size, 256, "buffer_size has an incorrect value."); + TEST_ASSERT_TRUE_MESSAGE(configuration->format, "format has an incorrect value."); + TEST_ASSERT_TRUE_MESSAGE(configuration->case_sensitive, "case_sensitive has an incorrect value."); + TEST_ASSERT_TRUE_MESSAGE(configuration->allow_data_after_json, "allow_data_after_json has an incorrect value."); + TEST_ASSERT_TRUE_MESSAGE(configuration->userdata == &userdata, "Incorrect userdata"); + TEST_ASSERT_TRUE_MESSAGE(global_allocate_wrapper == configuration->allocators.allocate, "Wrong malloc."); + TEST_ASSERT_TRUE_MESSAGE(global_reallocate_wrapper == configuration->allocators.reallocate, "Wrong realloc."); + TEST_ASSERT_TRUE_MESSAGE(global_deallocate_wrapper == configuration->allocators.deallocate, "Wrong free."); + + free(configuration); +} + +static void* custom_allocator(size_t size, void *userdata) +{ + *((size_t*)userdata) = size; + return malloc(size); +} +static void custom_deallocator(void *pointer, void *userdata) +{ + *((size_t*)userdata) = (size_t)pointer; + free(pointer); +} + +static void create_configuration_should_take_custom_allocators(void) +{ + internal_configuration *configuration = NULL; + cJSON_Allocators allocators = {custom_allocator, custom_deallocator, NULL}; + size_t userdata = 0; + + configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, &allocators, &userdata); + TEST_ASSERT_NOT_NULL(configuration); + TEST_ASSERT_EQUAL_MESSAGE(userdata, sizeof(internal_configuration), "custom allocator wasn't run properly."); + TEST_ASSERT_TRUE_MESSAGE(custom_allocator == configuration->allocators.allocate, "Wrong allocator."); + TEST_ASSERT_TRUE_MESSAGE(custom_deallocator == configuration->allocators.deallocate, "Wrong deallocator."); + TEST_ASSERT_NULL_MESSAGE(configuration->allocators.reallocate, "Reallocator is not null"); + + custom_deallocator(configuration, &userdata); +} + +static void configuration_change_allocators_should_change_allocators(void) +{ + internal_configuration *configuration = NULL; + cJSON_Allocators allocators = {custom_allocator, custom_deallocator, NULL}; + size_t userdata = 0; + + configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, &allocators, &userdata); + TEST_ASSERT_NOT_NULL(configuration); + + configuration = (internal_configuration*)cJSON_ConfigurationChangeAllocators(configuration, allocators); + TEST_ASSERT_NOT_NULL(configuration); + TEST_ASSERT_TRUE_MESSAGE(custom_allocator == configuration->allocators.allocate, "Wrong allocator."); + TEST_ASSERT_TRUE_MESSAGE(custom_deallocator == configuration->allocators.deallocate, "Wrong deallocator."); + TEST_ASSERT_NULL_MESSAGE(configuration->allocators.reallocate, "Reallocator is not null"); + + custom_deallocator(configuration, &userdata); +} + +static void configuration_change_userdata_should_change_userdata(void) +{ + internal_configuration *configuration = NULL; + size_t userdata = 0; + configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + TEST_ASSERT_NOT_NULL(configuration); + + configuration = (internal_configuration*)cJSON_ConfigurationChangeUserdata(configuration, &userdata); + TEST_ASSERT_TRUE_MESSAGE(configuration->userdata == &userdata, "Userdata is incorrect."); + + free(configuration); +} + +int main(void) +{ + UNITY_BEGIN(); + + RUN_TEST(create_configuration_should_create_a_configuration); + RUN_TEST(create_configuration_should_work_with_an_empty_object); + RUN_TEST(create_configuration_should_take_custom_allocators); + RUN_TEST(configuration_change_allocators_should_change_allocators); + RUN_TEST(configuration_change_userdata_should_change_userdata); + + return UNITY_END(); +} From 88c39fa2e44e30a47528f794057b25e59714b1f9 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 2 Feb 2018 00:57:00 +0100 Subject: [PATCH 26/38] cJSON_ConfigurationChangeParseEnd Add a pointer to an end position of parsing to the cJSON_Configuration object. (Essentially like return_parse_end, but as offset instead of pointer). --- cJSON.c | 33 ++++++++++++++++++++++++++------- cJSON.h | 2 ++ tests/configuration_tests.c | 15 +++++++++++++++ tests/misc_tests.c | 2 +- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/cJSON.c b/cJSON.c index 6386cc44..c199859f 100644 --- a/cJSON.c +++ b/cJSON.c @@ -128,6 +128,7 @@ typedef struct internal_configuration cJSON_bool case_sensitive; cJSON_Allocators allocators; void *userdata; + size_t *end_position; } internal_configuration; #if defined(_MSC_VER) @@ -192,7 +193,8 @@ static void deallocate(const internal_configuration * const configuration, void global_deallocate_wrapper,\ global_reallocate_wrapper\ },\ - NULL /* no userdata */\ + NULL, /* no userdata */\ + NULL /* no end position */\ } /* this is necessary to assign the default configuration after initialization */ @@ -1058,7 +1060,7 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) } /* Parse an object - create a new root, and populate. */ -static cJSON *parse(const char * const json, const internal_configuration * const configuration, size_t *end_position) +static cJSON *parse(const char * const json, const internal_configuration * const configuration) { parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; cJSON *item = NULL; @@ -1097,7 +1099,10 @@ static cJSON *parse(const char * const json, const internal_configuration * cons goto fail; } } - *end_position = buffer.offset; + if (configuration->end_position != NULL) + { + *configuration->end_position = buffer.offset; + } return item; @@ -1122,7 +1127,10 @@ static cJSON *parse(const char * const json, const internal_configuration * cons local_error.position = buffer.length - 1; } - *end_position = local_error.position; + if (configuration->end_position != NULL) + { + *configuration->end_position = local_error.position; + } global_error = local_error; } @@ -1137,7 +1145,8 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *json, const char **return_ cJSON *item = NULL; configuration.allow_data_after_json = !require_null_terminated; - item = parse(json, &configuration, &end_position); + configuration.end_position = &end_position; + item = parse(json, &configuration); if (return_parse_end != NULL) { @@ -1150,8 +1159,7 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *json, const char **return_ /* Default options for cJSON_Parse */ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *json) { - size_t end_position = 0; - return parse(json, &global_configuration, &end_position); + return parse(json, &global_configuration); } #define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) @@ -3012,6 +3020,17 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeUserdata(cJSON_Config return configuration; } +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeParseEnd(cJSON_Configuration configuration, size_t * const parse_end) +{ + if (configuration == NULL) + { + return NULL; + } + + ((internal_configuration*)configuration)->end_position = parse_end; + return configuration; +} + static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const internal_configuration * const configuration) { if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) diff --git a/cJSON.h b/cJSON.h index 8b434c4e..4e72df2f 100644 --- a/cJSON.h +++ b/cJSON.h @@ -179,6 +179,8 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON * const CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllocators(cJSON_Configuration configuration, const cJSON_Allocators allocators); /* Change the allocator userdata attached to a cJSON_Configuration */ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeUserdata(cJSON_Configuration configuration, void *userdata); +/* Change the pointer where the end of parsing is written to */ +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeParseEnd(cJSON_Configuration configuration, size_t * const parse_end); /* Supply malloc and free functions to cJSON globally */ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); diff --git a/tests/configuration_tests.c b/tests/configuration_tests.c index e4489a9b..4319ef65 100644 --- a/tests/configuration_tests.c +++ b/tests/configuration_tests.c @@ -129,6 +129,20 @@ static void configuration_change_userdata_should_change_userdata(void) free(configuration); } +static void configuration_change_parse_end_should_change_parse_end(void) +{ + size_t end_position = 0; + internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + TEST_ASSERT_NOT_NULL(configuration); + + configuration = (internal_configuration*)cJSON_ConfigurationChangeParseEnd(configuration, &end_position); + TEST_ASSERT_NOT_NULL(configuration); + + TEST_ASSERT_TRUE_MESSAGE(configuration->end_position == &end_position, "Failed to set parse end."); + + free(configuration); +} + int main(void) { UNITY_BEGIN(); @@ -138,6 +152,7 @@ int main(void) RUN_TEST(create_configuration_should_take_custom_allocators); RUN_TEST(configuration_change_allocators_should_change_allocators); RUN_TEST(configuration_change_userdata_should_change_userdata); + RUN_TEST(configuration_change_parse_end_should_change_parse_end); return UNITY_END(); } diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 18e3d336..64636391 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -419,7 +419,7 @@ static void *failing_realloc(void *pointer, size_t size, void *userdata) static void ensure_should_fail_on_failed_realloc(void) { - printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, {global_allocate_wrapper, global_deallocate_wrapper, failing_realloc}, NULL } }; + printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, {global_allocate_wrapper, global_deallocate_wrapper, failing_realloc}, NULL, NULL } }; buffer.configuration.userdata = &buffer; buffer.buffer = (unsigned char*)malloc(100); TEST_ASSERT_NOT_NULL(buffer.buffer); From 1a8f73274925d101a59499116510679ae1eab86e Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 02:09:10 +0100 Subject: [PATCH 27/38] cJSON_ConfigurationChangePrebufferSize --- cJSON.c | 36 +++++++++++------------------------- cJSON.h | 3 ++- tests/configuration_tests.c | 28 ++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/cJSON.c b/cJSON.c index c199859f..6920d867 100644 --- a/cJSON.c +++ b/cJSON.c @@ -60,10 +60,6 @@ #define true ((cJSON_bool)1) #define false ((cJSON_bool)0) -#ifndef SIZE_MAX -#define SIZE_MAX ((size_t)-1) -#endif - typedef struct { const unsigned char *json; size_t position; @@ -2893,21 +2889,6 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) return (item->type & 0xFF) == cJSON_Raw; } -static size_t get_size_from_number(const cJSON * const number) -{ - if (number->valuedouble >= SIZE_MAX) - { - return SIZE_MAX; - } - - if (number->valuedouble <= 0) - { - return 0; - } - - return (size_t)number->valuedouble; -} - CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON * const json, const cJSON_Allocators * const allocators, void *allocator_userdata) { internal_configuration *configuration = NULL; @@ -2948,12 +2929,6 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON * const /* then overwrite with other options if they exist */ - option = get_object_item(json, "buffer_size", &global_configuration); - if (cJSON_IsNumber(option)) - { - configuration->buffer_size = get_size_from_number(option); - } - option = get_object_item(json, "format", &global_configuration); if (cJSON_IsTrue(option)) { @@ -3031,6 +3006,17 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeParseEnd(cJSON_Config return configuration; } +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangePrebufferSize(cJSON_Configuration configuration, const size_t buffer_size) +{ + if ((configuration == NULL) || (buffer_size == 0)) + { + return NULL; + } + + ((internal_configuration*)configuration)->buffer_size = buffer_size; + return configuration; +} + static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const internal_configuration * const configuration) { if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) diff --git a/cJSON.h b/cJSON.h index 4e72df2f..321e44a0 100644 --- a/cJSON.h +++ b/cJSON.h @@ -155,7 +155,6 @@ CJSON_PUBLIC(const char*) cJSON_Version(void); * If NULL is passed to a function that expects an object of type cJSON_Configuration, * the following default configuration is used: * { - * "buffer_size": 256, * "format": true, * "case_sensitive": true, * "allow_data_after_json": true @@ -181,6 +180,8 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllocators(cJSON_Conf CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeUserdata(cJSON_Configuration configuration, void *userdata); /* Change the pointer where the end of parsing is written to */ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeParseEnd(cJSON_Configuration configuration, size_t * const parse_end); +/* Set how many bytes should be initially allocated for printing */ +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangePrebufferSize(cJSON_Configuration configuration, const size_t buffer_size); /* Supply malloc and free functions to cJSON globally */ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); diff --git a/tests/configuration_tests.c b/tests/configuration_tests.c index 4319ef65..19743d11 100644 --- a/tests/configuration_tests.c +++ b/tests/configuration_tests.c @@ -34,13 +34,13 @@ static void create_configuration_should_create_a_configuration(void) internal_configuration *configuration = NULL; int userdata = 1; - json = cJSON_Parse("{\"buffer_size\":1024,\"format\":false,\"case_sensitive\":false,\"allow_data_after_json\":false}"); + json = cJSON_Parse("{\"format\":false,\"case_sensitive\":false,\"allow_data_after_json\":false}"); TEST_ASSERT_NOT_NULL(json); configuration = (internal_configuration*)cJSON_CreateConfiguration(json, NULL, &userdata); cJSON_Delete(json); json = NULL; TEST_ASSERT_NOT_NULL(configuration); - TEST_ASSERT_EQUAL_MESSAGE(configuration->buffer_size, 1024, "buffer_size has an incorrect value."); + TEST_ASSERT_EQUAL_MESSAGE(configuration->buffer_size, 256, "buffer_size has an incorrect value."); TEST_ASSERT_FALSE_MESSAGE(configuration->format, "format has an incorrect value."); TEST_ASSERT_FALSE_MESSAGE(configuration->case_sensitive, "case_sensitive has an incorrect value."); TEST_ASSERT_FALSE_MESSAGE(configuration->allow_data_after_json, "allow_data_after_json has an incorrect value."); @@ -143,6 +143,28 @@ static void configuration_change_parse_end_should_change_parse_end(void) free(configuration); } +static void configuration_change_prebuffer_size_should_change_buffer_size(void) +{ + internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + TEST_ASSERT_NOT_NULL(configuration); + + configuration = (internal_configuration*)cJSON_ConfigurationChangePrebufferSize(configuration, 1024); + TEST_ASSERT_NOT_NULL(configuration); + + TEST_ASSERT_EQUAL_MESSAGE(configuration->buffer_size, 1024, "Didn't set the buffer size correctly."); + + free(configuration); +} + +static void configuration_change_prebuffer_size_should_not_allow_empty_sizes(void) +{ + internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + TEST_ASSERT_NOT_NULL(configuration); + + TEST_ASSERT_NULL(cJSON_ConfigurationChangePrebufferSize(configuration, 0)); + + free(configuration); +} int main(void) { UNITY_BEGIN(); @@ -153,6 +175,8 @@ int main(void) RUN_TEST(configuration_change_allocators_should_change_allocators); RUN_TEST(configuration_change_userdata_should_change_userdata); RUN_TEST(configuration_change_parse_end_should_change_parse_end); + RUN_TEST(configuration_change_prebuffer_size_should_change_buffer_size); + RUN_TEST(configuration_change_prebuffer_size_should_not_allow_empty_sizes); return UNITY_END(); } From 78b5bed9a023d83ca7ba56efcb9086d025f599f9 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 02:32:17 +0100 Subject: [PATCH 28/38] cJSON_ConfigurationChangeFormat --- cJSON.c | 34 ++++++++++++++++++++++++---------- cJSON.h | 3 +++ tests/configuration_tests.c | 24 ++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/cJSON.c b/cJSON.c index 6920d867..25f391f1 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2929,16 +2929,6 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON * const /* then overwrite with other options if they exist */ - option = get_object_item(json, "format", &global_configuration); - if (cJSON_IsTrue(option)) - { - configuration->format = true; - } - else if (cJSON_IsFalse(option)) - { - configuration->format = false; - } - option = get_object_item(json, "case_sensitive", &global_configuration); if (cJSON_IsTrue(option)) { @@ -3017,6 +3007,30 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangePrebufferSize(cJSON_C return configuration; } +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeFormat(cJSON_Configuration configuration, cJSON_Format format) +{ + if (configuration == NULL) + { + return NULL; + } + + switch (format) + { + case CJSON_FORMAT_MINIFIED: + ((internal_configuration*)configuration)->format = false; + break; + + case CJSON_FORMAT_DEFAULT: + ((internal_configuration*)configuration)->format = true; + break; + + default: + return NULL; + } + + return configuration; +} + static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const internal_configuration * const configuration) { if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) diff --git a/cJSON.h b/cJSON.h index 321e44a0..0f976b7c 100644 --- a/cJSON.h +++ b/cJSON.h @@ -182,6 +182,9 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeUserdata(cJSON_Config CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeParseEnd(cJSON_Configuration configuration, size_t * const parse_end); /* Set how many bytes should be initially allocated for printing */ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangePrebufferSize(cJSON_Configuration configuration, const size_t buffer_size); +typedef enum { CJSON_FORMAT_MINIFIED = 0, CJSON_FORMAT_DEFAULT = 1 } cJSON_Format; +/* Change the format for printing */ +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeFormat(cJSON_Configuration configuration, cJSON_Format format); /* Supply malloc and free functions to cJSON globally */ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); diff --git a/tests/configuration_tests.c b/tests/configuration_tests.c index 19743d11..3078132f 100644 --- a/tests/configuration_tests.c +++ b/tests/configuration_tests.c @@ -34,14 +34,14 @@ static void create_configuration_should_create_a_configuration(void) internal_configuration *configuration = NULL; int userdata = 1; - json = cJSON_Parse("{\"format\":false,\"case_sensitive\":false,\"allow_data_after_json\":false}"); + json = cJSON_Parse("{\"case_sensitive\":false,\"allow_data_after_json\":false}"); TEST_ASSERT_NOT_NULL(json); configuration = (internal_configuration*)cJSON_CreateConfiguration(json, NULL, &userdata); cJSON_Delete(json); json = NULL; TEST_ASSERT_NOT_NULL(configuration); TEST_ASSERT_EQUAL_MESSAGE(configuration->buffer_size, 256, "buffer_size has an incorrect value."); - TEST_ASSERT_FALSE_MESSAGE(configuration->format, "format has an incorrect value."); + TEST_ASSERT_TRUE_MESSAGE(configuration->format, "format has an incorrect value."); TEST_ASSERT_FALSE_MESSAGE(configuration->case_sensitive, "case_sensitive has an incorrect value."); TEST_ASSERT_FALSE_MESSAGE(configuration->allow_data_after_json, "allow_data_after_json has an incorrect value."); TEST_ASSERT_TRUE_MESSAGE(configuration->userdata == &userdata, "Incorrect userdata"); @@ -165,6 +165,25 @@ static void configuration_change_prebuffer_size_should_not_allow_empty_sizes(voi free(configuration); } + +static void configuration_change_format_should_change_format(void) +{ + internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + TEST_ASSERT_NOT_NULL(configuration); + + configuration = (internal_configuration*)cJSON_ConfigurationChangeFormat(configuration, CJSON_FORMAT_MINIFIED); + TEST_ASSERT_NOT_NULL(configuration); + TEST_ASSERT_FALSE_MESSAGE(configuration->format, "Failed to set CJSON_FORMAT_MINIFIED."); + + configuration = (internal_configuration*)cJSON_ConfigurationChangeFormat(configuration, CJSON_FORMAT_DEFAULT); + TEST_ASSERT_NOT_NULL(configuration); + TEST_ASSERT_TRUE_MESSAGE(configuration->format, "Failed to set CJSON_FORMAT_DEFAULT."); + + TEST_ASSERT_NULL_MESSAGE(cJSON_ConfigurationChangeFormat(configuration, (cJSON_Format)3), "Failed to detect invalid format."); + + free(configuration); +} + int main(void) { UNITY_BEGIN(); @@ -177,6 +196,7 @@ int main(void) RUN_TEST(configuration_change_parse_end_should_change_parse_end); RUN_TEST(configuration_change_prebuffer_size_should_change_buffer_size); RUN_TEST(configuration_change_prebuffer_size_should_not_allow_empty_sizes); + RUN_TEST(configuration_change_format_should_change_format); return UNITY_END(); } From eeaaaac63e6542623cd1f328fcb6f32d63ed6941 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 02:48:14 +0100 Subject: [PATCH 29/38] cJSON_ConfigurationChangeCaseSensitivity --- cJSON.c | 21 +++++++++++---------- cJSON.h | 2 ++ tests/configuration_tests.c | 18 ++++++++++++++++-- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/cJSON.c b/cJSON.c index 25f391f1..321e82ca 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2929,16 +2929,6 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON * const /* then overwrite with other options if they exist */ - option = get_object_item(json, "case_sensitive", &global_configuration); - if (cJSON_IsTrue(option)) - { - configuration->case_sensitive = true; - } - else if (cJSON_IsFalse(option)) - { - configuration->case_sensitive = false; - } - option = get_object_item(json, "allow_data_after_json", &global_configuration); if (cJSON_IsTrue(option)) { @@ -3031,6 +3021,17 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeFormat(cJSON_Configur return configuration; } +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeCaseSensitivity(cJSON_Configuration configuration, cJSON_bool case_sensitive) +{ + if (configuration == NULL) + { + return NULL; + } + + ((internal_configuration*)configuration)->case_sensitive = case_sensitive; + return configuration; +} + static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const internal_configuration * const configuration) { if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) diff --git a/cJSON.h b/cJSON.h index 0f976b7c..6ad17597 100644 --- a/cJSON.h +++ b/cJSON.h @@ -185,6 +185,8 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangePrebufferSize(cJSON_C typedef enum { CJSON_FORMAT_MINIFIED = 0, CJSON_FORMAT_DEFAULT = 1 } cJSON_Format; /* Change the format for printing */ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeFormat(cJSON_Configuration configuration, cJSON_Format format); +/* Change the case sensitivity */ +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeCaseSensitivity(cJSON_Configuration configuration, cJSON_bool case_sensitive); /* Supply malloc and free functions to cJSON globally */ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); diff --git a/tests/configuration_tests.c b/tests/configuration_tests.c index 3078132f..f2f4f3ec 100644 --- a/tests/configuration_tests.c +++ b/tests/configuration_tests.c @@ -34,7 +34,7 @@ static void create_configuration_should_create_a_configuration(void) internal_configuration *configuration = NULL; int userdata = 1; - json = cJSON_Parse("{\"case_sensitive\":false,\"allow_data_after_json\":false}"); + json = cJSON_Parse("{\"allow_data_after_json\":false}"); TEST_ASSERT_NOT_NULL(json); configuration = (internal_configuration*)cJSON_CreateConfiguration(json, NULL, &userdata); cJSON_Delete(json); @@ -42,7 +42,7 @@ static void create_configuration_should_create_a_configuration(void) TEST_ASSERT_NOT_NULL(configuration); TEST_ASSERT_EQUAL_MESSAGE(configuration->buffer_size, 256, "buffer_size has an incorrect value."); TEST_ASSERT_TRUE_MESSAGE(configuration->format, "format has an incorrect value."); - TEST_ASSERT_FALSE_MESSAGE(configuration->case_sensitive, "case_sensitive has an incorrect value."); + TEST_ASSERT_TRUE_MESSAGE(configuration->case_sensitive, "case_sensitive has an incorrect value."); TEST_ASSERT_FALSE_MESSAGE(configuration->allow_data_after_json, "allow_data_after_json has an incorrect value."); TEST_ASSERT_TRUE_MESSAGE(configuration->userdata == &userdata, "Incorrect userdata"); TEST_ASSERT_TRUE_MESSAGE(global_allocate_wrapper == configuration->allocators.allocate, "Wrong malloc."); @@ -184,6 +184,19 @@ static void configuration_change_format_should_change_format(void) free(configuration); } +static void configuration_change_case_sensitivity_should_change_case_sensitivity(void) +{ + internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + TEST_ASSERT_NOT_NULL(configuration); + + configuration = (internal_configuration*)cJSON_ConfigurationChangeCaseSensitivity(configuration, false); + TEST_ASSERT_NOT_NULL(configuration); + + TEST_ASSERT_FALSE_MESSAGE(configuration->case_sensitive, "Didn't set the case sensitivity correctly."); + + free(configuration); +} + int main(void) { UNITY_BEGIN(); @@ -197,6 +210,7 @@ int main(void) RUN_TEST(configuration_change_prebuffer_size_should_change_buffer_size); RUN_TEST(configuration_change_prebuffer_size_should_not_allow_empty_sizes); RUN_TEST(configuration_change_format_should_change_format); + RUN_TEST(configuration_change_case_sensitivity_should_change_case_sensitivity); return UNITY_END(); } From ae9dc3e7dbb13a7f5ce30f80ff6139d3cc733fad Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 02:55:06 +0100 Subject: [PATCH 30/38] cJSON_ConfigurationChangeAllowDataAfterJson --- cJSON.c | 24 +++++++++++------------- cJSON.h | 2 ++ tests/configuration_tests.c | 16 +++++++++++++++- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/cJSON.c b/cJSON.c index 321e82ca..a54d7f71 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2892,7 +2892,6 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON * const json, const cJSON_Allocators * const allocators, void *allocator_userdata) { internal_configuration *configuration = NULL; - cJSON *option = NULL; const cJSON_Allocators *local_allocators = &global_configuration.allocators; if (allocators != NULL) @@ -2927,18 +2926,6 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON * const return configuration; } - /* then overwrite with other options if they exist */ - - option = get_object_item(json, "allow_data_after_json", &global_configuration); - if (cJSON_IsTrue(option)) - { - configuration->allow_data_after_json = true; - } - else if (cJSON_IsFalse(option)) - { - configuration->allow_data_after_json = false; - } - return (cJSON_Configuration)configuration; fail: @@ -3032,6 +3019,17 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeCaseSensitivity(cJSON return configuration; } +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllowDataAfterJson(cJSON_Configuration configuration, cJSON_bool allow_data_after_json) +{ + if (configuration == NULL) + { + return NULL; + } + + ((internal_configuration*)configuration)->allow_data_after_json = allow_data_after_json; + return configuration; +} + static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const internal_configuration * const configuration) { if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) diff --git a/cJSON.h b/cJSON.h index 6ad17597..21a6a436 100644 --- a/cJSON.h +++ b/cJSON.h @@ -187,6 +187,8 @@ typedef enum { CJSON_FORMAT_MINIFIED = 0, CJSON_FORMAT_DEFAULT = 1 } cJSON_Forma CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeFormat(cJSON_Configuration configuration, cJSON_Format format); /* Change the case sensitivity */ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeCaseSensitivity(cJSON_Configuration configuration, cJSON_bool case_sensitive); +/* Change if data is allowed after the JSON */ +CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllowDataAfterJson(cJSON_Configuration configuration, cJSON_bool allow_data_after_json); /* Supply malloc and free functions to cJSON globally */ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); diff --git a/tests/configuration_tests.c b/tests/configuration_tests.c index f2f4f3ec..1587e8e3 100644 --- a/tests/configuration_tests.c +++ b/tests/configuration_tests.c @@ -43,7 +43,7 @@ static void create_configuration_should_create_a_configuration(void) TEST_ASSERT_EQUAL_MESSAGE(configuration->buffer_size, 256, "buffer_size has an incorrect value."); TEST_ASSERT_TRUE_MESSAGE(configuration->format, "format has an incorrect value."); TEST_ASSERT_TRUE_MESSAGE(configuration->case_sensitive, "case_sensitive has an incorrect value."); - TEST_ASSERT_FALSE_MESSAGE(configuration->allow_data_after_json, "allow_data_after_json has an incorrect value."); + TEST_ASSERT_TRUE_MESSAGE(configuration->allow_data_after_json, "allow_data_after_json has an incorrect value."); TEST_ASSERT_TRUE_MESSAGE(configuration->userdata == &userdata, "Incorrect userdata"); TEST_ASSERT_TRUE_MESSAGE(global_allocate_wrapper == configuration->allocators.allocate, "Wrong malloc."); TEST_ASSERT_TRUE_MESSAGE(global_reallocate_wrapper == configuration->allocators.reallocate, "Wrong realloc."); @@ -197,6 +197,19 @@ static void configuration_change_case_sensitivity_should_change_case_sensitivity free(configuration); } +static void configuration_change_allow_data_after_json_should_change_allow_data_after_json(void) +{ + internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + TEST_ASSERT_NOT_NULL(configuration); + + configuration = (internal_configuration*)cJSON_ConfigurationChangeAllowDataAfterJson(configuration, false); + TEST_ASSERT_NOT_NULL(configuration); + + TEST_ASSERT_FALSE_MESSAGE(configuration->allow_data_after_json, "Didn't set allow_data_after_json property correctly."); + + free(configuration); +} + int main(void) { UNITY_BEGIN(); @@ -211,6 +224,7 @@ int main(void) RUN_TEST(configuration_change_prebuffer_size_should_not_allow_empty_sizes); RUN_TEST(configuration_change_format_should_change_format); RUN_TEST(configuration_change_case_sensitivity_should_change_case_sensitivity); + RUN_TEST(configuration_change_allow_data_after_json_should_change_allow_data_after_json); return UNITY_END(); } From 691a83a479d5512c1067649f799a07b14870faf4 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 03:49:00 +0100 Subject: [PATCH 31/38] cJSON_CreateConfig: Don't allow configuration, always use default --- cJSON.c | 64 ++++++++++++--------------- cJSON.h | 34 +++------------ tests/configuration_tests.c | 87 +++++++++++++++++++------------------ tests/misc_tests.c | 2 +- 4 files changed, 80 insertions(+), 107 deletions(-) diff --git a/cJSON.c b/cJSON.c index a54d7f71..e73a487c 100644 --- a/cJSON.c +++ b/cJSON.c @@ -149,20 +149,32 @@ static cJSON_Hooks global_allocators = { }; /* wrappers around global old style allocators */ -static void *global_allocate_wrapper(size_t size, void *userdata) +static void *global_allocate(size_t size, void *userdata) { (void)userdata; return global_allocators.malloc_fn(size); } -static void *global_reallocate_wrapper(void *pointer, size_t size, void *userdata) +static void global_deallocate(void *pointer, void *userdata) +{ + (void)userdata; + free(pointer); +} + +/* wrappers around standard allocators */ +static void *malloc_wrapper(size_t size, void *userdata) +{ + (void)userdata; + return malloc(size); +} +static void *realloc_wrapper(void *pointer, size_t size, void *userdata) { (void)userdata; return realloc(pointer, size); } -static void global_deallocate_wrapper(void *pointer, void *userdata) +static void free_wrapper(void *pointer, void *userdata) { (void)userdata; - global_allocators.free_fn(pointer); + free(pointer); } /* helpers to allocate memory from a configuration */ @@ -185,9 +197,9 @@ static void deallocate(const internal_configuration * const configuration, void true, /* allow data after the JSON by default */\ true, /* case sensitive by default */\ {\ - global_allocate_wrapper,\ - global_deallocate_wrapper,\ - global_reallocate_wrapper\ + malloc_wrapper,\ + free_wrapper,\ + realloc_wrapper\ },\ NULL, /* no userdata */\ NULL /* no end position */\ @@ -221,17 +233,12 @@ static unsigned char* custom_strdup(const unsigned char* string, const internal_ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) { - /* set the wrappers in the global configuration */ - global_configuration.userdata = NULL; - global_configuration.allocators.allocate = global_allocate_wrapper; - global_configuration.allocators.deallocate = global_deallocate_wrapper; - global_configuration.allocators.reallocate = global_reallocate_wrapper; - if (hooks == NULL) { - /* reset global allocators */ - global_allocators.malloc_fn = internal_malloc; - global_allocators.free_fn = internal_free; + /* reset global configuration */ + global_configuration.allocators.allocate = malloc_wrapper; + global_configuration.allocators.deallocate = free_wrapper; + global_configuration.allocators.reallocate = realloc_wrapper; return; } @@ -248,12 +255,10 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) global_allocators.free_fn = hooks->free_fn; } - /* use realloc only if both free and malloc are used */ + /* set the wrappers in the global configuration */ + global_configuration.allocators.allocate = global_allocate; + global_configuration.allocators.deallocate = global_deallocate; global_configuration.allocators.reallocate = NULL; - if ((hooks->malloc_fn == malloc) && (hooks->free_fn == free)) - { - global_configuration.allocators.reallocate = global_reallocate_wrapper; - } } /* Internal constructor. */ @@ -2889,7 +2894,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) return (item->type & 0xFF) == cJSON_Raw; } -CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON * const json, const cJSON_Allocators * const allocators, void *allocator_userdata) +CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON_Allocators * const allocators, void *allocator_userdata) { internal_configuration *configuration = NULL; const cJSON_Allocators *local_allocators = &global_configuration.allocators; @@ -2898,17 +2903,12 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON * const { if ((allocators->allocate == NULL) || (allocators->deallocate == NULL)) { - goto fail; + return NULL; } local_allocators = allocators; } - if ((json != NULL) && !cJSON_IsObject(json)) - { - goto fail; - } - configuration = (internal_configuration*)local_allocators->allocate(sizeof(internal_configuration), allocator_userdata); if (configuration == NULL) { @@ -2917,14 +2917,6 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON * const /* initialize with the default */ *configuration = global_default_configuration; - configuration->userdata = allocator_userdata; - configuration->allocators = *local_allocators; - - if (json == NULL) - { - /* default configuration */ - return configuration; - } return (cJSON_Configuration)configuration; diff --git a/cJSON.h b/cJSON.h index 21a6a436..d423d1b7 100644 --- a/cJSON.h +++ b/cJSON.h @@ -141,39 +141,19 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* returns the version of cJSON as a string */ CJSON_PUBLIC(const char*) cJSON_Version(void); -/* Create a configuration object that can be passed to several functions - * to configure their behavior. - * A configuration is given in JSON form (case sensitive) and can optionally contain any - * of the following options: - * - buffer_size: number of bytes that the printbuffer should be initially - * - format: boolean that indicates if the output should be formatted - * - case_sensitive: boolean that indicates if object keys should be considered case_sensitive - * - allow_data_after_json: boolean that indicates if parsing succeeds if the JSON in the - * input is followed by non JSON data - * - * - * If NULL is passed to a function that expects an object of type cJSON_Configuration, - * the following default configuration is used: - * { - * "format": true, - * "case_sensitive": true, - * "allow_data_after_json": true - * } +/* + * Create a configuration object that can be passed to several functions + * to configure their behavior. It will be set to the default values initially, they + * can be changed later. * * A cJSON_Configuration object is dynamically allocated and you are responsible to free it * after use. * - * If allocators is a NULL pointer, the global default allocators are used (the one that is set - * by cJSON_InitHooks, malloc/free by default). - * The allocator is automatically attached to the configuration, so it will be used by functions - * that the configuration is passed to. This can be changed later with - * cJSON_ConfigurationChangeAllocator. + * If allocators is a NULL pointer, malloc and free are used. * - * allocator_userdata can be used to pass custom data to your allocator. It also gets attached to - * the configuration automatically. This can later be changed with - * cJSON_ConfigurationChangeUserdata. + * allocator_userdata can be used to pass custom data to your allocator (e.g. for pool allocators). * */ -CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON * const json, const cJSON_Allocators * const allocators, void *allocator_userdata); +CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON_Allocators * const allocators, void *allocator_userdata); /* Change the allocators of a cJSON_Configuration and reset the userdata */ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllocators(cJSON_Configuration configuration, const cJSON_Allocators allocators); /* Change the allocator userdata attached to a cJSON_Configuration */ diff --git a/tests/configuration_tests.c b/tests/configuration_tests.c index 1587e8e3..2afe7e6e 100644 --- a/tests/configuration_tests.c +++ b/tests/configuration_tests.c @@ -30,43 +30,18 @@ static void create_configuration_should_create_a_configuration(void) { - cJSON *json = NULL; internal_configuration *configuration = NULL; - int userdata = 1; - json = cJSON_Parse("{\"allow_data_after_json\":false}"); - TEST_ASSERT_NOT_NULL(json); - configuration = (internal_configuration*)cJSON_CreateConfiguration(json, NULL, &userdata); - cJSON_Delete(json); - json = NULL; + configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); TEST_ASSERT_NOT_NULL(configuration); TEST_ASSERT_EQUAL_MESSAGE(configuration->buffer_size, 256, "buffer_size has an incorrect value."); TEST_ASSERT_TRUE_MESSAGE(configuration->format, "format has an incorrect value."); TEST_ASSERT_TRUE_MESSAGE(configuration->case_sensitive, "case_sensitive has an incorrect value."); TEST_ASSERT_TRUE_MESSAGE(configuration->allow_data_after_json, "allow_data_after_json has an incorrect value."); - TEST_ASSERT_TRUE_MESSAGE(configuration->userdata == &userdata, "Incorrect userdata"); - TEST_ASSERT_TRUE_MESSAGE(global_allocate_wrapper == configuration->allocators.allocate, "Wrong malloc."); - TEST_ASSERT_TRUE_MESSAGE(global_reallocate_wrapper == configuration->allocators.reallocate, "Wrong realloc."); - TEST_ASSERT_TRUE_MESSAGE(global_deallocate_wrapper == configuration->allocators.deallocate, "Wrong realloc."); - - free(configuration); -} - -static void create_configuration_should_work_with_an_empty_object(void) -{ - internal_configuration *configuration = NULL; - int userdata = 1; - - configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, &userdata); - TEST_ASSERT_NOT_NULL(configuration); - TEST_ASSERT_EQUAL_MESSAGE(configuration->buffer_size, 256, "buffer_size has an incorrect value."); - TEST_ASSERT_TRUE_MESSAGE(configuration->format, "format has an incorrect value."); - TEST_ASSERT_TRUE_MESSAGE(configuration->case_sensitive, "case_sensitive has an incorrect value."); - TEST_ASSERT_TRUE_MESSAGE(configuration->allow_data_after_json, "allow_data_after_json has an incorrect value."); - TEST_ASSERT_TRUE_MESSAGE(configuration->userdata == &userdata, "Incorrect userdata"); - TEST_ASSERT_TRUE_MESSAGE(global_allocate_wrapper == configuration->allocators.allocate, "Wrong malloc."); - TEST_ASSERT_TRUE_MESSAGE(global_reallocate_wrapper == configuration->allocators.reallocate, "Wrong realloc."); - TEST_ASSERT_TRUE_MESSAGE(global_deallocate_wrapper == configuration->allocators.deallocate, "Wrong free."); + TEST_ASSERT_NULL_MESSAGE(configuration->userdata, "Userdata should be NULL"); + TEST_ASSERT_TRUE_MESSAGE(malloc_wrapper == configuration->allocators.allocate, "Wrong malloc."); + TEST_ASSERT_TRUE_MESSAGE(realloc_wrapper == configuration->allocators.reallocate, "Wrong realloc."); + TEST_ASSERT_TRUE_MESSAGE(free_wrapper == configuration->allocators.deallocate, "Wrong free."); free(configuration); } @@ -88,23 +63,33 @@ static void create_configuration_should_take_custom_allocators(void) cJSON_Allocators allocators = {custom_allocator, custom_deallocator, NULL}; size_t userdata = 0; - configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, &allocators, &userdata); + configuration = (internal_configuration*)cJSON_CreateConfiguration(&allocators, &userdata); TEST_ASSERT_NOT_NULL(configuration); TEST_ASSERT_EQUAL_MESSAGE(userdata, sizeof(internal_configuration), "custom allocator wasn't run properly."); - TEST_ASSERT_TRUE_MESSAGE(custom_allocator == configuration->allocators.allocate, "Wrong allocator."); - TEST_ASSERT_TRUE_MESSAGE(custom_deallocator == configuration->allocators.deallocate, "Wrong deallocator."); - TEST_ASSERT_NULL_MESSAGE(configuration->allocators.reallocate, "Reallocator is not null"); + TEST_ASSERT_TRUE_MESSAGE(global_default_configuration.allocators.allocate == configuration->allocators.allocate, "Wrong allocator."); + TEST_ASSERT_TRUE_MESSAGE(global_default_configuration.allocators.deallocate == configuration->allocators.deallocate, "Wrong deallocator."); + TEST_ASSERT_TRUE_MESSAGE(global_default_configuration.allocators.reallocate == configuration->allocators.reallocate, "Wrong reallocator."); custom_deallocator(configuration, &userdata); } +static void create_configuration_should_not_take_incomplete_allocators(void) +{ + cJSON_Allocators allocators1 = {custom_allocator, NULL, NULL}; + cJSON_Allocators allocators2 = {NULL, custom_deallocator, NULL}; + size_t userdata = 0; + + TEST_ASSERT_NULL(cJSON_CreateConfiguration(&allocators1, &userdata)); + TEST_ASSERT_NULL(cJSON_CreateConfiguration(&allocators2, &userdata)); +} + static void configuration_change_allocators_should_change_allocators(void) { internal_configuration *configuration = NULL; cJSON_Allocators allocators = {custom_allocator, custom_deallocator, NULL}; size_t userdata = 0; - configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, &allocators, &userdata); + configuration = (internal_configuration*)cJSON_CreateConfiguration(&allocators, &userdata); TEST_ASSERT_NOT_NULL(configuration); configuration = (internal_configuration*)cJSON_ConfigurationChangeAllocators(configuration, allocators); @@ -116,11 +101,26 @@ static void configuration_change_allocators_should_change_allocators(void) custom_deallocator(configuration, &userdata); } +static void configuration_change_allocators_should_not_change_incomplete_allocators(void) +{ + internal_configuration *configuration = NULL; + cJSON_Allocators allocators1 = {custom_allocator, NULL, NULL}; + cJSON_Allocators allocators2 = {NULL, custom_deallocator, NULL}; + + configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); + TEST_ASSERT_NOT_NULL(configuration); + + TEST_ASSERT_NULL(cJSON_ConfigurationChangeAllocators(configuration, allocators1)); + TEST_ASSERT_NULL(cJSON_ConfigurationChangeAllocators(configuration, allocators2)); + + free(configuration); +} + static void configuration_change_userdata_should_change_userdata(void) { internal_configuration *configuration = NULL; size_t userdata = 0; - configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); TEST_ASSERT_NOT_NULL(configuration); configuration = (internal_configuration*)cJSON_ConfigurationChangeUserdata(configuration, &userdata); @@ -132,7 +132,7 @@ static void configuration_change_userdata_should_change_userdata(void) static void configuration_change_parse_end_should_change_parse_end(void) { size_t end_position = 0; - internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); TEST_ASSERT_NOT_NULL(configuration); configuration = (internal_configuration*)cJSON_ConfigurationChangeParseEnd(configuration, &end_position); @@ -145,7 +145,7 @@ static void configuration_change_parse_end_should_change_parse_end(void) static void configuration_change_prebuffer_size_should_change_buffer_size(void) { - internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); TEST_ASSERT_NOT_NULL(configuration); configuration = (internal_configuration*)cJSON_ConfigurationChangePrebufferSize(configuration, 1024); @@ -158,7 +158,7 @@ static void configuration_change_prebuffer_size_should_change_buffer_size(void) static void configuration_change_prebuffer_size_should_not_allow_empty_sizes(void) { - internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); TEST_ASSERT_NOT_NULL(configuration); TEST_ASSERT_NULL(cJSON_ConfigurationChangePrebufferSize(configuration, 0)); @@ -168,7 +168,7 @@ static void configuration_change_prebuffer_size_should_not_allow_empty_sizes(voi static void configuration_change_format_should_change_format(void) { - internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); TEST_ASSERT_NOT_NULL(configuration); configuration = (internal_configuration*)cJSON_ConfigurationChangeFormat(configuration, CJSON_FORMAT_MINIFIED); @@ -186,7 +186,7 @@ static void configuration_change_format_should_change_format(void) static void configuration_change_case_sensitivity_should_change_case_sensitivity(void) { - internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); TEST_ASSERT_NOT_NULL(configuration); configuration = (internal_configuration*)cJSON_ConfigurationChangeCaseSensitivity(configuration, false); @@ -199,7 +199,7 @@ static void configuration_change_case_sensitivity_should_change_case_sensitivity static void configuration_change_allow_data_after_json_should_change_allow_data_after_json(void) { - internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL, NULL); + internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); TEST_ASSERT_NOT_NULL(configuration); configuration = (internal_configuration*)cJSON_ConfigurationChangeAllowDataAfterJson(configuration, false); @@ -215,9 +215,10 @@ int main(void) UNITY_BEGIN(); RUN_TEST(create_configuration_should_create_a_configuration); - RUN_TEST(create_configuration_should_work_with_an_empty_object); RUN_TEST(create_configuration_should_take_custom_allocators); + RUN_TEST(create_configuration_should_not_take_incomplete_allocators); RUN_TEST(configuration_change_allocators_should_change_allocators); + RUN_TEST(configuration_change_allocators_should_not_change_incomplete_allocators); RUN_TEST(configuration_change_userdata_should_change_userdata); RUN_TEST(configuration_change_parse_end_should_change_parse_end); RUN_TEST(configuration_change_prebuffer_size_should_change_buffer_size); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 64636391..10c0f92f 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -419,7 +419,7 @@ static void *failing_realloc(void *pointer, size_t size, void *userdata) static void ensure_should_fail_on_failed_realloc(void) { - printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, {global_allocate_wrapper, global_deallocate_wrapper, failing_realloc}, NULL, NULL } }; + printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, {malloc_wrapper, free_wrapper, failing_realloc}, NULL, NULL } }; buffer.configuration.userdata = &buffer; buffer.buffer = (unsigned char*)malloc(100); TEST_ASSERT_NOT_NULL(buffer.buffer); From d2d19127d3021a84e2fbe994b5591424a280c476 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 04:28:44 +0100 Subject: [PATCH 32/38] cJSON_ConfigurationChangeParseEnd -> cJSON_ConfigurationGetParseEnd This is probably a better approach than potentially having a pointer that points to garbage on the stack and gets written to by cJSON. --- cJSON.c | 28 ++++++++++------------------ cJSON.h | 4 ++-- tests/configuration_tests.c | 16 +++++----------- tests/misc_tests.c | 2 +- 4 files changed, 18 insertions(+), 32 deletions(-) diff --git a/cJSON.c b/cJSON.c index e73a487c..343620ca 100644 --- a/cJSON.c +++ b/cJSON.c @@ -124,7 +124,7 @@ typedef struct internal_configuration cJSON_bool case_sensitive; cJSON_Allocators allocators; void *userdata; - size_t *end_position; + size_t end_position; } internal_configuration; #if defined(_MSC_VER) @@ -202,7 +202,7 @@ static void deallocate(const internal_configuration * const configuration, void realloc_wrapper\ },\ NULL, /* no userdata */\ - NULL /* no end position */\ + 0 /* default end position */\ } /* this is necessary to assign the default configuration after initialization */ @@ -1061,7 +1061,7 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) } /* Parse an object - create a new root, and populate. */ -static cJSON *parse(const char * const json, const internal_configuration * const configuration) +static cJSON *parse(const char * const json, internal_configuration * const configuration) { parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; cJSON *item = NULL; @@ -1100,10 +1100,8 @@ static cJSON *parse(const char * const json, const internal_configuration * cons goto fail; } } - if (configuration->end_position != NULL) - { - *configuration->end_position = buffer.offset; - } + + configuration->end_position = buffer.offset; return item; @@ -1128,10 +1126,7 @@ static cJSON *parse(const char * const json, const internal_configuration * cons local_error.position = buffer.length - 1; } - if (configuration->end_position != NULL) - { - *configuration->end_position = local_error.position; - } + configuration->end_position = local_error.position; global_error = local_error; } @@ -1141,17 +1136,15 @@ static cJSON *parse(const char * const json, const internal_configuration * cons /* Parse an object - create a new root, and populate. */ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *json, const char **return_parse_end, cJSON_bool require_null_terminated) { - size_t end_position = 0; internal_configuration configuration = global_configuration; cJSON *item = NULL; configuration.allow_data_after_json = !require_null_terminated; - configuration.end_position = &end_position; item = parse(json, &configuration); if (return_parse_end != NULL) { - *return_parse_end = json + end_position; + *return_parse_end = json + configuration.end_position; } return item; @@ -2954,15 +2947,14 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeUserdata(cJSON_Config return configuration; } -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeParseEnd(cJSON_Configuration configuration, size_t * const parse_end) +CJSON_PUBLIC(size_t) cJSON_ConfigurationGetParseEnd(cJSON_Configuration configuration) { if (configuration == NULL) { - return NULL; + return 0; } - ((internal_configuration*)configuration)->end_position = parse_end; - return configuration; + return ((internal_configuration*)configuration)->end_position; } CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangePrebufferSize(cJSON_Configuration configuration, const size_t buffer_size) diff --git a/cJSON.h b/cJSON.h index d423d1b7..729c04a2 100644 --- a/cJSON.h +++ b/cJSON.h @@ -158,8 +158,8 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON_Allocato CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllocators(cJSON_Configuration configuration, const cJSON_Allocators allocators); /* Change the allocator userdata attached to a cJSON_Configuration */ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeUserdata(cJSON_Configuration configuration, void *userdata); -/* Change the pointer where the end of parsing is written to */ -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeParseEnd(cJSON_Configuration configuration, size_t * const parse_end); +/* Get the position relative to the JSON where the parser stopped, return 0 if invalid. */ +CJSON_PUBLIC(size_t) cJSON_ConfigurationGetParseEnd(cJSON_Configuration configuration); /* Set how many bytes should be initially allocated for printing */ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangePrebufferSize(cJSON_Configuration configuration, const size_t buffer_size); typedef enum { CJSON_FORMAT_MINIFIED = 0, CJSON_FORMAT_DEFAULT = 1 } cJSON_Format; diff --git a/tests/configuration_tests.c b/tests/configuration_tests.c index 2afe7e6e..99021368 100644 --- a/tests/configuration_tests.c +++ b/tests/configuration_tests.c @@ -129,18 +129,12 @@ static void configuration_change_userdata_should_change_userdata(void) free(configuration); } -static void configuration_change_parse_end_should_change_parse_end(void) +static void configuration_get_parse_end_should_get_the_parse_end(void) { - size_t end_position = 0; - internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); - TEST_ASSERT_NOT_NULL(configuration); - - configuration = (internal_configuration*)cJSON_ConfigurationChangeParseEnd(configuration, &end_position); - TEST_ASSERT_NOT_NULL(configuration); - - TEST_ASSERT_TRUE_MESSAGE(configuration->end_position == &end_position, "Failed to set parse end."); + internal_configuration configuration = global_default_configuration; + configuration.end_position = 42; - free(configuration); + TEST_ASSERT_EQUAL_MESSAGE(cJSON_ConfigurationGetParseEnd(&configuration), 42, "Failed to get parse end."); } static void configuration_change_prebuffer_size_should_change_buffer_size(void) @@ -220,7 +214,7 @@ int main(void) RUN_TEST(configuration_change_allocators_should_change_allocators); RUN_TEST(configuration_change_allocators_should_not_change_incomplete_allocators); RUN_TEST(configuration_change_userdata_should_change_userdata); - RUN_TEST(configuration_change_parse_end_should_change_parse_end); + RUN_TEST(configuration_get_parse_end_should_get_the_parse_end); RUN_TEST(configuration_change_prebuffer_size_should_change_buffer_size); RUN_TEST(configuration_change_prebuffer_size_should_not_allow_empty_sizes); RUN_TEST(configuration_change_format_should_change_format); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 10c0f92f..e70f0749 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -419,7 +419,7 @@ static void *failing_realloc(void *pointer, size_t size, void *userdata) static void ensure_should_fail_on_failed_realloc(void) { - printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, {malloc_wrapper, free_wrapper, failing_realloc}, NULL, NULL } }; + printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, {malloc_wrapper, free_wrapper, failing_realloc}, NULL, 0 } }; buffer.configuration.userdata = &buffer; buffer.buffer = (unsigned char*)malloc(100); TEST_ASSERT_NOT_NULL(buffer.buffer); From 050f982608f41f65eec2556f6a8093c9182cc206 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 05:02:05 +0100 Subject: [PATCH 33/38] cJSON_DuplicateConfiguration --- cJSON.c | 30 +++++++++++++--------------- cJSON.h | 2 ++ tests/configuration_tests.c | 39 +++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/cJSON.c b/cJSON.c index 343620ca..3c147a3e 100644 --- a/cJSON.c +++ b/cJSON.c @@ -206,7 +206,7 @@ static void deallocate(const internal_configuration * const configuration, void } /* this is necessary to assign the default configuration after initialization */ -static const internal_configuration global_default_configuration = default_configuration; +static internal_configuration global_default_configuration = default_configuration; static internal_configuration global_configuration = default_configuration; @@ -2887,10 +2887,10 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) return (item->type & 0xFF) == cJSON_Raw; } -CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON_Allocators * const allocators, void *allocator_userdata) +CJSON_PUBLIC(cJSON_Configuration) cJSON_DuplicateConfiguration(const cJSON_Configuration configuration, const cJSON_Allocators * const allocators, void *allocator_userdata) { - internal_configuration *configuration = NULL; - const cJSON_Allocators *local_allocators = &global_configuration.allocators; + internal_configuration *duplicate = NULL; + const cJSON_Allocators *local_allocators = &global_default_configuration.allocators; if (allocators != NULL) { @@ -2902,24 +2902,20 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON_Allocato local_allocators = allocators; } - configuration = (internal_configuration*)local_allocators->allocate(sizeof(internal_configuration), allocator_userdata); - if (configuration == NULL) + duplicate = (internal_configuration*)local_allocators->allocate(sizeof(internal_configuration), allocator_userdata); + if (duplicate == NULL) { - goto fail; + return NULL; } - /* initialize with the default */ - *configuration = global_default_configuration; - - return (cJSON_Configuration)configuration; + memcpy(duplicate, configuration, sizeof(internal_configuration)); -fail: - if (configuration != NULL) - { - local_allocators->deallocate(configuration, allocator_userdata); - } + return duplicate; +} - return NULL; +CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON_Allocators * const allocators, void *allocator_userdata) +{ + return cJSON_DuplicateConfiguration((cJSON_Configuration)&global_default_configuration, allocators, allocator_userdata); } CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllocators(cJSON_Configuration configuration, const cJSON_Allocators allocators) diff --git a/cJSON.h b/cJSON.h index 729c04a2..b7036a21 100644 --- a/cJSON.h +++ b/cJSON.h @@ -154,6 +154,8 @@ CJSON_PUBLIC(const char*) cJSON_Version(void); * allocator_userdata can be used to pass custom data to your allocator (e.g. for pool allocators). * */ CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON_Allocators * const allocators, void *allocator_userdata); +/* Create a copy of an existing configuration */ +CJSON_PUBLIC(cJSON_Configuration) cJSON_DuplicateConfiguration(const cJSON_Configuration, const cJSON_Allocators * const allocators, void *allocator_userdata); /* Change the allocators of a cJSON_Configuration and reset the userdata */ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllocators(cJSON_Configuration configuration, const cJSON_Allocators allocators); /* Change the allocator userdata attached to a cJSON_Configuration */ diff --git a/tests/configuration_tests.c b/tests/configuration_tests.c index 99021368..04d9a37f 100644 --- a/tests/configuration_tests.c +++ b/tests/configuration_tests.c @@ -83,6 +83,42 @@ static void create_configuration_should_not_take_incomplete_allocators(void) TEST_ASSERT_NULL(cJSON_CreateConfiguration(&allocators2, &userdata)); } +static void duplicate_configuration_should_duplicate_a_configuration(void) +{ + internal_configuration *configuration = NULL; + + configuration = (internal_configuration*)cJSON_DuplicateConfiguration(&global_configuration, NULL, NULL); + TEST_ASSERT_NOT_NULL(configuration); + + TEST_ASSERT_EQUAL_MEMORY(&global_configuration, configuration, sizeof(internal_configuration)); + + free(configuration); +} + +static void duplicate_configuration_should_take_custom_allocators(void) +{ + internal_configuration *configuration = NULL; + cJSON_Allocators allocators = {custom_allocator, custom_deallocator, NULL}; + size_t userdata = 0; + + configuration = (internal_configuration*)cJSON_DuplicateConfiguration(&global_configuration, &allocators, &userdata); + TEST_ASSERT_NOT_NULL(configuration); + TEST_ASSERT_EQUAL_MESSAGE(userdata, sizeof(internal_configuration), "custom allocator wasn't run properly"); + + TEST_ASSERT_EQUAL_MEMORY(&global_configuration, configuration, sizeof(internal_configuration)); + free(configuration); +} + +static void duplicate_configuration_should_not_take_incomplete_allocators(void) +{ + cJSON_Allocators allocators1 = {custom_allocator, NULL, NULL}; + cJSON_Allocators allocators2 = {NULL, custom_deallocator, NULL}; + size_t userdata = 0; + + TEST_ASSERT_NULL(cJSON_DuplicateConfiguration(&global_configuration, &allocators1, &userdata)); + TEST_ASSERT_NULL(cJSON_DuplicateConfiguration(&global_configuration, &allocators2, &userdata)); +} + static void configuration_change_allocators_should_change_allocators(void) { internal_configuration *configuration = NULL; @@ -211,6 +247,9 @@ int main(void) RUN_TEST(create_configuration_should_create_a_configuration); RUN_TEST(create_configuration_should_take_custom_allocators); RUN_TEST(create_configuration_should_not_take_incomplete_allocators); + RUN_TEST(duplicate_configuration_should_duplicate_a_configuration); + RUN_TEST(duplicate_configuration_should_take_custom_allocators); + RUN_TEST(duplicate_configuration_should_not_take_incomplete_allocators); RUN_TEST(configuration_change_allocators_should_change_allocators); RUN_TEST(configuration_change_allocators_should_not_change_incomplete_allocators); RUN_TEST(configuration_change_userdata_should_change_userdata); From 064eec8208952d61855a826670fb77c3b4b303a4 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 12:48:34 +0100 Subject: [PATCH 34/38] Change name from Configuration to Context --- cJSON.c | 412 ++++++++++++++++++------------------ cJSON.h | 37 ++-- tests/CMakeLists.txt | 2 +- tests/common.h | 4 +- tests/configuration_tests.c | 264 ----------------------- tests/context_tests.c | 264 +++++++++++++++++++++++ tests/misc_tests.c | 12 +- tests/parse_array.c | 8 +- tests/parse_number.c | 2 +- tests/parse_object.c | 8 +- tests/parse_string.c | 10 +- tests/parse_value.c | 4 +- tests/print_array.c | 16 +- tests/print_number.c | 4 +- tests/print_object.c | 16 +- tests/print_string.c | 4 +- tests/print_value.c | 10 +- 17 files changed, 540 insertions(+), 537 deletions(-) delete mode 100644 tests/configuration_tests.c create mode 100644 tests/context_tests.c diff --git a/cJSON.c b/cJSON.c index 3c147a3e..d3e4131e 100644 --- a/cJSON.c +++ b/cJSON.c @@ -116,7 +116,7 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned return tolower(*string1) - tolower(*string2); } -typedef struct internal_configuration +typedef struct internal_context { size_t buffer_size; cJSON_bool format; @@ -125,7 +125,7 @@ typedef struct internal_configuration cJSON_Allocators allocators; void *userdata; size_t end_position; -} internal_configuration; +} internal_context; #if defined(_MSC_VER) /* work around MSVC error C2322: '...' address of dillimport '...' is not static */ @@ -177,21 +177,21 @@ static void free_wrapper(void *pointer, void *userdata) free(pointer); } -/* helpers to allocate memory from a configuration */ -static void *allocate(const internal_configuration * const configuration, size_t size) +/* helpers to allocate memory with the allocators in a context */ +static void *allocate(const internal_context * const context, size_t size) { - return configuration->allocators.allocate(size, configuration->userdata); + return context->allocators.allocate(size, context->userdata); } -static void *reallocate(const internal_configuration * const configuration, void *pointer, size_t size) +static void *reallocate(const internal_context * const context, void *pointer, size_t size) { - return configuration->allocators.reallocate(pointer, size, configuration->userdata); + return context->allocators.reallocate(pointer, size, context->userdata); } -static void deallocate(const internal_configuration * const configuration, void *pointer) +static void deallocate(const internal_context * const context, void *pointer) { - configuration->allocators.deallocate(pointer, configuration->userdata); + context->allocators.deallocate(pointer, context->userdata); } -#define default_configuration {\ +#define default_context {\ 256, /* default buffer size */\ true, /* enable formatting by default */\ true, /* allow data after the JSON by default */\ @@ -205,12 +205,12 @@ static void deallocate(const internal_configuration * const configuration, void 0 /* default end position */\ } -/* this is necessary to assign the default configuration after initialization */ -static internal_configuration global_default_configuration = default_configuration; +/* this is necessary to assign the default context after initialization */ +static internal_context global_default_context = default_context; -static internal_configuration global_configuration = default_configuration; +static internal_context global_context = default_context; -static unsigned char* custom_strdup(const unsigned char* string, const internal_configuration * const configuration) +static unsigned char* custom_strdup(const unsigned char* string, const internal_context * const context) { size_t length = 0; unsigned char *copy = NULL; @@ -221,7 +221,7 @@ static unsigned char* custom_strdup(const unsigned char* string, const internal_ } length = strlen((const char*)string) + sizeof(""); - copy = (unsigned char*)allocate(configuration, length); + copy = (unsigned char*)allocate(context, length); if (copy == NULL) { return NULL; @@ -235,10 +235,10 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) { if (hooks == NULL) { - /* reset global configuration */ - global_configuration.allocators.allocate = malloc_wrapper; - global_configuration.allocators.deallocate = free_wrapper; - global_configuration.allocators.reallocate = realloc_wrapper; + /* reset global context */ + global_context.allocators.allocate = malloc_wrapper; + global_context.allocators.deallocate = free_wrapper; + global_context.allocators.reallocate = realloc_wrapper; return; } @@ -255,16 +255,16 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) global_allocators.free_fn = hooks->free_fn; } - /* set the wrappers in the global configuration */ - global_configuration.allocators.allocate = global_allocate; - global_configuration.allocators.deallocate = global_deallocate; - global_configuration.allocators.reallocate = NULL; + /* set the wrappers in the global context */ + global_context.allocators.allocate = global_allocate; + global_context.allocators.deallocate = global_deallocate; + global_context.allocators.reallocate = NULL; } /* Internal constructor. */ -static cJSON *create_item(const internal_configuration * const configuration) +static cJSON *create_item(const internal_context * const context) { - cJSON* node = (cJSON*)allocate(configuration, sizeof(cJSON)); + cJSON* node = (cJSON*)allocate(context, sizeof(cJSON)); if (node) { memset(node, '\0', sizeof(cJSON)); @@ -274,7 +274,7 @@ static cJSON *create_item(const internal_configuration * const configuration) } /* Delete a cJSON structure. */ -static void delete_item(cJSON *item, const internal_configuration * const configuration) +static void delete_item(cJSON *item, const internal_context * const context) { cJSON *next = NULL; while (item != NULL) @@ -282,17 +282,17 @@ static void delete_item(cJSON *item, const internal_configuration * const config next = item->next; if (!(item->type & cJSON_IsReference) && (item->child != NULL)) { - delete_item(item->child, configuration); + delete_item(item->child, context); } if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) { - deallocate(configuration, item->valuestring); + deallocate(context, item->valuestring); } if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { - deallocate(configuration, item->string); + deallocate(context, item->string); } - deallocate(configuration, item); + deallocate(context, item); item = next; } } @@ -300,7 +300,7 @@ static void delete_item(cJSON *item, const internal_configuration * const config /* Delete a cJSON structure. */ CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) { - delete_item(item, &global_configuration); + delete_item(item, &global_context); } static int double_to_saturated_integer(double number) @@ -334,7 +334,7 @@ typedef struct size_t length; size_t offset; size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ - internal_configuration configuration; + internal_context context; } parse_buffer; /* check if the given size is left to read in a given parse buffer (starting with 1) */ @@ -423,7 +423,7 @@ typedef struct size_t offset; size_t depth; /* current nesting depth (for formatted printing) */ cJSON_bool noalloc; - internal_configuration configuration; + internal_context context; } printbuffer; /* realloc printbuffer if necessary to have at least "needed" bytes more */ @@ -477,13 +477,13 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) newsize = needed * 2; } - if (p->configuration.allocators.reallocate != NULL) + if (p->context.allocators.reallocate != NULL) { /* reallocate with realloc if available */ - newbuffer = (unsigned char*)reallocate(&p->configuration, p->buffer, newsize); + newbuffer = (unsigned char*)reallocate(&p->context, p->buffer, newsize); if (newbuffer == NULL) { - deallocate(&p->configuration, p->buffer); + deallocate(&p->context, p->buffer); p->length = 0; p->buffer = NULL; @@ -493,10 +493,10 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) else { /* otherwise reallocate manually */ - newbuffer = (unsigned char*)allocate(&p->configuration, newsize); + newbuffer = (unsigned char*)allocate(&p->context, newsize); if (!newbuffer) { - deallocate(&p->configuration, p->buffer); + deallocate(&p->context, p->buffer); p->length = 0; p->buffer = NULL; @@ -506,7 +506,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) { memcpy(newbuffer, p->buffer, p->offset + 1); } - deallocate(&p->configuration, p->buffer); + deallocate(&p->context, p->buffer); } p->length = newsize; p->buffer = newbuffer; @@ -798,7 +798,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu /* This is at most how much we need for the output */ allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; - output = (unsigned char*)allocate(&input_buffer->configuration, allocation_length + sizeof("")); + output = (unsigned char*)allocate(&input_buffer->context, allocation_length + sizeof("")); if (output == NULL) { goto fail; /* allocation failure */ @@ -876,7 +876,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu fail: if (output != NULL) { - deallocate(&input_buffer->configuration, output); + deallocate(&input_buffer->context, output); } if (input_pointer != NULL) @@ -1061,9 +1061,9 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) } /* Parse an object - create a new root, and populate. */ -static cJSON *parse(const char * const json, internal_configuration * const configuration) +static cJSON *parse(const char * const json, internal_context * const context) { - parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; + parse_buffer buffer = { 0, 0, 0, 0, default_context }; cJSON *item = NULL; /* reset global error position */ @@ -1078,9 +1078,9 @@ static cJSON *parse(const char * const json, internal_configuration * const conf buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); buffer.offset = 0; - buffer.configuration = *configuration; + buffer.context = *context; - item = create_item(configuration); + item = create_item(context); if (item == NULL) { goto fail; @@ -1092,7 +1092,7 @@ static cJSON *parse(const char * const json, internal_configuration * const conf goto fail; } - if (!configuration->allow_data_after_json) + if (!context->allow_data_after_json) { buffer_skip_whitespace(&buffer); if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') @@ -1101,14 +1101,14 @@ static cJSON *parse(const char * const json, internal_configuration * const conf } } - configuration->end_position = buffer.offset; + context->end_position = buffer.offset; return item; fail: if (item != NULL) { - delete_item(item, configuration); + delete_item(item, context); } if (json != NULL) @@ -1126,7 +1126,7 @@ static cJSON *parse(const char * const json, internal_configuration * const conf local_error.position = buffer.length - 1; } - configuration->end_position = local_error.position; + context->end_position = local_error.position; global_error = local_error; } @@ -1136,15 +1136,15 @@ static cJSON *parse(const char * const json, internal_configuration * const conf /* Parse an object - create a new root, and populate. */ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *json, const char **return_parse_end, cJSON_bool require_null_terminated) { - internal_configuration configuration = global_configuration; + internal_context context = global_context; cJSON *item = NULL; - configuration.allow_data_after_json = !require_null_terminated; - item = parse(json, &configuration); + context.allow_data_after_json = !require_null_terminated; + item = parse(json, &context); if (return_parse_end != NULL) { - *return_parse_end = json + configuration.end_position; + *return_parse_end = json + context.end_position; } return item; @@ -1153,12 +1153,12 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *json, const char **return_ /* Default options for cJSON_Parse */ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *json) { - return parse(json, &global_configuration); + return parse(json, &global_context); } #define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) -static unsigned char *print(const cJSON * const item, const internal_configuration * const configuration) +static unsigned char *print(const cJSON * const item, const internal_context * const context) { printbuffer buffer[1]; unsigned char *printed = NULL; @@ -1166,9 +1166,9 @@ static unsigned char *print(const cJSON * const item, const internal_configurati memset(buffer, 0, sizeof(buffer)); /* create buffer */ - buffer->buffer = (unsigned char*)allocate(configuration, configuration->buffer_size); - buffer->length = configuration->buffer_size; - buffer->configuration = *configuration; + buffer->buffer = (unsigned char*)allocate(context, context->buffer_size); + buffer->length = context->buffer_size; + buffer->context = *context; if (buffer->buffer == NULL) { goto fail; @@ -1184,9 +1184,9 @@ static unsigned char *print(const cJSON * const item, const internal_configurati /* 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 (configuration->allocators.reallocate != NULL) + if (context->allocators.reallocate != NULL) { - printed = (unsigned char*)reallocate(configuration, buffer->buffer, buffer->offset + 1); + printed = (unsigned char*)reallocate(context, buffer->buffer, buffer->offset + 1); buffer->buffer = NULL; if (printed == NULL) { goto fail; @@ -1194,7 +1194,7 @@ static unsigned char *print(const cJSON * const item, const internal_configurati } else /* otherwise copy the JSON over to a new buffer */ { - printed = (unsigned char*)allocate(configuration, buffer->offset + 1); + printed = (unsigned char*)allocate(context, buffer->offset + 1); if (printed == NULL) { goto fail; @@ -1203,7 +1203,7 @@ static unsigned char *print(const cJSON * const item, const internal_configurati printed[buffer->offset] = '\0'; /* just to be sure */ /* free the buffer */ - deallocate(configuration, buffer->buffer); + deallocate(context, buffer->buffer); } return printed; @@ -1211,12 +1211,12 @@ static unsigned char *print(const cJSON * const item, const internal_configurati fail: if (buffer->buffer != NULL) { - deallocate(configuration, buffer->buffer); + deallocate(context, buffer->buffer); } if (printed != NULL) { - deallocate(configuration, printed); + deallocate(context, printed); } return NULL; @@ -1225,34 +1225,34 @@ static unsigned char *print(const cJSON * const item, const internal_configurati /* Render a cJSON item/entity/structure to text. */ CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) { - return (char*)print(item, &global_configuration); + return (char*)print(item, &global_context); } CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) { - internal_configuration configuration = global_configuration; - configuration.format = false; - return (char*)print(item, &configuration); + internal_context context = global_context; + context.format = false; + return (char*)print(item, &context); } CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool format) { - internal_configuration configuration = global_configuration; + internal_context context = global_context; if (prebuffer < 0) { return NULL; } - configuration.buffer_size = (size_t)prebuffer; - configuration.format = format; + context.buffer_size = (size_t)prebuffer; + context.format = format; - return (char*)print(item, &configuration); + return (char*)print(item, &context); } CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) { - printbuffer p = { 0, 0, 0, 0, 0, default_configuration }; + printbuffer p = { 0, 0, 0, 0, 0, default_context }; if ((length < 0) || (buffer == NULL)) { @@ -1263,8 +1263,8 @@ CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, cons p.length = (size_t)length; p.offset = 0; p.noalloc = true; - p.configuration = global_configuration; - p.configuration.format = format; + p.context = global_context; + p.context.format = format; return print_value(item, &p); } @@ -1461,7 +1461,7 @@ static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buf do { /* allocate next item */ - cJSON *new_item = create_item(&(input_buffer->configuration)); + cJSON *new_item = create_item(&(input_buffer->context)); if (new_item == NULL) { goto fail; /* allocation failure */ @@ -1510,7 +1510,7 @@ static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buf fail: if (head != NULL) { - delete_item(head, &input_buffer->configuration); + delete_item(head, &input_buffer->context); } return false; @@ -1549,14 +1549,14 @@ static cJSON_bool print_array(const cJSON * const item, printbuffer * const outp update_offset(output_buffer); if (current_element->next) { - length = (size_t) (output_buffer->configuration.format ? 2 : 1); + length = (size_t) (output_buffer->context.format ? 2 : 1); output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) { return false; } *output_pointer++ = ','; - if(output_buffer->configuration.format) + if(output_buffer->context.format) { *output_pointer++ = ' '; } @@ -1615,7 +1615,7 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu do { /* allocate next item */ - cJSON *new_item = create_item(&(input_buffer->configuration)); + cJSON *new_item = create_item(&(input_buffer->context)); if (new_item == NULL) { goto fail; /* allocation failure */ @@ -1681,7 +1681,7 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu fail: if (head != NULL) { - delete_item(head, &input_buffer->configuration); + delete_item(head, &input_buffer->context); } return false; @@ -1700,7 +1700,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out } /* Compose the output: */ - length = (size_t) (output_buffer->configuration.format ? 2 : 1); /* fmt: {\n */ + length = (size_t) (output_buffer->context.format ? 2 : 1); /* fmt: {\n */ output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) { @@ -1709,7 +1709,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out *output_pointer++ = '{'; output_buffer->depth++; - if (output_buffer->configuration.format) + if (output_buffer->context.format) { *output_pointer++ = '\n'; } @@ -1717,7 +1717,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out while (current_item) { - if (output_buffer->configuration.format) + if (output_buffer->context.format) { size_t i; output_pointer = ensure(output_buffer, output_buffer->depth); @@ -1739,14 +1739,14 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out } update_offset(output_buffer); - length = (size_t) (output_buffer->configuration.format ? 2 : 1); + length = (size_t) (output_buffer->context.format ? 2 : 1); output_pointer = ensure(output_buffer, length); if (output_pointer == NULL) { return false; } *output_pointer++ = ':'; - if (output_buffer->configuration.format) + if (output_buffer->context.format) { *output_pointer++ = '\t'; } @@ -1760,7 +1760,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->configuration.format ? 1 : 0) + (current_item->next ? 1 : 0)); + length = (size_t) ((output_buffer->context.format ? 1 : 0) + (current_item->next ? 1 : 0)); output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) { @@ -1771,7 +1771,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out *output_pointer++ = ','; } - if (output_buffer->configuration.format) + if (output_buffer->context.format) { *output_pointer++ = '\n'; } @@ -1781,12 +1781,12 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out current_item = current_item->next; } - output_pointer = ensure(output_buffer, output_buffer->configuration.format ? (output_buffer->depth + 1) : 2); + output_pointer = ensure(output_buffer, output_buffer->context.format ? (output_buffer->depth + 1) : 2); if (output_pointer == NULL) { return false; } - if (output_buffer->configuration.format) + if (output_buffer->context.format) { size_t i; for (i = 0; i < (output_buffer->depth - 1); i++) @@ -1865,7 +1865,7 @@ CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) return get_array_item(array, (size_t)index); } -static cJSON *get_object_item(const cJSON * const object, const char * const name, const internal_configuration * const configuration) +static cJSON *get_object_item(const cJSON * const object, const char * const name, const internal_context * const context) { cJSON *current_element = NULL; @@ -1875,7 +1875,7 @@ static cJSON *get_object_item(const cJSON * const object, const char * const nam } current_element = object->child; - if (configuration->case_sensitive) + if (context->case_sensitive) { while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) { @@ -1895,16 +1895,16 @@ static cJSON *get_object_item(const cJSON * const object, const char * const nam CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) { - internal_configuration configuration = default_configuration; - configuration.case_sensitive = false; - return get_object_item(object, string, &configuration); + internal_context context = default_context; + context.case_sensitive = false; + return get_object_item(object, string, &context); } CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) { - internal_configuration configuration = default_configuration; - configuration.case_sensitive = true; - return get_object_item(object, string, &configuration); + internal_context context = default_context; + context.case_sensitive = true; + return get_object_item(object, string, &context); } CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) @@ -1920,7 +1920,7 @@ static void suffix_object(cJSON *prev, cJSON *item) } /* Utility for handling references. */ -static cJSON *create_reference(const cJSON *item, const internal_configuration * const configuration) +static cJSON *create_reference(const cJSON *item, const internal_context * const context) { cJSON *reference = NULL; if (item == NULL) @@ -1928,7 +1928,7 @@ static cJSON *create_reference(const cJSON *item, const internal_configuration * return NULL; } - reference = create_item(configuration); + reference = create_item(context); if (reference == NULL) { return NULL; @@ -1992,7 +1992,7 @@ static void* cast_away_const(const void* string) #endif -static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_configuration * const configuration, const cJSON_bool constant_key) +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_context * const context, const cJSON_bool constant_key) { char *new_key = NULL; int new_type = cJSON_Invalid; @@ -2009,7 +2009,7 @@ static cJSON_bool add_item_to_object(cJSON * const object, const char * const st } else { - new_key = (char*)custom_strdup((const unsigned char*)string, configuration); + new_key = (char*)custom_strdup((const unsigned char*)string, context); if (new_key == NULL) { return false; @@ -2020,7 +2020,7 @@ static cJSON_bool add_item_to_object(cJSON * const object, const char * const st if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { - deallocate(configuration, item->string); + deallocate(context, item->string); } item->string = new_key; @@ -2031,13 +2031,13 @@ static cJSON_bool add_item_to_object(cJSON * const object, const char * const st CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) { - add_item_to_object(object, string, item, &global_configuration, false); + add_item_to_object(object, string, item, &global_context, false); } /* Add an item to an object with constant string as key */ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) { - add_item_to_object(object, string, item, &global_configuration, true); + add_item_to_object(object, string, item, &global_context, true); } CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) @@ -2047,7 +2047,7 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) return; } - add_item_to_array(array, create_reference(item, &global_configuration)); + add_item_to_array(array, create_reference(item, &global_context)); } CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) @@ -2057,114 +2057,114 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *str return; } - add_item_to_object(object, string, create_reference(item, &global_configuration), &global_configuration, false); + add_item_to_object(object, string, create_reference(item, &global_context), &global_context, false); } CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) { cJSON *null = cJSON_CreateNull(); - if (add_item_to_object(object, name, null, &global_configuration, false)) + if (add_item_to_object(object, name, null, &global_context, false)) { return null; } - delete_item(null, &global_configuration); + delete_item(null, &global_context); return NULL; } CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) { cJSON *true_item = cJSON_CreateTrue(); - if (add_item_to_object(object, name, true_item, &global_configuration, false)) + if (add_item_to_object(object, name, true_item, &global_context, false)) { return true_item; } - delete_item(true_item, &global_configuration); + delete_item(true_item, &global_context); return NULL; } CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) { cJSON *false_item = cJSON_CreateFalse(); - if (add_item_to_object(object, name, false_item, &global_configuration, false)) + if (add_item_to_object(object, name, false_item, &global_context, false)) { return false_item; } - delete_item(false_item, &global_configuration); + delete_item(false_item, &global_context); return NULL; } CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) { cJSON *bool_item = cJSON_CreateBool(boolean); - if (add_item_to_object(object, name, bool_item, &global_configuration, false)) + if (add_item_to_object(object, name, bool_item, &global_context, false)) { return bool_item; } - delete_item(bool_item, &global_configuration); + delete_item(bool_item, &global_context); return NULL; } CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) { cJSON *number_item = cJSON_CreateNumber(number); - if (add_item_to_object(object, name, number_item, &global_configuration, false)) + if (add_item_to_object(object, name, number_item, &global_context, false)) { return number_item; } - delete_item(number_item, &global_configuration); + delete_item(number_item, &global_context); return NULL; } CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) { cJSON *string_item = cJSON_CreateString(string); - if (add_item_to_object(object, name, string_item, &global_configuration, false)) + if (add_item_to_object(object, name, string_item, &global_context, false)) { return string_item; } - delete_item(string_item, &global_configuration); + delete_item(string_item, &global_context); return NULL; } CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) { cJSON *raw_item = cJSON_CreateRaw(raw); - if (add_item_to_object(object, name, raw_item, &global_configuration, false)) + if (add_item_to_object(object, name, raw_item, &global_context, false)) { return raw_item; } - delete_item(raw_item, &global_configuration); + delete_item(raw_item, &global_context); return NULL; } CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) { cJSON *object_item = cJSON_CreateObject(); - if (add_item_to_object(object, name, object_item, &global_configuration, false)) + if (add_item_to_object(object, name, object_item, &global_context, false)) { return object_item; } - delete_item(object_item, &global_configuration); + delete_item(object_item, &global_context); return NULL; } CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) { cJSON *array = cJSON_CreateArray(); - if (add_item_to_object(object, name, array, &global_configuration, false)) + if (add_item_to_object(object, name, array, &global_context, false)) { return array; } - delete_item(array, &global_configuration); + delete_item(array, &global_context); return NULL; } @@ -2210,7 +2210,7 @@ CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) { - delete_item(cJSON_DetachItemFromArray(array, which), &global_configuration); + delete_item(cJSON_DetachItemFromArray(array, which), &global_context); } CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) @@ -2229,12 +2229,12 @@ CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, con CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) { - delete_item(cJSON_DetachItemFromObject(object, string), &global_configuration); + delete_item(cJSON_DetachItemFromObject(object, string), &global_context); } CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) { - delete_item(cJSON_DetachItemFromObjectCaseSensitive(object, string), &global_configuration); + delete_item(cJSON_DetachItemFromObjectCaseSensitive(object, string), &global_context); } /* Replace array/object items with new ones. */ @@ -2297,7 +2297,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON item->next = NULL; item->prev = NULL; - delete_item(item, &global_configuration); + delete_item(item, &global_context); return true; } @@ -2312,7 +2312,7 @@ CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newi cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); } -static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, const internal_configuration * const configuration) +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, const internal_context * const context) { if ((replacement == NULL) || (string == NULL)) { @@ -2324,32 +2324,32 @@ static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSO { cJSON_free(replacement->string); } - replacement->string = (char*)custom_strdup((const unsigned char*)string, &global_configuration); + replacement->string = (char*)custom_strdup((const unsigned char*)string, &global_context); replacement->type &= ~cJSON_StringIsConst; - cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, configuration), replacement); + cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, context), replacement); return true; } CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) { - internal_configuration configuration = global_configuration; - configuration.case_sensitive = false; - replace_item_in_object(object, string, newitem, &configuration); + internal_context context = global_context; + context.case_sensitive = false; + replace_item_in_object(object, string, newitem, &context); } CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) { - internal_configuration configuration = global_configuration; - configuration.case_sensitive = true; - replace_item_in_object(object, string, newitem, &configuration); + internal_context context = global_context; + context.case_sensitive = true; + replace_item_in_object(object, string, newitem, &context); } /* Create basic types: */ CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) { - cJSON *item = create_item(&global_configuration); + cJSON *item = create_item(&global_context); if(item) { item->type = cJSON_NULL; @@ -2360,7 +2360,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) { - cJSON *item = create_item(&global_configuration); + cJSON *item = create_item(&global_context); if(item) { item->type = cJSON_True; @@ -2371,7 +2371,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) { - cJSON *item = create_item(&global_configuration); + cJSON *item = create_item(&global_context); if(item) { item->type = cJSON_False; @@ -2382,7 +2382,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) { - cJSON *item = create_item(&global_configuration); + cJSON *item = create_item(&global_context); if(item) { item->type = boolean ? cJSON_True : cJSON_False; @@ -2393,7 +2393,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) { - cJSON *item = create_item(&global_configuration); + cJSON *item = create_item(&global_context); if(item) { item->type = cJSON_Number; @@ -2406,14 +2406,14 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) { - cJSON *item = create_item(&global_configuration); + cJSON *item = create_item(&global_context); if(item) { item->type = cJSON_String; - item->valuestring = (char*)custom_strdup((const unsigned char*)string, &global_configuration); + item->valuestring = (char*)custom_strdup((const unsigned char*)string, &global_context); if(!item->valuestring) { - delete_item(item, &global_configuration); + delete_item(item, &global_context); return NULL; } } @@ -2423,7 +2423,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) { - cJSON *item = create_item(&global_configuration); + cJSON *item = create_item(&global_context); if (item != NULL) { item->type = cJSON_String | cJSON_IsReference; @@ -2435,7 +2435,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) { - cJSON *item = create_item(&global_configuration); + cJSON *item = create_item(&global_context); if (item != NULL) { item->type = cJSON_Object | cJSON_IsReference; item->child = (cJSON*)cast_away_const(child); @@ -2445,7 +2445,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) } CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { - cJSON *item = create_item(&global_configuration); + cJSON *item = create_item(&global_context); if (item != NULL) { item->type = cJSON_Array | cJSON_IsReference; item->child = (cJSON*)cast_away_const(child); @@ -2456,14 +2456,14 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) { - cJSON *item = create_item(&global_configuration); + cJSON *item = create_item(&global_context); if(item) { item->type = cJSON_Raw; - item->valuestring = (char*)custom_strdup((const unsigned char*)raw, &global_configuration); + item->valuestring = (char*)custom_strdup((const unsigned char*)raw, &global_context); if(!item->valuestring) { - delete_item(item, &global_configuration); + delete_item(item, &global_context); return NULL; } } @@ -2473,7 +2473,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) { - cJSON *item = create_item(&global_configuration); + cJSON *item = create_item(&global_context); if(item) { item->type=cJSON_Array; @@ -2484,7 +2484,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) { - cJSON *item = create_item(&global_configuration); + cJSON *item = create_item(&global_context); if (item) { item->type = cJSON_Object; @@ -2512,7 +2512,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) n = cJSON_CreateNumber(numbers[i]); if (!n) { - delete_item(a, &global_configuration); + delete_item(a, &global_context); return NULL; } if(!i) @@ -2548,7 +2548,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) n = cJSON_CreateNumber((double)numbers[i]); if(!n) { - delete_item(a, &global_configuration); + delete_item(a, &global_context); return NULL; } if(!i) @@ -2584,7 +2584,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) n = cJSON_CreateNumber(numbers[i]); if(!n) { - delete_item(a, &global_configuration); + delete_item(a, &global_context); return NULL; } if(!i) @@ -2620,7 +2620,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) n = cJSON_CreateString(strings[i]); if(!n) { - delete_item(a, &global_configuration); + delete_item(a, &global_context); return NULL; } if(!i) @@ -2651,7 +2651,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) goto fail; } /* Create new item */ - newitem = create_item(&global_configuration); + newitem = create_item(&global_context); if (!newitem) { goto fail; @@ -2662,7 +2662,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) newitem->valuedouble = item->valuedouble; if (item->valuestring) { - newitem->valuestring = (char*)custom_strdup((unsigned char*)item->valuestring, &global_configuration); + newitem->valuestring = (char*)custom_strdup((unsigned char*)item->valuestring, &global_context); if (!newitem->valuestring) { goto fail; @@ -2670,7 +2670,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) } if (item->string) { - newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)custom_strdup((unsigned char*)item->string, &global_configuration); + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)custom_strdup((unsigned char*)item->string, &global_context); if (!newitem->string) { goto fail; @@ -2711,7 +2711,7 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) fail: if (newitem != NULL) { - delete_item(newitem, &global_configuration); + delete_item(newitem, &global_context); } return NULL; @@ -2887,10 +2887,10 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) return (item->type & 0xFF) == cJSON_Raw; } -CJSON_PUBLIC(cJSON_Configuration) cJSON_DuplicateConfiguration(const cJSON_Configuration configuration, const cJSON_Allocators * const allocators, void *allocator_userdata) +CJSON_PUBLIC(cJSON_Context) cJSON_DuplicateContext(const cJSON_Context context, const cJSON_Allocators * const allocators, void *allocator_userdata) { - internal_configuration *duplicate = NULL; - const cJSON_Allocators *local_allocators = &global_default_configuration.allocators; + internal_context *duplicate = NULL; + const cJSON_Allocators *local_allocators = &global_default_context.allocators; if (allocators != NULL) { @@ -2902,71 +2902,71 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_DuplicateConfiguration(const cJSON_Confi local_allocators = allocators; } - duplicate = (internal_configuration*)local_allocators->allocate(sizeof(internal_configuration), allocator_userdata); + duplicate = (internal_context*)local_allocators->allocate(sizeof(internal_context), allocator_userdata); if (duplicate == NULL) { return NULL; } - memcpy(duplicate, configuration, sizeof(internal_configuration)); + memcpy(duplicate, context, sizeof(internal_context)); return duplicate; } -CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON_Allocators * const allocators, void *allocator_userdata) +CJSON_PUBLIC(cJSON_Context) cJSON_CreateContext(const cJSON_Allocators * const allocators, void *allocator_userdata) { - return cJSON_DuplicateConfiguration((cJSON_Configuration)&global_default_configuration, allocators, allocator_userdata); + return cJSON_DuplicateContext((cJSON_Context)&global_default_context, allocators, allocator_userdata); } -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllocators(cJSON_Configuration configuration, const cJSON_Allocators allocators) +CJSON_PUBLIC(cJSON_Context) cJSON_SetAllocators(cJSON_Context context, const cJSON_Allocators allocators) { - if ((configuration == NULL) || (allocators.allocate == NULL) || (allocators.deallocate == NULL)) + if ((context == NULL) || (allocators.allocate == NULL) || (allocators.deallocate == NULL)) { return NULL; } - ((internal_configuration*)configuration)->allocators = allocators; - ((internal_configuration*)configuration)->userdata = NULL; + ((internal_context*)context)->allocators = allocators; + ((internal_context*)context)->userdata = NULL; - return configuration; + return context; } -/* Change the allocator userdata attached to a cJSON_Configuration */ -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeUserdata(cJSON_Configuration configuration, void *userdata) +/* Change the allocator userdata attached to a cJSON_Context */ +CJSON_PUBLIC(cJSON_Context) cJSON_SetUserdata(cJSON_Context context, void *userdata) { - if (configuration == NULL) + if (context == NULL) { return NULL; } - ((internal_configuration*)configuration)->userdata = userdata; - return configuration; + ((internal_context*)context)->userdata = userdata; + return context; } -CJSON_PUBLIC(size_t) cJSON_ConfigurationGetParseEnd(cJSON_Configuration configuration) +CJSON_PUBLIC(size_t) cJSON_GetParseEnd(cJSON_Context context) { - if (configuration == NULL) + if (context == NULL) { return 0; } - return ((internal_configuration*)configuration)->end_position; + return ((internal_context*)context)->end_position; } -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangePrebufferSize(cJSON_Configuration configuration, const size_t buffer_size) +CJSON_PUBLIC(cJSON_Context) cJSON_SetPrebufferSize(cJSON_Context context, const size_t buffer_size) { - if ((configuration == NULL) || (buffer_size == 0)) + if ((context == NULL) || (buffer_size == 0)) { return NULL; } - ((internal_configuration*)configuration)->buffer_size = buffer_size; - return configuration; + ((internal_context*)context)->buffer_size = buffer_size; + return context; } -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeFormat(cJSON_Configuration configuration, cJSON_Format format) +CJSON_PUBLIC(cJSON_Context) cJSON_SetFormat(cJSON_Context context, cJSON_Format format) { - if (configuration == NULL) + if (context == NULL) { return NULL; } @@ -2974,43 +2974,43 @@ CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeFormat(cJSON_Configur switch (format) { case CJSON_FORMAT_MINIFIED: - ((internal_configuration*)configuration)->format = false; + ((internal_context*)context)->format = false; break; case CJSON_FORMAT_DEFAULT: - ((internal_configuration*)configuration)->format = true; + ((internal_context*)context)->format = true; break; default: return NULL; } - return configuration; + return context; } -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeCaseSensitivity(cJSON_Configuration configuration, cJSON_bool case_sensitive) +CJSON_PUBLIC(cJSON_Context) cJSON_MakeCaseSensitive(cJSON_Context context, cJSON_bool case_sensitive) { - if (configuration == NULL) + if (context == NULL) { return NULL; } - ((internal_configuration*)configuration)->case_sensitive = case_sensitive; - return configuration; + ((internal_context*)context)->case_sensitive = case_sensitive; + return context; } -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllowDataAfterJson(cJSON_Configuration configuration, cJSON_bool allow_data_after_json) +CJSON_PUBLIC(cJSON_Context) cJSON_AllowDataAfterJson(cJSON_Context context, cJSON_bool allow_data_after_json) { - if (configuration == NULL) + if (context == NULL) { return NULL; } - ((internal_configuration*)configuration)->allow_data_after_json = allow_data_after_json; - return configuration; + ((internal_context*)context)->allow_data_after_json = allow_data_after_json; + return context; } -static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const internal_configuration * const configuration) +static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const internal_context * const context) { if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) { @@ -3075,7 +3075,7 @@ static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const in for (; (a_element != NULL) && (b_element != NULL);) { - if (!compare(a_element, b_element, configuration)) + if (!compare(a_element, b_element, context)) { return false; } @@ -3107,13 +3107,13 @@ static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const in cJSON_ArrayForEach(a_element, a) { /* TODO This has O(n^2) runtime, which is horrible! */ - b_element = get_object_item(b, a_element->string, configuration); + b_element = get_object_item(b, a_element->string, context); if (b_element == NULL) { return false; } - if (!compare(a_element, b_element, configuration)) + if (!compare(a_element, b_element, context)) { return false; } @@ -3129,9 +3129,9 @@ static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const in CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) { - internal_configuration configuration = global_configuration; - configuration.case_sensitive = case_sensitive; - return compare(a, b, &configuration); + internal_context context = global_context; + context.case_sensitive = case_sensitive; + return compare(a, b, &context); } CJSON_PUBLIC(void *) cJSON_malloc(size_t size) diff --git a/cJSON.h b/cJSON.h index b7036a21..675594af 100644 --- a/cJSON.h +++ b/cJSON.h @@ -87,7 +87,6 @@ typedef struct cJSON_Allocators } cJSON_Allocators; typedef int cJSON_bool; -typedef void* cJSON_Configuration; #if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) #define __WINDOWS__ @@ -141,36 +140,40 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* returns the version of cJSON as a string */ CJSON_PUBLIC(const char*) cJSON_Version(void); +typedef void* cJSON_Context; /* - * Create a configuration object that can be passed to several functions - * to configure their behavior. It will be set to the default values initially, they - * can be changed later. + * Create a context object that can be passed to several functions + * to configure their behavior and/or take their output. It will be set to the default values + * initially, they can be changed later using the builder pattern by passing it to functions + * that change one setting. * - * A cJSON_Configuration object is dynamically allocated and you are responsible to free it + * A cJSON_Context object is dynamically allocated and you are responsible to free it * after use. * * If allocators is a NULL pointer, malloc and free are used. * * allocator_userdata can be used to pass custom data to your allocator (e.g. for pool allocators). * */ -CJSON_PUBLIC(cJSON_Configuration) cJSON_CreateConfiguration(const cJSON_Allocators * const allocators, void *allocator_userdata); -/* Create a copy of an existing configuration */ -CJSON_PUBLIC(cJSON_Configuration) cJSON_DuplicateConfiguration(const cJSON_Configuration, const cJSON_Allocators * const allocators, void *allocator_userdata); -/* Change the allocators of a cJSON_Configuration and reset the userdata */ -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllocators(cJSON_Configuration configuration, const cJSON_Allocators allocators); -/* Change the allocator userdata attached to a cJSON_Configuration */ -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeUserdata(cJSON_Configuration configuration, void *userdata); +CJSON_PUBLIC(cJSON_Context) cJSON_CreateContext(const cJSON_Allocators * const allocators, void *allocator_userdata); +/* Create a copy of an existing context */ +CJSON_PUBLIC(cJSON_Context) cJSON_DuplicateContext(const cJSON_Context, const cJSON_Allocators * const allocators, void *allocator_userdata); + +/* The following functions work on a context in order to set and retrieve data: */ +/* Change the allocators of a cJSON_Context and reset the userdata */ +CJSON_PUBLIC(cJSON_Context) cJSON_SetAllocators(cJSON_Context context, const cJSON_Allocators allocators); +/* Change the allocator userdata attached to a cJSON_Context */ +CJSON_PUBLIC(cJSON_Context) cJSON_SetUserdata(cJSON_Context context, void *userdata); /* Get the position relative to the JSON where the parser stopped, return 0 if invalid. */ -CJSON_PUBLIC(size_t) cJSON_ConfigurationGetParseEnd(cJSON_Configuration configuration); +CJSON_PUBLIC(size_t) cJSON_GetParseEnd(cJSON_Context context); /* Set how many bytes should be initially allocated for printing */ -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangePrebufferSize(cJSON_Configuration configuration, const size_t buffer_size); +CJSON_PUBLIC(cJSON_Context) cJSON_SetPrebufferSize(cJSON_Context context, const size_t buffer_size); typedef enum { CJSON_FORMAT_MINIFIED = 0, CJSON_FORMAT_DEFAULT = 1 } cJSON_Format; /* Change the format for printing */ -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeFormat(cJSON_Configuration configuration, cJSON_Format format); +CJSON_PUBLIC(cJSON_Context) cJSON_SetFormat(cJSON_Context context, cJSON_Format format); /* Change the case sensitivity */ -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeCaseSensitivity(cJSON_Configuration configuration, cJSON_bool case_sensitive); +CJSON_PUBLIC(cJSON_Context) cJSON_MakeCaseSensitive(cJSON_Context context, cJSON_bool case_sensitive); /* Change if data is allowed after the JSON */ -CJSON_PUBLIC(cJSON_Configuration) cJSON_ConfigurationChangeAllowDataAfterJson(cJSON_Configuration configuration, cJSON_bool allow_data_after_json); +CJSON_PUBLIC(cJSON_Context) cJSON_AllowDataAfterJson(cJSON_Context context, cJSON_bool allow_data_after_json); /* Supply malloc and free functions to cJSON globally */ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 14bdf34e..f7d0180a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -57,7 +57,7 @@ if(ENABLE_CJSON_TEST) compare_tests cjson_add readme_examples - configuration_tests + context_tests ) option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.") diff --git a/tests/common.h b/tests/common.h index 27c7587b..0853fb01 100644 --- a/tests/common.h +++ b/tests/common.h @@ -33,11 +33,11 @@ void reset(cJSON *item) { } if ((item->valuestring != NULL) && !(item->type & cJSON_IsReference)) { - global_configuration.allocators.deallocate(item->valuestring, global_configuration.userdata); + global_context.allocators.deallocate(item->valuestring, global_context.userdata); } if ((item->string != NULL) && !(item->type & cJSON_StringIsConst)) { - global_configuration.allocators.deallocate(item->string, global_configuration.userdata); + global_context.allocators.deallocate(item->string, global_context.userdata); } memset(item, 0, sizeof(cJSON)); diff --git a/tests/configuration_tests.c b/tests/configuration_tests.c deleted file mode 100644 index 04d9a37f..00000000 --- a/tests/configuration_tests.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -#include -#include -#include - -#include "unity/examples/unity_config.h" -#include "unity/src/unity.h" -#include "common.h" - -static void create_configuration_should_create_a_configuration(void) -{ - internal_configuration *configuration = NULL; - - configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); - TEST_ASSERT_NOT_NULL(configuration); - TEST_ASSERT_EQUAL_MESSAGE(configuration->buffer_size, 256, "buffer_size has an incorrect value."); - TEST_ASSERT_TRUE_MESSAGE(configuration->format, "format has an incorrect value."); - TEST_ASSERT_TRUE_MESSAGE(configuration->case_sensitive, "case_sensitive has an incorrect value."); - TEST_ASSERT_TRUE_MESSAGE(configuration->allow_data_after_json, "allow_data_after_json has an incorrect value."); - TEST_ASSERT_NULL_MESSAGE(configuration->userdata, "Userdata should be NULL"); - TEST_ASSERT_TRUE_MESSAGE(malloc_wrapper == configuration->allocators.allocate, "Wrong malloc."); - TEST_ASSERT_TRUE_MESSAGE(realloc_wrapper == configuration->allocators.reallocate, "Wrong realloc."); - TEST_ASSERT_TRUE_MESSAGE(free_wrapper == configuration->allocators.deallocate, "Wrong free."); - - free(configuration); -} - -static void* custom_allocator(size_t size, void *userdata) -{ - *((size_t*)userdata) = size; - return malloc(size); -} -static void custom_deallocator(void *pointer, void *userdata) -{ - *((size_t*)userdata) = (size_t)pointer; - free(pointer); -} - -static void create_configuration_should_take_custom_allocators(void) -{ - internal_configuration *configuration = NULL; - cJSON_Allocators allocators = {custom_allocator, custom_deallocator, NULL}; - size_t userdata = 0; - - configuration = (internal_configuration*)cJSON_CreateConfiguration(&allocators, &userdata); - TEST_ASSERT_NOT_NULL(configuration); - TEST_ASSERT_EQUAL_MESSAGE(userdata, sizeof(internal_configuration), "custom allocator wasn't run properly."); - TEST_ASSERT_TRUE_MESSAGE(global_default_configuration.allocators.allocate == configuration->allocators.allocate, "Wrong allocator."); - TEST_ASSERT_TRUE_MESSAGE(global_default_configuration.allocators.deallocate == configuration->allocators.deallocate, "Wrong deallocator."); - TEST_ASSERT_TRUE_MESSAGE(global_default_configuration.allocators.reallocate == configuration->allocators.reallocate, "Wrong reallocator."); - - custom_deallocator(configuration, &userdata); -} - -static void create_configuration_should_not_take_incomplete_allocators(void) -{ - cJSON_Allocators allocators1 = {custom_allocator, NULL, NULL}; - cJSON_Allocators allocators2 = {NULL, custom_deallocator, NULL}; - size_t userdata = 0; - - TEST_ASSERT_NULL(cJSON_CreateConfiguration(&allocators1, &userdata)); - TEST_ASSERT_NULL(cJSON_CreateConfiguration(&allocators2, &userdata)); -} - -static void duplicate_configuration_should_duplicate_a_configuration(void) -{ - internal_configuration *configuration = NULL; - - configuration = (internal_configuration*)cJSON_DuplicateConfiguration(&global_configuration, NULL, NULL); - TEST_ASSERT_NOT_NULL(configuration); - - TEST_ASSERT_EQUAL_MEMORY(&global_configuration, configuration, sizeof(internal_configuration)); - - free(configuration); -} - -static void duplicate_configuration_should_take_custom_allocators(void) -{ - internal_configuration *configuration = NULL; - cJSON_Allocators allocators = {custom_allocator, custom_deallocator, NULL}; - size_t userdata = 0; - - configuration = (internal_configuration*)cJSON_DuplicateConfiguration(&global_configuration, &allocators, &userdata); - TEST_ASSERT_NOT_NULL(configuration); - TEST_ASSERT_EQUAL_MESSAGE(userdata, sizeof(internal_configuration), "custom allocator wasn't run properly"); - - TEST_ASSERT_EQUAL_MEMORY(&global_configuration, configuration, sizeof(internal_configuration)); - free(configuration); -} - -static void duplicate_configuration_should_not_take_incomplete_allocators(void) -{ - cJSON_Allocators allocators1 = {custom_allocator, NULL, NULL}; - cJSON_Allocators allocators2 = {NULL, custom_deallocator, NULL}; - size_t userdata = 0; - - TEST_ASSERT_NULL(cJSON_DuplicateConfiguration(&global_configuration, &allocators1, &userdata)); - TEST_ASSERT_NULL(cJSON_DuplicateConfiguration(&global_configuration, &allocators2, &userdata)); -} - -static void configuration_change_allocators_should_change_allocators(void) -{ - internal_configuration *configuration = NULL; - cJSON_Allocators allocators = {custom_allocator, custom_deallocator, NULL}; - size_t userdata = 0; - - configuration = (internal_configuration*)cJSON_CreateConfiguration(&allocators, &userdata); - TEST_ASSERT_NOT_NULL(configuration); - - configuration = (internal_configuration*)cJSON_ConfigurationChangeAllocators(configuration, allocators); - TEST_ASSERT_NOT_NULL(configuration); - TEST_ASSERT_TRUE_MESSAGE(custom_allocator == configuration->allocators.allocate, "Wrong allocator."); - TEST_ASSERT_TRUE_MESSAGE(custom_deallocator == configuration->allocators.deallocate, "Wrong deallocator."); - TEST_ASSERT_NULL_MESSAGE(configuration->allocators.reallocate, "Reallocator is not null"); - - custom_deallocator(configuration, &userdata); -} - -static void configuration_change_allocators_should_not_change_incomplete_allocators(void) -{ - internal_configuration *configuration = NULL; - cJSON_Allocators allocators1 = {custom_allocator, NULL, NULL}; - cJSON_Allocators allocators2 = {NULL, custom_deallocator, NULL}; - - configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); - TEST_ASSERT_NOT_NULL(configuration); - - TEST_ASSERT_NULL(cJSON_ConfigurationChangeAllocators(configuration, allocators1)); - TEST_ASSERT_NULL(cJSON_ConfigurationChangeAllocators(configuration, allocators2)); - - free(configuration); -} - -static void configuration_change_userdata_should_change_userdata(void) -{ - internal_configuration *configuration = NULL; - size_t userdata = 0; - configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); - TEST_ASSERT_NOT_NULL(configuration); - - configuration = (internal_configuration*)cJSON_ConfigurationChangeUserdata(configuration, &userdata); - TEST_ASSERT_TRUE_MESSAGE(configuration->userdata == &userdata, "Userdata is incorrect."); - - free(configuration); -} - -static void configuration_get_parse_end_should_get_the_parse_end(void) -{ - internal_configuration configuration = global_default_configuration; - configuration.end_position = 42; - - TEST_ASSERT_EQUAL_MESSAGE(cJSON_ConfigurationGetParseEnd(&configuration), 42, "Failed to get parse end."); -} - -static void configuration_change_prebuffer_size_should_change_buffer_size(void) -{ - internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); - TEST_ASSERT_NOT_NULL(configuration); - - configuration = (internal_configuration*)cJSON_ConfigurationChangePrebufferSize(configuration, 1024); - TEST_ASSERT_NOT_NULL(configuration); - - TEST_ASSERT_EQUAL_MESSAGE(configuration->buffer_size, 1024, "Didn't set the buffer size correctly."); - - free(configuration); -} - -static void configuration_change_prebuffer_size_should_not_allow_empty_sizes(void) -{ - internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); - TEST_ASSERT_NOT_NULL(configuration); - - TEST_ASSERT_NULL(cJSON_ConfigurationChangePrebufferSize(configuration, 0)); - - free(configuration); -} - -static void configuration_change_format_should_change_format(void) -{ - internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); - TEST_ASSERT_NOT_NULL(configuration); - - configuration = (internal_configuration*)cJSON_ConfigurationChangeFormat(configuration, CJSON_FORMAT_MINIFIED); - TEST_ASSERT_NOT_NULL(configuration); - TEST_ASSERT_FALSE_MESSAGE(configuration->format, "Failed to set CJSON_FORMAT_MINIFIED."); - - configuration = (internal_configuration*)cJSON_ConfigurationChangeFormat(configuration, CJSON_FORMAT_DEFAULT); - TEST_ASSERT_NOT_NULL(configuration); - TEST_ASSERT_TRUE_MESSAGE(configuration->format, "Failed to set CJSON_FORMAT_DEFAULT."); - - TEST_ASSERT_NULL_MESSAGE(cJSON_ConfigurationChangeFormat(configuration, (cJSON_Format)3), "Failed to detect invalid format."); - - free(configuration); -} - -static void configuration_change_case_sensitivity_should_change_case_sensitivity(void) -{ - internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); - TEST_ASSERT_NOT_NULL(configuration); - - configuration = (internal_configuration*)cJSON_ConfigurationChangeCaseSensitivity(configuration, false); - TEST_ASSERT_NOT_NULL(configuration); - - TEST_ASSERT_FALSE_MESSAGE(configuration->case_sensitive, "Didn't set the case sensitivity correctly."); - - free(configuration); -} - -static void configuration_change_allow_data_after_json_should_change_allow_data_after_json(void) -{ - internal_configuration *configuration = (internal_configuration*)cJSON_CreateConfiguration(NULL, NULL); - TEST_ASSERT_NOT_NULL(configuration); - - configuration = (internal_configuration*)cJSON_ConfigurationChangeAllowDataAfterJson(configuration, false); - TEST_ASSERT_NOT_NULL(configuration); - - TEST_ASSERT_FALSE_MESSAGE(configuration->allow_data_after_json, "Didn't set allow_data_after_json property correctly."); - - free(configuration); -} - -int main(void) -{ - UNITY_BEGIN(); - - RUN_TEST(create_configuration_should_create_a_configuration); - RUN_TEST(create_configuration_should_take_custom_allocators); - RUN_TEST(create_configuration_should_not_take_incomplete_allocators); - RUN_TEST(duplicate_configuration_should_duplicate_a_configuration); - RUN_TEST(duplicate_configuration_should_take_custom_allocators); - RUN_TEST(duplicate_configuration_should_not_take_incomplete_allocators); - RUN_TEST(configuration_change_allocators_should_change_allocators); - RUN_TEST(configuration_change_allocators_should_not_change_incomplete_allocators); - RUN_TEST(configuration_change_userdata_should_change_userdata); - RUN_TEST(configuration_get_parse_end_should_get_the_parse_end); - RUN_TEST(configuration_change_prebuffer_size_should_change_buffer_size); - RUN_TEST(configuration_change_prebuffer_size_should_not_allow_empty_sizes); - RUN_TEST(configuration_change_format_should_change_format); - RUN_TEST(configuration_change_case_sensitivity_should_change_case_sensitivity); - RUN_TEST(configuration_change_allow_data_after_json_should_change_allow_data_after_json); - - return UNITY_END(); -} diff --git a/tests/context_tests.c b/tests/context_tests.c new file mode 100644 index 00000000..e6e552fc --- /dev/null +++ b/tests/context_tests.c @@ -0,0 +1,264 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include +#include + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" + +static void create_context_should_create_a_context(void) +{ + internal_context *context = NULL; + + context = (internal_context*)cJSON_CreateContext(NULL, NULL); + TEST_ASSERT_NOT_NULL(context); + TEST_ASSERT_EQUAL_MESSAGE(context->buffer_size, 256, "buffer_size has an incorrect value."); + TEST_ASSERT_TRUE_MESSAGE(context->format, "format has an incorrect value."); + TEST_ASSERT_TRUE_MESSAGE(context->case_sensitive, "case_sensitive has an incorrect value."); + TEST_ASSERT_TRUE_MESSAGE(context->allow_data_after_json, "allow_data_after_json has an incorrect value."); + TEST_ASSERT_NULL_MESSAGE(context->userdata, "Userdata should be NULL"); + TEST_ASSERT_TRUE_MESSAGE(malloc_wrapper == context->allocators.allocate, "Wrong malloc."); + TEST_ASSERT_TRUE_MESSAGE(realloc_wrapper == context->allocators.reallocate, "Wrong realloc."); + TEST_ASSERT_TRUE_MESSAGE(free_wrapper == context->allocators.deallocate, "Wrong free."); + + free(context); +} + +static void* custom_allocator(size_t size, void *userdata) +{ + *((size_t*)userdata) = size; + return malloc(size); +} +static void custom_deallocator(void *pointer, void *userdata) +{ + *((size_t*)userdata) = (size_t)pointer; + free(pointer); +} + +static void create_context_should_take_custom_allocators(void) +{ + internal_context *context = NULL; + cJSON_Allocators allocators = {custom_allocator, custom_deallocator, NULL}; + size_t userdata = 0; + + context = (internal_context*)cJSON_CreateContext(&allocators, &userdata); + TEST_ASSERT_NOT_NULL(context); + TEST_ASSERT_EQUAL_MESSAGE(userdata, sizeof(internal_context), "custom allocator wasn't run properly."); + TEST_ASSERT_TRUE_MESSAGE(global_default_context.allocators.allocate == context->allocators.allocate, "Wrong allocator."); + TEST_ASSERT_TRUE_MESSAGE(global_default_context.allocators.deallocate == context->allocators.deallocate, "Wrong deallocator."); + TEST_ASSERT_TRUE_MESSAGE(global_default_context.allocators.reallocate == context->allocators.reallocate, "Wrong reallocator."); + + custom_deallocator(context, &userdata); +} + +static void create_context_should_not_take_incomplete_allocators(void) +{ + cJSON_Allocators allocators1 = {custom_allocator, NULL, NULL}; + cJSON_Allocators allocators2 = {NULL, custom_deallocator, NULL}; + size_t userdata = 0; + + TEST_ASSERT_NULL(cJSON_CreateContext(&allocators1, &userdata)); + TEST_ASSERT_NULL(cJSON_CreateContext(&allocators2, &userdata)); +} + +static void duplicate_context_should_duplicate_a_context(void) +{ + internal_context *context = NULL; + + context = (internal_context*)cJSON_DuplicateContext(&global_context, NULL, NULL); + TEST_ASSERT_NOT_NULL(context); + + TEST_ASSERT_EQUAL_MEMORY(&global_context, context, sizeof(internal_context)); + + free(context); +} + +static void duplicate_context_should_take_custom_allocators(void) +{ + internal_context *context = NULL; + cJSON_Allocators allocators = {custom_allocator, custom_deallocator, NULL}; + size_t userdata = 0; + + context = (internal_context*)cJSON_DuplicateContext(&global_context, &allocators, &userdata); + TEST_ASSERT_NOT_NULL(context); + TEST_ASSERT_EQUAL_MESSAGE(userdata, sizeof(internal_context), "custom allocator wasn't run properly"); + + TEST_ASSERT_EQUAL_MEMORY(&global_context, context, sizeof(internal_context)); + free(context); +} + +static void duplicate_context_should_not_take_incomplete_allocators(void) +{ + cJSON_Allocators allocators1 = {custom_allocator, NULL, NULL}; + cJSON_Allocators allocators2 = {NULL, custom_deallocator, NULL}; + size_t userdata = 0; + + TEST_ASSERT_NULL(cJSON_DuplicateContext(&global_context, &allocators1, &userdata)); + TEST_ASSERT_NULL(cJSON_DuplicateContext(&global_context, &allocators2, &userdata)); +} + +static void set_allocators_should_set_allocators(void) +{ + internal_context *context = NULL; + cJSON_Allocators allocators = {custom_allocator, custom_deallocator, NULL}; + size_t userdata = 0; + + context = (internal_context*)cJSON_CreateContext(&allocators, &userdata); + TEST_ASSERT_NOT_NULL(context); + + context = (internal_context*)cJSON_SetAllocators(context, allocators); + TEST_ASSERT_NOT_NULL(context); + TEST_ASSERT_TRUE_MESSAGE(custom_allocator == context->allocators.allocate, "Wrong allocator."); + TEST_ASSERT_TRUE_MESSAGE(custom_deallocator == context->allocators.deallocate, "Wrong deallocator."); + TEST_ASSERT_NULL_MESSAGE(context->allocators.reallocate, "Reallocator is not null"); + + custom_deallocator(context, &userdata); +} + +static void set_allocators_should_not_set_incomplete_allocators(void) +{ + internal_context *context = NULL; + cJSON_Allocators allocators1 = {custom_allocator, NULL, NULL}; + cJSON_Allocators allocators2 = {NULL, custom_deallocator, NULL}; + + context = (internal_context*)cJSON_CreateContext(NULL, NULL); + TEST_ASSERT_NOT_NULL(context); + + TEST_ASSERT_NULL(cJSON_SetAllocators(context, allocators1)); + TEST_ASSERT_NULL(cJSON_SetAllocators(context, allocators2)); + + free(context); +} + +static void set_userdata_should_set_userdata(void) +{ + internal_context *context = NULL; + size_t userdata = 0; + context = (internal_context*)cJSON_CreateContext(NULL, NULL); + TEST_ASSERT_NOT_NULL(context); + + context = (internal_context*)cJSON_SetUserdata(context, &userdata); + TEST_ASSERT_TRUE_MESSAGE(context->userdata == &userdata, "Userdata is incorrect."); + + free(context); +} + +static void get_parse_end_should_get_the_parse_end(void) +{ + internal_context context = global_default_context; + context.end_position = 42; + + TEST_ASSERT_EQUAL_MESSAGE(cJSON_GetParseEnd(&context), 42, "Failed to get parse end."); +} + +static void set_prebuffer_size_should_set_buffer_size(void) +{ + internal_context *context = (internal_context*)cJSON_CreateContext(NULL, NULL); + TEST_ASSERT_NOT_NULL(context); + + context = (internal_context*)cJSON_SetPrebufferSize(context, 1024); + TEST_ASSERT_NOT_NULL(context); + + TEST_ASSERT_EQUAL_MESSAGE(context->buffer_size, 1024, "Didn't set the buffer size correctly."); + + free(context); +} + +static void set_prebuffer_size_should_not_allow_empty_sizes(void) +{ + internal_context *context = (internal_context*)cJSON_CreateContext(NULL, NULL); + TEST_ASSERT_NOT_NULL(context); + + TEST_ASSERT_NULL(cJSON_SetPrebufferSize(context, 0)); + + free(context); +} + +static void set_format_should_set_format(void) +{ + internal_context *context = (internal_context*)cJSON_CreateContext(NULL, NULL); + TEST_ASSERT_NOT_NULL(context); + + context = (internal_context*)cJSON_SetFormat(context, CJSON_FORMAT_MINIFIED); + TEST_ASSERT_NOT_NULL(context); + TEST_ASSERT_FALSE_MESSAGE(context->format, "Failed to set CJSON_FORMAT_MINIFIED."); + + context = (internal_context*)cJSON_SetFormat(context, CJSON_FORMAT_DEFAULT); + TEST_ASSERT_NOT_NULL(context); + TEST_ASSERT_TRUE_MESSAGE(context->format, "Failed to set CJSON_FORMAT_DEFAULT."); + + TEST_ASSERT_NULL_MESSAGE(cJSON_SetFormat(context, (cJSON_Format)3), "Failed to detect invalid format."); + + free(context); +} + +static void make_case_sensitive_should_change_case_sensitivity(void) +{ + internal_context *context = (internal_context*)cJSON_CreateContext(NULL, NULL); + TEST_ASSERT_NOT_NULL(context); + + context = (internal_context*)cJSON_MakeCaseSensitive(context, false); + TEST_ASSERT_NOT_NULL(context); + + TEST_ASSERT_FALSE_MESSAGE(context->case_sensitive, "Didn't set the case sensitivity correctly."); + + free(context); +} + +static void allow_data_after_json_should_change_allow_data_after_json(void) +{ + internal_context *context = (internal_context*)cJSON_CreateContext(NULL, NULL); + TEST_ASSERT_NOT_NULL(context); + + context = (internal_context*)cJSON_AllowDataAfterJson(context, false); + TEST_ASSERT_NOT_NULL(context); + + TEST_ASSERT_FALSE_MESSAGE(context->allow_data_after_json, "Didn't set allow_data_after_json property correctly."); + + free(context); +} + +int main(void) +{ + UNITY_BEGIN(); + + RUN_TEST(create_context_should_create_a_context); + RUN_TEST(create_context_should_take_custom_allocators); + RUN_TEST(create_context_should_not_take_incomplete_allocators); + RUN_TEST(duplicate_context_should_duplicate_a_context); + RUN_TEST(duplicate_context_should_take_custom_allocators); + RUN_TEST(duplicate_context_should_not_take_incomplete_allocators); + RUN_TEST(set_allocators_should_set_allocators); + RUN_TEST(set_allocators_should_not_set_incomplete_allocators); + RUN_TEST(set_userdata_should_set_userdata); + RUN_TEST(get_parse_end_should_get_the_parse_end); + RUN_TEST(set_prebuffer_size_should_set_buffer_size); + RUN_TEST(set_prebuffer_size_should_not_allow_empty_sizes); + RUN_TEST(set_format_should_set_format); + RUN_TEST(make_case_sensitive_should_change_case_sensitivity); + RUN_TEST(allow_data_after_json_should_change_allow_data_after_json); + + return UNITY_END(); +} diff --git a/tests/misc_tests.c b/tests/misc_tests.c index e70f0749..3fc2ef66 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -420,7 +420,7 @@ static void *failing_realloc(void *pointer, size_t size, void *userdata) static void ensure_should_fail_on_failed_realloc(void) { printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, {malloc_wrapper, free_wrapper, failing_realloc}, NULL, 0 } }; - buffer.configuration.userdata = &buffer; + buffer.context.userdata = &buffer; buffer.buffer = (unsigned char*)malloc(100); TEST_ASSERT_NOT_NULL(buffer.buffer); @@ -430,10 +430,10 @@ static void ensure_should_fail_on_failed_realloc(void) static void skip_utf8_bom_should_skip_bom(void) { const unsigned char string[] = "\xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; + parse_buffer buffer = { 0, 0, 0, 0, default_context }; buffer.content = string; buffer.length = sizeof(string); - buffer.configuration = global_configuration; + buffer.context = global_context; TEST_ASSERT_TRUE(skip_utf8_bom(&buffer) == &buffer); TEST_ASSERT_EQUAL_UINT(3U, (unsigned int)buffer.offset); @@ -442,10 +442,10 @@ static void skip_utf8_bom_should_skip_bom(void) static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void) { const unsigned char string[] = " \xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; + parse_buffer buffer = { 0, 0, 0, 0, default_context }; buffer.content = string; buffer.length = sizeof(string); - buffer.configuration = global_configuration; + buffer.context = global_context; buffer.offset = 1; TEST_ASSERT_NULL(skip_utf8_bom(&buffer)); @@ -513,7 +513,7 @@ static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_al { cJSON *object = cJSON_CreateObject(); cJSON *number = cJSON_CreateNumber(42); - char *name = (char*)custom_strdup((const unsigned char*)"number", &global_configuration); + char *name = (char*)custom_strdup((const unsigned char*)"number", &global_context); TEST_ASSERT_NOT_NULL(object); TEST_ASSERT_NOT_NULL(number); diff --git a/tests/parse_array.c b/tests/parse_array.c index 4143966f..f41721d1 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -44,10 +44,10 @@ static void assert_is_array(cJSON *array_item) static void assert_not_array(const char *json) { - parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; + parse_buffer buffer = { 0, 0, 0, 0, default_context }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); - buffer.configuration = global_configuration; + buffer.context = global_context; TEST_ASSERT_FALSE(parse_array(item, &buffer)); assert_is_invalid(item); @@ -55,10 +55,10 @@ static void assert_not_array(const char *json) static void assert_parse_array(const char *json) { - parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; + parse_buffer buffer = { 0, 0, 0, 0, default_context }; buffer.content = (const unsigned char*)json; buffer.length = strlen(json) + sizeof(""); - buffer.configuration = global_configuration; + buffer.context = global_context; TEST_ASSERT_TRUE(parse_array(item, &buffer)); assert_is_array(item); diff --git a/tests/parse_number.c b/tests/parse_number.c index 5850265d..04fa218f 100644 --- a/tests/parse_number.c +++ b/tests/parse_number.c @@ -45,7 +45,7 @@ static void assert_is_number(cJSON *number_item) static void assert_parse_number(const char *string, int integer, double real) { - parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; + parse_buffer buffer = { 0, 0, 0, 0, default_context }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); diff --git a/tests/parse_object.c b/tests/parse_object.c index 0f46a22a..ca9902e2 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -52,10 +52,10 @@ static void assert_is_child(cJSON *child_item, const char *name, int type) static void assert_not_object(const char *json) { - parse_buffer parsebuffer = { 0, 0, 0, 0, default_configuration }; + parse_buffer parsebuffer = { 0, 0, 0, 0, default_context }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); - parsebuffer.configuration = global_configuration; + parsebuffer.context = global_context; TEST_ASSERT_FALSE(parse_object(item, &parsebuffer)); assert_is_invalid(item); @@ -64,10 +64,10 @@ static void assert_not_object(const char *json) static void assert_parse_object(const char *json) { - parse_buffer parsebuffer = { 0, 0, 0, 0, default_configuration }; + parse_buffer parsebuffer = { 0, 0, 0, 0, default_context }; parsebuffer.content = (const unsigned char*)json; parsebuffer.length = strlen(json) + sizeof(""); - parsebuffer.configuration = global_configuration; + parsebuffer.context = global_context; TEST_ASSERT_TRUE(parse_object(item, &parsebuffer)); assert_is_object(item); diff --git a/tests/parse_string.c b/tests/parse_string.c index 39955e56..5dc13128 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -45,24 +45,24 @@ static void assert_is_string(cJSON *string_item) static void assert_parse_string(const char *string, const char *expected) { - parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; + parse_buffer buffer = { 0, 0, 0, 0, default_context }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); - buffer.configuration = global_configuration; + buffer.context = global_context; TEST_ASSERT_TRUE_MESSAGE(parse_string(item, &buffer), "Couldn't parse string."); assert_is_string(item); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, item->valuestring, "The parsed result isn't as expected."); - global_configuration.allocators.deallocate(item->valuestring, global_configuration.userdata); + global_context.allocators.deallocate(item->valuestring, global_context.userdata); item->valuestring = NULL; } static void assert_not_parse_string(const char * const string) { - parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; + parse_buffer buffer = { 0, 0, 0, 0, default_context }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); - buffer.configuration = global_configuration; + buffer.context = global_context; TEST_ASSERT_FALSE_MESSAGE(parse_string(item, &buffer), "Malformed string should not be accepted."); assert_is_invalid(item); diff --git a/tests/parse_value.c b/tests/parse_value.c index 2b17fc8b..a42832a9 100644 --- a/tests/parse_value.c +++ b/tests/parse_value.c @@ -43,10 +43,10 @@ static void assert_is_value(cJSON *value_item, int type) static void assert_parse_value(const char *string, int type) { - parse_buffer buffer = { 0, 0, 0, 0, default_configuration }; + parse_buffer buffer = { 0, 0, 0, 0, default_context }; buffer.content = (const unsigned char*) string; buffer.length = strlen(string) + sizeof(""); - buffer.configuration = global_configuration; + buffer.context = global_context; TEST_ASSERT_TRUE(parse_value(item, &buffer)); assert_is_value(item, type); diff --git a/tests/print_array.c b/tests/print_array.c index 05636c30..a8dac86d 100644 --- a/tests/print_array.c +++ b/tests/print_array.c @@ -31,36 +31,36 @@ static void assert_print_array(const char * const expected, const char * const i cJSON item[1]; - printbuffer formatted_buffer = { 0, 0, 0, 0, 0, default_configuration }; - printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, default_configuration }; + printbuffer formatted_buffer = { 0, 0, 0, 0, 0, default_context }; + printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, default_context }; - parse_buffer parsebuffer = { 0, 0, 0, 0, default_configuration }; + parse_buffer parsebuffer = { 0, 0, 0, 0, default_context }; parsebuffer.content = (const unsigned char*)input; parsebuffer.length = strlen(input) + sizeof(""); - parsebuffer.configuration = global_configuration; + parsebuffer.context = global_context; /* buffer for formatted printing */ formatted_buffer.buffer = printed_formatted; formatted_buffer.length = sizeof(printed_formatted); formatted_buffer.offset = 0; formatted_buffer.noalloc = true; - formatted_buffer.configuration = global_configuration; + formatted_buffer.context = global_context; /* buffer for unformatted printing */ unformatted_buffer.buffer = printed_unformatted; unformatted_buffer.length = sizeof(printed_unformatted); unformatted_buffer.offset = 0; unformatted_buffer.noalloc = true; - unformatted_buffer.configuration = global_configuration; + unformatted_buffer.context = global_context; memset(item, 0, sizeof(item)); TEST_ASSERT_TRUE_MESSAGE(parse_array(item, &parsebuffer), "Failed to parse array."); - unformatted_buffer.configuration.format = false; + unformatted_buffer.context.format = false; TEST_ASSERT_TRUE_MESSAGE(print_array(item, &unformatted_buffer), "Failed to print unformatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted array is not correct."); - formatted_buffer.configuration.format = true; + formatted_buffer.context.format = true; TEST_ASSERT_TRUE_MESSAGE(print_array(item, &formatted_buffer), "Failed to print formatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted array is not correct."); diff --git a/tests/print_number.c b/tests/print_number.c index c5174c5d..6963a390 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -28,12 +28,12 @@ static void assert_print_number(const char *expected, double input) { unsigned char printed[1024]; cJSON item[1]; - printbuffer buffer = { 0, 0, 0, 0, 0, default_configuration }; + printbuffer buffer = { 0, 0, 0, 0, 0, default_context }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; buffer.noalloc = true; - buffer.configuration = global_configuration; + buffer.context = global_context; memset(item, 0, sizeof(item)); cJSON_SetNumberValue(item, input); diff --git a/tests/print_object.c b/tests/print_object.c index 582a10be..b1337ecd 100644 --- a/tests/print_object.c +++ b/tests/print_object.c @@ -31,37 +31,37 @@ static void assert_print_object(const char * const expected, const char * const cJSON item[1]; - printbuffer formatted_buffer = { 0, 0, 0, 0, 0, default_configuration }; - printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, default_configuration }; - parse_buffer parsebuffer = { 0, 0, 0, 0, default_configuration }; + printbuffer formatted_buffer = { 0, 0, 0, 0, 0, default_context }; + printbuffer unformatted_buffer = { 0, 0, 0, 0, 0, default_context }; + parse_buffer parsebuffer = { 0, 0, 0, 0, default_context }; /* buffer for parsing */ parsebuffer.content = (const unsigned char*)input; parsebuffer.length = strlen(input) + sizeof(""); - parsebuffer.configuration = global_configuration; + parsebuffer.context = global_context; /* buffer for formatted printing */ formatted_buffer.buffer = printed_formatted; formatted_buffer.length = sizeof(printed_formatted); formatted_buffer.offset = 0; formatted_buffer.noalloc = true; - formatted_buffer.configuration = global_configuration; + formatted_buffer.context = global_context; /* buffer for unformatted printing */ unformatted_buffer.buffer = printed_unformatted; unformatted_buffer.length = sizeof(printed_unformatted); unformatted_buffer.offset = 0; unformatted_buffer.noalloc = true; - unformatted_buffer.configuration = global_configuration; + unformatted_buffer.context = global_context; memset(item, 0, sizeof(item)); TEST_ASSERT_TRUE_MESSAGE(parse_object(item, &parsebuffer), "Failed to parse object."); - unformatted_buffer.configuration.format = false; + unformatted_buffer.context.format = false; TEST_ASSERT_TRUE_MESSAGE(print_object(item, &unformatted_buffer), "Failed to print unformatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(input, printed_unformatted, "Unformatted object is not correct."); - formatted_buffer.configuration.format = true; + formatted_buffer.context.format = true; TEST_ASSERT_TRUE_MESSAGE(print_object(item, &formatted_buffer), "Failed to print formatted string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted ojbect is not correct."); diff --git a/tests/print_string.c b/tests/print_string.c index c0a8eee3..f855ce64 100644 --- a/tests/print_string.c +++ b/tests/print_string.c @@ -27,12 +27,12 @@ static void assert_print_string(const char *expected, const char *input) { unsigned char printed[1024]; - printbuffer buffer = { 0, 0, 0, 0, 0, default_configuration }; + printbuffer buffer = { 0, 0, 0, 0, 0, default_context }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; buffer.noalloc = true; - buffer.configuration = global_configuration; + buffer.context = global_context; TEST_ASSERT_TRUE_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer), "Failed to print string."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed, "The printed string isn't as expected."); diff --git a/tests/print_value.c b/tests/print_value.c index 45a9d2ce..8453d618 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -32,18 +32,18 @@ static void assert_print_value(const char *input) { unsigned char printed[1024]; cJSON item[1]; - printbuffer buffer = { 0, 0, 0, 0, 0, default_configuration }; - parse_buffer parsebuffer = { 0, 0, 0, 0, default_configuration }; + printbuffer buffer = { 0, 0, 0, 0, 0, default_context }; + parse_buffer parsebuffer = { 0, 0, 0, 0, default_context }; buffer.buffer = printed; buffer.length = sizeof(printed); buffer.offset = 0; buffer.noalloc = true; - buffer.configuration = global_configuration; - buffer.configuration.format = false; + buffer.context = global_context; + buffer.context.format = false; parsebuffer.content = (const unsigned char*)input; parsebuffer.length = strlen(input) + sizeof(""); - parsebuffer.configuration = global_configuration; + parsebuffer.context = global_context; memset(item, 0, sizeof(item)); From e8f56bd194d19b49e375e67beae12d19b56b3db8 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 17:27:50 +0100 Subject: [PATCH 35/38] Context: Add duplicate_recursive for cJSON_Duplicate --- cJSON.c | 45 ++++++++++++++++++++++++++++--------------- tests/context_tests.c | 1 + tests/misc_tests.c | 2 +- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/cJSON.c b/cJSON.c index d3e4131e..72bd852e 100644 --- a/cJSON.c +++ b/cJSON.c @@ -122,6 +122,7 @@ typedef struct internal_context cJSON_bool format; cJSON_bool allow_data_after_json; cJSON_bool case_sensitive; + cJSON_bool duplicate_recursive; cJSON_Allocators allocators; void *userdata; size_t end_position; @@ -196,6 +197,7 @@ static void deallocate(const internal_context * const context, void *pointer) true, /* enable formatting by default */\ true, /* allow data after the JSON by default */\ true, /* case sensitive by default */\ + true, /* Do cJSON_Duplicate recursively by default */\ {\ malloc_wrapper,\ free_wrapper,\ @@ -2637,56 +2639,60 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) return a; } -/* Duplication */ -CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +static cJSON *duplicate_json(const cJSON *item, const internal_context * const context) { cJSON *newitem = NULL; cJSON *child = NULL; cJSON *next = NULL; cJSON *newchild = NULL; - /* Bail on bad ptr */ - if (!item) + if (item == NULL) { goto fail; } - /* Create new item */ - newitem = create_item(&global_context); - if (!newitem) + + newitem = create_item(context); + if (newitem == NULL) { goto fail; } + /* Copy over all vars */ newitem->type = item->type & (~cJSON_IsReference); newitem->valueint = item->valueint; newitem->valuedouble = item->valuedouble; - if (item->valuestring) + + if (item->valuestring != NULL) { - newitem->valuestring = (char*)custom_strdup((unsigned char*)item->valuestring, &global_context); - if (!newitem->valuestring) + newitem->valuestring = (char*)custom_strdup((unsigned char*)item->valuestring, context); + if (newitem->valuestring == NULL) { goto fail; } } - if (item->string) + + if (item->string != NULL) { - newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)custom_strdup((unsigned char*)item->string, &global_context); + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)custom_strdup((unsigned char*)item->string, context); if (!newitem->string) { goto fail; } } + /* If non-recursive, then we're done! */ - if (!recurse) + if (!context->duplicate_recursive) { return newitem; } + /* Walk the ->next chain for the child. */ child = item->child; while (child != NULL) { - newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ - if (!newchild) + /* Each item in the ->next chain */ + newchild = duplicate_json(child, context); + if (newchild == NULL) { goto fail; } @@ -2711,12 +2717,19 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) fail: if (newitem != NULL) { - delete_item(newitem, &global_context); + delete_item(newitem, context); } return NULL; } +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + internal_context context = global_context; + context.duplicate_recursive = recurse; + return duplicate_json(item, &context); +} + CJSON_PUBLIC(void) cJSON_Minify(char *json) { unsigned char *into = (unsigned char*)json; diff --git a/tests/context_tests.c b/tests/context_tests.c index e6e552fc..0e2aeaef 100644 --- a/tests/context_tests.c +++ b/tests/context_tests.c @@ -39,6 +39,7 @@ static void create_context_should_create_a_context(void) TEST_ASSERT_TRUE_MESSAGE(context->case_sensitive, "case_sensitive has an incorrect value."); TEST_ASSERT_TRUE_MESSAGE(context->allow_data_after_json, "allow_data_after_json has an incorrect value."); TEST_ASSERT_NULL_MESSAGE(context->userdata, "Userdata should be NULL"); + TEST_ASSERT_TRUE_MESSAGE(context->duplicate_recursive, "Duplicating is not recursive."); TEST_ASSERT_TRUE_MESSAGE(malloc_wrapper == context->allocators.allocate, "Wrong malloc."); TEST_ASSERT_TRUE_MESSAGE(realloc_wrapper == context->allocators.reallocate, "Wrong realloc."); TEST_ASSERT_TRUE_MESSAGE(free_wrapper == context->allocators.deallocate, "Wrong free."); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 3fc2ef66..57e9b2dc 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -419,7 +419,7 @@ static void *failing_realloc(void *pointer, size_t size, void *userdata) static void ensure_should_fail_on_failed_realloc(void) { - printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, {malloc_wrapper, free_wrapper, failing_realloc}, NULL, 0 } }; + printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, true, {malloc_wrapper, free_wrapper, failing_realloc}, NULL, 0 } }; buffer.context.userdata = &buffer; buffer.buffer = (unsigned char*)malloc(100); TEST_ASSERT_NOT_NULL(buffer.buffer); From 409c2aaea7c9957fbd8cc44dfb0202cf0983e1b4 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 17:49:37 +0100 Subject: [PATCH 36/38] cJSON_MakeDuplicateRecursive --- cJSON.c | 11 +++++++++++ cJSON.h | 2 ++ tests/context_tests.c | 13 +++++++++++++ 3 files changed, 26 insertions(+) diff --git a/cJSON.c b/cJSON.c index 72bd852e..442c3aca 100644 --- a/cJSON.c +++ b/cJSON.c @@ -3023,6 +3023,17 @@ CJSON_PUBLIC(cJSON_Context) cJSON_AllowDataAfterJson(cJSON_Context context, cJSO return context; } +CJSON_PUBLIC(cJSON_Context) cJSON_MakeDuplicateRecursive(cJSON_Context context, cJSON_bool recursive) +{ + if (context == NULL) + { + return NULL; + } + + ((internal_context*)context)->duplicate_recursive = recursive; + return context; +} + static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const internal_context * const context) { if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) diff --git a/cJSON.h b/cJSON.h index 675594af..094785d7 100644 --- a/cJSON.h +++ b/cJSON.h @@ -174,6 +174,8 @@ CJSON_PUBLIC(cJSON_Context) cJSON_SetFormat(cJSON_Context context, cJSON_Format CJSON_PUBLIC(cJSON_Context) cJSON_MakeCaseSensitive(cJSON_Context context, cJSON_bool case_sensitive); /* Change if data is allowed after the JSON */ CJSON_PUBLIC(cJSON_Context) cJSON_AllowDataAfterJson(cJSON_Context context, cJSON_bool allow_data_after_json); +/* Change if cJSON_Duplicate copies recursively */ +CJSON_PUBLIC(cJSON_Context) cJSON_MakeDuplicateRecursive(cJSON_Context context, cJSON_bool recursive); /* Supply malloc and free functions to cJSON globally */ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); diff --git a/tests/context_tests.c b/tests/context_tests.c index 0e2aeaef..cbc3d6a5 100644 --- a/tests/context_tests.c +++ b/tests/context_tests.c @@ -241,6 +241,18 @@ static void allow_data_after_json_should_change_allow_data_after_json(void) free(context); } +static void make_duplicate_recursive_should_make_duplicate_recursive(void) +{ + internal_context *context = (internal_context*)cJSON_CreateContext(NULL, NULL); + TEST_ASSERT_NOT_NULL(context); + + context = (internal_context*)cJSON_MakeDuplicateRecursive(context, false); + TEST_ASSERT_NOT_NULL(context); + TEST_ASSERT_FALSE_MESSAGE(context->duplicate_recursive, "Duplicating is not set correctly."); + + free(context); +} + int main(void) { UNITY_BEGIN(); @@ -260,6 +272,7 @@ int main(void) RUN_TEST(set_format_should_set_format); RUN_TEST(make_case_sensitive_should_change_case_sensitivity); RUN_TEST(allow_data_after_json_should_change_allow_data_after_json); + RUN_TEST(make_duplicate_recursive_should_make_duplicate_recursive); return UNITY_END(); } From 1b001ab0475e792300b54498298196505ce19d37 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 4 Feb 2018 01:42:17 +0100 Subject: [PATCH 37/38] parse: Pull length calculation out. --- cJSON.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/cJSON.c b/cJSON.c index 442c3aca..e386dcfc 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1038,6 +1038,7 @@ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) buffer->offset++; } + /* step back if we went over the end */ if (buffer->offset == buffer->length) { buffer->offset--; @@ -1063,7 +1064,7 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) } /* Parse an object - create a new root, and populate. */ -static cJSON *parse(const char * const json, internal_context * const context) +static cJSON *parse(const char * const json, const size_t length, internal_context * const context) { parse_buffer buffer = { 0, 0, 0, 0, default_context }; cJSON *item = NULL; @@ -1078,7 +1079,7 @@ static cJSON *parse(const char * const json, internal_context * const context) } buffer.content = (const unsigned char*)json; - buffer.length = strlen(json) + sizeof(""); + buffer.length = length; buffer.offset = 0; buffer.context = *context; @@ -1113,7 +1114,6 @@ static cJSON *parse(const char * const json, internal_context * const context) delete_item(item, context); } - if (json != NULL) { error local_error; local_error.json = (const unsigned char*)json; @@ -1141,8 +1141,13 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *json, const char **return_ internal_context context = global_context; cJSON *item = NULL; + if (json == NULL) + { + return NULL; + } + context.allow_data_after_json = !require_null_terminated; - item = parse(json, &context); + item = parse(json, strlen((const char*)json) + sizeof(""), &context); if (return_parse_end != NULL) { @@ -1155,7 +1160,12 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *json, const char **return_ /* Default options for cJSON_Parse */ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *json) { - return parse(json, &global_context); + if (json == NULL) + { + return NULL; + } + + return parse(json, strlen((const char*)json) + sizeof(""), &global_context); } #define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) From 08738673be15861a7ec6a3f76027001a339ff96a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 25 Mar 2018 23:27:35 +0200 Subject: [PATCH 38/38] Reorder the context fields --- cJSON.c | 18 +++++++++--------- tests/misc_tests.c | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cJSON.c b/cJSON.c index e386dcfc..2862fd48 100644 --- a/cJSON.c +++ b/cJSON.c @@ -119,13 +119,13 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned typedef struct internal_context { size_t buffer_size; + size_t end_position; + void *userdata; + cJSON_Allocators allocators; cJSON_bool format; cJSON_bool allow_data_after_json; cJSON_bool case_sensitive; cJSON_bool duplicate_recursive; - cJSON_Allocators allocators; - void *userdata; - size_t end_position; } internal_context; #if defined(_MSC_VER) @@ -194,17 +194,17 @@ static void deallocate(const internal_context * const context, void *pointer) #define default_context {\ 256, /* default buffer size */\ - true, /* enable formatting by default */\ - true, /* allow data after the JSON by default */\ - true, /* case sensitive by default */\ - true, /* Do cJSON_Duplicate recursively by default */\ + 0, /* default end position */\ + NULL, /* no userdata */\ {\ malloc_wrapper,\ free_wrapper,\ realloc_wrapper\ },\ - NULL, /* no userdata */\ - 0 /* default end position */\ + true, /* enable formatting by default */\ + true, /* allow data after the JSON by default */\ + true, /* case sensitive by default */\ + true /* Do cJSON_Duplicate recursively by default */\ } /* this is necessary to assign the default context after initialization */ diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 57e9b2dc..8cb4f882 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -419,7 +419,7 @@ static void *failing_realloc(void *pointer, size_t size, void *userdata) static void ensure_should_fail_on_failed_realloc(void) { - printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, true, {malloc_wrapper, free_wrapper, failing_realloc}, NULL, 0 } }; + printbuffer buffer = {NULL, 10, 0, 0, false, {256, 0, NULL, {malloc_wrapper, free_wrapper, failing_realloc}, false, true, true, true} }; buffer.context.userdata = &buffer; buffer.buffer = (unsigned char*)malloc(100); TEST_ASSERT_NOT_NULL(buffer.buffer);