Selaa lähdekoodia

refactor cJSONUtils_ApplyPatch

Max Bruckner 8 vuotta sitten
vanhempi
commit
48c97985d6
1 muutettua tiedostoa jossa 143 lisäystä ja 110 poistoa
  1. 143 110
      cJSON_Utils.c

+ 143 - 110
cJSON_Utils.c

@@ -533,54 +533,100 @@ static cJSON_bool insert_item_in_array(cJSON *array, size_t which, cJSON *newite
 
 enum patch_operation { INVALID, ADD, REMOVE, REPLACE, MOVE, COPY, TEST };
 
-static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
+static enum patch_operation decode_patch_operation(const cJSON * const patch)
 {
-    cJSON *op = NULL;
-    cJSON *path = NULL;
-    cJSON *value = NULL;
-    cJSON *parent = NULL;
-    enum patch_operation opcode = INVALID;
-    unsigned char *parentptr = NULL;
-    unsigned char *childptr = NULL;
+    cJSON *operation = cJSON_GetObjectItem(patch, "op");
+    if (!cJSON_IsString(operation))
+    {
+        return INVALID;
+    }
 
-    op = cJSON_GetObjectItem(patch, "op");
-    path = cJSON_GetObjectItem(patch, "path");
-    if (!cJSON_IsString(op) || !cJSON_IsString(path))
+    if (strcmp(operation->valuestring, "add") == 0)
     {
-        /* malformed patch. */
-        return 2;
+        return ADD;
     }
 
-    /* decode operation */
-    if (!strcmp(op->valuestring, "add"))
+    if (strcmp(operation->valuestring, "remove") == 0)
     {
-        opcode = ADD;
+        return REMOVE;
     }
-    else if (!strcmp(op->valuestring, "remove"))
+
+    if (strcmp(operation->valuestring, "replace") == 0)
     {
-        opcode = REMOVE;
+        return REPLACE;
     }
-    else if (!strcmp(op->valuestring, "replace"))
+
+    if (strcmp(operation->valuestring, "move") == 0)
     {
-        opcode = REPLACE;
+        return MOVE;
     }
-    else if (!strcmp(op->valuestring, "move"))
+
+    if (strcmp(operation->valuestring, "copy") == 0)
     {
-        opcode = MOVE;
+        return COPY;
     }
-    else if (!strcmp(op->valuestring, "copy"))
+
+    if (strcmp(operation->valuestring, "test") == 0)
     {
-        opcode = COPY;
+        return TEST;
     }
-    else if (!strcmp(op->valuestring, "test"))
+
+    return INVALID;
+}
+
+/* overwrite and existing item with another one and free resources on the way */
+static void overwrite_item(cJSON * const root, const cJSON replacement)
+{
+    if (root == NULL)
     {
-        /* compare value: {...} with the given path */
-        return cJSONUtils_Compare(cJSONUtils_GetPointer(object, path->valuestring), cJSON_GetObjectItem(patch, "value"));
+        return;
     }
-    else
+
+    if (root->string != NULL)
+    {
+        cJSON_free(root->string);
+    }
+    if (root->valuestring != NULL)
+    {
+        cJSON_free(root->valuestring);
+    }
+    if (root->child != NULL)
+    {
+        cJSON_Delete(root->child);
+    }
+
+    memcpy(root, &replacement, sizeof(cJSON));
+}
+
+static int cJSONUtils_ApplyPatch(cJSON *object, const cJSON *patch)
+{
+    cJSON *path = NULL;
+    cJSON *value = NULL;
+    cJSON *parent = NULL;
+    enum patch_operation opcode = INVALID;
+    unsigned char *parent_pointer = NULL;
+    unsigned char *child_pointer = NULL;
+    int status = 0;
+
+    path = cJSON_GetObjectItem(patch, "path");
+    if (!cJSON_IsString(path))
     {
-        /* unknown opcode. */
-        return 3;
+        /* malformed patch. */
+        status = 2;
+        goto cleanup;
+    }
+
+    opcode = decode_patch_operation(patch);
+    if (opcode == INVALID)
+    {
+        status = 3;
+        goto cleanup;
+    }
+    else if (opcode == TEST)
+    {
+        /* compare value: {...} with the given path */
+        status = cJSONUtils_Compare(cJSONUtils_GetPointer(object, path->valuestring), cJSON_GetObjectItem(patch, "value"));
+        goto cleanup;
     }
 
     /* special case for replacing the root */
@@ -588,73 +634,47 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
     {
         if (opcode == REMOVE)
         {
-            /* remove possible children */
-            if (object->child != NULL)
-            {
-                cJSON_Delete(object->child);
-            }
+            static const cJSON invalid = { NULL, NULL, NULL, cJSON_Invalid, NULL, 0, 0, NULL};
 
-            /* remove other allocated resources */
-            if (object->string != NULL)
-            {
-                cJSON_free(object->string);
-            }
-            if (object->valuestring != NULL)
-            {
-                cJSON_free(object->valuestring);
-            }
-
-            /* make it invalid */
-            memset(object, '\0', sizeof(cJSON));
+            overwrite_item(object, invalid);
 
-            return 0;
+            status = 0;
+            goto cleanup;
         }
 
         if ((opcode == REPLACE) || (opcode == ADD))
         {
-            /* remove possible children */
-            if (object->child != NULL)
-            {
-                cJSON_Delete(object->child);
-            }
-
-            /* remove other allocated resources */
-            if (object->string != NULL)
-            {
-                cJSON_free(object->string);
-            }
-            if (object->valuestring != NULL)
-            {
-                cJSON_free(object->valuestring);
-            }
-
             value = cJSON_GetObjectItem(patch, "value");
             if (value == NULL)
             {
                 /* missing "value" for add/replace. */
-                return 7;
+                status = 7;
+                goto cleanup;
             }
 
             value = cJSON_Duplicate(value, 1);
             if (value == NULL)
             {
                 /* out of memory for add/replace. */
-                return 8;
-            }
-            /* the string "value" isn't needed */
-            if (value->string != NULL)
-            {
-                cJSON_free(value->string);
-                value->string = NULL;
+                status = 8;
+                goto cleanup;
             }
 
-            /* copy over the value object */
-            memcpy(object, value, sizeof(cJSON));
+            overwrite_item(object, *value);
 
             /* delete the duplicated value */
             cJSON_free(value);
+            value = NULL;
 
-            return 0;
+            /* the string "value" isn't needed */
+            if (object->string != NULL)
+            {
+                cJSON_free(object->string);
+                object->string = NULL;
+            }
+
+            status = 0;
+            goto cleanup;
         }
     }
 
@@ -664,13 +684,15 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
         cJSON *old_item = cJSONUtils_PatchDetach(object, (unsigned char*)path->valuestring);
         if (old_item == NULL)
         {
-            return 13;
+            status = 13;
+            goto cleanup;
         }
         cJSON_Delete(old_item);
         if (opcode == REMOVE)
         {
             /* For Remove, this job is done. */
-            return 0;
+            status = 0;
+            goto cleanup;
         }
     }
 
@@ -678,10 +700,11 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
     if ((opcode == MOVE) || (opcode == COPY))
     {
         cJSON *from = cJSON_GetObjectItem(patch, "from");
-        if (!from)
+        if (from == NULL)
         {
             /* missing "from" for copy/move. */
-            return 4;
+            status = 4;
+            goto cleanup;
         }
 
         if (opcode == MOVE)
@@ -692,93 +715,103 @@ static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch)
         {
             value = cJSONUtils_GetPointer(object, from->valuestring);
         }
-        if (!value)
+        if (value == NULL)
         {
             /* missing "from" for copy/move. */
-            return 5;
+            status = 5;
+            goto cleanup;
         }
         if (opcode == COPY)
         {
             value = cJSON_Duplicate(value, 1);
         }
-        if (!value)
+        if (value == NULL)
         {
             /* out of memory for copy/move. */
-            return 6;
+            status = 6;
+            goto cleanup;
         }
     }
     else /* Add/Replace uses "value". */
     {
         value = cJSON_GetObjectItem(patch, "value");
-        if (!value)
+        if (value == NULL)
         {
             /* missing "value" for add/replace. */
-            return 7;
+            status = 7;
+            goto cleanup;
         }
         value = cJSON_Duplicate(value, 1);
-        if (!value)
+        if (value == NULL)
         {
             /* out of memory for add/replace. */
-            return 8;
+            status = 8;
+            goto cleanup;
         }
     }
 
     /* Now, just add "value" to "path". */
 
     /* split pointer in parent and child */
-    parentptr = cJSONUtils_strdup((unsigned char*)path->valuestring);
-    childptr = (unsigned char*)strrchr((char*)parentptr, '/');
-    if (childptr)
+    parent_pointer = cJSONUtils_strdup((unsigned char*)path->valuestring);
+    child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/');
+    if (child_pointer != NULL)
     {
-        *childptr++ = '\0';
+        child_pointer[0] = '\0';
+        child_pointer++;
     }
-    parent = cJSONUtils_GetPointer(object, (char*)parentptr);
-    cJSONUtils_InplaceDecodePointerString(childptr);
+    parent = cJSONUtils_GetPointer(object, (char*)parent_pointer);
+    cJSONUtils_InplaceDecodePointerString(child_pointer);
 
     /* add, remove, replace, move, copy, test. */
-    if ((parent == NULL) || (childptr == NULL))
+    if ((parent == NULL) || (child_pointer == NULL))
     {
         /* Couldn't find object to add to. */
-        free(parentptr);
-        cJSON_Delete(value);
-        return 9;
+        status = 9;
+        goto cleanup;
     }
     else if (cJSON_IsArray(parent))
     {
-        if (!strcmp((char*)childptr, "-"))
+        if (strcmp((char*)child_pointer, "-") == 0)
         {
             cJSON_AddItemToArray(parent, value);
+            value = NULL;
         }
         else
         {
             size_t index = 0;
-            if (!decode_array_index_from_pointer(childptr, &index))
+            if (!decode_array_index_from_pointer(child_pointer, &index))
             {
-                free(parentptr);
-                cJSON_Delete(value);
-                return 11;
+                status = 11;
+                goto cleanup;
             }
 
             if (!insert_item_in_array(parent, index, value))
             {
-                free(parentptr);
-                cJSON_Delete(value);
-                return 10;
+                status = 10;
+                goto cleanup;
             }
+            value = NULL;
         }
     }
     else if (cJSON_IsObject(parent))
     {
-        cJSON_DeleteItemFromObject(parent, (char*)childptr);
-        cJSON_AddItemToObject(parent, (char*)childptr, value);
+        cJSON_DeleteItemFromObject(parent, (char*)child_pointer);
+        cJSON_AddItemToObject(parent, (char*)child_pointer, value);
+        value = NULL;
     }
-    else
+
+cleanup:
+    if (value != NULL)
     {
         cJSON_Delete(value);
     }
-    free(parentptr);
+    if (parent_pointer != NULL)
+    {
+        cJSON_free(parent_pointer);
+    }
 
-    return 0;
+    return status;
 }
 
 CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches)