From 5a46a3b76d774ab3f2d884462d4bd4c382f3e835 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Tue, 20 Apr 2021 16:23:47 +0300 Subject: [PATCH] json_pointer: introduce json_pointer_get_internal() for internal usage 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 --- json-c.sym | 1 + json_object_private.h | 12 +++++++ json_pointer.c | 78 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 75 insertions(+), 16 deletions(-) diff --git a/json-c.sym b/json-c.sym index de1fdeb3..ab96eccc 100644 --- a/json-c.sym +++ b/json-c.sym @@ -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; diff --git a/json_object_private.h b/json_object_private.h index e143b464..3e60f648 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -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 diff --git a/json_pointer.c b/json_pointer.c index 15f50261..f04b487c 100644 --- a/json_pointer.c +++ b/json_pointer.c @@ -15,6 +15,7 @@ #include #include +#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; -- 2.47.3