* 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 * 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 typedef struct _FbJsonValue FbJsonValue; * Represents a JSON value handler. FbJsonValuesPrivate *priv; G_DEFINE_TYPE_WITH_PRIVATE(FbJsonValues, fb_json_values, G_TYPE_OBJECT); fb_json_values_dispose(GObject *obj) 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); if (priv->array != NULL) { json_array_unref(priv->array); if (priv->error != NULL) { g_error_free(priv->error); g_queue_free(priv->queue); fb_json_values_class_init(FbJsonValuesClass *klass) GObjectClass *gklass = G_OBJECT_CLASS(klass); gklass->dispose = fb_json_values_dispose; fb_json_values_init(FbJsonValues *values) FbJsonValuesPrivate *priv = fb_json_values_get_instance_private(values); priv->queue = g_queue_new(); fb_json_error_quark(void) if (G_UNLIKELY(q == 0)) { q = g_quark_from_static_string("fb-json-error-quark"); fb_json_bldr_new(JsonNodeType type) bldr = json_builder_new(); fb_json_bldr_arr_begin(bldr, NULL); fb_json_bldr_obj_begin(bldr, NULL); fb_json_bldr_close(JsonBuilder *bldr, JsonNodeType type, gsize *size) fb_json_bldr_arr_end(bldr); fb_json_bldr_obj_end(bldr); genr = json_generator_new(); root = json_builder_get_root(bldr); json_generator_set_root(genr, root); ret = json_generator_to_data(genr, size); fb_json_bldr_arr_begin(JsonBuilder *bldr, const gchar *name) json_builder_set_member_name(bldr, name); json_builder_begin_array(bldr); fb_json_bldr_arr_end(JsonBuilder *bldr) json_builder_end_array(bldr); fb_json_bldr_obj_begin(JsonBuilder *bldr, const gchar *name) json_builder_set_member_name(bldr, name); json_builder_begin_object(bldr); fb_json_bldr_obj_end(JsonBuilder *bldr) json_builder_end_object(bldr); fb_json_bldr_add_bool(JsonBuilder *bldr, const gchar *name, gboolean value) json_builder_set_member_name(bldr, name); json_builder_add_boolean_value(bldr, value); fb_json_bldr_add_dbl(JsonBuilder *bldr, const gchar *name, gdouble value) json_builder_set_member_name(bldr, name); json_builder_add_double_value(bldr, value); fb_json_bldr_add_int(JsonBuilder *bldr, const gchar *name, gint64 value) json_builder_set_member_name(bldr, name); json_builder_add_int_value(bldr, value); fb_json_bldr_add_str(JsonBuilder *bldr, const gchar *name, const gchar *value) json_builder_set_member_name(bldr, name); json_builder_add_string_value(bldr, value); fb_json_bldr_add_strf(JsonBuilder *bldr, const gchar *name, const gchar *format, ...) value = g_strdup_vprintf(format, ap); fb_json_bldr_add_str(bldr, name, value); fb_json_node_new(const gchar *data, gssize size, GError **error) g_return_val_if_fail(data != NULL, NULL); /* 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)) { root = json_parser_get_root(prsr); root = json_node_copy(root); fb_json_node_get(JsonNode *root, const gchar *expr, GError **error) /* Special case for json-glib < 0.99.2 */ if (purple_strequal(expr, "$")) { return json_node_copy(root); node = json_path_query(expr, root, &err); g_propagate_error(error, err); rslt = json_node_get_array(node); size = json_array_get_length(rslt); g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NOMATCH, _("No matches for %s"), expr); g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_AMBIGUOUS, _("Ambiguous matches for %s"), expr); if (json_array_get_null_element(rslt, 0)) { g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NULL, _("Null value for %s"), expr); ret = json_array_dup_element(rslt, 0); fb_json_node_get_nth(JsonNode *root, guint n) obj = json_node_get_object(root); vals = json_object_get_values(obj); ret = g_list_nth_data(vals, n); fb_json_node_get_arr(JsonNode *root, const gchar *expr, GError **error) rslt = fb_json_node_get(root, expr, error); ret = json_node_dup_array(rslt); fb_json_node_get_bool(JsonNode *root, const gchar *expr, GError **error) rslt = fb_json_node_get(root, expr, error); ret = json_node_get_boolean(rslt); fb_json_node_get_dbl(JsonNode *root, const gchar *expr, GError **error) rslt = fb_json_node_get(root, expr, error); ret = json_node_get_double(rslt); fb_json_node_get_int(JsonNode *root, const gchar *expr, GError **error) rslt = fb_json_node_get(root, expr, error); ret = json_node_get_int(rslt); fb_json_node_get_str(JsonNode *root, const gchar *expr, GError **error) rslt = fb_json_node_get(root, expr, error); ret = json_node_dup_string(rslt); fb_json_values_new(JsonNode *root) FbJsonValuesPrivate *priv; g_return_val_if_fail(root != NULL, NULL); values = g_object_new(FB_TYPE_JSON_VALUES, NULL); fb_json_values_add(FbJsonValues *values, FbJsonType type, gboolean required, FbJsonValuesPrivate *priv; g_return_if_fail(values != NULL); g_return_if_fail(expr != NULL); value = g_new0(FbJsonValue, 1); value->required = required; g_queue_push_tail(priv->queue, value); fb_json_values_get_root(FbJsonValues *values) FbJsonValuesPrivate *priv; g_return_val_if_fail(values != NULL, NULL); if (priv->array == NULL) { g_return_val_if_fail(priv->index > 0, NULL); if (json_array_get_length(priv->array) <= index) { return json_array_get_element(priv->array, index); fb_json_values_set_array(FbJsonValues *values, gboolean required, FbJsonValuesPrivate *priv; g_return_if_fail(values != NULL); priv->array = fb_json_node_get_arr(priv->root, expr, &priv->error); if ((priv->error != NULL) && !required) { g_clear_error(&priv->error); fb_json_values_update(FbJsonValues *values, GError **error) FbJsonValuesPrivate *priv; g_return_val_if_fail(values != NULL, FALSE); if (G_UNLIKELY(priv->error != NULL)) { g_propagate_error(error, priv->error); if ((priv->array == NULL) || (json_array_get_length(priv->array) <= priv->index)) root = json_array_get_element(priv->array, priv->index++); g_return_val_if_fail(root != NULL, FALSE); for (l = priv->queue->head; l != NULL; l = l->next) { node = fb_json_node_get(root, value->expr, &err); if (G_IS_VALUE(&value->value)) { g_value_unset(&value->value); g_propagate_error(error, err); 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), json_node_get_value(node, &value->value); priv->next = priv->queue->head; fb_json_values_next(FbJsonValues *values) FbJsonValuesPrivate *priv; g_return_val_if_fail(values != NULL, NULL); g_return_val_if_fail(priv->next != NULL, NULL); value = priv->next->data; priv->next = priv->next->next; if (!G_IS_VALUE(&value->value)) { fb_json_values_next_bool(FbJsonValues *values, gboolean defval) value = fb_json_values_next(values); if (G_UNLIKELY(value == NULL)) { return g_value_get_boolean(value); fb_json_values_next_dbl(FbJsonValues *values, gdouble defval) value = fb_json_values_next(values); if (G_UNLIKELY(value == NULL)) { return g_value_get_double(value); fb_json_values_next_int(FbJsonValues *values, gint64 defval) value = fb_json_values_next(values); if (G_UNLIKELY(value == NULL)) { return g_value_get_int64(value); fb_json_values_next_str(FbJsonValues *values, const gchar *defval) value = fb_json_values_next(values); if (G_UNLIKELY(value == NULL)) { return g_value_get_string(value); fb_json_values_next_str_dup(FbJsonValues *values, const gchar *defval) value = fb_json_values_next(values); if (G_UNLIKELY(value == NULL)) { return g_value_dup_string(value);