diff --git a/json-c.sym b/json-c.sym index de1fdeb..ab96ecc 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 e143b46..3e60f64 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 15f5026..f04b487 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;