Context: Add duplicate_recursive for cJSON_Duplicate

This commit is contained in:
Max Bruckner 2018-02-03 17:27:50 +01:00
parent 064eec8208
commit e8f56bd194
3 changed files with 31 additions and 17 deletions

45
cJSON.c
View File

@ -122,6 +122,7 @@ typedef struct internal_context
cJSON_bool format; cJSON_bool format;
cJSON_bool allow_data_after_json; cJSON_bool allow_data_after_json;
cJSON_bool case_sensitive; cJSON_bool case_sensitive;
cJSON_bool duplicate_recursive;
cJSON_Allocators allocators; cJSON_Allocators allocators;
void *userdata; void *userdata;
size_t end_position; size_t end_position;
@ -196,6 +197,7 @@ static void deallocate(const internal_context * const context, void *pointer)
true, /* enable formatting by default */\ true, /* enable formatting by default */\
true, /* allow data after the JSON by default */\ true, /* allow data after the JSON by default */\
true, /* case sensitive by default */\ true, /* case sensitive by default */\
true, /* Do cJSON_Duplicate recursively by default */\
{\ {\
malloc_wrapper,\ malloc_wrapper,\
free_wrapper,\ free_wrapper,\
@ -2637,56 +2639,60 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
return a; return a;
} }
/* Duplication */ static cJSON *duplicate_json(const cJSON *item, const internal_context * const context)
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
{ {
cJSON *newitem = NULL; cJSON *newitem = NULL;
cJSON *child = NULL; cJSON *child = NULL;
cJSON *next = NULL; cJSON *next = NULL;
cJSON *newchild = NULL; cJSON *newchild = NULL;
/* Bail on bad ptr */ if (item == NULL)
if (!item)
{ {
goto fail; goto fail;
} }
/* Create new item */
newitem = create_item(&global_context); newitem = create_item(context);
if (!newitem) if (newitem == NULL)
{ {
goto fail; goto fail;
} }
/* Copy over all vars */ /* Copy over all vars */
newitem->type = item->type & (~cJSON_IsReference); newitem->type = item->type & (~cJSON_IsReference);
newitem->valueint = item->valueint; newitem->valueint = item->valueint;
newitem->valuedouble = item->valuedouble; newitem->valuedouble = item->valuedouble;
if (item->valuestring)
if (item->valuestring != NULL)
{ {
newitem->valuestring = (char*)custom_strdup((unsigned char*)item->valuestring, &global_context); newitem->valuestring = (char*)custom_strdup((unsigned char*)item->valuestring, context);
if (!newitem->valuestring) if (newitem->valuestring == NULL)
{ {
goto fail; 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) if (!newitem->string)
{ {
goto fail; goto fail;
} }
} }
/* If non-recursive, then we're done! */ /* If non-recursive, then we're done! */
if (!recurse) if (!context->duplicate_recursive)
{ {
return newitem; return newitem;
} }
/* Walk the ->next chain for the child. */ /* Walk the ->next chain for the child. */
child = item->child; child = item->child;
while (child != NULL) while (child != NULL)
{ {
newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ /* Each item in the ->next chain */
if (!newchild) newchild = duplicate_json(child, context);
if (newchild == NULL)
{ {
goto fail; goto fail;
} }
@ -2711,12 +2717,19 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
fail: fail:
if (newitem != NULL) if (newitem != NULL)
{ {
delete_item(newitem, &global_context); delete_item(newitem, context);
} }
return NULL; 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) CJSON_PUBLIC(void) cJSON_Minify(char *json)
{ {
unsigned char *into = (unsigned char*)json; unsigned char *into = (unsigned char*)json;

View File

@ -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->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_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_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(malloc_wrapper == context->allocators.allocate, "Wrong malloc.");
TEST_ASSERT_TRUE_MESSAGE(realloc_wrapper == context->allocators.reallocate, "Wrong realloc."); TEST_ASSERT_TRUE_MESSAGE(realloc_wrapper == context->allocators.reallocate, "Wrong realloc.");
TEST_ASSERT_TRUE_MESSAGE(free_wrapper == context->allocators.deallocate, "Wrong free."); TEST_ASSERT_TRUE_MESSAGE(free_wrapper == context->allocators.deallocate, "Wrong free.");

View File

@ -419,7 +419,7 @@ static void *failing_realloc(void *pointer, size_t size, void *userdata)
static void ensure_should_fail_on_failed_realloc(void) 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.context.userdata = &buffer;
buffer.buffer = (unsigned char*)malloc(100); buffer.buffer = (unsigned char*)malloc(100);
TEST_ASSERT_NOT_NULL(buffer.buffer); TEST_ASSERT_NOT_NULL(buffer.buffer);