Browse Source

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 <ardeleanalex@gmail.com>
tags/json-c-0.17-20230812
Alexandru Ardelean Eric Hawicz 4 years ago
parent
commit
5a46a3b76d
3 changed files with 75 additions and 16 deletions
  1. +1
    -0
      json-c.sym
  2. +12
    -0
      json_object_private.h
  3. +62
    -16
      json_pointer.c

+ 1
- 0
json-c.sym View File

@@ -18,6 +18,7 @@ JSONC_PRIVATE {
array_list_new; array_list_new;
array_list_put_idx; array_list_put_idx;
array_list_sort; array_list_sort;
json_pointer_get_internal;
json_hex_chars; json_hex_chars;
json_parse_double; json_parse_double;
json_parse_int64; json_parse_int64;


+ 12
- 0
json_object_private.h View File

@@ -100,6 +100,18 @@ void _json_c_set_last_err(const char *err_fmt, ...);


extern const char *json_hex_chars; 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 #ifdef __cplusplus
} }
#endif #endif


+ 62
- 16
json_pointer.c View File

@@ -15,6 +15,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>


#include "json_object_private.h"
#include "json_pointer.h" #include "json_pointer.h"
#include "strdup_compat.h" #include "strdup_compat.h"
#include "vasprintf_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, 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)) 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; return -1;
obj = json_object_array_get_idx(obj, idx);
obj = json_object_array_get_idx(obj, *idx);
if (obj) if (obj)
{ {
if (value) if (value)
@@ -147,9 +147,11 @@ static int json_pointer_set_single_path(struct json_object *parent, const char *
return -1; 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; char *endp;
int rc; int rc;


@@ -166,24 +168,47 @@ static int json_pointer_get_recursive(struct json_object *obj, char *path,
*endp = '\0'; *endp = '\0';


/* If we err-ed here, return here */ /* 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; return rc;


if (endp) if (endp)
{ {
/* Put the slash back, so that the sanity check passes on next recursion level */ /* Put the slash back, so that the sanity check passes on next recursion level */
*endp = '/'; *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 */ /* 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) if (value)
*value = obj;
*value = res.obj;


return 0; 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; char *path_copy = NULL;
int rc; 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 (path[0] == '\0')
{ {
if (res)
*res = obj;
if (res) {
res->parent = NULL;
res->obj = obj;
}
res->id.key = NULL;
return 0; return 0;
} }


@@ -207,12 +235,30 @@ int json_pointer_get(struct json_object *obj, const char *path, struct json_obje
errno = ENOMEM; errno = ENOMEM;
return -1; 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); free(path_copy);


return rc; 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, ...) int json_pointer_getf(struct json_object *obj, struct json_object **res, const char *path_fmt, ...)
{ {
char *path_copy = NULL; char *path_copy = NULL;
@@ -239,7 +285,7 @@ int json_pointer_getf(struct json_object *obj, struct json_object **res, const c
goto out; goto out;
} }


rc = json_pointer_get_recursive(obj, path_copy, res);
rc = json_pointer_object_get_recursive(obj, path_copy, res);
out: out:
free(path_copy); free(path_copy);


@@ -286,7 +332,7 @@ int json_pointer_set(struct json_object **obj, const char *path, struct json_obj
return -1; return -1;
} }
path_copy[endp - path] = '\0'; 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); free(path_copy);


if (rc) if (rc)
@@ -341,7 +387,7 @@ int json_pointer_setf(struct json_object **obj, struct json_object *value, const
} }


*endp = '\0'; *endp = '\0';
rc = json_pointer_get_recursive(*obj, path_copy, &set);
rc = json_pointer_object_get_recursive(*obj, path_copy, &set);


if (rc) if (rc)
goto out; goto out;


Loading…
Cancel
Save