libpurple/protocols/facebook/json.c

changeset 42187
fc241db9162d
parent 42186
637ba5491231
child 42188
04c0398f1046
equal deleted inserted replaced
42186:637ba5491231 42187:fc241db9162d
1 /* purple
2 *
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.
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include <glib/gi18n-lib.h>
23
24 #include <stdarg.h>
25 #include <string.h>
26
27 #include "json.h"
28 #include "util.h"
29
30 typedef struct _FbJsonValue FbJsonValue;
31
32 struct _FbJsonValue
33 {
34 const gchar *expr;
35 FbJsonType type;
36 gboolean required;
37 GValue value;
38 };
39
40 /**
41 * FbJsonValues:
42 *
43 * Represents a JSON value handler.
44 */
45 struct _FbJsonValues
46 {
47 GObject parent;
48
49 JsonNode *root;
50 GQueue *queue;
51 GList *next;
52
53 gboolean isarray;
54 JsonArray *array;
55 guint index;
56
57 GError *error;
58 };
59
60 G_DEFINE_TYPE(FbJsonValues, fb_json_values, G_TYPE_OBJECT);
61
62 static void
63 fb_json_values_dispose(GObject *obj)
64 {
65 FbJsonValues *values = FB_JSON_VALUES(obj);
66
67 if(values->queue != NULL) {
68 while(!g_queue_is_empty(values->queue)) {
69 FbJsonValue *value = g_queue_pop_head(values->queue);
70
71 if(G_IS_VALUE(&value->value)) {
72 g_value_unset(&value->value);
73 }
74
75 g_free(value);
76 }
77 }
78
79 g_clear_pointer(&values->array, json_array_unref);
80 g_clear_error(&values->error);
81 g_clear_pointer(&values->queue, g_queue_free);
82 }
83
84 static void
85 fb_json_values_class_init(FbJsonValuesClass *klass)
86 {
87 GObjectClass *gklass = G_OBJECT_CLASS(klass);
88
89 gklass->dispose = fb_json_values_dispose;
90 }
91
92 static void
93 fb_json_values_init(FbJsonValues *values)
94 {
95 values->queue = g_queue_new();
96 }
97
98 GQuark
99 fb_json_error_quark(void)
100 {
101 static GQuark q = 0;
102
103 if (G_UNLIKELY(q == 0)) {
104 q = g_quark_from_static_string("fb-json-error-quark");
105 }
106
107 return q;
108 }
109
110 JsonBuilder *
111 fb_json_bldr_new(JsonNodeType type)
112 {
113 JsonBuilder *bldr;
114
115 bldr = json_builder_new();
116
117 switch (type) {
118 case JSON_NODE_ARRAY:
119 fb_json_bldr_arr_begin(bldr, NULL);
120 break;
121
122 case JSON_NODE_OBJECT:
123 fb_json_bldr_obj_begin(bldr, NULL);
124 break;
125
126 default:
127 break;
128 }
129
130 return bldr;
131 }
132
133 gchar *
134 fb_json_bldr_close(JsonBuilder *bldr, JsonNodeType type, gsize *size)
135 {
136 gchar *ret;
137 JsonGenerator *genr;
138 JsonNode *root;
139
140 switch (type) {
141 case JSON_NODE_ARRAY:
142 fb_json_bldr_arr_end(bldr);
143 break;
144
145 case JSON_NODE_OBJECT:
146 fb_json_bldr_obj_end(bldr);
147 break;
148
149 default:
150 break;
151 }
152
153 genr = json_generator_new();
154 root = json_builder_get_root(bldr);
155
156 json_generator_set_root(genr, root);
157 ret = json_generator_to_data(genr, size);
158
159 json_node_free(root);
160 g_object_unref(genr);
161 g_object_unref(bldr);
162
163 return ret;
164 }
165
166 void
167 fb_json_bldr_arr_begin(JsonBuilder *bldr, const gchar *name)
168 {
169 if (name != NULL) {
170 json_builder_set_member_name(bldr, name);
171 }
172
173 json_builder_begin_array(bldr);
174 }
175
176 void
177 fb_json_bldr_arr_end(JsonBuilder *bldr)
178 {
179 json_builder_end_array(bldr);
180 }
181
182 void
183 fb_json_bldr_obj_begin(JsonBuilder *bldr, const gchar *name)
184 {
185 if (name != NULL) {
186 json_builder_set_member_name(bldr, name);
187 }
188
189 json_builder_begin_object(bldr);
190 }
191
192 void
193 fb_json_bldr_obj_end(JsonBuilder *bldr)
194 {
195 json_builder_end_object(bldr);
196 }
197
198 void
199 fb_json_bldr_add_bool(JsonBuilder *bldr, const gchar *name, gboolean value)
200 {
201 if (name != NULL) {
202 json_builder_set_member_name(bldr, name);
203 }
204
205 json_builder_add_boolean_value(bldr, value);
206 }
207
208 void
209 fb_json_bldr_add_dbl(JsonBuilder *bldr, const gchar *name, gdouble value)
210 {
211 if (name != NULL) {
212 json_builder_set_member_name(bldr, name);
213 }
214
215 json_builder_add_double_value(bldr, value);
216 }
217
218 void
219 fb_json_bldr_add_int(JsonBuilder *bldr, const gchar *name, gint64 value)
220 {
221 if (name != NULL) {
222 json_builder_set_member_name(bldr, name);
223 }
224
225 json_builder_add_int_value(bldr, value);
226 }
227
228 void
229 fb_json_bldr_add_str(JsonBuilder *bldr, const gchar *name, const gchar *value)
230 {
231 if (name != NULL) {
232 json_builder_set_member_name(bldr, name);
233 }
234
235 json_builder_add_string_value(bldr, value);
236 }
237
238 void
239 fb_json_bldr_add_strf(JsonBuilder *bldr, const gchar *name,
240 const gchar *format, ...)
241 {
242 gchar *value;
243 va_list ap;
244
245 va_start(ap, format);
246 value = g_strdup_vprintf(format, ap);
247 va_end(ap);
248
249 fb_json_bldr_add_str(bldr, name, value);
250 g_free(value);
251 }
252
253 JsonNode *
254 fb_json_node_new(const gchar *data, gssize size, GError **error)
255 {
256 gchar *slice;
257 JsonNode *root;
258 JsonParser *prsr;
259
260 g_return_val_if_fail(data != NULL, NULL);
261
262 if (size < 0) {
263 size = strlen(data);
264 }
265
266 /* Ensure data is null terminated for json-glib < 1.0.2 */
267 slice = g_strndup(data, size);
268 prsr = json_parser_new();
269
270 if (!json_parser_load_from_data(prsr, slice, size, error)) {
271 g_object_unref(prsr);
272 g_free(slice);
273 return NULL;
274 }
275
276 root = json_parser_get_root(prsr);
277 root = json_node_copy(root);
278
279 g_object_unref(prsr);
280 g_free(slice);
281 return root;
282 }
283
284 JsonNode *
285 fb_json_node_get(JsonNode *root, const gchar *expr, GError **error)
286 {
287 GError *err = NULL;
288 guint size;
289 JsonArray *rslt;
290 JsonNode *node;
291 JsonNode *ret;
292
293 /* Special case for json-glib < 0.99.2 */
294 if (purple_strequal(expr, "$")) {
295 return json_node_copy(root);
296 }
297
298 node = json_path_query(expr, root, &err);
299
300 if (err != NULL) {
301 g_propagate_error(error, err);
302 json_node_free(node);
303 return NULL;
304 }
305
306 rslt = json_node_get_array(node);
307 size = json_array_get_length(rslt);
308
309 if (size < 1) {
310 g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NOMATCH,
311 _("No matches for %s"), expr);
312 json_node_free(node);
313 return NULL;
314 }
315
316 if (size > 1) {
317 g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_AMBIGUOUS,
318 _("Ambiguous matches for %s"), expr);
319 json_node_free(node);
320 return NULL;
321 }
322
323 if (json_array_get_null_element(rslt, 0)) {
324 g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_NULL,
325 _("Null value for %s"), expr);
326 json_node_free(node);
327 return NULL;
328 }
329
330 ret = json_array_dup_element(rslt, 0);
331 json_node_free(node);
332 return ret;
333 }
334
335 JsonNode *
336 fb_json_node_get_nth(JsonNode *root, guint n)
337 {
338 GList *vals;
339 JsonNode *ret;
340 JsonObject *obj;
341
342 obj = json_node_get_object(root);
343 vals = json_object_get_values(obj);
344 ret = g_list_nth_data(vals, n);
345
346 g_list_free(vals);
347 return ret;
348 }
349
350 JsonArray *
351 fb_json_node_get_arr(JsonNode *root, const gchar *expr, GError **error)
352 {
353 JsonArray *ret;
354 JsonNode *rslt;
355
356 rslt = fb_json_node_get(root, expr, error);
357
358 if (rslt == NULL) {
359 return NULL;
360 }
361
362 ret = json_node_dup_array(rslt);
363 json_node_free(rslt);
364 return ret;
365 }
366
367 gboolean
368 fb_json_node_get_bool(JsonNode *root, const gchar *expr, GError **error)
369 {
370 gboolean ret;
371 JsonNode *rslt;
372
373 rslt = fb_json_node_get(root, expr, error);
374
375 if (rslt == NULL) {
376 return FALSE;
377 }
378
379 ret = json_node_get_boolean(rslt);
380 json_node_free(rslt);
381 return ret;
382 }
383
384 gdouble
385 fb_json_node_get_dbl(JsonNode *root, const gchar *expr, GError **error)
386 {
387 gdouble ret;
388 JsonNode *rslt;
389
390 rslt = fb_json_node_get(root, expr, error);
391
392 if (rslt == NULL) {
393 return 0.0;
394 }
395
396 ret = json_node_get_double(rslt);
397 json_node_free(rslt);
398 return ret;
399 }
400
401 gint64
402 fb_json_node_get_int(JsonNode *root, const gchar *expr, GError **error)
403 {
404 gint64 ret;
405 JsonNode *rslt;
406
407 rslt = fb_json_node_get(root, expr, error);
408
409 if (rslt == NULL) {
410 return 0;
411 }
412
413 ret = json_node_get_int(rslt);
414 json_node_free(rslt);
415 return ret;
416 }
417
418 gchar *
419 fb_json_node_get_str(JsonNode *root, const gchar *expr, GError **error)
420 {
421 gchar *ret;
422 JsonNode *rslt;
423
424 rslt = fb_json_node_get(root, expr, error);
425
426 if (rslt == NULL) {
427 return NULL;
428 }
429
430 ret = json_node_dup_string(rslt);
431 json_node_free(rslt);
432 return ret;
433 }
434
435 FbJsonValues *
436 fb_json_values_new(JsonNode *root)
437 {
438 FbJsonValues *values;
439
440 g_return_val_if_fail(root != NULL, NULL);
441
442 values = g_object_new(FB_TYPE_JSON_VALUES, NULL);
443 values->root = root;
444
445 return values;
446 }
447
448 void
449 fb_json_values_add(FbJsonValues *values, FbJsonType type, gboolean required,
450 const gchar *expr)
451 {
452 FbJsonValue *value;
453
454 g_return_if_fail(values != NULL);
455 g_return_if_fail(expr != NULL);
456
457 value = g_new0(FbJsonValue, 1);
458 value->expr = expr;
459 value->type = type;
460 value->required = required;
461
462 g_queue_push_tail(values->queue, value);
463 }
464
465 JsonNode *
466 fb_json_values_get_root(FbJsonValues *values)
467 {
468 guint index;
469
470 g_return_val_if_fail(values != NULL, NULL);
471
472 if(values->array == NULL) {
473 return values->root;
474 }
475
476 g_return_val_if_fail(values->index > 0, NULL);
477 index = values->index - 1;
478
479 if(json_array_get_length(values->array) <= index) {
480 return NULL;
481 }
482
483 return json_array_get_element(values->array, index);
484 }
485
486 void
487 fb_json_values_set_array(FbJsonValues *values, gboolean required,
488 const gchar *expr)
489 {
490 g_return_if_fail(values != NULL);
491
492 values->array = fb_json_node_get_arr(values->root, expr, &values->error);
493 values->isarray = TRUE;
494
495 if(!required) {
496 g_clear_error(&values->error);
497 }
498 }
499
500 gboolean
501 fb_json_values_update(FbJsonValues *values, GError **error)
502 {
503 FbJsonValue *value;
504 GError *err = NULL;
505 GList *l;
506 GType type;
507 JsonNode *root;
508 JsonNode *node;
509
510 g_return_val_if_fail(values != NULL, FALSE);
511
512 if(G_UNLIKELY(values->error != NULL)) {
513 g_propagate_error(error, values->error);
514 values->error = NULL;
515 return FALSE;
516 }
517
518 if(values->isarray) {
519 if(values->array == NULL ||
520 json_array_get_length(values->array) <= values->index)
521 {
522 return FALSE;
523 }
524
525 root = json_array_get_element(values->array, values->index++);
526 } else {
527 root = values->root;
528 }
529
530 g_return_val_if_fail(root != NULL, FALSE);
531
532 for(l = values->queue->head; l != NULL; l = l->next) {
533 value = l->data;
534 node = fb_json_node_get(root, value->expr, &err);
535
536 if (G_IS_VALUE(&value->value)) {
537 g_value_unset(&value->value);
538 }
539
540 if (err != NULL) {
541 json_node_free(node);
542
543 if (value->required) {
544 g_propagate_error(error, err);
545 return FALSE;
546 }
547
548 g_clear_error(&err);
549 continue;
550 }
551
552 type = json_node_get_value_type(node);
553
554 if (G_UNLIKELY(type != value->type)) {
555 g_set_error(error, FB_JSON_ERROR, FB_JSON_ERROR_TYPE,
556 _("Expected a %s but got a %s for %s"),
557 g_type_name(value->type),
558 g_type_name(type),
559 value->expr);
560 json_node_free(node);
561 return FALSE;
562 }
563
564 json_node_get_value(node, &value->value);
565 json_node_free(node);
566 }
567
568 values->next = values->queue->head;
569 return TRUE;
570 }
571
572 const GValue *
573 fb_json_values_next(FbJsonValues *values)
574 {
575 FbJsonValue *value;
576
577 g_return_val_if_fail(values != NULL, NULL);
578
579 g_return_val_if_fail(values->next != NULL, NULL);
580 value = values->next->data;
581 values->next = values->next->next;
582
583 if (!G_IS_VALUE(&value->value)) {
584 return NULL;
585 }
586
587 return &value->value;
588 }
589
590 gboolean
591 fb_json_values_next_bool(FbJsonValues *values, gboolean defval)
592 {
593 const GValue *value;
594
595 value = fb_json_values_next(values);
596
597 if (G_UNLIKELY(value == NULL)) {
598 return defval;
599 }
600
601 return g_value_get_boolean(value);
602 }
603
604 gdouble
605 fb_json_values_next_dbl(FbJsonValues *values, gdouble defval)
606 {
607 const GValue *value;
608
609 value = fb_json_values_next(values);
610
611 if (G_UNLIKELY(value == NULL)) {
612 return defval;
613 }
614
615 return g_value_get_double(value);
616 }
617
618 gint64
619 fb_json_values_next_int(FbJsonValues *values, gint64 defval)
620 {
621 const GValue *value;
622
623 value = fb_json_values_next(values);
624
625 if (G_UNLIKELY(value == NULL)) {
626 return defval;
627 }
628
629 return g_value_get_int64(value);
630 }
631
632 const gchar *
633 fb_json_values_next_str(FbJsonValues *values, const gchar *defval)
634 {
635 const GValue *value;
636
637 value = fb_json_values_next(values);
638
639 if (G_UNLIKELY(value == NULL)) {
640 return defval;
641 }
642
643 return g_value_get_string(value);
644 }
645
646 gchar *
647 fb_json_values_next_str_dup(FbJsonValues *values, const gchar *defval)
648 {
649 const GValue *value;
650
651 value = fb_json_values_next(values);
652
653 if (G_UNLIKELY(value == NULL)) {
654 return g_strdup(defval);
655 }
656
657 return g_value_dup_string(value);
658 }

mercurial