|
|
@ -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; |
|
|
|