mirror of
https://github.com/json-c/json-c.git
synced 2026-04-06 22:09:06 +08:00
json_object: implement json_object_deep_copy()
Because doing `json_tokener_parse(json_object_get_string(src))` feels sloppy, dirty, and makes me want to cry at night sometimes. Signed-off-by: Alexandru Ardelean <ardeleanalex@gmail.com>
This commit is contained in:
103
json_object.c
103
json_object.c
@@ -1313,3 +1313,106 @@ int json_object_equal(struct json_object* jso1, struct json_object* jso2)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int json_object_copy_serializer_data(struct json_object *src, struct json_object *dst)
|
||||||
|
{
|
||||||
|
/* FIXME: this is shared between copies ; maybe add a `_user_copy` cb here */
|
||||||
|
dst->_userdata = src->_userdata;
|
||||||
|
dst->_to_json_string = src->_to_json_string;
|
||||||
|
dst->_user_delete = src->_user_delete;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int json_object_deep_copy_recursive(struct json_object *src, struct json_object **dst)
|
||||||
|
{
|
||||||
|
struct json_object *jso = NULL;
|
||||||
|
struct json_object_iter iter;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (!src || !dst) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (src->o_type) {
|
||||||
|
case json_type_boolean:
|
||||||
|
*dst = json_object_new_boolean(src->o.c_boolean);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_type_double:
|
||||||
|
*dst = json_object_new_double(src->o.c_double);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_type_int:
|
||||||
|
*dst = json_object_new_int64(src->o.c_int64);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_type_string:
|
||||||
|
*dst = json_object_new_string(get_string_component(src));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_type_object:
|
||||||
|
*dst = json_object_new_object();
|
||||||
|
if (!*dst) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
json_object_object_foreachC(src, iter) {
|
||||||
|
/* This handles the `json_type_null` case */
|
||||||
|
if (!iter.val)
|
||||||
|
jso = NULL;
|
||||||
|
else if (json_object_deep_copy_recursive(iter.val, &jso) < 0)
|
||||||
|
return -1;
|
||||||
|
if (json_object_object_add(*dst, iter.key, jso) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case json_type_array:
|
||||||
|
*dst = json_object_new_array();
|
||||||
|
if (!*dst) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (i = 0; i < json_object_array_length(src); i++) {
|
||||||
|
struct json_object *jso1 = json_object_array_get_idx(src, i);
|
||||||
|
/* This handles the `json_type_null` case */
|
||||||
|
if (!jso1)
|
||||||
|
jso = NULL;
|
||||||
|
else if (json_object_deep_copy_recursive(jso1, &jso) < 0)
|
||||||
|
return -1;
|
||||||
|
if (json_object_array_add(*dst, jso) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* errno should be set by the function that faulted */
|
||||||
|
if (!*dst)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return json_object_copy_serializer_data(src, *dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_object_deep_copy(struct json_object *src, struct json_object **dst)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Check if arguments are sane ; *dst must not point to a non-NULL object */
|
||||||
|
if (!src || !dst || *dst) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = json_object_deep_copy_recursive(src, dst);
|
||||||
|
if (rc < 0) {
|
||||||
|
json_object_put(*dst);
|
||||||
|
*dst = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -979,6 +979,24 @@ JSON_EXPORT int json_object_set_string_len(json_object* obj, const char* new_val
|
|||||||
JSON_EXPORT int json_object_equal(struct json_object *obj1,
|
JSON_EXPORT int json_object_equal(struct json_object *obj1,
|
||||||
struct json_object *obj2);
|
struct json_object *obj2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the contents of the JSON object.
|
||||||
|
* The destination object must be initialized to NULL,
|
||||||
|
* to make sure this function won't overwrite an existing JSON object.
|
||||||
|
*
|
||||||
|
* This does roughly the same thing as
|
||||||
|
* `json_tokener_parse(json_object_get_string(src))`.
|
||||||
|
*
|
||||||
|
* @param src source JSON object whose contents will be copied
|
||||||
|
* @param dst pointer to the destination object where the contents of `src`;
|
||||||
|
* make sure this pointer is initialized to NULL
|
||||||
|
*
|
||||||
|
* @returns 0 if the copy went well, -1 if an error occured during copy
|
||||||
|
* or if the destination pointer is non-NULL
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern int json_object_deep_copy(struct json_object *src, struct json_object **dst);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user