]> git.ipfire.org Git - thirdparty/json-c.git/commitdiff
json_object: implement json_object_deep_copy()
authorAlexandru Ardelean <ardeleanalex@gmail.com>
Fri, 16 Jun 2017 07:05:32 +0000 (10:05 +0300)
committerAlexandru Ardelean <ardeleanalex@gmail.com>
Mon, 27 Nov 2017 14:17:48 +0000 (16:17 +0200)
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>
json_object.c
json_object.h

index df20de15560c3f3220d459d3369f2c5d949eb325..3099c27741cf72ee2968be936ceab51350cc4452 100644 (file)
@@ -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;
+}
+
index 1f45286905e90d6a58e5429a7c2316a31b1eed2a..852de38377fea7bd085fdaa6fdcb754446c2616e 100644 (file)
@@ -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