Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dequis/purple-facebook.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pidgin/libpurple/protocols/facebook/json.c')
-rw-r--r--pidgin/libpurple/protocols/facebook/json.c676
1 files changed, 676 insertions, 0 deletions
diff --git a/pidgin/libpurple/protocols/facebook/json.c b/pidgin/libpurple/protocols/facebook/json.c
new file mode 100644
index 0000000..f36839c
--- /dev/null
+++ b/pidgin/libpurple/protocols/facebook/json.c
@@ -0,0 +1,676 @@
+/* purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+
+#include "internal.h"
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "json.h"
+#include "util.h"
+
+typedef struct _FbJsonValue FbJsonValue;
+
+struct _FbJsonValue
+{
+ const gchar *expr;
+ FbJsonType type;
+ gboolean required;
+ GValue value;
+};
+
+struct _FbJsonValuesPrivate
+{
+ JsonNode *root;
+ GQueue *queue;
+ GList *next;
+
+ gboolean isarray;
+ JsonArray *array;
+ guint index;
+
+ GError *error;
+};
+
+G_DEFINE_TYPE(FbJsonValues, fb_json_values, G_TYPE_OBJECT);
+
+static void
+fb_json_values_dispose(GObject *obj)
+{
+ FbJsonValue *value;
+ FbJsonValuesPrivate *priv = FB_JSON_VALUES(obj)->priv;
+
+ while (!g_queue_is_empty(priv->queue)) {
+ value = g_queue_pop_head(priv->queue);
+
+ if (G_IS_VALUE(&value->value)) {
+ g_value_unset(&value->value);
+ }
+
+ g_free(value);
+ }
+
+ if (priv->array != NULL) {
+ json_array_unref(priv->array);
+ }
+
+ if (priv->error != NULL) {
+ g_error_free(priv->error);
+ }
+
+ g_queue_free(priv->queue);
+}
+
+static void
+fb_json_values_class_init(FbJsonValuesClass *klass)
+{
+ GObjectClass *gklass = G_OBJECT_CLASS(klass);
+
+ gklass->dispose = fb_json_values_dispose;
+ g_type_class_add_private(klass, sizeof (FbJsonValuesPrivate));
+}
+
+static void
+fb_json_values_init(FbJsonValues *values)
+{
+ FbJsonValuesPrivate *priv;
+
+ priv = G_TYPE_INSTANCE_GET_PRIVATE(values, FB_TYPE_JSON_VALUES,
+ FbJsonValuesPrivate);
+ values->priv = priv;
+
+ priv->queue = g_queue_new();
+}
+
+GQuark
+fb_json_error_quark(void)
+{
+ static GQuark q = 0;
+
+ if (G_UNLIKELY(q == 0)) {
+ q = g_quark_from_static_string("fb-json-error-quark");
+ }
+
+ return q;
+}
+
+JsonBuilder *
+fb_json_bldr_new(JsonNodeType type)
+{
+ JsonBuilder *bldr;
+
+ bldr = json_builder_new();
+
+ switch (type) {
+ case JSON_NODE_ARRAY:
+ fb_json_bldr_arr_begin(bldr, NULL);
+ break;
+
+ case JSON_NODE_OBJECT:
+ fb_json_bldr_obj_begin(bldr, NULL);
+ break;
+
+ default:
+ break;
+ }
+
+ return bldr;
+}
+
+gchar *
+fb_json_bldr_close(JsonBuilder *bldr, JsonNodeType type, gsize *size)
+{
+ gchar *ret;
+ JsonGenerator *genr;
+ JsonNode *root;
+
+ switch (type) {
+ case JSON_NODE_ARRAY:
+ fb_json_bldr_arr_end(bldr);
+ break;
+
+ case JSON_NODE_OBJECT:
+ fb_json_bldr_obj_end(bldr);
+ break;
+
+ default:
+ break;
+ }
+
+ genr = json_generator_new();
+ root = json_builder_get_root(bldr);
+
+ json_generator_set_root(genr, root);
+ ret = json_generator_to_data(genr, size);
+
+ json_node_free(root);
+ g_object_unref(genr);
+ g_object_unref(bldr);
+
+ return ret;
+}
+
+void
+fb_json_bldr_arr_begin(JsonBuilder *bldr, const gchar *name)
+{
+ if (name != NULL) {
+ json_builder_set_member_name(bldr, name);
+ }
+
+ json_builder_begin_array(bldr);
+}
+
+void
+fb_json_bldr_arr_end(JsonBuilder *bldr)
+{
+ json_builder_end_array(bldr);
+}
+
+void
+fb_json_bldr_obj_begin(JsonBuilder *bldr, const gchar *name)
+{
+ if (name != NULL) {
+ json_builder_set_member_name(bldr, name);
+ }
+
+ json_builder_begin_object(bldr);
+}
+
+void
+fb_json_bldr_obj_end(JsonBuilder *bldr)
+{
+ json_builder_end_object(bldr);
+}
+
+void
+fb_json_bldr_add_bool(JsonBuilder *bldr, const gchar *name, gboolean value)
+{
+ if (name != NULL) {
+ json_builder_set_member_name(bldr, name);
+ }
+
+ json_builder_add_boolean_value(bldr, value);
+}
+
+void
+fb_json_bldr_add_dbl(JsonBuilder *bldr, const gchar *name, gdouble value)
+{
+ if (name != NULL) {
+ json_builder_set_member_name(bldr, name);
+ }
+
+ json_builder_add_double_value(bldr, value);
+}
+
+void
+fb_json_bldr_add_int(JsonBuilder *bldr, const gchar *name, gint64 value)
+{
+ if (name != NULL) {
+ json_builder_set_member_name(bldr, name);
+ }
+
+ json_builder_add_int_value(bldr, value);
+}
+
+void
+fb_json_bldr_add_str(JsonBuilder *bldr, const gchar *name, const gchar *value)
+{
+ if (name != NULL) {
+ json_builder_set_member_name(bldr, name);
+ }
+
+ json_builder_add_string_value(bldr, value);
+}
+
+void
+fb_json_bldr_add_strf(JsonBuilder *bldr, const gchar *name,
+ const gchar *format, ...)
+{
+ gchar *value;
+ va_list ap;
+
+ va_start(ap, format);
+ value = g_strdup_vprintf(format, ap);
+ va_end(ap);
+
+ fb_json_bldr_add_str(bldr, name, value);
+ g_free(value);
+}
+
+JsonNode *
+fb_json_node_new(const gchar *data, gssize size, GError **error)
+{
+ gchar *slice;
+ JsonNode *root;
+ JsonParser *prsr;
+
+ g_return_val_if_fail(data != NULL, NULL);
+
+ if (size < 0) {
+ size = strlen(data);
+ }
+
+ /* Ensure data is null terminated for json-glib < 1.0.2 */
+ slice = g_strndup(data, size);
+ prsr = json_parser_new();
+
+ if (!json_parser_load_from_data(prsr, slice, size, error)) {
+ g_object_unref(prsr);
+ g_free(slice);
+ return NULL;
+ }
+
+ root = json_parser_get_root(prsr);
+ root = json_node_copy(root);
+
+ g_object_unref(prsr);
+ g_free(slice);
+ return root;
+}
+
+JsonNode *
+fb_json_node_get(JsonNode *root, const gchar *expr, GError **error)
+{
+ GError *err = NULL;
+ guint size;
+ JsonArray *rslt;
+ JsonNode *node;
+ JsonNode *ret;
+
+ /* Special case for json-glib < 0.99.2 */
+ if (purple_strequal(expr, "$")) {
+ return json_node_copy(root);
+ }
+
+ node = json_path_query(expr, root, &err);
+
+ if (err != NULL) {
+ g_propagate_error(error, err);
+ json_node_free(node);
+ return NULL;
+ }
+
+ rslt = json_node_get_array(node);
+ size = json_array_get_length(rslt);
+
+ if (size < 1) {
+ g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NOMATCH,
+ _("No matches for %s"), expr);
+ json_node_free(node);
+ return NULL;
+ }
+
+ if (size > 1) {
+ g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_AMBIGUOUS,
+ _("Ambiguous matches for %s"), expr);
+ json_node_free(node);
+ return NULL;
+ }
+
+ if (json_array_get_null_element(rslt, 0)) {
+ g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NULL,
+ _("Null value for %s"), expr);
+ json_node_free(node);
+ return NULL;
+ }
+
+ ret = json_array_dup_element(rslt, 0);
+ json_node_free(node);
+ return ret;
+}
+
+JsonNode *
+fb_json_node_get_nth(JsonNode *root, guint n)
+{
+ GList *vals;
+ JsonNode *ret;
+ JsonObject *obj;
+
+ obj = json_node_get_object(root);
+ vals = json_object_get_values(obj);
+ ret = g_list_nth_data(vals, n);
+
+ g_list_free(vals);
+ return ret;
+}
+
+JsonArray *
+fb_json_node_get_arr(JsonNode *root, const gchar *expr, GError **error)
+{
+ JsonArray *ret;
+ JsonNode *rslt;
+
+ rslt = fb_json_node_get(root, expr, error);
+
+ if (rslt == NULL) {
+ return NULL;
+ }
+
+ ret = json_node_dup_array(rslt);
+ json_node_free(rslt);
+ return ret;
+}
+
+gboolean
+fb_json_node_get_bool(JsonNode *root, const gchar *expr, GError **error)
+{
+ gboolean ret;
+ JsonNode *rslt;
+
+ rslt = fb_json_node_get(root, expr, error);
+
+ if (rslt == NULL) {
+ return FALSE;
+ }
+
+ ret = json_node_get_boolean(rslt);
+ json_node_free(rslt);
+ return ret;
+}
+
+gdouble
+fb_json_node_get_dbl(JsonNode *root, const gchar *expr, GError **error)
+{
+ gdouble ret;
+ JsonNode *rslt;
+
+ rslt = fb_json_node_get(root, expr, error);
+
+ if (rslt == NULL) {
+ return 0.0;
+ }
+
+ ret = json_node_get_double(rslt);
+ json_node_free(rslt);
+ return ret;
+}
+
+gint64
+fb_json_node_get_int(JsonNode *root, const gchar *expr, GError **error)
+{
+ gint64 ret;
+ JsonNode *rslt;
+
+ rslt = fb_json_node_get(root, expr, error);
+
+ if (rslt == NULL) {
+ return 0;
+ }
+
+ ret = json_node_get_int(rslt);
+ json_node_free(rslt);
+ return ret;
+}
+
+gchar *
+fb_json_node_get_str(JsonNode *root, const gchar *expr, GError **error)
+{
+ gchar *ret;
+ JsonNode *rslt;
+
+ rslt = fb_json_node_get(root, expr, error);
+
+ if (rslt == NULL) {
+ return NULL;
+ }
+
+ ret = json_node_dup_string(rslt);
+ json_node_free(rslt);
+ return ret;
+}
+
+FbJsonValues *
+fb_json_values_new(JsonNode *root)
+{
+ FbJsonValues *values;
+ FbJsonValuesPrivate *priv;
+
+ g_return_val_if_fail(root != NULL, NULL);
+
+ values = g_object_new(FB_TYPE_JSON_VALUES, NULL);
+ priv = values->priv;
+ priv->root = root;
+
+ return values;
+}
+
+void
+fb_json_values_add(FbJsonValues *values, FbJsonType type, gboolean required,
+ const gchar *expr)
+{
+ FbJsonValue *value;
+ FbJsonValuesPrivate *priv;
+
+ g_return_if_fail(values != NULL);
+ g_return_if_fail(expr != NULL);
+ priv = values->priv;
+
+ value = g_new0(FbJsonValue, 1);
+ value->expr = expr;
+ value->type = type;
+ value->required = required;
+
+ g_queue_push_tail(priv->queue, value);
+}
+
+JsonNode *
+fb_json_values_get_root(FbJsonValues *values)
+{
+ FbJsonValuesPrivate *priv;
+ guint index;
+
+ g_return_val_if_fail(values != NULL, NULL);
+ priv = values->priv;
+
+ if (priv->array == NULL) {
+ return priv->root;
+ }
+
+ g_return_val_if_fail(priv->index > 0, NULL);
+ index = priv->index - 1;
+
+ if (json_array_get_length(priv->array) <= index) {
+ return NULL;
+ }
+
+ return json_array_get_element(priv->array, index);
+}
+
+void
+fb_json_values_set_array(FbJsonValues *values, gboolean required,
+ const gchar *expr)
+{
+ FbJsonValuesPrivate *priv;
+
+ g_return_if_fail(values != NULL);
+ priv = values->priv;
+
+ priv->array = fb_json_node_get_arr(priv->root, expr, &priv->error);
+ priv->isarray = TRUE;
+
+ if ((priv->error != NULL) && !required) {
+ g_clear_error(&priv->error);
+ }
+}
+
+gboolean
+fb_json_values_update(FbJsonValues *values, GError **error)
+{
+ FbJsonValue *value;
+ FbJsonValuesPrivate *priv;
+ GError *err = NULL;
+ GList *l;
+ GType type;
+ JsonNode *root;
+ JsonNode *node;
+
+ g_return_val_if_fail(values != NULL, FALSE);
+ priv = values->priv;
+
+ if (G_UNLIKELY(priv->error != NULL)) {
+ g_propagate_error(error, priv->error);
+ priv->error = NULL;
+ return FALSE;
+ }
+
+ if (priv->isarray) {
+ if ((priv->array == NULL) ||
+ (json_array_get_length(priv->array) <= priv->index))
+ {
+ return FALSE;
+ }
+
+ root = json_array_get_element(priv->array, priv->index++);
+ } else {
+ root = priv->root;
+ }
+
+ g_return_val_if_fail(root != NULL, FALSE);
+
+ for (l = priv->queue->head; l != NULL; l = l->next) {
+ value = l->data;
+ node = fb_json_node_get(root, value->expr, &err);
+
+ if (G_IS_VALUE(&value->value)) {
+ g_value_unset(&value->value);
+ }
+
+ if (err != NULL) {
+ json_node_free(node);
+
+ if (value->required) {
+ g_propagate_error(error, err);
+ return FALSE;
+ }
+
+ g_clear_error(&err);
+ continue;
+ }
+
+ type = json_node_get_value_type(node);
+
+ if (G_UNLIKELY(type != value->type)) {
+ g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_TYPE,
+ _("Expected a %s but got a %s for %s"),
+ g_type_name(value->type),
+ g_type_name(type),
+ value->expr);
+ json_node_free(node);
+ return FALSE;
+ }
+
+ json_node_get_value(node, &value->value);
+ json_node_free(node);
+ }
+
+ priv->next = priv->queue->head;
+ return TRUE;
+}
+
+const GValue *
+fb_json_values_next(FbJsonValues *values)
+{
+ FbJsonValue *value;
+ FbJsonValuesPrivate *priv;
+
+ g_return_val_if_fail(values != NULL, NULL);
+ priv = values->priv;
+
+ g_return_val_if_fail(priv->next != NULL, NULL);
+ value = priv->next->data;
+ priv->next = priv->next->next;
+
+ if (!G_IS_VALUE(&value->value)) {
+ return NULL;
+ }
+
+ return &value->value;
+}
+
+gboolean
+fb_json_values_next_bool(FbJsonValues *values, gboolean defval)
+{
+ const GValue *value;
+
+ value = fb_json_values_next(values);
+
+ if (G_UNLIKELY(value == NULL)) {
+ return defval;
+ }
+
+ return g_value_get_boolean(value);
+}
+
+gdouble
+fb_json_values_next_dbl(FbJsonValues *values, gdouble defval)
+{
+ const GValue *value;
+
+ value = fb_json_values_next(values);
+
+ if (G_UNLIKELY(value == NULL)) {
+ return defval;
+ }
+
+ return g_value_get_double(value);
+}
+
+gint64
+fb_json_values_next_int(FbJsonValues *values, gint64 defval)
+{
+ const GValue *value;
+
+ value = fb_json_values_next(values);
+
+ if (G_UNLIKELY(value == NULL)) {
+ return defval;
+ }
+
+ return g_value_get_int64(value);
+}
+
+const gchar *
+fb_json_values_next_str(FbJsonValues *values, const gchar *defval)
+{
+ const GValue *value;
+
+ value = fb_json_values_next(values);
+
+ if (G_UNLIKELY(value == NULL)) {
+ return defval;
+ }
+
+ return g_value_get_string(value);
+}
+
+gchar *
+fb_json_values_next_str_dup(FbJsonValues *values, const gchar *defval)
+{
+ const GValue *value;
+
+ value = fb_json_values_next(values);
+
+ if (G_UNLIKELY(value == NULL)) {
+ return g_strdup(defval);
+ }
+
+ return g_value_dup_string(value);
+}