From e8f56bd194d19b49e375e67beae12d19b56b3db8 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 3 Feb 2018 17:27:50 +0100 Subject: [PATCH] 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 d3e4131..72bd852 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 e6e552f..0e2aeae 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 3fc2ef6..57e9b2d 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);