소스 검색

Context: Add duplicate_recursive for cJSON_Duplicate

Max Bruckner 7 년 전
부모
커밋
e8f56bd194
3개의 변경된 파일31개의 추가작업 그리고 17개의 파일을 삭제
  1. 29 16
      cJSON.c
  2. 1 0
      tests/context_tests.c
  3. 1 1
      tests/misc_tests.c

+ 29 - 16
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;

+ 1 - 0
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.");

+ 1 - 1
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);