Replace functions which called once with their bodies
[pidgin-git.git] / libpurple / protocols / facebook / json.c
bloba8e50e082265ef05b036e17b769c69ca15bfb7c1
1 /* purple
3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * source distribution.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
22 #include "internal.h"
24 #include <stdarg.h>
25 #include <string.h>
27 #include "json.h"
28 #include "util.h"
30 typedef struct _FbJsonValue FbJsonValue;
32 struct _FbJsonValue
34 const gchar *expr;
35 FbJsonType type;
36 gboolean required;
37 GValue value;
40 typedef struct
42 JsonNode *root;
43 GQueue *queue;
44 GList *next;
46 gboolean isarray;
47 JsonArray *array;
48 guint index;
50 GError *error;
51 } FbJsonValuesPrivate;
53 /**
54 * FbJsonValues:
56 * Represents a JSON value handler.
58 struct _FbJsonValues
60 GObject parent;
61 FbJsonValuesPrivate *priv;
64 G_DEFINE_TYPE_WITH_PRIVATE(FbJsonValues, fb_json_values, G_TYPE_OBJECT);
66 static void
67 fb_json_values_dispose(GObject *obj)
69 FbJsonValue *value;
70 FbJsonValuesPrivate *priv = FB_JSON_VALUES(obj)->priv;
72 while (!g_queue_is_empty(priv->queue)) {
73 value = g_queue_pop_head(priv->queue);
75 if (G_IS_VALUE(&value->value)) {
76 g_value_unset(&value->value);
79 g_free(value);
82 if (priv->array != NULL) {
83 json_array_unref(priv->array);
86 if (priv->error != NULL) {
87 g_error_free(priv->error);
90 g_queue_free(priv->queue);
93 static void
94 fb_json_values_class_init(FbJsonValuesClass *klass)
96 GObjectClass *gklass = G_OBJECT_CLASS(klass);
98 gklass->dispose = fb_json_values_dispose;
101 static void
102 fb_json_values_init(FbJsonValues *values)
104 FbJsonValuesPrivate *priv = fb_json_values_get_instance_private(values);
106 values->priv = priv;
108 priv->queue = g_queue_new();
111 GQuark
112 fb_json_error_quark(void)
114 static GQuark q = 0;
116 if (G_UNLIKELY(q == 0)) {
117 q = g_quark_from_static_string("fb-json-error-quark");
120 return q;
123 JsonBuilder *
124 fb_json_bldr_new(JsonNodeType type)
126 JsonBuilder *bldr;
128 bldr = json_builder_new();
130 switch (type) {
131 case JSON_NODE_ARRAY:
132 fb_json_bldr_arr_begin(bldr, NULL);
133 break;
135 case JSON_NODE_OBJECT:
136 fb_json_bldr_obj_begin(bldr, NULL);
137 break;
139 default:
140 break;
143 return bldr;
146 gchar *
147 fb_json_bldr_close(JsonBuilder *bldr, JsonNodeType type, gsize *size)
149 gchar *ret;
150 JsonGenerator *genr;
151 JsonNode *root;
153 switch (type) {
154 case JSON_NODE_ARRAY:
155 fb_json_bldr_arr_end(bldr);
156 break;
158 case JSON_NODE_OBJECT:
159 fb_json_bldr_obj_end(bldr);
160 break;
162 default:
163 break;
166 genr = json_generator_new();
167 root = json_builder_get_root(bldr);
169 json_generator_set_root(genr, root);
170 ret = json_generator_to_data(genr, size);
172 json_node_free(root);
173 g_object_unref(genr);
174 g_object_unref(bldr);
176 return ret;
179 void
180 fb_json_bldr_arr_begin(JsonBuilder *bldr, const gchar *name)
182 if (name != NULL) {
183 json_builder_set_member_name(bldr, name);
186 json_builder_begin_array(bldr);
189 void
190 fb_json_bldr_arr_end(JsonBuilder *bldr)
192 json_builder_end_array(bldr);
195 void
196 fb_json_bldr_obj_begin(JsonBuilder *bldr, const gchar *name)
198 if (name != NULL) {
199 json_builder_set_member_name(bldr, name);
202 json_builder_begin_object(bldr);
205 void
206 fb_json_bldr_obj_end(JsonBuilder *bldr)
208 json_builder_end_object(bldr);
211 void
212 fb_json_bldr_add_bool(JsonBuilder *bldr, const gchar *name, gboolean value)
214 if (name != NULL) {
215 json_builder_set_member_name(bldr, name);
218 json_builder_add_boolean_value(bldr, value);
221 void
222 fb_json_bldr_add_dbl(JsonBuilder *bldr, const gchar *name, gdouble value)
224 if (name != NULL) {
225 json_builder_set_member_name(bldr, name);
228 json_builder_add_double_value(bldr, value);
231 void
232 fb_json_bldr_add_int(JsonBuilder *bldr, const gchar *name, gint64 value)
234 if (name != NULL) {
235 json_builder_set_member_name(bldr, name);
238 json_builder_add_int_value(bldr, value);
241 void
242 fb_json_bldr_add_str(JsonBuilder *bldr, const gchar *name, const gchar *value)
244 if (name != NULL) {
245 json_builder_set_member_name(bldr, name);
248 json_builder_add_string_value(bldr, value);
251 void
252 fb_json_bldr_add_strf(JsonBuilder *bldr, const gchar *name,
253 const gchar *format, ...)
255 gchar *value;
256 va_list ap;
258 va_start(ap, format);
259 value = g_strdup_vprintf(format, ap);
260 va_end(ap);
262 fb_json_bldr_add_str(bldr, name, value);
263 g_free(value);
266 JsonNode *
267 fb_json_node_new(const gchar *data, gssize size, GError **error)
269 gchar *slice;
270 JsonNode *root;
271 JsonParser *prsr;
273 g_return_val_if_fail(data != NULL, NULL);
275 if (size < 0) {
276 size = strlen(data);
279 /* Ensure data is null terminated for json-glib < 1.0.2 */
280 slice = g_strndup(data, size);
281 prsr = json_parser_new();
283 if (!json_parser_load_from_data(prsr, slice, size, error)) {
284 g_object_unref(prsr);
285 g_free(slice);
286 return NULL;
289 root = json_parser_get_root(prsr);
290 root = json_node_copy(root);
292 g_object_unref(prsr);
293 g_free(slice);
294 return root;
297 JsonNode *
298 fb_json_node_get(JsonNode *root, const gchar *expr, GError **error)
300 GError *err = NULL;
301 guint size;
302 JsonArray *rslt;
303 JsonNode *node;
304 JsonNode *ret;
306 /* Special case for json-glib < 0.99.2 */
307 if (purple_strequal(expr, "$")) {
308 return json_node_copy(root);
311 node = json_path_query(expr, root, &err);
313 if (err != NULL) {
314 g_propagate_error(error, err);
315 json_node_free(node);
316 return NULL;
319 rslt = json_node_get_array(node);
320 size = json_array_get_length(rslt);
322 if (size < 1) {
323 g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NOMATCH,
324 _("No matches for %s"), expr);
325 json_node_free(node);
326 return NULL;
329 if (size > 1) {
330 g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_AMBIGUOUS,
331 _("Ambiguous matches for %s"), expr);
332 json_node_free(node);
333 return NULL;
336 if (json_array_get_null_element(rslt, 0)) {
337 g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NULL,
338 _("Null value for %s"), expr);
339 json_node_free(node);
340 return NULL;
343 ret = json_array_dup_element(rslt, 0);
344 json_node_free(node);
345 return ret;
348 JsonNode *
349 fb_json_node_get_nth(JsonNode *root, guint n)
351 GList *vals;
352 JsonNode *ret;
353 JsonObject *obj;
355 obj = json_node_get_object(root);
356 vals = json_object_get_values(obj);
357 ret = g_list_nth_data(vals, n);
359 g_list_free(vals);
360 return ret;
363 JsonArray *
364 fb_json_node_get_arr(JsonNode *root, const gchar *expr, GError **error)
366 JsonArray *ret;
367 JsonNode *rslt;
369 rslt = fb_json_node_get(root, expr, error);
371 if (rslt == NULL) {
372 return NULL;
375 ret = json_node_dup_array(rslt);
376 json_node_free(rslt);
377 return ret;
380 gboolean
381 fb_json_node_get_bool(JsonNode *root, const gchar *expr, GError **error)
383 gboolean ret;
384 JsonNode *rslt;
386 rslt = fb_json_node_get(root, expr, error);
388 if (rslt == NULL) {
389 return FALSE;
392 ret = json_node_get_boolean(rslt);
393 json_node_free(rslt);
394 return ret;
397 gdouble
398 fb_json_node_get_dbl(JsonNode *root, const gchar *expr, GError **error)
400 gdouble ret;
401 JsonNode *rslt;
403 rslt = fb_json_node_get(root, expr, error);
405 if (rslt == NULL) {
406 return 0.0;
409 ret = json_node_get_double(rslt);
410 json_node_free(rslt);
411 return ret;
414 gint64
415 fb_json_node_get_int(JsonNode *root, const gchar *expr, GError **error)
417 gint64 ret;
418 JsonNode *rslt;
420 rslt = fb_json_node_get(root, expr, error);
422 if (rslt == NULL) {
423 return 0;
426 ret = json_node_get_int(rslt);
427 json_node_free(rslt);
428 return ret;
431 gchar *
432 fb_json_node_get_str(JsonNode *root, const gchar *expr, GError **error)
434 gchar *ret;
435 JsonNode *rslt;
437 rslt = fb_json_node_get(root, expr, error);
439 if (rslt == NULL) {
440 return NULL;
443 ret = json_node_dup_string(rslt);
444 json_node_free(rslt);
445 return ret;
448 FbJsonValues *
449 fb_json_values_new(JsonNode *root)
451 FbJsonValues *values;
452 FbJsonValuesPrivate *priv;
454 g_return_val_if_fail(root != NULL, NULL);
456 values = g_object_new(FB_TYPE_JSON_VALUES, NULL);
457 priv = values->priv;
458 priv->root = root;
460 return values;
463 void
464 fb_json_values_add(FbJsonValues *values, FbJsonType type, gboolean required,
465 const gchar *expr)
467 FbJsonValue *value;
468 FbJsonValuesPrivate *priv;
470 g_return_if_fail(values != NULL);
471 g_return_if_fail(expr != NULL);
472 priv = values->priv;
474 value = g_new0(FbJsonValue, 1);
475 value->expr = expr;
476 value->type = type;
477 value->required = required;
479 g_queue_push_tail(priv->queue, value);
482 JsonNode *
483 fb_json_values_get_root(FbJsonValues *values)
485 FbJsonValuesPrivate *priv;
486 guint index;
488 g_return_val_if_fail(values != NULL, NULL);
489 priv = values->priv;
491 if (priv->array == NULL) {
492 return priv->root;
495 g_return_val_if_fail(priv->index > 0, NULL);
496 index = priv->index - 1;
498 if (json_array_get_length(priv->array) <= index) {
499 return NULL;
502 return json_array_get_element(priv->array, index);
505 void
506 fb_json_values_set_array(FbJsonValues *values, gboolean required,
507 const gchar *expr)
509 FbJsonValuesPrivate *priv;
511 g_return_if_fail(values != NULL);
512 priv = values->priv;
514 priv->array = fb_json_node_get_arr(priv->root, expr, &priv->error);
515 priv->isarray = TRUE;
517 if ((priv->error != NULL) && !required) {
518 g_clear_error(&priv->error);
522 gboolean
523 fb_json_values_update(FbJsonValues *values, GError **error)
525 FbJsonValue *value;
526 FbJsonValuesPrivate *priv;
527 GError *err = NULL;
528 GList *l;
529 GType type;
530 JsonNode *root;
531 JsonNode *node;
533 g_return_val_if_fail(values != NULL, FALSE);
534 priv = values->priv;
536 if (G_UNLIKELY(priv->error != NULL)) {
537 g_propagate_error(error, priv->error);
538 priv->error = NULL;
539 return FALSE;
542 if (priv->isarray) {
543 if ((priv->array == NULL) ||
544 (json_array_get_length(priv->array) <= priv->index))
546 return FALSE;
549 root = json_array_get_element(priv->array, priv->index++);
550 } else {
551 root = priv->root;
554 g_return_val_if_fail(root != NULL, FALSE);
556 for (l = priv->queue->head; l != NULL; l = l->next) {
557 value = l->data;
558 node = fb_json_node_get(root, value->expr, &err);
560 if (G_IS_VALUE(&value->value)) {
561 g_value_unset(&value->value);
564 if (err != NULL) {
565 json_node_free(node);
567 if (value->required) {
568 g_propagate_error(error, err);
569 return FALSE;
572 g_clear_error(&err);
573 continue;
576 type = json_node_get_value_type(node);
578 if (G_UNLIKELY(type != value->type)) {
579 g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_TYPE,
580 _("Expected a %s but got a %s for %s"),
581 g_type_name(value->type),
582 g_type_name(type),
583 value->expr);
584 json_node_free(node);
585 return FALSE;
588 json_node_get_value(node, &value->value);
589 json_node_free(node);
592 priv->next = priv->queue->head;
593 return TRUE;
596 const GValue *
597 fb_json_values_next(FbJsonValues *values)
599 FbJsonValue *value;
600 FbJsonValuesPrivate *priv;
602 g_return_val_if_fail(values != NULL, NULL);
603 priv = values->priv;
605 g_return_val_if_fail(priv->next != NULL, NULL);
606 value = priv->next->data;
607 priv->next = priv->next->next;
609 if (!G_IS_VALUE(&value->value)) {
610 return NULL;
613 return &value->value;
616 gboolean
617 fb_json_values_next_bool(FbJsonValues *values, gboolean defval)
619 const GValue *value;
621 value = fb_json_values_next(values);
623 if (G_UNLIKELY(value == NULL)) {
624 return defval;
627 return g_value_get_boolean(value);
630 gdouble
631 fb_json_values_next_dbl(FbJsonValues *values, gdouble defval)
633 const GValue *value;
635 value = fb_json_values_next(values);
637 if (G_UNLIKELY(value == NULL)) {
638 return defval;
641 return g_value_get_double(value);
644 gint64
645 fb_json_values_next_int(FbJsonValues *values, gint64 defval)
647 const GValue *value;
649 value = fb_json_values_next(values);
651 if (G_UNLIKELY(value == NULL)) {
652 return defval;
655 return g_value_get_int64(value);
658 const gchar *
659 fb_json_values_next_str(FbJsonValues *values, const gchar *defval)
661 const GValue *value;
663 value = fb_json_values_next(values);
665 if (G_UNLIKELY(value == NULL)) {
666 return defval;
669 return g_value_get_string(value);
672 gchar *
673 fb_json_values_next_str_dup(FbJsonValues *values, const gchar *defval)
675 const GValue *value;
677 value = fb_json_values_next(values);
679 if (G_UNLIKELY(value == NULL)) {
680 return g_strdup(defval);
683 return g_value_dup_string(value);