]> git.ipfire.org Git - thirdparty/json-c.git/commitdiff
json_pointer: split json_pointer_set_with_array_cb()
authorAlexandru Ardelean <ardeleanalex@gmail.com>
Fri, 23 Apr 2021 18:56:29 +0000 (21:56 +0300)
committerEric Hawicz <erh+git@nimenees.com>
Tue, 1 Aug 2023 02:17:30 +0000 (22:17 -0400)
JSON patch is a bit more clear on how some array operations should be
handled. Unfortunately, handling them on a case-by-case is a bit tricky
because it's difficult to satisfy properly an 'add' operating with a 'move'
operation and the basic json_pointer_set().

With json_pointer_set{f}() we use json_object_array_put_idx() to insert a
value at a certain index.

With JSON patch:
* for the 'add' operation, we need to insert a value at a given index,
  which means shifting existing values by one to the right
  - also, we cannot allow values to be inserted/added outside the bounds of
    the array
* a 'move' operation, is described as a 'remove' and then an 'add';
  for arrays this complicates things, because when we want to a move a
  value within the array, we have to remove it first (during which the size
  of the array is reduced by one); when the size of the array is reduced by
  one, we can't add it to the last position in the array (before the
  remove)

The only sane method to handle this (after a few considerations) is to
provide a callback to the function that does the final put/insert into
the array. That way, we can do some final checks where these are needed to
handle each corner-case.

Signed-off-by: Alexandru Ardelean <ardeleanalex@gmail.com>
json_object_private.h
json_pointer.c

index 3e60f648eebf8a5dea70e67d0180dad3d3ee7082..ff7bbef0a3338e0e3fd3896d4ae13a059108c03b 100644 (file)
@@ -112,6 +112,13 @@ struct json_pointer_get_result {
 int json_pointer_get_internal(struct json_object *obj, const char *path,
                               struct json_pointer_get_result *res);
 
+typedef int(*json_pointer_array_set_cb)(json_object *parent, size_t idx,
+                                        json_object *value, void *priv);
+
+int json_pointer_set_with_array_cb(struct json_object **obj, const char *path,
+                                   struct json_object *value,
+                                   json_pointer_array_set_cb array_set_cb, void *priv);
+
 #ifdef __cplusplus
 }
 #endif
index e834c3b514389cee08a7e04b942b2ae1f93d84f0..826025668a1e862e4f6dd684868229c5beb52136 100644 (file)
@@ -119,8 +119,15 @@ static int json_pointer_get_single_path(struct json_object *obj, char *path,
        return 0;
 }
 
+static int json_object_array_put_idx_cb(struct json_object *parent, size_t idx,
+                                       struct json_object *value, void *priv)
+{
+       return json_object_array_put_idx(parent, idx, value);
+}
+
 static int json_pointer_set_single_path(struct json_object *parent, const char *path,
-                                        struct json_object *value)
+                                        struct json_object *value,
+                                       json_pointer_array_set_cb array_set_cb, void *priv)
 {
        if (json_object_is_type(parent, json_type_array))
        {
@@ -130,7 +137,7 @@ static int json_pointer_set_single_path(struct json_object *parent, const char *
                        return json_object_array_add(parent, value);
                if (!is_valid_index(path, &idx))
                        return -1;
-               return json_object_array_put_idx(parent, idx, value);
+               return array_set_cb(parent, idx, value, priv);
        }
 
        /* path replacements should have been done in json_pointer_get_single_path(),
@@ -291,7 +298,9 @@ out:
        return rc;
 }
 
-int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value)
+int json_pointer_set_with_array_cb(struct json_object **obj, const char *path,
+                                  struct json_object *value,
+                                  json_pointer_array_set_cb array_set_cb, void *priv)
 {
        const char *endp;
        char *path_copy = NULL;
@@ -321,7 +330,7 @@ int json_pointer_set(struct json_object **obj, const char *path, struct json_obj
        if ((endp = strrchr(path, '/')) == path)
        {
                path++;
-               return json_pointer_set_single_path(*obj, path, value);
+               return json_pointer_set_single_path(*obj, path, value, array_set_cb, priv);
        }
 
        /* pass a working copy to the recursive call */
@@ -338,7 +347,12 @@ int json_pointer_set(struct json_object **obj, const char *path, struct json_obj
                return rc;
 
        endp++;
-       return json_pointer_set_single_path(set, endp, value);
+       return json_pointer_set_single_path(set, endp, value, array_set_cb, priv);
+}
+
+int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value)
+{
+       return json_pointer_set_with_array_cb(obj, path, value, json_object_array_put_idx_cb, NULL);
 }
 
 int json_pointer_setf(struct json_object **obj, struct json_object *value, const char *path_fmt,
@@ -393,7 +407,8 @@ int json_pointer_setf(struct json_object **obj, struct json_object *value, const
 
 set_single_path:
        endp++;
-       rc = json_pointer_set_single_path(set, endp, value);
+       rc = json_pointer_set_single_path(set, endp, value,
+                                         json_object_array_put_idx_cb, NULL);
 out:
        free(path_copy);
        return rc;