]> git.ipfire.org Git - thirdparty/json-c.git/commitdiff
json_pointer: introduce json_pointer_get_internal() for internal usage
authorAlexandru Ardelean <ardeleanalex@gmail.com>
Tue, 20 Apr 2021 13:23:47 +0000 (16:23 +0300)
committerEric Hawicz <erh+git@nimenees.com>
Tue, 1 Aug 2023 02:17:30 +0000 (22:17 -0400)
For JSON patch, we require that we get access to the parent of a JSON
object as well in order to do some operations via the API.

For example, given the object:
{
  "foo": "bar",
  "array", [ 1, 2, 3]
}

Using JSON pointer with the path
 * '/foo' will return 'bar' of type string
 * '/array/0' will return '1', of type integer

The problem is, that if we do 'json_object_put()' on any of the objects
above, this will not detach them from the parent, because there is no
information back to the parent.

One way to fix this, is to introduce links back to the parent, and have
these links be made by 'json_object_array_{put,insert}_idx()' and
'json_object_object_add{_ex}()'[1].

[1] For json_object_object_add_ex() we would need to de-constify the second
parameter, as we need to change it's internal state when being added to a
parent object. It may break some applications, but who knows.

But, since this information is needed mostly for JSON patch, another way to
address this, is to also retrieve the parent of an object via JSON pointer
and use json_object_object_del() and json_object_array_del_idx() on the
object's parent.

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

index de1fdeb3c97fd96d3dba97589feeddc9926d6f58..ab96eccc9036bad94ed94ee67c62c0de9449da96 100644 (file)
@@ -18,6 +18,7 @@ JSONC_PRIVATE {
     array_list_new;
     array_list_put_idx;
     array_list_sort;
+    json_pointer_get_internal;
     json_hex_chars;
     json_parse_double;
     json_parse_int64;
index e143b4649acdd8e8815aab0fbed5e36506c95a9d..3e60f648eebf8a5dea70e67d0180dad3d3ee7082 100644 (file)
@@ -100,6 +100,18 @@ void _json_c_set_last_err(const char *err_fmt, ...);
 
 extern const char *json_hex_chars;
 
+struct json_pointer_get_result {
+       struct json_object *parent;
+       struct json_object *obj;
+       union {
+               const char *key;
+               uint32_t index;
+       } id;
+};
+
+int json_pointer_get_internal(struct json_object *obj, const char *path,
+                              struct json_pointer_get_result *res);
+
 #ifdef __cplusplus
 }
 #endif
index 15f502619715023932573600ccd9e240aa0d15ea..f04b487ccc236a37779fe04b21884ca506789837 100644 (file)
@@ -15,6 +15,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "json_object_private.h"
 #include "json_pointer.h"
 #include "strdup_compat.h"
 #include "vasprintf_compat.h"
@@ -88,14 +89,13 @@ check_oob:
 }
 
 static int json_pointer_get_single_path(struct json_object *obj, char *path,
-                                        struct json_object **value)
+                                        struct json_object **value, size_t *idx)
 {
        if (json_object_is_type(obj, json_type_array))
        {
-               size_t idx;
-               if (!is_valid_index(obj, path, &idx))
+               if (!is_valid_index(obj, path, idx))
                        return -1;
-               obj = json_object_array_get_idx(obj, idx);
+               obj = json_object_array_get_idx(obj, *idx);
                if (obj)
                {
                        if (value)
@@ -147,9 +147,11 @@ static int json_pointer_set_single_path(struct json_object *parent, const char *
        return -1;
 }
 
-static int json_pointer_get_recursive(struct json_object *obj, char *path,
-                                      struct json_object **value)
+static int json_pointer_result_get_recursive(struct json_object *obj, char *path,
+                                             struct json_pointer_get_result *res)
 {
+       struct json_object *parent_obj = obj;
+       size_t idx;
        char *endp;
        int rc;
 
@@ -166,24 +168,47 @@ static int json_pointer_get_recursive(struct json_object *obj, char *path,
                *endp = '\0';
 
        /* If we err-ed here, return here */
-       if ((rc = json_pointer_get_single_path(obj, path, &obj)))
+       if ((rc = json_pointer_get_single_path(obj, path, &obj, &idx)))
                return rc;
 
        if (endp)
        {
                /* Put the slash back, so that the sanity check passes on next recursion level */
                *endp = '/';
-               return json_pointer_get_recursive(obj, endp, value);
+               return json_pointer_result_get_recursive(obj, endp, res);
        }
 
        /* We should be at the end of the recursion here */
+       if (res) {
+               res->parent = parent_obj;
+               res->obj = obj;
+               if (json_object_is_type(res->parent, json_type_array))
+                       res->id.index = idx;
+               else
+                       res->id.key = path;
+       }
+
+       return 0;
+}
+
+static int json_pointer_object_get_recursive(struct json_object *obj, char *path,
+                                             struct json_object **value)
+{
+       struct json_pointer_get_result res;
+       int rc;
+
+       rc = json_pointer_result_get_recursive(obj, path, &res);
+       if (rc)
+               return rc;
+
        if (value)
-               *value = obj;
+               *value = res.obj;
 
        return 0;
 }
 
-int json_pointer_get(struct json_object *obj, const char *path, struct json_object **res)
+int json_pointer_get_internal(struct json_object *obj, const char *path,
+                              struct json_pointer_get_result *res)
 {
        char *path_copy = NULL;
        int rc;
@@ -196,8 +221,11 @@ int json_pointer_get(struct json_object *obj, const char *path, struct json_obje
 
        if (path[0] == '\0')
        {
-               if (res)
-                       *res = obj;
+               if (res) {
+                       res->parent = NULL;
+                       res->obj = obj;
+               }
+               res->id.key = NULL;
                return 0;
        }
 
@@ -207,12 +235,30 @@ int json_pointer_get(struct json_object *obj, const char *path, struct json_obje
                errno = ENOMEM;
                return -1;
        }
-       rc = json_pointer_get_recursive(obj, path_copy, res);
+       rc = json_pointer_result_get_recursive(obj, path_copy, res);
+       /* re-map the path string to the const-path string */
+       if (rc == 0 && res->id.key && !json_object_is_type(res->parent, json_type_array))
+               res->id.key = path + (res->id.key - path_copy);
        free(path_copy);
 
        return rc;
 }
 
+int json_pointer_get(struct json_object *obj, const char *path, struct json_object **res)
+{
+       struct json_pointer_get_result jpres;
+       int rc;
+
+       rc = json_pointer_get_internal(obj, path, &jpres);
+       if (rc)
+               return rc;
+
+       if (res)
+               *res = jpres.obj;
+
+       return 0;
+}
+
 int json_pointer_getf(struct json_object *obj, struct json_object **res, const char *path_fmt, ...)
 {
        char *path_copy = NULL;
@@ -239,7 +285,7 @@ int json_pointer_getf(struct json_object *obj, struct json_object **res, const c
                goto out;
        }
 
-       rc = json_pointer_get_recursive(obj, path_copy, res);
+       rc = json_pointer_object_get_recursive(obj, path_copy, res);
 out:
        free(path_copy);
 
@@ -286,7 +332,7 @@ int json_pointer_set(struct json_object **obj, const char *path, struct json_obj
                return -1;
        }
        path_copy[endp - path] = '\0';
-       rc = json_pointer_get_recursive(*obj, path_copy, &set);
+       rc = json_pointer_object_get_recursive(*obj, path_copy, &set);
        free(path_copy);
 
        if (rc)
@@ -341,7 +387,7 @@ int json_pointer_setf(struct json_object **obj, struct json_object *value, const
        }
 
        *endp = '\0';
-       rc = json_pointer_get_recursive(*obj, path_copy, &set);
+       rc = json_pointer_object_get_recursive(*obj, path_copy, &set);
 
        if (rc)
                goto out;