Migrate certificates, icons, logs to XDG dirs
[pidgin-git.git] / libpurple / protocols / facebook / json.c
blobf36839c534f80925836559ef40df60e43aabc698
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 struct _FbJsonValuesPrivate
42 JsonNode *root;
43 GQueue *queue;
44 GList *next;
46 gboolean isarray;
47 JsonArray *array;
48 guint index;
50 GError *error;
53 G_DEFINE_TYPE(FbJsonValues, fb_json_values, G_TYPE_OBJECT);
55 static void
56 fb_json_values_dispose(GObject *obj)
58 FbJsonValue *value;
59 FbJsonValuesPrivate *priv = FB_JSON_VALUES(obj)->priv;
61 while (!g_queue_is_empty(priv->queue)) {
62 value = g_queue_pop_head(priv->queue);
64 if (G_IS_VALUE(&value->value)) {
65 g_value_unset(&value->value);
68 g_free(value);
71 if (priv->array != NULL) {
72 json_array_unref(priv->array);
75 if (priv->error != NULL) {
76 g_error_free(priv->error);
79 g_queue_free(priv->queue);
82 static void
83 fb_json_values_class_init(FbJsonValuesClass *klass)
85 GObjectClass *gklass = G_OBJECT_CLASS(klass);
87 gklass->dispose = fb_json_values_dispose;
88 g_type_class_add_private(klass, sizeof (FbJsonValuesPrivate));
91 static void
92 fb_json_values_init(FbJsonValues *values)
94 FbJsonValuesPrivate *priv;
96 priv = G_TYPE_INSTANCE_GET_PRIVATE(values, FB_TYPE_JSON_VALUES,
97 FbJsonValuesPrivate);
98 values->priv = priv;
100 priv->queue = g_queue_new();
103 GQuark
104 fb_json_error_quark(void)
106 static GQuark q = 0;
108 if (G_UNLIKELY(q == 0)) {
109 q = g_quark_from_static_string("fb-json-error-quark");
112 return q;
115 JsonBuilder *
116 fb_json_bldr_new(JsonNodeType type)
118 JsonBuilder *bldr;
120 bldr = json_builder_new();
122 switch (type) {
123 case JSON_NODE_ARRAY:
124 fb_json_bldr_arr_begin(bldr, NULL);
125 break;
127 case JSON_NODE_OBJECT:
128 fb_json_bldr_obj_begin(bldr, NULL);
129 break;
131 default:
132 break;
135 return bldr;
138 gchar *
139 fb_json_bldr_close(JsonBuilder *bldr, JsonNodeType type, gsize *size)
141 gchar *ret;
142 JsonGenerator *genr;
143 JsonNode *root;
145 switch (type) {
146 case JSON_NODE_ARRAY:
147 fb_json_bldr_arr_end(bldr);
148 break;
150 case JSON_NODE_OBJECT:
151 fb_json_bldr_obj_end(bldr);
152 break;
154 default:
155 break;
158 genr = json_generator_new();
159 root = json_builder_get_root(bldr);
161 json_generator_set_root(genr, root);
162 ret = json_generator_to_data(genr, size);
164 json_node_free(root);
165 g_object_unref(genr);
166 g_object_unref(bldr);
168 return ret;
171 void
172 fb_json_bldr_arr_begin(JsonBuilder *bldr, const gchar *name)
174 if (name != NULL) {
175 json_builder_set_member_name(bldr, name);
178 json_builder_begin_array(bldr);
181 void
182 fb_json_bldr_arr_end(JsonBuilder *bldr)
184 json_builder_end_array(bldr);
187 void
188 fb_json_bldr_obj_begin(JsonBuilder *bldr, const gchar *name)
190 if (name != NULL) {
191 json_builder_set_member_name(bldr, name);
194 json_builder_begin_object(bldr);
197 void
198 fb_json_bldr_obj_end(JsonBuilder *bldr)
200 json_builder_end_object(bldr);
203 void
204 fb_json_bldr_add_bool(JsonBuilder *bldr, const gchar *name, gboolean value)
206 if (name != NULL) {
207 json_builder_set_member_name(bldr, name);
210 json_builder_add_boolean_value(bldr, value);
213 void
214 fb_json_bldr_add_dbl(JsonBuilder *bldr, const gchar *name, gdouble value)
216 if (name != NULL) {
217 json_builder_set_member_name(bldr, name);
220 json_builder_add_double_value(bldr, value);
223 void
224 fb_json_bldr_add_int(JsonBuilder *bldr, const gchar *name, gint64 value)
226 if (name != NULL) {
227 json_builder_set_member_name(bldr, name);
230 json_builder_add_int_value(bldr, value);
233 void
234 fb_json_bldr_add_str(JsonBuilder *bldr, const gchar *name, const gchar *value)
236 if (name != NULL) {
237 json_builder_set_member_name(bldr, name);
240 json_builder_add_string_value(bldr, value);
243 void
244 fb_json_bldr_add_strf(JsonBuilder *bldr, const gchar *name,
245 const gchar *format, ...)
247 gchar *value;
248 va_list ap;
250 va_start(ap, format);
251 value = g_strdup_vprintf(format, ap);
252 va_end(ap);
254 fb_json_bldr_add_str(bldr, name, value);
255 g_free(value);
258 JsonNode *
259 fb_json_node_new(const gchar *data, gssize size, GError **error)
261 gchar *slice;
262 JsonNode *root;
263 JsonParser *prsr;
265 g_return_val_if_fail(data != NULL, NULL);
267 if (size < 0) {
268 size = strlen(data);
271 /* Ensure data is null terminated for json-glib < 1.0.2 */
272 slice = g_strndup(data, size);
273 prsr = json_parser_new();
275 if (!json_parser_load_from_data(prsr, slice, size, error)) {
276 g_object_unref(prsr);
277 g_free(slice);
278 return NULL;
281 root = json_parser_get_root(prsr);
282 root = json_node_copy(root);
284 g_object_unref(prsr);
285 g_free(slice);
286 return root;
289 JsonNode *
290 fb_json_node_get(JsonNode *root, const gchar *expr, GError **error)
292 GError *err = NULL;
293 guint size;
294 JsonArray *rslt;
295 JsonNode *node;
296 JsonNode *ret;
298 /* Special case for json-glib < 0.99.2 */
299 if (purple_strequal(expr, "$")) {
300 return json_node_copy(root);
303 node = json_path_query(expr, root, &err);
305 if (err != NULL) {
306 g_propagate_error(error, err);
307 json_node_free(node);
308 return NULL;
311 rslt = json_node_get_array(node);
312 size = json_array_get_length(rslt);
314 if (size < 1) {
315 g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NOMATCH,
316 _("No matches for %s"), expr);
317 json_node_free(node);
318 return NULL;
321 if (size > 1) {
322 g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_AMBIGUOUS,
323 _("Ambiguous matches for %s"), expr);
324 json_node_free(node);
325 return NULL;
328 if (json_array_get_null_element(rslt, 0)) {
329 g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NULL,
330 _("Null value for %s"), expr);
331 json_node_free(node);
332 return NULL;
335 ret = json_array_dup_element(rslt, 0);
336 json_node_free(node);
337 return ret;
340 JsonNode *
341 fb_json_node_get_nth(JsonNode *root, guint n)
343 GList *vals;
344 JsonNode *ret;
345 JsonObject *obj;
347 obj = json_node_get_object(root);
348 vals = json_object_get_values(obj);
349 ret = g_list_nth_data(vals, n);
351 g_list_free(vals);
352 return ret;
355 JsonArray *
356 fb_json_node_get_arr(JsonNode *root, const gchar *expr, GError **error)
358 JsonArray *ret;
359 JsonNode *rslt;
361 rslt = fb_json_node_get(root, expr, error);
363 if (rslt == NULL) {
364 return NULL;
367 ret = json_node_dup_array(rslt);
368 json_node_free(rslt);
369 return ret;
372 gboolean
373 fb_json_node_get_bool(JsonNode *root, const gchar *expr, GError **error)
375 gboolean ret;
376 JsonNode *rslt;
378 rslt = fb_json_node_get(root, expr, error);
380 if (rslt == NULL) {
381 return FALSE;
384 ret = json_node_get_boolean(rslt);
385 json_node_free(rslt);
386 return ret;
389 gdouble
390 fb_json_node_get_dbl(JsonNode *root, const gchar *expr, GError **error)
392 gdouble ret;
393 JsonNode *rslt;
395 rslt = fb_json_node_get(root, expr, error);
397 if (rslt == NULL) {
398 return 0.0;
401 ret = json_node_get_double(rslt);
402 json_node_free(rslt);
403 return ret;
406 gint64
407 fb_json_node_get_int(JsonNode *root, const gchar *expr, GError **error)
409 gint64 ret;
410 JsonNode *rslt;
412 rslt = fb_json_node_get(root, expr, error);
414 if (rslt == NULL) {
415 return 0;
418 ret = json_node_get_int(rslt);
419 json_node_free(rslt);
420 return ret;
423 gchar *
424 fb_json_node_get_str(JsonNode *root, const gchar *expr, GError **error)
426 gchar *ret;
427 JsonNode *rslt;
429 rslt = fb_json_node_get(root, expr, error);
431 if (rslt == NULL) {
432 return NULL;
435 ret = json_node_dup_string(rslt);
436 json_node_free(rslt);
437 return ret;
440 FbJsonValues *
441 fb_json_values_new(JsonNode *root)
443 FbJsonValues *values;
444 FbJsonValuesPrivate *priv;
446 g_return_val_if_fail(root != NULL, NULL);
448 values = g_object_new(FB_TYPE_JSON_VALUES, NULL);
449 priv = values->priv;
450 priv->root = root;
452 return values;
455 void
456 fb_json_values_add(FbJsonValues *values, FbJsonType type, gboolean required,
457 const gchar *expr)
459 FbJsonValue *value;
460 FbJsonValuesPrivate *priv;
462 g_return_if_fail(values != NULL);
463 g_return_if_fail(expr != NULL);
464 priv = values->priv;
466 value = g_new0(FbJsonValue, 1);
467 value->expr = expr;
468 value->type = type;
469 value->required = required;
471 g_queue_push_tail(priv->queue, value);
474 JsonNode *
475 fb_json_values_get_root(FbJsonValues *values)
477 FbJsonValuesPrivate *priv;
478 guint index;
480 g_return_val_if_fail(values != NULL, NULL);
481 priv = values->priv;
483 if (priv->array == NULL) {
484 return priv->root;
487 g_return_val_if_fail(priv->index > 0, NULL);
488 index = priv->index - 1;
490 if (json_array_get_length(priv->array) <= index) {
491 return NULL;
494 return json_array_get_element(priv->array, index);
497 void
498 fb_json_values_set_array(FbJsonValues *values, gboolean required,
499 const gchar *expr)
501 FbJsonValuesPrivate *priv;
503 g_return_if_fail(values != NULL);
504 priv = values->priv;
506 priv->array = fb_json_node_get_arr(priv->root, expr, &priv->error);
507 priv->isarray = TRUE;
509 if ((priv->error != NULL) && !required) {
510 g_clear_error(&priv->error);
514 gboolean
515 fb_json_values_update(FbJsonValues *values, GError **error)
517 FbJsonValue *value;
518 FbJsonValuesPrivate *priv;
519 GError *err = NULL;
520 GList *l;
521 GType type;
522 JsonNode *root;
523 JsonNode *node;
525 g_return_val_if_fail(values != NULL, FALSE);
526 priv = values->priv;
528 if (G_UNLIKELY(priv->error != NULL)) {
529 g_propagate_error(error, priv->error);
530 priv->error = NULL;
531 return FALSE;
534 if (priv->isarray) {
535 if ((priv->array == NULL) ||
536 (json_array_get_length(priv->array) <= priv->index))
538 return FALSE;
541 root = json_array_get_element(priv->array, priv->index++);
542 } else {
543 root = priv->root;
546 g_return_val_if_fail(root != NULL, FALSE);
548 for (l = priv->queue->head; l != NULL; l = l->next) {
549 value = l->data;
550 node = fb_json_node_get(root, value->expr, &err);
552 if (G_IS_VALUE(&value->value)) {
553 g_value_unset(&value->value);
556 if (err != NULL) {
557 json_node_free(node);
559 if (value->required) {
560 g_propagate_error(error, err);
561 return FALSE;
564 g_clear_error(&err);
565 continue;
568 type = json_node_get_value_type(node);
570 if (G_UNLIKELY(type != value->type)) {
571 g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_TYPE,
572 _("Expected a %s but got a %s for %s"),
573 g_type_name(value->type),
574 g_type_name(type),
575 value->expr);
576 json_node_free(node);
577 return FALSE;
580 json_node_get_value(node, &value->value);
581 json_node_free(node);
584 priv->next = priv->queue->head;
585 return TRUE;
588 const GValue *
589 fb_json_values_next(FbJsonValues *values)
591 FbJsonValue *value;
592 FbJsonValuesPrivate *priv;
594 g_return_val_if_fail(values != NULL, NULL);
595 priv = values->priv;
597 g_return_val_if_fail(priv->next != NULL, NULL);
598 value = priv->next->data;
599 priv->next = priv->next->next;
601 if (!G_IS_VALUE(&value->value)) {
602 return NULL;
605 return &value->value;
608 gboolean
609 fb_json_values_next_bool(FbJsonValues *values, gboolean defval)
611 const GValue *value;
613 value = fb_json_values_next(values);
615 if (G_UNLIKELY(value == NULL)) {
616 return defval;
619 return g_value_get_boolean(value);
622 gdouble
623 fb_json_values_next_dbl(FbJsonValues *values, gdouble defval)
625 const GValue *value;
627 value = fb_json_values_next(values);
629 if (G_UNLIKELY(value == NULL)) {
630 return defval;
633 return g_value_get_double(value);
636 gint64
637 fb_json_values_next_int(FbJsonValues *values, gint64 defval)
639 const GValue *value;
641 value = fb_json_values_next(values);
643 if (G_UNLIKELY(value == NULL)) {
644 return defval;
647 return g_value_get_int64(value);
650 const gchar *
651 fb_json_values_next_str(FbJsonValues *values, const gchar *defval)
653 const GValue *value;
655 value = fb_json_values_next(values);
657 if (G_UNLIKELY(value == NULL)) {
658 return defval;
661 return g_value_get_string(value);
664 gchar *
665 fb_json_values_next_str_dup(FbJsonValues *values, const gchar *defval)
667 const GValue *value;
669 value = fb_json_values_next(values);
671 if (G_UNLIKELY(value == NULL)) {
672 return g_strdup(defval);
675 return g_value_dup_string(value);