 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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago  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>
4 years ago |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- /*
- * Copyright (c) 2016 Alexandru Ardelean.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the MIT license. See COPYING for details.
- *
- */
-
- #include "config.h"
-
- #include "strerror_override.h"
-
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include "json_object_private.h"
- #include "json_pointer.h"
- #include "json_pointer_private.h"
- #include "strdup_compat.h"
- #include "vasprintf_compat.h"
-
- /* Avoid ctype.h and locale overhead */
- #define is_plain_digit(c) ((c) >= '0' && (c) <= '9')
-
- /**
- * JavaScript Object Notation (JSON) Pointer
- * RFC 6901 - https://tools.ietf.org/html/rfc6901
- */
-
- static void string_replace_all_occurrences_with_char(char *s, const char *occur, char repl_char)
- {
- size_t slen = strlen(s);
- size_t skip = strlen(occur) - 1; /* length of the occurrence, minus the char we're replacing */
- char *p = s;
- while ((p = strstr(p, occur)))
- {
- *p = repl_char;
- p++;
- slen -= skip;
- memmove(p, (p + skip), slen - (p - s) + 1); /* includes null char too */
- }
- }
-
- static int is_valid_index(const char *path, size_t *idx)
- {
- size_t i, len = strlen(path);
- /* this code-path optimizes a bit, for when we reference the 0-9 index range
- * in a JSON array and because leading zeros not allowed
- */
- if (len == 1)
- {
- if (is_plain_digit(path[0]))
- {
- *idx = (path[0] - '0');
- return 1;
- }
- errno = EINVAL;
- return 0;
- }
- /* leading zeros not allowed per RFC */
- if (path[0] == '0')
- {
- errno = EINVAL;
- return 0;
- }
- /* RFC states base-10 decimals */
- for (i = 0; i < len; i++)
- {
- if (!is_plain_digit(path[i]))
- {
- errno = EINVAL;
- return 0;
- }
- }
-
- // We know it's all digits, so the only error case here is overflow,
- // but ULLONG_MAX will be longer than any array length so that's ok.
- *idx = strtoull(path, NULL, 10);
-
- return 1;
- }
-
- static int json_pointer_get_single_path(struct json_object *obj, char *path,
- struct json_object **value, size_t *idx)
- {
- if (json_object_is_type(obj, json_type_array))
- {
- if (!is_valid_index(path, idx))
- return -1;
- if (*idx >= json_object_array_length(obj))
- {
- errno = ENOENT;
- return -1;
- }
-
- obj = json_object_array_get_idx(obj, *idx);
- if (obj)
- {
- if (value)
- *value = obj;
- return 0;
- }
- /* Entry not found */
- errno = ENOENT;
- return -1;
- }
-
- /* RFC states that we first must eval all ~1 then all ~0 */
- string_replace_all_occurrences_with_char(path, "~1", '/');
- string_replace_all_occurrences_with_char(path, "~0", '~');
-
- if (!json_object_object_get_ex(obj, path, value))
- {
- errno = ENOENT;
- return -1;
- }
-
- 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,
- json_pointer_array_set_cb array_set_cb, void *priv)
- {
- if (json_object_is_type(parent, json_type_array))
- {
- size_t idx;
- /* RFC (Chapter 4) states that '-' may be used to add new elements to an array */
- if (path[0] == '-' && path[1] == '\0')
- return json_object_array_add(parent, value);
- if (!is_valid_index(path, &idx))
- return -1;
- return array_set_cb(parent, idx, value, priv);
- }
-
- /* path replacements should have been done in json_pointer_get_single_path(),
- * and we should still be good here
- */
- if (json_object_is_type(parent, json_type_object))
- return json_object_object_add(parent, path, value);
-
- /* Getting here means that we tried to "dereference" a primitive JSON type
- * (like string, int, bool).i.e. add a sub-object to it
- */
- errno = ENOENT;
- return -1;
- }
-
- 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;
-
- /* All paths (on each recursion level must have a leading '/' */
- if (path[0] != '/')
- {
- errno = EINVAL;
- return -1;
- }
- path++;
-
- endp = strchr(path, '/');
- if (endp)
- *endp = '\0';
-
- /* If we err-ed here, return here */
- 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_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->index_in_parent = idx;
- else
- res->key_in_parent = 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 = res.obj;
-
- return 0;
- }
-
- int json_pointer_get_internal(struct json_object *obj, const char *path,
- struct json_pointer_get_result *res)
- {
- char *path_copy = NULL;
- int rc;
-
- if (!obj || !path)
- {
- errno = EINVAL;
- return -1;
- }
-
- if (path[0] == '\0')
- {
- res->parent = NULL;
- res->obj = obj;
- res->key_in_parent = NULL;
- res->index_in_parent = -1;
- return 0;
- }
-
- /* pass a working copy to the recursive call */
- if (!(path_copy = strdup(path)))
- {
- errno = ENOMEM;
- return -1;
- }
- rc = json_pointer_result_get_recursive(obj, path_copy, res);
- /* re-map the path string to the const-path string */
- if (rc == 0 && json_object_is_type(res->parent, json_type_object) && res->key_in_parent)
- res->key_in_parent = path + (res->key_in_parent - 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;
- int rc = 0;
- va_list args;
-
- if (!obj || !path_fmt)
- {
- errno = EINVAL;
- return -1;
- }
-
- va_start(args, path_fmt);
- rc = vasprintf(&path_copy, path_fmt, args);
- va_end(args);
-
- if (rc < 0)
- return rc;
-
- if (path_copy[0] == '\0')
- {
- if (res)
- *res = obj;
- goto out;
- }
-
- rc = json_pointer_object_get_recursive(obj, path_copy, res);
- out:
- free(path_copy);
-
- return rc;
- }
-
- 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;
- struct json_object *set = NULL;
- int rc;
-
- if (!obj || !path)
- {
- errno = EINVAL;
- return -1;
- }
-
- if (path[0] == '\0')
- {
- json_object_put(*obj);
- *obj = value;
- return 0;
- }
-
- if (path[0] != '/')
- {
- errno = EINVAL;
- return -1;
- }
-
- /* If there's only 1 level to set, stop here */
- if ((endp = strrchr(path, '/')) == path)
- {
- path++;
- return json_pointer_set_single_path(*obj, path, value, array_set_cb, priv);
- }
-
- /* pass a working copy to the recursive call */
- if (!(path_copy = strdup(path)))
- {
- errno = ENOMEM;
- return -1;
- }
- path_copy[endp - path] = '\0';
- rc = json_pointer_object_get_recursive(*obj, path_copy, &set);
- free(path_copy);
-
- if (rc)
- return rc;
-
- endp++;
- 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,
- ...)
- {
- char *endp;
- char *path_copy = NULL;
- struct json_object *set = NULL;
- va_list args;
- int rc = 0;
-
- if (!obj || !path_fmt)
- {
- errno = EINVAL;
- return -1;
- }
-
- /* pass a working copy to the recursive call */
- va_start(args, path_fmt);
- rc = vasprintf(&path_copy, path_fmt, args);
- va_end(args);
-
- if (rc < 0)
- return rc;
-
- if (path_copy[0] == '\0')
- {
- json_object_put(*obj);
- *obj = value;
- goto out;
- }
-
- if (path_copy[0] != '/')
- {
- errno = EINVAL;
- rc = -1;
- goto out;
- }
-
- /* If there's only 1 level to set, stop here */
- if ((endp = strrchr(path_copy, '/')) == path_copy)
- {
- set = *obj;
- goto set_single_path;
- }
-
- *endp = '\0';
- rc = json_pointer_object_get_recursive(*obj, path_copy, &set);
-
- if (rc)
- goto out;
-
- set_single_path:
- endp++;
- rc = json_pointer_set_single_path(set, endp, value,
- json_object_array_put_idx_cb, NULL);
- out:
- free(path_copy);
- return rc;
- }
|