mirror of
https://github.com/DaveGamble/cJSON.git
synced 2023-08-10 21:13:26 +03:00
Context: Add duplicate_recursive for cJSON_Duplicate
This commit is contained in:
parent
064eec8208
commit
e8f56bd194
45
cJSON.c
45
cJSON.c
@ -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;
|
||||||
|
@ -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.");
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user