From: Alexandru Ardelean Date: Fri, 16 Jun 2017 07:05:32 +0000 (+0300) Subject: json_object: implement json_object_deep_copy() X-Git-Tag: json-c-0.13-20171207~22^2^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bf80d5ad0ed3b34c54d6fce47edb16ed704f47bc;p=thirdparty%2Fjson-c.git 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 --- diff --git a/json_object.c b/json_object.c index df20de15..3099c277 100644 --- a/json_object.c +++ b/json_object.c @@ -1313,3 +1313,106 @@ int json_object_equal(struct json_object* jso1, struct json_object* jso2) 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; +} + diff --git a/json_object.h b/json_object.h index 1f452869..852de383 100644 --- a/json_object.h +++ b/json_object.h @@ -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, 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 } #endif