Browse Source

Add obs_data JSON loading/saving functions

jp9000 12 years ago
parent
commit
3cbc711f02
1 changed files with 175 additions and 5 deletions
  1. 175 5
      libobs/obs-data.c

+ 175 - 5
libobs/obs-data.c

@@ -20,6 +20,8 @@
 #include "util/darray.h"
 #include "obs-data.h"
 
+#include <jansson.h>
+
 struct obs_data_item {
 	volatile long        ref;
 	struct obs_data      *parent;
@@ -235,6 +237,154 @@ static inline void obs_data_item_setdata(
 
 /* ------------------------------------------------------------------------- */
 
+static void obs_data_add_json_item(obs_data_t data, const char *key,
+		json_t *json);
+
+static inline void obs_data_add_json_object_data(obs_data_t data, json_t *jobj)
+{
+	const char *item_key;
+	json_t *jitem;
+
+	json_object_foreach (jobj, item_key, jitem) {
+		obs_data_add_json_item(data, item_key, jitem);
+	}
+}
+
+static inline void obs_data_add_json_object(obs_data_t data, const char *key,
+		json_t *jobj)
+{
+	obs_data_t sub_obj = obs_data_create();
+
+	obs_data_add_json_object_data(sub_obj, jobj);
+	obs_data_setobj(data, key, sub_obj);
+	obs_data_release(sub_obj);
+}
+
+static void obs_data_add_json_array(obs_data_t data, const char *key,
+		json_t *jarray)
+{
+	obs_data_array_t array = obs_data_array_create();
+	size_t idx;
+	json_t *jitem;
+
+	json_array_foreach (jarray, idx, jitem) {
+		obs_data_t item;
+
+		if (!json_is_object(jitem))
+			continue;
+
+		item = obs_data_create();
+		obs_data_add_json_object_data(item, jitem);
+		obs_data_array_push_back(array, item);
+		obs_data_release(item);
+	}
+
+	obs_data_setarray(data, key, array);
+	obs_data_array_release(array);
+}
+
+static void obs_data_add_json_item(obs_data_t data, const char *key,
+		json_t *json)
+{
+	if (json_is_object(json))
+		obs_data_add_json_object(data, key, json);
+	else if (json_is_array(json))
+		obs_data_add_json_array(data, key, json);
+	else if (json_is_string(json))
+		obs_data_setstring(data, key, json_string_value(json));
+	else if (json_is_integer(json))
+		obs_data_setint(data, key, json_integer_value(json));
+	else if (json_is_real(json))
+		obs_data_setdouble(data, key, json_real_value(json));
+	else if (json_is_true(json))
+		obs_data_setbool(data, key, true);
+	else if (json_is_false(json))
+		obs_data_setbool(data, key, false);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static inline void set_json_string(json_t *json, const char *name,
+		obs_data_item_t item)
+{
+	const char *val = obs_data_item_getstring(item);
+	json_object_set_new(json, name, json_string(val));
+}
+
+static inline void set_json_number(json_t *json, const char *name,
+		obs_data_item_t item)
+{
+	enum obs_data_number_type type = obs_data_item_numtype(item);
+
+	if (type == OBS_DATA_NUM_INT) {
+		long long val = obs_data_item_getint(item);
+		json_object_set_new(json, name, json_integer(val));
+	} else {
+		double val = obs_data_item_getdouble(item);
+		json_object_set_new(json, name, json_real(val));
+	}
+}
+
+static inline void set_json_bool(json_t *json, const char *name,
+		obs_data_item_t item)
+{
+	bool val = obs_data_item_getbool(item);
+	json_object_set_new(json, name, val ? json_true() : json_false());
+}
+
+static json_t *obs_data_to_json(obs_data_t data);
+
+static inline void set_json_obj(json_t *json, const char *name,
+		obs_data_item_t item)
+{
+	obs_data_t obj = obs_data_item_getobj(item);
+	json_object_set_new(json, name, obs_data_to_json(obj));
+	obs_data_release(obj);
+}
+
+static inline void set_json_array(json_t *json, const char *name,
+		obs_data_item_t item)
+{
+	json_t           *jarray = json_array();
+	obs_data_array_t array   = obs_data_item_getarray(item);
+	size_t           count   = obs_data_array_count(array);
+
+	for (size_t idx = 0; idx < count; idx++) {
+		obs_data_t sub_item = obs_data_array_item(array, idx);
+		json_t     *jitem   = obs_data_to_json(sub_item);
+		json_array_append_new(jarray, jitem);
+	}
+
+	json_object_set_new(json, name, jarray);
+	obs_data_array_release(array);
+}
+
+static json_t *obs_data_to_json(obs_data_t data)
+{
+	json_t *json = json_object();
+	obs_data_item_t item = obs_data_first(data);
+
+	while (item) {
+		enum obs_data_type type = obs_data_item_gettype(item);
+		const char *name        = get_item_name(item);
+
+		if (type == OBS_DATA_STRING)
+			set_json_string(json, name, item);
+		else if (type == OBS_DATA_NUMBER)
+			set_json_number(json, name, item);
+		else if (type == OBS_DATA_BOOLEAN)
+			set_json_bool(json, name, item);
+		else if (type == OBS_DATA_OBJECT)
+			set_json_obj(json, name, item);
+
+		obs_data_item_next(&item);
+	}
+
+	return json;
+}
+
+/* ------------------------------------------------------------------------- */
+
 obs_data_t obs_data_create()
 {
 	struct obs_data *data = bzalloc(sizeof(struct obs_data));
@@ -245,9 +395,21 @@ obs_data_t obs_data_create()
 
 obs_data_t obs_data_create_from_json(const char *json_string)
 {
-	/* TODO */
-	UNUSED_PARAMETER(json_string);
-	return NULL;
+	obs_data_t data = obs_data_create();
+
+	json_error_t error;
+	json_t *root = json_loads(json_string, JSON_REJECT_DUPLICATES, &error);
+
+	if (root) {
+		obs_data_add_json_object_data(data, root);
+		json_decref(root);
+	} else {
+		blog(LOG_ERROR, "obs-data.c: [obs_data_create_from_json] "
+		                "Failed reading json string (%d): %s",
+		                error.line, error.text);
+	}
+
+	return data;
 }
 
 void obs_data_addref(obs_data_t data)
@@ -266,7 +428,8 @@ static inline void obs_data_destroy(struct obs_data *data)
 		item = next;
 	}
 
-	bfree(data->json);
+	/* NOTE: don't use bfree for json text, allocated by json */
+	free(data->json);
 	bfree(data);
 }
 
@@ -282,7 +445,14 @@ const char *obs_data_getjson(obs_data_t data)
 {
 	if (!data) return NULL;
 
-	/* TODO */
+	/* NOTE: don't use libobs bfree for json text */
+	free(data->json);
+	data->json = NULL;
+
+	json_t *root = obs_data_to_json(data);
+	data->json = json_dumps(root, JSON_PRESERVE_ORDER | JSON_INDENT(4));
+	json_decref(root);
+
 	return data->json;
 }